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; | |
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; | |
184 | u32 n, girq; | |
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 | ||
192 | for_each_set_bit(n, &status, RDA_GPIO_BANK_NR) { | |
193 | girq = irq_find_mapping(chip->irq.domain, n); | |
194 | generic_handle_irq(girq); | |
195 | } | |
196 | ||
197 | chained_irq_exit(ic, desc); | |
198 | } | |
199 | ||
200 | static int rda_gpio_probe(struct platform_device *pdev) | |
201 | { | |
202 | struct device_node *np = pdev->dev.of_node; | |
203 | struct device *dev = &pdev->dev; | |
204 | struct gpio_irq_chip *girq; | |
205 | struct rda_gpio *rda_gpio; | |
206 | u32 ngpios; | |
207 | int ret; | |
208 | ||
209 | rda_gpio = devm_kzalloc(dev, sizeof(*rda_gpio), GFP_KERNEL); | |
210 | if (!rda_gpio) | |
211 | return -ENOMEM; | |
212 | ||
213 | ret = device_property_read_u32(dev, "ngpios", &ngpios); | |
214 | if (ret < 0) | |
215 | return ret; | |
216 | ||
217 | /* | |
218 | * Not all ports have interrupt capability. For instance, on | |
219 | * RDA8810PL, GPIOC doesn't support interrupt. So we must handle | |
220 | * those also. | |
221 | */ | |
222 | rda_gpio->irq = platform_get_irq(pdev, 0); | |
223 | ||
224 | rda_gpio->base = devm_platform_ioremap_resource(pdev, 0); | |
225 | if (IS_ERR(rda_gpio->base)) | |
226 | return PTR_ERR(rda_gpio->base); | |
227 | ||
228 | spin_lock_init(&rda_gpio->lock); | |
229 | ||
230 | ret = bgpio_init(&rda_gpio->chip, dev, 4, | |
231 | rda_gpio->base + RDA_GPIO_VAL, | |
232 | rda_gpio->base + RDA_GPIO_SET, | |
233 | rda_gpio->base + RDA_GPIO_CLR, | |
234 | rda_gpio->base + RDA_GPIO_OEN_SET_OUT, | |
235 | rda_gpio->base + RDA_GPIO_OEN_SET_IN, | |
236 | BGPIOF_READ_OUTPUT_REG_SET); | |
237 | if (ret) { | |
238 | dev_err(dev, "bgpio_init failed\n"); | |
239 | return ret; | |
240 | } | |
241 | ||
242 | rda_gpio->chip.label = dev_name(dev); | |
243 | rda_gpio->chip.ngpio = ngpios; | |
244 | rda_gpio->chip.base = -1; | |
245 | rda_gpio->chip.parent = dev; | |
246 | rda_gpio->chip.of_node = np; | |
247 | ||
248 | if (rda_gpio->irq >= 0) { | |
249 | rda_gpio->irq_chip.name = "rda-gpio", | |
250 | rda_gpio->irq_chip.irq_ack = rda_gpio_irq_ack, | |
251 | rda_gpio->irq_chip.irq_mask = rda_gpio_irq_mask, | |
252 | rda_gpio->irq_chip.irq_unmask = rda_gpio_irq_unmask, | |
253 | rda_gpio->irq_chip.irq_set_type = rda_gpio_irq_set_type, | |
254 | rda_gpio->irq_chip.flags = IRQCHIP_SKIP_SET_WAKE, | |
255 | ||
256 | girq = &rda_gpio->chip.irq; | |
257 | girq->chip = &rda_gpio->irq_chip; | |
258 | girq->handler = handle_bad_irq; | |
259 | girq->default_type = IRQ_TYPE_NONE; | |
260 | girq->parent_handler = rda_gpio_irq_handler; | |
261 | girq->parent_handler_data = rda_gpio; | |
262 | girq->num_parents = 1; | |
263 | girq->parents = devm_kcalloc(dev, 1, | |
264 | sizeof(*girq->parents), | |
265 | GFP_KERNEL); | |
266 | if (!girq->parents) | |
267 | return -ENOMEM; | |
268 | girq->parents[0] = rda_gpio->irq; | |
269 | } | |
270 | ||
271 | platform_set_drvdata(pdev, rda_gpio); | |
272 | ||
273 | return devm_gpiochip_add_data(dev, &rda_gpio->chip, rda_gpio); | |
274 | } | |
275 | ||
276 | static const struct of_device_id rda_gpio_of_match[] = { | |
277 | { .compatible = "rda,8810pl-gpio", }, | |
278 | { /* sentinel */ } | |
279 | }; | |
280 | MODULE_DEVICE_TABLE(of, rda_gpio_of_match); | |
281 | ||
282 | static struct platform_driver rda_gpio_driver = { | |
283 | .probe = rda_gpio_probe, | |
284 | .driver = { | |
285 | .name = "rda-gpio", | |
286 | .of_match_table = rda_gpio_of_match, | |
287 | }, | |
288 | }; | |
289 | ||
290 | module_platform_driver_probe(rda_gpio_driver, rda_gpio_probe); | |
291 | ||
292 | MODULE_DESCRIPTION("RDA Micro GPIO driver"); | |
293 | MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); | |
294 | MODULE_LICENSE("GPL v2"); |