gpio-lpc18xx.c (985d8d5c76dcdc8f4c8ceea8fae71e4a45a0a200) | gpio-lpc18xx.c (5ddabfe8d3ded5dd5e760bf66ebb4241e5314e8d) |
---|---|
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * GPIO driver for NXP LPC18xx/43xx. 4 * | 1// SPDX-License-Identifier: GPL-2.0 2/* 3 * GPIO driver for NXP LPC18xx/43xx. 4 * |
5 * Copyright (C) 2018 Vladimir Zapolskiy <vz@mleia.com> |
|
5 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> 6 * 7 */ 8 9#include <linux/clk.h> 10#include <linux/gpio/driver.h> 11#include <linux/io.h> | 6 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> 7 * 8 */ 9 10#include <linux/clk.h> 11#include <linux/gpio/driver.h> 12#include <linux/io.h> |
13#include <linux/irqdomain.h> 14#include <linux/irqchip.h> |
|
12#include <linux/module.h> 13#include <linux/of.h> | 15#include <linux/module.h> 16#include <linux/of.h> |
17#include <linux/of_address.h> |
|
14#include <linux/of_gpio.h> | 18#include <linux/of_gpio.h> |
19#include <linux/of_irq.h> |
|
15#include <linux/pinctrl/consumer.h> 16#include <linux/platform_device.h> 17 18/* LPC18xx GPIO register offsets */ 19#define LPC18XX_REG_DIR(n) (0x2000 + n * sizeof(u32)) 20 21#define LPC18XX_MAX_PORTS 8 22#define LPC18XX_PINS_PER_PORT 32 23 | 20#include <linux/pinctrl/consumer.h> 21#include <linux/platform_device.h> 22 23/* LPC18xx GPIO register offsets */ 24#define LPC18XX_REG_DIR(n) (0x2000 + n * sizeof(u32)) 25 26#define LPC18XX_MAX_PORTS 8 27#define LPC18XX_PINS_PER_PORT 32 28 |
29/* LPC18xx GPIO pin interrupt controller register offsets */ 30#define LPC18XX_GPIO_PIN_IC_ISEL 0x00 31#define LPC18XX_GPIO_PIN_IC_IENR 0x04 32#define LPC18XX_GPIO_PIN_IC_SIENR 0x08 33#define LPC18XX_GPIO_PIN_IC_CIENR 0x0c 34#define LPC18XX_GPIO_PIN_IC_IENF 0x10 35#define LPC18XX_GPIO_PIN_IC_SIENF 0x14 36#define LPC18XX_GPIO_PIN_IC_CIENF 0x18 37#define LPC18XX_GPIO_PIN_IC_RISE 0x1c 38#define LPC18XX_GPIO_PIN_IC_FALL 0x20 39#define LPC18XX_GPIO_PIN_IC_IST 0x24 40 41#define NR_LPC18XX_GPIO_PIN_IC_IRQS 8 42 43struct lpc18xx_gpio_pin_ic { 44 void __iomem *base; 45 struct irq_domain *domain; 46 struct raw_spinlock lock; 47}; 48 |
|
24struct lpc18xx_gpio_chip { 25 struct gpio_chip gpio; 26 void __iomem *base; 27 struct clk *clk; | 49struct lpc18xx_gpio_chip { 50 struct gpio_chip gpio; 51 void __iomem *base; 52 struct clk *clk; |
53 struct lpc18xx_gpio_pin_ic *pin_ic; |
|
28 spinlock_t lock; 29}; 30 | 54 spinlock_t lock; 55}; 56 |
57static inline void lpc18xx_gpio_pin_ic_isel(struct lpc18xx_gpio_pin_ic *ic, 58 u32 pin, bool set) 59{ 60 u32 val = readl_relaxed(ic->base + LPC18XX_GPIO_PIN_IC_ISEL); 61 62 if (set) 63 val &= ~BIT(pin); 64 else 65 val |= BIT(pin); 66 67 writel_relaxed(val, ic->base + LPC18XX_GPIO_PIN_IC_ISEL); 68} 69 70static inline void lpc18xx_gpio_pin_ic_set(struct lpc18xx_gpio_pin_ic *ic, 71 u32 pin, u32 reg) 72{ 73 writel_relaxed(BIT(pin), ic->base + reg); 74} 75 76static void lpc18xx_gpio_pin_ic_mask(struct irq_data *d) 77{ 78 struct lpc18xx_gpio_pin_ic *ic = d->chip_data; 79 u32 type = irqd_get_trigger_type(d); 80 81 raw_spin_lock(&ic->lock); 82 83 if (type & IRQ_TYPE_LEVEL_MASK || type & IRQ_TYPE_EDGE_RISING) 84 lpc18xx_gpio_pin_ic_set(ic, d->hwirq, 85 LPC18XX_GPIO_PIN_IC_CIENR); 86 87 if (type & IRQ_TYPE_EDGE_FALLING) 88 lpc18xx_gpio_pin_ic_set(ic, d->hwirq, 89 LPC18XX_GPIO_PIN_IC_CIENF); 90 91 raw_spin_unlock(&ic->lock); 92 93 irq_chip_mask_parent(d); 94} 95 96static void lpc18xx_gpio_pin_ic_unmask(struct irq_data *d) 97{ 98 struct lpc18xx_gpio_pin_ic *ic = d->chip_data; 99 u32 type = irqd_get_trigger_type(d); 100 101 raw_spin_lock(&ic->lock); 102 103 if (type & IRQ_TYPE_LEVEL_MASK || type & IRQ_TYPE_EDGE_RISING) 104 lpc18xx_gpio_pin_ic_set(ic, d->hwirq, 105 LPC18XX_GPIO_PIN_IC_SIENR); 106 107 if (type & IRQ_TYPE_EDGE_FALLING) 108 lpc18xx_gpio_pin_ic_set(ic, d->hwirq, 109 LPC18XX_GPIO_PIN_IC_SIENF); 110 111 raw_spin_unlock(&ic->lock); 112 113 irq_chip_unmask_parent(d); 114} 115 116static void lpc18xx_gpio_pin_ic_eoi(struct irq_data *d) 117{ 118 struct lpc18xx_gpio_pin_ic *ic = d->chip_data; 119 u32 type = irqd_get_trigger_type(d); 120 121 raw_spin_lock(&ic->lock); 122 123 if (type & IRQ_TYPE_EDGE_BOTH) 124 lpc18xx_gpio_pin_ic_set(ic, d->hwirq, 125 LPC18XX_GPIO_PIN_IC_IST); 126 127 raw_spin_unlock(&ic->lock); 128 129 irq_chip_eoi_parent(d); 130} 131 132static int lpc18xx_gpio_pin_ic_set_type(struct irq_data *d, unsigned int type) 133{ 134 struct lpc18xx_gpio_pin_ic *ic = d->chip_data; 135 136 raw_spin_lock(&ic->lock); 137 138 if (type & IRQ_TYPE_LEVEL_HIGH) { 139 lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, true); 140 lpc18xx_gpio_pin_ic_set(ic, d->hwirq, 141 LPC18XX_GPIO_PIN_IC_SIENF); 142 } else if (type & IRQ_TYPE_LEVEL_LOW) { 143 lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, true); 144 lpc18xx_gpio_pin_ic_set(ic, d->hwirq, 145 LPC18XX_GPIO_PIN_IC_CIENF); 146 } else { 147 lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, false); 148 } 149 150 raw_spin_unlock(&ic->lock); 151 152 return 0; 153} 154 155static struct irq_chip lpc18xx_gpio_pin_ic = { 156 .name = "LPC18xx GPIO pin", 157 .irq_mask = lpc18xx_gpio_pin_ic_mask, 158 .irq_unmask = lpc18xx_gpio_pin_ic_unmask, 159 .irq_eoi = lpc18xx_gpio_pin_ic_eoi, 160 .irq_set_type = lpc18xx_gpio_pin_ic_set_type, 161 .irq_retrigger = irq_chip_retrigger_hierarchy, 162 .flags = IRQCHIP_SET_TYPE_MASKED, 163}; 164 165static int lpc18xx_gpio_pin_ic_domain_alloc(struct irq_domain *domain, 166 unsigned int virq, 167 unsigned int nr_irqs, void *data) 168{ 169 struct irq_fwspec parent_fwspec, *fwspec = data; 170 struct lpc18xx_gpio_pin_ic *ic = domain->host_data; 171 irq_hw_number_t hwirq; 172 int ret; 173 174 if (nr_irqs != 1) 175 return -EINVAL; 176 177 hwirq = fwspec->param[0]; 178 if (hwirq >= NR_LPC18XX_GPIO_PIN_IC_IRQS) 179 return -EINVAL; 180 181 /* 182 * All LPC18xx/LPC43xx GPIO pin hardware interrupts are translated 183 * into edge interrupts 32...39 on parent Cortex-M3/M4 NVIC 184 */ 185 parent_fwspec.fwnode = domain->parent->fwnode; 186 parent_fwspec.param_count = 1; 187 parent_fwspec.param[0] = hwirq + 32; 188 189 ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec); 190 if (ret < 0) { 191 pr_err("failed to allocate parent irq %u: %d\n", 192 parent_fwspec.param[0], ret); 193 return ret; 194 } 195 196 return irq_domain_set_hwirq_and_chip(domain, virq, hwirq, 197 &lpc18xx_gpio_pin_ic, ic); 198} 199 200static const struct irq_domain_ops lpc18xx_gpio_pin_ic_domain_ops = { 201 .alloc = lpc18xx_gpio_pin_ic_domain_alloc, 202 .xlate = irq_domain_xlate_twocell, 203 .free = irq_domain_free_irqs_common, 204}; 205 206static int lpc18xx_gpio_pin_ic_probe(struct lpc18xx_gpio_chip *gc) 207{ 208 struct device *dev = gc->gpio.parent; 209 struct irq_domain *parent_domain; 210 struct device_node *parent_node; 211 struct lpc18xx_gpio_pin_ic *ic; 212 struct resource res; 213 int ret, index; 214 215 parent_node = of_irq_find_parent(dev->of_node); 216 if (!parent_node) 217 return -ENXIO; 218 219 parent_domain = irq_find_host(parent_node); 220 of_node_put(parent_node); 221 if (!parent_domain) 222 return -ENXIO; 223 224 ic = devm_kzalloc(dev, sizeof(*ic), GFP_KERNEL); 225 if (!ic) 226 return -ENOMEM; 227 228 index = of_property_match_string(dev->of_node, "reg-names", 229 "gpio-pin-ic"); 230 if (index < 0) { 231 ret = -ENODEV; 232 goto free_ic; 233 } 234 235 ret = of_address_to_resource(dev->of_node, index, &res); 236 if (ret < 0) 237 goto free_ic; 238 239 ic->base = devm_ioremap_resource(dev, &res); 240 if (IS_ERR(ic->base)) { 241 ret = PTR_ERR(ic->base); 242 goto free_ic; 243 } 244 245 raw_spin_lock_init(&ic->lock); 246 247 ic->domain = irq_domain_add_hierarchy(parent_domain, 0, 248 NR_LPC18XX_GPIO_PIN_IC_IRQS, 249 dev->of_node, 250 &lpc18xx_gpio_pin_ic_domain_ops, 251 ic); 252 if (!ic->domain) { 253 pr_err("unable to add irq domain\n"); 254 ret = -ENODEV; 255 goto free_iomap; 256 } 257 258 gc->pin_ic = ic; 259 260 return 0; 261 262free_iomap: 263 devm_iounmap(dev, ic->base); 264free_ic: 265 devm_kfree(dev, ic); 266 267 return ret; 268} 269 |
|
31static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 32{ 33 struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip); 34 writeb(value ? 1 : 0, gc->base + offset); 35} 36 37static int lpc18xx_gpio_get(struct gpio_chip *chip, unsigned offset) 38{ --- 47 unchanged lines hidden (view full) --- 86 .ngpio = LPC18XX_MAX_PORTS * LPC18XX_PINS_PER_PORT, 87 .owner = THIS_MODULE, 88}; 89 90static int lpc18xx_gpio_probe(struct platform_device *pdev) 91{ 92 struct device *dev = &pdev->dev; 93 struct lpc18xx_gpio_chip *gc; | 270static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 271{ 272 struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip); 273 writeb(value ? 1 : 0, gc->base + offset); 274} 275 276static int lpc18xx_gpio_get(struct gpio_chip *chip, unsigned offset) 277{ --- 47 unchanged lines hidden (view full) --- 325 .ngpio = LPC18XX_MAX_PORTS * LPC18XX_PINS_PER_PORT, 326 .owner = THIS_MODULE, 327}; 328 329static int lpc18xx_gpio_probe(struct platform_device *pdev) 330{ 331 struct device *dev = &pdev->dev; 332 struct lpc18xx_gpio_chip *gc; |
94 struct resource *res; 95 int ret; | 333 int index, ret; |
96 97 gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL); 98 if (!gc) 99 return -ENOMEM; 100 101 gc->gpio = lpc18xx_chip; 102 platform_set_drvdata(pdev, gc); 103 | 334 335 gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL); 336 if (!gc) 337 return -ENOMEM; 338 339 gc->gpio = lpc18xx_chip; 340 platform_set_drvdata(pdev, gc); 341 |
104 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 105 gc->base = devm_ioremap_resource(dev, res); | 342 index = of_property_match_string(dev->of_node, "reg-names", "gpio"); 343 if (index < 0) { 344 /* To support backward compatibility take the first resource */ 345 struct resource *res; 346 347 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 348 gc->base = devm_ioremap_resource(dev, res); 349 } else { 350 struct resource res; 351 352 ret = of_address_to_resource(dev->of_node, index, &res); 353 if (ret < 0) 354 return ret; 355 356 gc->base = devm_ioremap_resource(dev, &res); 357 } |
106 if (IS_ERR(gc->base)) 107 return PTR_ERR(gc->base); 108 109 gc->clk = devm_clk_get(dev, NULL); 110 if (IS_ERR(gc->clk)) { 111 dev_err(dev, "input clock not found\n"); 112 return PTR_ERR(gc->clk); 113 } --- 10 unchanged lines hidden (view full) --- 124 125 ret = devm_gpiochip_add_data(dev, &gc->gpio, gc); 126 if (ret) { 127 dev_err(dev, "failed to add gpio chip\n"); 128 clk_disable_unprepare(gc->clk); 129 return ret; 130 } 131 | 358 if (IS_ERR(gc->base)) 359 return PTR_ERR(gc->base); 360 361 gc->clk = devm_clk_get(dev, NULL); 362 if (IS_ERR(gc->clk)) { 363 dev_err(dev, "input clock not found\n"); 364 return PTR_ERR(gc->clk); 365 } --- 10 unchanged lines hidden (view full) --- 376 377 ret = devm_gpiochip_add_data(dev, &gc->gpio, gc); 378 if (ret) { 379 dev_err(dev, "failed to add gpio chip\n"); 380 clk_disable_unprepare(gc->clk); 381 return ret; 382 } 383 |
384 /* On error GPIO pin interrupt controller just won't be registered */ 385 lpc18xx_gpio_pin_ic_probe(gc); 386 |
|
132 return 0; 133} 134 135static int lpc18xx_gpio_remove(struct platform_device *pdev) 136{ 137 struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev); 138 | 387 return 0; 388} 389 390static int lpc18xx_gpio_remove(struct platform_device *pdev) 391{ 392 struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev); 393 |
394 if (gc->pin_ic) 395 irq_domain_remove(gc->pin_ic->domain); 396 |
|
139 clk_disable_unprepare(gc->clk); 140 141 return 0; 142} 143 144static const struct of_device_id lpc18xx_gpio_match[] = { 145 { .compatible = "nxp,lpc1850-gpio" }, 146 { } --- 6 unchanged lines hidden (view full) --- 153 .driver = { 154 .name = "lpc18xx-gpio", 155 .of_match_table = lpc18xx_gpio_match, 156 }, 157}; 158module_platform_driver(lpc18xx_gpio_driver); 159 160MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); | 397 clk_disable_unprepare(gc->clk); 398 399 return 0; 400} 401 402static const struct of_device_id lpc18xx_gpio_match[] = { 403 { .compatible = "nxp,lpc1850-gpio" }, 404 { } --- 6 unchanged lines hidden (view full) --- 411 .driver = { 412 .name = "lpc18xx-gpio", 413 .of_match_table = lpc18xx_gpio_match, 414 }, 415}; 416module_platform_driver(lpc18xx_gpio_driver); 417 418MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); |
419MODULE_AUTHOR("Vladimir Zapolskiy <vz@mleia.com>"); |
|
161MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx"); 162MODULE_LICENSE("GPL v2"); | 420MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx"); 421MODULE_LICENSE("GPL v2"); |