Manivannan Sadhasivam | d57eb82 | 2019-10-21 12:14:12 +0530 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* |
| 3 | * RDA Micro GPIO driver |
| 4 | * |
| 5 | * Copyright (C) 2012 RDA Micro Inc. |
| 6 | * Copyright (C) 2019 Manivannan Sadhasivam |
| 7 | */ |
| 8 | |
| 9 | #include <linux/bitops.h> |
| 10 | #include <linux/gpio/driver.h> |
| 11 | #include <linux/kernel.h> |
| 12 | #include <linux/module.h> |
| 13 | #include <linux/platform_device.h> |
| 14 | #include <linux/spinlock.h> |
| 15 | |
| 16 | #define RDA_GPIO_OEN_VAL 0x00 |
| 17 | #define RDA_GPIO_OEN_SET_OUT 0x04 |
| 18 | #define RDA_GPIO_OEN_SET_IN 0x08 |
| 19 | #define RDA_GPIO_VAL 0x0c |
| 20 | #define RDA_GPIO_SET 0x10 |
| 21 | #define RDA_GPIO_CLR 0x14 |
| 22 | #define RDA_GPIO_INT_CTRL_SET 0x18 |
| 23 | #define RDA_GPIO_INT_CTRL_CLR 0x1c |
| 24 | #define RDA_GPIO_INT_CLR 0x20 |
| 25 | #define RDA_GPIO_INT_STATUS 0x24 |
| 26 | |
| 27 | #define RDA_GPIO_IRQ_RISE_SHIFT 0 |
| 28 | #define RDA_GPIO_IRQ_FALL_SHIFT 8 |
| 29 | #define RDA_GPIO_DEBOUCE_SHIFT 16 |
| 30 | #define RDA_GPIO_LEVEL_SHIFT 24 |
| 31 | |
| 32 | #define RDA_GPIO_IRQ_MASK 0xff |
| 33 | |
| 34 | /* Each bank consists of 32 GPIOs */ |
| 35 | #define RDA_GPIO_BANK_NR 32 |
| 36 | |
| 37 | struct rda_gpio { |
| 38 | struct gpio_chip chip; |
| 39 | void __iomem *base; |
| 40 | spinlock_t lock; |
| 41 | struct irq_chip irq_chip; |
| 42 | int irq; |
| 43 | }; |
| 44 | |
| 45 | static inline void rda_gpio_update(struct gpio_chip *chip, unsigned int offset, |
| 46 | u16 reg, int val) |
| 47 | { |
| 48 | struct rda_gpio *rda_gpio = gpiochip_get_data(chip); |
| 49 | void __iomem *base = rda_gpio->base; |
| 50 | unsigned long flags; |
| 51 | u32 tmp; |
| 52 | |
| 53 | spin_lock_irqsave(&rda_gpio->lock, flags); |
| 54 | tmp = readl_relaxed(base + reg); |
| 55 | |
| 56 | if (val) |
| 57 | tmp |= BIT(offset); |
| 58 | else |
| 59 | tmp &= ~BIT(offset); |
| 60 | |
| 61 | writel_relaxed(tmp, base + reg); |
| 62 | spin_unlock_irqrestore(&rda_gpio->lock, flags); |
| 63 | } |
| 64 | |
| 65 | static void rda_gpio_irq_mask(struct irq_data *data) |
| 66 | { |
| 67 | struct gpio_chip *chip = irq_data_get_irq_chip_data(data); |
| 68 | struct rda_gpio *rda_gpio = gpiochip_get_data(chip); |
| 69 | void __iomem *base = rda_gpio->base; |
| 70 | u32 offset = irqd_to_hwirq(data); |
| 71 | u32 value; |
| 72 | |
| 73 | value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; |
| 74 | value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; |
| 75 | |
| 76 | writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); |
| 77 | } |
| 78 | |
| 79 | static void rda_gpio_irq_ack(struct irq_data *data) |
| 80 | { |
| 81 | struct gpio_chip *chip = irq_data_get_irq_chip_data(data); |
| 82 | u32 offset = irqd_to_hwirq(data); |
| 83 | |
| 84 | rda_gpio_update(chip, offset, RDA_GPIO_INT_CLR, 1); |
| 85 | } |
| 86 | |
| 87 | static int rda_gpio_set_irq(struct gpio_chip *chip, u32 offset, |
| 88 | unsigned int flow_type) |
| 89 | { |
| 90 | struct rda_gpio *rda_gpio = gpiochip_get_data(chip); |
| 91 | void __iomem *base = rda_gpio->base; |
| 92 | u32 value; |
| 93 | |
| 94 | switch (flow_type) { |
| 95 | case IRQ_TYPE_EDGE_RISING: |
| 96 | /* Set rising edge trigger */ |
| 97 | value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; |
| 98 | writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); |
| 99 | |
| 100 | /* Switch to edge trigger interrupt */ |
| 101 | value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT; |
| 102 | writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); |
| 103 | break; |
| 104 | |
| 105 | case IRQ_TYPE_EDGE_FALLING: |
| 106 | /* Set falling edge trigger */ |
| 107 | value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; |
| 108 | writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); |
| 109 | |
| 110 | /* Switch to edge trigger interrupt */ |
| 111 | value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT; |
| 112 | writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); |
| 113 | break; |
| 114 | |
| 115 | case IRQ_TYPE_EDGE_BOTH: |
| 116 | /* Set both edge trigger */ |
| 117 | value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; |
| 118 | value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; |
| 119 | writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); |
| 120 | |
| 121 | /* Switch to edge trigger interrupt */ |
| 122 | value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT; |
| 123 | writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); |
| 124 | break; |
| 125 | |
| 126 | case IRQ_TYPE_LEVEL_HIGH: |
| 127 | /* Set high level trigger */ |
| 128 | value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; |
| 129 | |
| 130 | /* Switch to level trigger interrupt */ |
| 131 | value |= BIT(offset) << RDA_GPIO_LEVEL_SHIFT; |
| 132 | writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); |
| 133 | break; |
| 134 | |
| 135 | case IRQ_TYPE_LEVEL_LOW: |
| 136 | /* Set low level trigger */ |
| 137 | value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; |
| 138 | |
| 139 | /* Switch to level trigger interrupt */ |
| 140 | value |= BIT(offset) << RDA_GPIO_LEVEL_SHIFT; |
| 141 | writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); |
| 142 | break; |
| 143 | |
| 144 | default: |
| 145 | return -EINVAL; |
| 146 | } |
| 147 | |
| 148 | return 0; |
| 149 | } |
| 150 | |
| 151 | static void rda_gpio_irq_unmask(struct irq_data *data) |
| 152 | { |
| 153 | struct gpio_chip *chip = irq_data_get_irq_chip_data(data); |
| 154 | u32 offset = irqd_to_hwirq(data); |
| 155 | u32 trigger = irqd_get_trigger_type(data); |
| 156 | |
| 157 | rda_gpio_set_irq(chip, offset, trigger); |
| 158 | } |
| 159 | |
| 160 | static int rda_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) |
| 161 | { |
| 162 | struct gpio_chip *chip = irq_data_get_irq_chip_data(data); |
| 163 | u32 offset = irqd_to_hwirq(data); |
| 164 | int ret; |
| 165 | |
| 166 | ret = rda_gpio_set_irq(chip, offset, flow_type); |
| 167 | if (ret) |
| 168 | return ret; |
| 169 | |
| 170 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) |
| 171 | irq_set_handler_locked(data, handle_level_irq); |
| 172 | else if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) |
| 173 | irq_set_handler_locked(data, handle_edge_irq); |
| 174 | |
| 175 | return 0; |
| 176 | } |
| 177 | |
| 178 | static void rda_gpio_irq_handler(struct irq_desc *desc) |
| 179 | { |
| 180 | struct gpio_chip *chip = irq_desc_get_handler_data(desc); |
| 181 | struct irq_chip *ic = irq_desc_get_chip(desc); |
| 182 | struct rda_gpio *rda_gpio = gpiochip_get_data(chip); |
| 183 | unsigned long status; |
Marc Zyngier | dbd1c54 | 2021-05-04 17:42:18 +0100 | [diff] [blame] | 184 | u32 n; |
Manivannan Sadhasivam | d57eb82 | 2019-10-21 12:14:12 +0530 | [diff] [blame] | 185 | |
| 186 | chained_irq_enter(ic, desc); |
| 187 | |
| 188 | status = readl_relaxed(rda_gpio->base + RDA_GPIO_INT_STATUS); |
| 189 | /* Only lower 8 bits are capable of generating interrupts */ |
| 190 | status &= RDA_GPIO_IRQ_MASK; |
| 191 | |
Marc Zyngier | dbd1c54 | 2021-05-04 17:42:18 +0100 | [diff] [blame] | 192 | for_each_set_bit(n, &status, RDA_GPIO_BANK_NR) |
| 193 | generic_handle_domain_irq(chip->irq.domain, n); |
Manivannan Sadhasivam | d57eb82 | 2019-10-21 12:14:12 +0530 | [diff] [blame] | 194 | |
| 195 | chained_irq_exit(ic, desc); |
| 196 | } |
| 197 | |
| 198 | static int rda_gpio_probe(struct platform_device *pdev) |
| 199 | { |
| 200 | struct device_node *np = pdev->dev.of_node; |
| 201 | struct device *dev = &pdev->dev; |
| 202 | struct gpio_irq_chip *girq; |
| 203 | struct rda_gpio *rda_gpio; |
| 204 | u32 ngpios; |
| 205 | int ret; |
| 206 | |
| 207 | rda_gpio = devm_kzalloc(dev, sizeof(*rda_gpio), GFP_KERNEL); |
| 208 | if (!rda_gpio) |
| 209 | return -ENOMEM; |
| 210 | |
| 211 | ret = device_property_read_u32(dev, "ngpios", &ngpios); |
| 212 | if (ret < 0) |
| 213 | return ret; |
| 214 | |
| 215 | /* |
| 216 | * Not all ports have interrupt capability. For instance, on |
| 217 | * RDA8810PL, GPIOC doesn't support interrupt. So we must handle |
| 218 | * those also. |
| 219 | */ |
| 220 | rda_gpio->irq = platform_get_irq(pdev, 0); |
| 221 | |
| 222 | rda_gpio->base = devm_platform_ioremap_resource(pdev, 0); |
| 223 | if (IS_ERR(rda_gpio->base)) |
| 224 | return PTR_ERR(rda_gpio->base); |
| 225 | |
| 226 | spin_lock_init(&rda_gpio->lock); |
| 227 | |
| 228 | ret = bgpio_init(&rda_gpio->chip, dev, 4, |
| 229 | rda_gpio->base + RDA_GPIO_VAL, |
| 230 | rda_gpio->base + RDA_GPIO_SET, |
| 231 | rda_gpio->base + RDA_GPIO_CLR, |
| 232 | rda_gpio->base + RDA_GPIO_OEN_SET_OUT, |
| 233 | rda_gpio->base + RDA_GPIO_OEN_SET_IN, |
| 234 | BGPIOF_READ_OUTPUT_REG_SET); |
| 235 | if (ret) { |
| 236 | dev_err(dev, "bgpio_init failed\n"); |
| 237 | return ret; |
| 238 | } |
| 239 | |
| 240 | rda_gpio->chip.label = dev_name(dev); |
| 241 | rda_gpio->chip.ngpio = ngpios; |
| 242 | rda_gpio->chip.base = -1; |
| 243 | rda_gpio->chip.parent = dev; |
| 244 | rda_gpio->chip.of_node = np; |
| 245 | |
| 246 | if (rda_gpio->irq >= 0) { |
| 247 | rda_gpio->irq_chip.name = "rda-gpio", |
| 248 | rda_gpio->irq_chip.irq_ack = rda_gpio_irq_ack, |
| 249 | rda_gpio->irq_chip.irq_mask = rda_gpio_irq_mask, |
| 250 | rda_gpio->irq_chip.irq_unmask = rda_gpio_irq_unmask, |
| 251 | rda_gpio->irq_chip.irq_set_type = rda_gpio_irq_set_type, |
| 252 | rda_gpio->irq_chip.flags = IRQCHIP_SKIP_SET_WAKE, |
| 253 | |
| 254 | girq = &rda_gpio->chip.irq; |
| 255 | girq->chip = &rda_gpio->irq_chip; |
| 256 | girq->handler = handle_bad_irq; |
| 257 | girq->default_type = IRQ_TYPE_NONE; |
| 258 | girq->parent_handler = rda_gpio_irq_handler; |
| 259 | girq->parent_handler_data = rda_gpio; |
| 260 | girq->num_parents = 1; |
| 261 | girq->parents = devm_kcalloc(dev, 1, |
| 262 | sizeof(*girq->parents), |
| 263 | GFP_KERNEL); |
| 264 | if (!girq->parents) |
| 265 | return -ENOMEM; |
| 266 | girq->parents[0] = rda_gpio->irq; |
| 267 | } |
| 268 | |
| 269 | platform_set_drvdata(pdev, rda_gpio); |
| 270 | |
| 271 | return devm_gpiochip_add_data(dev, &rda_gpio->chip, rda_gpio); |
| 272 | } |
| 273 | |
| 274 | static const struct of_device_id rda_gpio_of_match[] = { |
| 275 | { .compatible = "rda,8810pl-gpio", }, |
| 276 | { /* sentinel */ } |
| 277 | }; |
| 278 | MODULE_DEVICE_TABLE(of, rda_gpio_of_match); |
| 279 | |
| 280 | static struct platform_driver rda_gpio_driver = { |
| 281 | .probe = rda_gpio_probe, |
| 282 | .driver = { |
| 283 | .name = "rda-gpio", |
| 284 | .of_match_table = rda_gpio_of_match, |
| 285 | }, |
| 286 | }; |
| 287 | |
| 288 | module_platform_driver_probe(rda_gpio_driver, rda_gpio_probe); |
| 289 | |
| 290 | MODULE_DESCRIPTION("RDA Micro GPIO driver"); |
| 291 | MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); |
| 292 | MODULE_LICENSE("GPL v2"); |