1
2
3
4
5
6
7
8
9
10
11
12#include <linux/clk.h>
13#include <linux/gpio/driver.h>
14#include <linux/io.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/of_gpio.h>
18#include <linux/pinctrl/consumer.h>
19#include <linux/platform_device.h>
20
21
22#define LPC18XX_REG_DIR(n) (0x2000 + n * sizeof(u32))
23
24#define LPC18XX_MAX_PORTS 8
25#define LPC18XX_PINS_PER_PORT 32
26
27struct lpc18xx_gpio_chip {
28 struct gpio_chip gpio;
29 void __iomem *base;
30 struct clk *clk;
31 spinlock_t lock;
32};
33
34static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
35{
36 struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
37 writeb(value ? 1 : 0, gc->base + offset);
38}
39
40static int lpc18xx_gpio_get(struct gpio_chip *chip, unsigned offset)
41{
42 struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
43 return !!readb(gc->base + offset);
44}
45
46static int lpc18xx_gpio_direction(struct gpio_chip *chip, unsigned offset,
47 bool out)
48{
49 struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
50 unsigned long flags;
51 u32 port, pin, dir;
52
53 port = offset / LPC18XX_PINS_PER_PORT;
54 pin = offset % LPC18XX_PINS_PER_PORT;
55
56 spin_lock_irqsave(&gc->lock, flags);
57 dir = readl(gc->base + LPC18XX_REG_DIR(port));
58 if (out)
59 dir |= BIT(pin);
60 else
61 dir &= ~BIT(pin);
62 writel(dir, gc->base + LPC18XX_REG_DIR(port));
63 spin_unlock_irqrestore(&gc->lock, flags);
64
65 return 0;
66}
67
68static int lpc18xx_gpio_direction_input(struct gpio_chip *chip,
69 unsigned offset)
70{
71 return lpc18xx_gpio_direction(chip, offset, false);
72}
73
74static int lpc18xx_gpio_direction_output(struct gpio_chip *chip,
75 unsigned offset, int value)
76{
77 lpc18xx_gpio_set(chip, offset, value);
78 return lpc18xx_gpio_direction(chip, offset, true);
79}
80
81static const struct gpio_chip lpc18xx_chip = {
82 .label = "lpc18xx/43xx-gpio",
83 .request = gpiochip_generic_request,
84 .free = gpiochip_generic_free,
85 .direction_input = lpc18xx_gpio_direction_input,
86 .direction_output = lpc18xx_gpio_direction_output,
87 .set = lpc18xx_gpio_set,
88 .get = lpc18xx_gpio_get,
89 .ngpio = LPC18XX_MAX_PORTS * LPC18XX_PINS_PER_PORT,
90 .owner = THIS_MODULE,
91};
92
93static int lpc18xx_gpio_probe(struct platform_device *pdev)
94{
95 struct lpc18xx_gpio_chip *gc;
96 struct resource *res;
97 int ret;
98
99 gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
100 if (!gc)
101 return -ENOMEM;
102
103 gc->gpio = lpc18xx_chip;
104 platform_set_drvdata(pdev, gc);
105
106 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
107 gc->base = devm_ioremap_resource(&pdev->dev, res);
108 if (IS_ERR(gc->base))
109 return PTR_ERR(gc->base);
110
111 gc->clk = devm_clk_get(&pdev->dev, NULL);
112 if (IS_ERR(gc->clk)) {
113 dev_err(&pdev->dev, "input clock not found\n");
114 return PTR_ERR(gc->clk);
115 }
116
117 ret = clk_prepare_enable(gc->clk);
118 if (ret) {
119 dev_err(&pdev->dev, "unable to enable clock\n");
120 return ret;
121 }
122
123 spin_lock_init(&gc->lock);
124
125 gc->gpio.parent = &pdev->dev;
126
127 ret = gpiochip_add_data(&gc->gpio, gc);
128 if (ret) {
129 dev_err(&pdev->dev, "failed to add gpio chip\n");
130 clk_disable_unprepare(gc->clk);
131 return ret;
132 }
133
134 return 0;
135}
136
137static int lpc18xx_gpio_remove(struct platform_device *pdev)
138{
139 struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev);
140
141 gpiochip_remove(&gc->gpio);
142 clk_disable_unprepare(gc->clk);
143
144 return 0;
145}
146
147static const struct of_device_id lpc18xx_gpio_match[] = {
148 { .compatible = "nxp,lpc1850-gpio" },
149 { }
150};
151MODULE_DEVICE_TABLE(of, lpc18xx_gpio_match);
152
153static struct platform_driver lpc18xx_gpio_driver = {
154 .probe = lpc18xx_gpio_probe,
155 .remove = lpc18xx_gpio_remove,
156 .driver = {
157 .name = "lpc18xx-gpio",
158 .of_match_table = lpc18xx_gpio_match,
159 },
160};
161module_platform_driver(lpc18xx_gpio_driver);
162
163MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
164MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx");
165MODULE_LICENSE("GPL v2");
166