1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Toshiba Visconti GPIO Support 4 * 5 * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation 6 * (C) Copyright 2020 TOSHIBA CORPORATION 7 * 8 * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp> 9 */ 10 11 #include <linux/bitops.h> 12 #include <linux/gpio/driver.h> 13 #include <linux/init.h> 14 #include <linux/interrupt.h> 15 #include <linux/module.h> 16 #include <linux/io.h> 17 #include <linux/of_irq.h> 18 #include <linux/platform_device.h> 19 #include <linux/property.h> 20 #include <linux/seq_file.h> 21 22 /* register offset */ 23 #define GPIO_DIR 0x00 24 #define GPIO_IDATA 0x08 25 #define GPIO_ODATA 0x10 26 #define GPIO_OSET 0x18 27 #define GPIO_OCLR 0x20 28 #define GPIO_INTMODE 0x30 29 30 #define BASE_HW_IRQ 24 31 32 struct visconti_gpio { 33 void __iomem *base; 34 spinlock_t lock; /* protect gpio register */ 35 struct gpio_chip gpio_chip; 36 struct device *dev; 37 }; 38 39 static int visconti_gpio_irq_set_type(struct irq_data *d, unsigned int type) 40 { 41 struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 42 struct visconti_gpio *priv = gpiochip_get_data(gc); 43 u32 offset = irqd_to_hwirq(d); 44 u32 bit = BIT(offset); 45 u32 intc_type = IRQ_TYPE_EDGE_RISING; 46 u32 intmode, odata; 47 int ret = 0; 48 unsigned long flags; 49 50 spin_lock_irqsave(&priv->lock, flags); 51 52 odata = readl(priv->base + GPIO_ODATA); 53 intmode = readl(priv->base + GPIO_INTMODE); 54 55 switch (type) { 56 case IRQ_TYPE_EDGE_RISING: 57 odata &= ~bit; 58 intmode &= ~bit; 59 break; 60 case IRQ_TYPE_EDGE_FALLING: 61 odata |= bit; 62 intmode &= ~bit; 63 break; 64 case IRQ_TYPE_EDGE_BOTH: 65 intmode |= bit; 66 break; 67 case IRQ_TYPE_LEVEL_HIGH: 68 intc_type = IRQ_TYPE_LEVEL_HIGH; 69 odata &= ~bit; 70 intmode &= ~bit; 71 break; 72 case IRQ_TYPE_LEVEL_LOW: 73 intc_type = IRQ_TYPE_LEVEL_HIGH; 74 odata |= bit; 75 intmode &= ~bit; 76 break; 77 default: 78 ret = -EINVAL; 79 goto err; 80 } 81 82 writel(odata, priv->base + GPIO_ODATA); 83 writel(intmode, priv->base + GPIO_INTMODE); 84 irq_set_irq_type(offset, intc_type); 85 86 ret = irq_chip_set_type_parent(d, type); 87 err: 88 spin_unlock_irqrestore(&priv->lock, flags); 89 return ret; 90 } 91 92 static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip *gc, 93 unsigned int child, 94 unsigned int child_type, 95 unsigned int *parent, 96 unsigned int *parent_type) 97 { 98 /* Interrupts 0..15 mapped to interrupts 24..39 on the GIC */ 99 if (child < 16) { 100 /* All these interrupts are level high in the CPU */ 101 *parent_type = IRQ_TYPE_LEVEL_HIGH; 102 *parent = child + BASE_HW_IRQ; 103 return 0; 104 } 105 return -EINVAL; 106 } 107 108 static int visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip, 109 union gpio_irq_fwspec *gfwspec, 110 unsigned int parent_hwirq, 111 unsigned int parent_type) 112 { 113 struct irq_fwspec *fwspec = &gfwspec->fwspec; 114 115 fwspec->fwnode = chip->irq.parent_domain->fwnode; 116 fwspec->param_count = 3; 117 fwspec->param[0] = 0; 118 fwspec->param[1] = parent_hwirq; 119 fwspec->param[2] = parent_type; 120 121 return 0; 122 } 123 124 static void visconti_gpio_mask_irq(struct irq_data *d) 125 { 126 struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 127 128 irq_chip_mask_parent(d); 129 gpiochip_disable_irq(gc, irqd_to_hwirq(d)); 130 } 131 132 static void visconti_gpio_unmask_irq(struct irq_data *d) 133 { 134 struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 135 136 gpiochip_enable_irq(gc, irqd_to_hwirq(d)); 137 irq_chip_unmask_parent(d); 138 } 139 140 static void visconti_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) 141 { 142 struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 143 struct visconti_gpio *priv = gpiochip_get_data(gc); 144 145 seq_printf(p, dev_name(priv->dev)); 146 } 147 148 static const struct irq_chip visconti_gpio_irq_chip = { 149 .irq_mask = visconti_gpio_mask_irq, 150 .irq_unmask = visconti_gpio_unmask_irq, 151 .irq_eoi = irq_chip_eoi_parent, 152 .irq_set_type = visconti_gpio_irq_set_type, 153 .irq_print_chip = visconti_gpio_irq_print_chip, 154 .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND | 155 IRQCHIP_IMMUTABLE, 156 GPIOCHIP_IRQ_RESOURCE_HELPERS, 157 }; 158 159 static int visconti_gpio_probe(struct platform_device *pdev) 160 { 161 struct device *dev = &pdev->dev; 162 struct visconti_gpio *priv; 163 struct gpio_irq_chip *girq; 164 struct irq_domain *parent; 165 struct device_node *irq_parent; 166 int ret; 167 168 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 169 if (!priv) 170 return -ENOMEM; 171 172 spin_lock_init(&priv->lock); 173 priv->dev = dev; 174 175 priv->base = devm_platform_ioremap_resource(pdev, 0); 176 if (IS_ERR(priv->base)) 177 return PTR_ERR(priv->base); 178 179 irq_parent = of_irq_find_parent(dev->of_node); 180 if (!irq_parent) { 181 dev_err(dev, "No IRQ parent node\n"); 182 return -ENODEV; 183 } 184 185 parent = irq_find_host(irq_parent); 186 of_node_put(irq_parent); 187 if (!parent) { 188 dev_err(dev, "No IRQ parent domain\n"); 189 return -ENODEV; 190 } 191 192 ret = bgpio_init(&priv->gpio_chip, dev, 4, 193 priv->base + GPIO_IDATA, 194 priv->base + GPIO_OSET, 195 priv->base + GPIO_OCLR, 196 priv->base + GPIO_DIR, 197 NULL, 198 0); 199 if (ret) { 200 dev_err(dev, "unable to init generic GPIO\n"); 201 return ret; 202 } 203 204 girq = &priv->gpio_chip.irq; 205 gpio_irq_chip_set_chip(girq, &visconti_gpio_irq_chip); 206 girq->fwnode = dev_fwnode(dev); 207 girq->parent_domain = parent; 208 girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq; 209 girq->populate_parent_alloc_arg = visconti_gpio_populate_parent_fwspec; 210 girq->default_type = IRQ_TYPE_NONE; 211 girq->handler = handle_level_irq; 212 213 return devm_gpiochip_add_data(dev, &priv->gpio_chip, priv); 214 } 215 216 static const struct of_device_id visconti_gpio_of_match[] = { 217 { .compatible = "toshiba,gpio-tmpv7708", }, 218 { /* end of table */ } 219 }; 220 MODULE_DEVICE_TABLE(of, visconti_gpio_of_match); 221 222 static struct platform_driver visconti_gpio_driver = { 223 .probe = visconti_gpio_probe, 224 .driver = { 225 .name = "visconti_gpio", 226 .of_match_table = visconti_gpio_of_match, 227 } 228 }; 229 module_platform_driver(visconti_gpio_driver); 230 231 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>"); 232 MODULE_DESCRIPTION("Toshiba Visconti GPIO Driver"); 233 MODULE_LICENSE("GPL v2"); 234