Commit | Line | Data |
---|---|---|
d57eb825 MS |
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; | |
d57eb825 MS |
41 | int irq; |
42 | }; | |
43 | ||
44 | static inline void rda_gpio_update(struct gpio_chip *chip, unsigned int offset, | |
45 | u16 reg, int val) | |
46 | { | |
47 | struct rda_gpio *rda_gpio = gpiochip_get_data(chip); | |
48 | void __iomem *base = rda_gpio->base; | |
49 | unsigned long flags; | |
50 | u32 tmp; | |
51 | ||
52 | spin_lock_irqsave(&rda_gpio->lock, flags); | |
53 | tmp = readl_relaxed(base + reg); | |
54 | ||
55 | if (val) | |
56 | tmp |= BIT(offset); | |
57 | else | |
58 | tmp &= ~BIT(offset); | |
59 | ||
60 | writel_relaxed(tmp, base + reg); | |
61 | spin_unlock_irqrestore(&rda_gpio->lock, flags); | |
62 | } | |
63 | ||
64 | static void rda_gpio_irq_mask(struct irq_data *data) | |
65 | { | |
66 | struct gpio_chip *chip = irq_data_get_irq_chip_data(data); | |
67 | struct rda_gpio *rda_gpio = gpiochip_get_data(chip); | |
68 | void __iomem *base = rda_gpio->base; | |
69 | u32 offset = irqd_to_hwirq(data); | |
70 | u32 value; | |
71 | ||
72 | value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; | |
73 | value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; | |
74 | ||
75 | writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); | |
957e64be | 76 | gpiochip_disable_irq(chip, offset); |
d57eb825 MS |
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 | ||
957e64be | 157 | gpiochip_enable_irq(chip, offset); |
d57eb825 MS |
158 | rda_gpio_set_irq(chip, offset, trigger); |
159 | } | |
160 | ||
161 | static int rda_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) | |
162 | { | |
163 | struct gpio_chip *chip = irq_data_get_irq_chip_data(data); | |
164 | u32 offset = irqd_to_hwirq(data); | |
165 | int ret; | |
166 | ||
167 | ret = rda_gpio_set_irq(chip, offset, flow_type); | |
168 | if (ret) | |
169 | return ret; | |
170 | ||
171 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) | |
172 | irq_set_handler_locked(data, handle_level_irq); | |
173 | else if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) | |
174 | irq_set_handler_locked(data, handle_edge_irq); | |
175 | ||
176 | return 0; | |
177 | } | |
178 | ||
179 | static void rda_gpio_irq_handler(struct irq_desc *desc) | |
180 | { | |
181 | struct gpio_chip *chip = irq_desc_get_handler_data(desc); | |
182 | struct irq_chip *ic = irq_desc_get_chip(desc); | |
183 | struct rda_gpio *rda_gpio = gpiochip_get_data(chip); | |
184 | unsigned long status; | |
dbd1c54f | 185 | u32 n; |
d57eb825 MS |
186 | |
187 | chained_irq_enter(ic, desc); | |
188 | ||
189 | status = readl_relaxed(rda_gpio->base + RDA_GPIO_INT_STATUS); | |
190 | /* Only lower 8 bits are capable of generating interrupts */ | |
191 | status &= RDA_GPIO_IRQ_MASK; | |
192 | ||
dbd1c54f MZ |
193 | for_each_set_bit(n, &status, RDA_GPIO_BANK_NR) |
194 | generic_handle_domain_irq(chip->irq.domain, n); | |
d57eb825 MS |
195 | |
196 | chained_irq_exit(ic, desc); | |
197 | } | |
198 | ||
957e64be LW |
199 | static const struct irq_chip rda_gpio_irq_chip = { |
200 | .name = "rda-gpio", | |
201 | .irq_ack = rda_gpio_irq_ack, | |
202 | .irq_mask = rda_gpio_irq_mask, | |
203 | .irq_unmask = rda_gpio_irq_unmask, | |
204 | .irq_set_type = rda_gpio_irq_set_type, | |
205 | .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, | |
206 | GPIOCHIP_IRQ_RESOURCE_HELPERS, | |
207 | }; | |
208 | ||
d57eb825 MS |
209 | static int rda_gpio_probe(struct platform_device *pdev) |
210 | { | |
d57eb825 MS |
211 | struct device *dev = &pdev->dev; |
212 | struct gpio_irq_chip *girq; | |
213 | struct rda_gpio *rda_gpio; | |
214 | u32 ngpios; | |
215 | int ret; | |
216 | ||
217 | rda_gpio = devm_kzalloc(dev, sizeof(*rda_gpio), GFP_KERNEL); | |
218 | if (!rda_gpio) | |
219 | return -ENOMEM; | |
220 | ||
221 | ret = device_property_read_u32(dev, "ngpios", &ngpios); | |
222 | if (ret < 0) | |
223 | return ret; | |
224 | ||
225 | /* | |
226 | * Not all ports have interrupt capability. For instance, on | |
227 | * RDA8810PL, GPIOC doesn't support interrupt. So we must handle | |
228 | * those also. | |
229 | */ | |
230 | rda_gpio->irq = platform_get_irq(pdev, 0); | |
231 | ||
232 | rda_gpio->base = devm_platform_ioremap_resource(pdev, 0); | |
233 | if (IS_ERR(rda_gpio->base)) | |
234 | return PTR_ERR(rda_gpio->base); | |
235 | ||
236 | spin_lock_init(&rda_gpio->lock); | |
237 | ||
238 | ret = bgpio_init(&rda_gpio->chip, dev, 4, | |
239 | rda_gpio->base + RDA_GPIO_VAL, | |
240 | rda_gpio->base + RDA_GPIO_SET, | |
241 | rda_gpio->base + RDA_GPIO_CLR, | |
242 | rda_gpio->base + RDA_GPIO_OEN_SET_OUT, | |
243 | rda_gpio->base + RDA_GPIO_OEN_SET_IN, | |
244 | BGPIOF_READ_OUTPUT_REG_SET); | |
245 | if (ret) { | |
246 | dev_err(dev, "bgpio_init failed\n"); | |
247 | return ret; | |
248 | } | |
249 | ||
250 | rda_gpio->chip.label = dev_name(dev); | |
251 | rda_gpio->chip.ngpio = ngpios; | |
252 | rda_gpio->chip.base = -1; | |
d57eb825 MS |
253 | |
254 | if (rda_gpio->irq >= 0) { | |
d57eb825 | 255 | girq = &rda_gpio->chip.irq; |
957e64be | 256 | gpio_irq_chip_set_chip(girq, &rda_gpio_irq_chip); |
d57eb825 MS |
257 | girq->handler = handle_bad_irq; |
258 | girq->default_type = IRQ_TYPE_NONE; | |
259 | girq->parent_handler = rda_gpio_irq_handler; | |
260 | girq->parent_handler_data = rda_gpio; | |
261 | girq->num_parents = 1; | |
262 | girq->parents = devm_kcalloc(dev, 1, | |
263 | sizeof(*girq->parents), | |
264 | GFP_KERNEL); | |
265 | if (!girq->parents) | |
266 | return -ENOMEM; | |
267 | girq->parents[0] = rda_gpio->irq; | |
268 | } | |
269 | ||
270 | platform_set_drvdata(pdev, rda_gpio); | |
271 | ||
272 | return devm_gpiochip_add_data(dev, &rda_gpio->chip, rda_gpio); | |
273 | } | |
274 | ||
275 | static const struct of_device_id rda_gpio_of_match[] = { | |
276 | { .compatible = "rda,8810pl-gpio", }, | |
277 | { /* sentinel */ } | |
278 | }; | |
279 | MODULE_DEVICE_TABLE(of, rda_gpio_of_match); | |
280 | ||
281 | static struct platform_driver rda_gpio_driver = { | |
282 | .probe = rda_gpio_probe, | |
283 | .driver = { | |
284 | .name = "rda-gpio", | |
285 | .of_match_table = rda_gpio_of_match, | |
286 | }, | |
287 | }; | |
288 | ||
289 | module_platform_driver_probe(rda_gpio_driver, rda_gpio_probe); | |
290 | ||
291 | MODULE_DESCRIPTION("RDA Micro GPIO driver"); | |
292 | MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); |