Commit | Line | Data |
---|---|---|
eee636bf TC |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * Realtek DHC gpio driver | |
4 | * | |
5 | * Copyright (c) 2023 Realtek Semiconductor Corp. | |
6 | */ | |
7 | ||
8 | #include <linux/bitops.h> | |
9 | #include <linux/cleanup.h> | |
10 | #include <linux/gpio/driver.h> | |
11 | #include <linux/interrupt.h> | |
12 | #include <linux/irqchip.h> | |
13 | #include <linux/irqchip/chained_irq.h> | |
14 | #include <linux/irqdomain.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/platform_device.h> | |
17 | #include <linux/property.h> | |
18 | #include <linux/spinlock.h> | |
19 | #include <linux/types.h> | |
20 | ||
21 | #define RTD_GPIO_DEBOUNCE_1US 0 | |
22 | #define RTD_GPIO_DEBOUNCE_10US 1 | |
23 | #define RTD_GPIO_DEBOUNCE_100US 2 | |
24 | #define RTD_GPIO_DEBOUNCE_1MS 3 | |
25 | #define RTD_GPIO_DEBOUNCE_10MS 4 | |
26 | #define RTD_GPIO_DEBOUNCE_20MS 5 | |
27 | #define RTD_GPIO_DEBOUNCE_30MS 6 | |
28 | ||
29 | /** | |
30 | * struct rtd_gpio_info - Specific GPIO register information | |
31 | * @name: GPIO device name | |
32 | * @gpio_base: GPIO base number | |
33 | * @num_gpios: The number of GPIOs | |
34 | * @dir_offset: Offset for GPIO direction registers | |
35 | * @dato_offset: Offset for GPIO data output registers | |
36 | * @dati_offset: Offset for GPIO data input registers | |
37 | * @ie_offset: Offset for GPIO interrupt enable registers | |
38 | * @dp_offset: Offset for GPIO detection polarity registers | |
39 | * @gpa_offset: Offset for GPIO assert interrupt status registers | |
40 | * @gpda_offset: Offset for GPIO deassert interrupt status registers | |
41 | * @deb_offset: Offset for GPIO debounce registers | |
42 | * @deb_val: Register values representing the GPIO debounce time | |
43 | * @get_deb_setval: Used to get the corresponding value for setting the debounce register | |
44 | */ | |
45 | struct rtd_gpio_info { | |
46 | const char *name; | |
47 | unsigned int gpio_base; | |
48 | unsigned int num_gpios; | |
49 | u8 *dir_offset; | |
50 | u8 *dato_offset; | |
51 | u8 *dati_offset; | |
52 | u8 *ie_offset; | |
53 | u8 *dp_offset; | |
54 | u8 *gpa_offset; | |
55 | u8 *gpda_offset; | |
56 | u8 *deb_offset; | |
57 | u8 *deb_val; | |
58 | u8 (*get_deb_setval)(const struct rtd_gpio_info *info, | |
59 | unsigned int offset, u8 deb_index, | |
60 | u8 *reg_offset, u8 *shift); | |
61 | }; | |
62 | ||
63 | struct rtd_gpio { | |
64 | struct gpio_chip gpio_chip; | |
65 | const struct rtd_gpio_info *info; | |
66 | void __iomem *base; | |
67 | void __iomem *irq_base; | |
68 | unsigned int irqs[2]; | |
69 | raw_spinlock_t lock; | |
70 | }; | |
71 | ||
72 | static u8 rtd_gpio_get_deb_setval(const struct rtd_gpio_info *info, unsigned int offset, | |
73 | u8 deb_index, u8 *reg_offset, u8 *shift) | |
74 | { | |
75 | *reg_offset = info->deb_offset[offset / 8]; | |
76 | *shift = (offset % 8) * 4; | |
77 | return info->deb_val[deb_index]; | |
78 | } | |
79 | ||
80 | static u8 rtd1295_misc_gpio_get_deb_setval(const struct rtd_gpio_info *info, unsigned int offset, | |
81 | u8 deb_index, u8 *reg_offset, u8 *shift) | |
82 | { | |
83 | *reg_offset = info->deb_offset[0]; | |
84 | *shift = (offset % 8) * 4; | |
85 | return info->deb_val[deb_index]; | |
86 | } | |
87 | ||
88 | static u8 rtd1295_iso_gpio_get_deb_setval(const struct rtd_gpio_info *info, unsigned int offset, | |
89 | u8 deb_index, u8 *reg_offset, u8 *shift) | |
90 | { | |
91 | *reg_offset = info->deb_offset[0]; | |
92 | *shift = 0; | |
93 | return info->deb_val[deb_index]; | |
94 | } | |
95 | ||
96 | static const struct rtd_gpio_info rtd_iso_gpio_info = { | |
97 | .name = "rtd_iso_gpio", | |
98 | .gpio_base = 0, | |
99 | .num_gpios = 82, | |
100 | .dir_offset = (u8 []){ 0x0, 0x18, 0x2c }, | |
101 | .dato_offset = (u8 []){ 0x4, 0x1c, 0x30 }, | |
102 | .dati_offset = (u8 []){ 0x8, 0x20, 0x34 }, | |
103 | .ie_offset = (u8 []){ 0xc, 0x24, 0x38 }, | |
104 | .dp_offset = (u8 []){ 0x10, 0x28, 0x3c }, | |
105 | .gpa_offset = (u8 []){ 0x8, 0xe0, 0x90 }, | |
106 | .gpda_offset = (u8 []){ 0xc, 0xe4, 0x94 }, | |
107 | .deb_offset = (u8 []){ 0x44, 0x48, 0x4c, 0x50, 0x54, 0x58, 0x5c, | |
108 | 0x60, 0x64, 0x68, 0x6c }, | |
109 | .deb_val = (u8 []){ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 }, | |
110 | .get_deb_setval = rtd_gpio_get_deb_setval, | |
111 | }; | |
112 | ||
113 | static const struct rtd_gpio_info rtd1619_iso_gpio_info = { | |
114 | .name = "rtd1619_iso_gpio", | |
115 | .gpio_base = 0, | |
116 | .num_gpios = 86, | |
117 | .dir_offset = (u8 []){ 0x0, 0x18, 0x2c }, | |
118 | .dato_offset = (u8 []){ 0x4, 0x1c, 0x30 }, | |
119 | .dati_offset = (u8 []){ 0x8, 0x20, 0x34 }, | |
120 | .ie_offset = (u8 []){ 0xc, 0x24, 0x38 }, | |
121 | .dp_offset = (u8 []){ 0x10, 0x28, 0x3c }, | |
122 | .gpa_offset = (u8 []){ 0x8, 0xe0, 0x90 }, | |
123 | .gpda_offset = (u8 []){ 0xc, 0xe4, 0x94 }, | |
124 | .deb_offset = (u8 []){ 0x44, 0x48, 0x4c, 0x50, 0x54, 0x58, 0x5c, | |
125 | 0x60, 0x64, 0x68, 0x6c }, | |
126 | .deb_val = (u8 []){ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 }, | |
127 | .get_deb_setval = rtd_gpio_get_deb_setval, | |
128 | }; | |
129 | ||
130 | static const struct rtd_gpio_info rtd1395_iso_gpio_info = { | |
131 | .name = "rtd1395_iso_gpio", | |
132 | .gpio_base = 0, | |
133 | .num_gpios = 57, | |
134 | .dir_offset = (u8 []){ 0x0, 0x18 }, | |
135 | .dato_offset = (u8 []){ 0x4, 0x1c }, | |
136 | .dati_offset = (u8 []){ 0x8, 0x20 }, | |
137 | .ie_offset = (u8 []){ 0xc, 0x24 }, | |
138 | .dp_offset = (u8 []){ 0x10, 0x28 }, | |
139 | .gpa_offset = (u8 []){ 0x8, 0xe0 }, | |
140 | .gpda_offset = (u8 []){ 0xc, 0xe4 }, | |
141 | .deb_offset = (u8 []){ 0x30, 0x34, 0x38, 0x3c, 0x40, 0x44, 0x48, 0x4c }, | |
142 | .deb_val = (u8 []){ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 }, | |
143 | .get_deb_setval = rtd_gpio_get_deb_setval, | |
144 | }; | |
145 | ||
146 | static const struct rtd_gpio_info rtd1295_misc_gpio_info = { | |
147 | .name = "rtd1295_misc_gpio", | |
148 | .gpio_base = 0, | |
149 | .num_gpios = 101, | |
150 | .dir_offset = (u8 []){ 0x0, 0x4, 0x8, 0xc }, | |
151 | .dato_offset = (u8 []){ 0x10, 0x14, 0x18, 0x1c }, | |
152 | .dati_offset = (u8 []){ 0x20, 0x24, 0x28, 0x2c }, | |
153 | .ie_offset = (u8 []){ 0x30, 0x34, 0x38, 0x3c }, | |
154 | .dp_offset = (u8 []){ 0x40, 0x44, 0x48, 0x4c }, | |
155 | .gpa_offset = (u8 []){ 0x40, 0x44, 0xa4, 0xb8 }, | |
156 | .gpda_offset = (u8 []){ 0x54, 0x58, 0xa8, 0xbc}, | |
157 | .deb_offset = (u8 []){ 0x50 }, | |
158 | .deb_val = (u8 []){ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }, | |
159 | .get_deb_setval = rtd1295_misc_gpio_get_deb_setval, | |
160 | }; | |
161 | ||
162 | static const struct rtd_gpio_info rtd1295_iso_gpio_info = { | |
163 | .name = "rtd1295_iso_gpio", | |
164 | .gpio_base = 101, | |
165 | .num_gpios = 35, | |
166 | .dir_offset = (u8 []){ 0x0, 0x18 }, | |
167 | .dato_offset = (u8 []){ 0x4, 0x1c }, | |
168 | .dati_offset = (u8 []){ 0x8, 0x20 }, | |
169 | .ie_offset = (u8 []){ 0xc, 0x24 }, | |
170 | .dp_offset = (u8 []){ 0x10, 0x28 }, | |
171 | .gpa_offset = (u8 []){ 0x8, 0xe0 }, | |
172 | .gpda_offset = (u8 []){ 0xc, 0xe4 }, | |
173 | .deb_offset = (u8 []){ 0x14 }, | |
174 | .deb_val = (u8 []){ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }, | |
175 | .get_deb_setval = rtd1295_iso_gpio_get_deb_setval, | |
176 | }; | |
177 | ||
178 | static int rtd_gpio_dir_offset(struct rtd_gpio *data, unsigned int offset) | |
179 | { | |
180 | return data->info->dir_offset[offset / 32]; | |
181 | } | |
182 | ||
183 | static int rtd_gpio_dato_offset(struct rtd_gpio *data, unsigned int offset) | |
184 | { | |
185 | return data->info->dato_offset[offset / 32]; | |
186 | } | |
187 | ||
188 | static int rtd_gpio_dati_offset(struct rtd_gpio *data, unsigned int offset) | |
189 | { | |
190 | return data->info->dati_offset[offset / 32]; | |
191 | } | |
192 | ||
193 | static int rtd_gpio_ie_offset(struct rtd_gpio *data, unsigned int offset) | |
194 | { | |
195 | return data->info->ie_offset[offset / 32]; | |
196 | } | |
197 | ||
198 | static int rtd_gpio_dp_offset(struct rtd_gpio *data, unsigned int offset) | |
199 | { | |
200 | return data->info->dp_offset[offset / 32]; | |
201 | } | |
202 | ||
203 | ||
204 | static int rtd_gpio_gpa_offset(struct rtd_gpio *data, unsigned int offset) | |
205 | { | |
206 | /* Each GPIO assert interrupt status register contains 31 GPIOs. */ | |
207 | return data->info->gpa_offset[offset / 31]; | |
208 | } | |
209 | ||
210 | static int rtd_gpio_gpda_offset(struct rtd_gpio *data, unsigned int offset) | |
211 | { | |
212 | /* Each GPIO deassert interrupt status register contains 31 GPIOs. */ | |
213 | return data->info->gpda_offset[offset / 31]; | |
214 | } | |
215 | ||
216 | static int rtd_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, | |
217 | unsigned int debounce) | |
218 | { | |
219 | struct rtd_gpio *data = gpiochip_get_data(chip); | |
220 | u8 deb_val, deb_index, reg_offset, shift; | |
221 | unsigned int write_en; | |
222 | u32 val; | |
223 | ||
224 | switch (debounce) { | |
225 | case 1: | |
226 | deb_index = RTD_GPIO_DEBOUNCE_1US; | |
227 | break; | |
228 | case 10: | |
229 | deb_index = RTD_GPIO_DEBOUNCE_10US; | |
230 | break; | |
231 | case 100: | |
232 | deb_index = RTD_GPIO_DEBOUNCE_100US; | |
233 | break; | |
234 | case 1000: | |
235 | deb_index = RTD_GPIO_DEBOUNCE_1MS; | |
236 | break; | |
237 | case 10000: | |
238 | deb_index = RTD_GPIO_DEBOUNCE_10MS; | |
239 | break; | |
240 | case 20000: | |
241 | deb_index = RTD_GPIO_DEBOUNCE_20MS; | |
242 | break; | |
243 | case 30000: | |
244 | deb_index = RTD_GPIO_DEBOUNCE_30MS; | |
245 | break; | |
246 | default: | |
247 | return -ENOTSUPP; | |
248 | } | |
249 | ||
250 | deb_val = data->info->get_deb_setval(data->info, offset, deb_index, ®_offset, &shift); | |
251 | write_en = BIT(shift + 3); | |
252 | val = (deb_val << shift) | write_en; | |
253 | ||
254 | guard(raw_spinlock_irqsave)(&data->lock); | |
255 | writel_relaxed(val, data->base + reg_offset); | |
256 | ||
257 | return 0; | |
258 | } | |
259 | ||
260 | static int rtd_gpio_set_config(struct gpio_chip *chip, unsigned int offset, | |
261 | unsigned long config) | |
262 | { | |
263 | int debounce; | |
264 | ||
265 | switch (pinconf_to_config_param(config)) { | |
266 | case PIN_CONFIG_BIAS_DISABLE: | |
267 | case PIN_CONFIG_BIAS_PULL_UP: | |
268 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
269 | return gpiochip_generic_config(chip, offset, config); | |
270 | case PIN_CONFIG_INPUT_DEBOUNCE: | |
271 | debounce = pinconf_to_config_argument(config); | |
272 | return rtd_gpio_set_debounce(chip, offset, debounce); | |
273 | default: | |
274 | return -ENOTSUPP; | |
275 | } | |
276 | } | |
277 | ||
278 | static void rtd_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) | |
279 | { | |
280 | struct rtd_gpio *data = gpiochip_get_data(chip); | |
281 | u32 mask = BIT(offset % 32); | |
282 | int dato_reg_offset; | |
283 | u32 val; | |
284 | ||
285 | dato_reg_offset = rtd_gpio_dato_offset(data, offset); | |
286 | ||
287 | guard(raw_spinlock_irqsave)(&data->lock); | |
288 | ||
289 | val = readl_relaxed(data->base + dato_reg_offset); | |
290 | if (value) | |
291 | val |= mask; | |
292 | else | |
293 | val &= ~mask; | |
294 | writel_relaxed(val, data->base + dato_reg_offset); | |
295 | } | |
296 | ||
297 | static int rtd_gpio_get(struct gpio_chip *chip, unsigned int offset) | |
298 | { | |
299 | struct rtd_gpio *data = gpiochip_get_data(chip); | |
300 | int dato_reg_offset = rtd_gpio_dato_offset(data, offset); | |
301 | int dati_reg_offset = rtd_gpio_dati_offset(data, offset); | |
302 | int dir_reg_offset = rtd_gpio_dir_offset(data, offset); | |
303 | int dat_reg_offset; | |
304 | u32 val; | |
305 | ||
306 | guard(raw_spinlock_irqsave)(&data->lock); | |
307 | ||
308 | val = readl_relaxed(data->base + dir_reg_offset); | |
309 | dat_reg_offset = (val & BIT(offset % 32)) ? dato_reg_offset : dati_reg_offset; | |
310 | val = readl_relaxed(data->base + dat_reg_offset); | |
311 | ||
312 | return !!(val & BIT(offset % 32)); | |
313 | } | |
314 | ||
315 | static int rtd_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) | |
316 | { | |
317 | struct rtd_gpio *data = gpiochip_get_data(chip); | |
318 | int reg_offset; | |
319 | u32 val; | |
320 | ||
321 | reg_offset = rtd_gpio_dir_offset(data, offset); | |
322 | val = readl_relaxed(data->base + reg_offset); | |
323 | if (val & BIT(offset % 32)) | |
324 | return GPIO_LINE_DIRECTION_OUT; | |
325 | ||
326 | return GPIO_LINE_DIRECTION_IN; | |
327 | } | |
328 | ||
329 | static int rtd_gpio_set_direction(struct gpio_chip *chip, unsigned int offset, bool out) | |
330 | { | |
331 | struct rtd_gpio *data = gpiochip_get_data(chip); | |
332 | u32 mask = BIT(offset % 32); | |
333 | int reg_offset; | |
334 | u32 val; | |
335 | ||
336 | reg_offset = rtd_gpio_dir_offset(data, offset); | |
337 | ||
338 | guard(raw_spinlock_irqsave)(&data->lock); | |
339 | ||
340 | val = readl_relaxed(data->base + reg_offset); | |
341 | if (out) | |
342 | val |= mask; | |
343 | else | |
344 | val &= ~mask; | |
345 | writel_relaxed(val, data->base + reg_offset); | |
346 | ||
347 | return 0; | |
348 | } | |
349 | ||
350 | static int rtd_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) | |
351 | { | |
352 | return rtd_gpio_set_direction(chip, offset, false); | |
353 | } | |
354 | ||
355 | static int rtd_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) | |
356 | { | |
357 | rtd_gpio_set(chip, offset, value); | |
358 | ||
359 | return rtd_gpio_set_direction(chip, offset, true); | |
360 | } | |
361 | ||
362 | static bool rtd_gpio_check_ie(struct rtd_gpio *data, int irq) | |
363 | { | |
364 | int mask = BIT(irq % 32); | |
365 | int ie_reg_offset; | |
366 | u32 enable; | |
367 | ||
368 | ie_reg_offset = rtd_gpio_ie_offset(data, irq); | |
369 | enable = readl_relaxed(data->base + ie_reg_offset); | |
370 | ||
371 | return enable & mask; | |
372 | } | |
373 | ||
374 | static void rtd_gpio_irq_handle(struct irq_desc *desc) | |
375 | { | |
376 | int (*get_reg_offset)(struct rtd_gpio *gpio, unsigned int offset); | |
377 | struct rtd_gpio *data = irq_desc_get_handler_data(desc); | |
378 | struct irq_domain *domain = data->gpio_chip.irq.domain; | |
379 | struct irq_chip *chip = irq_desc_get_chip(desc); | |
380 | unsigned int irq = irq_desc_get_irq(desc); | |
381 | unsigned long status; | |
382 | int reg_offset, i, j; | |
383 | unsigned int hwirq; | |
384 | ||
385 | if (irq == data->irqs[0]) | |
386 | get_reg_offset = &rtd_gpio_gpa_offset; | |
387 | else if (irq == data->irqs[1]) | |
388 | get_reg_offset = &rtd_gpio_gpda_offset; | |
389 | ||
390 | chained_irq_enter(chip, desc); | |
391 | ||
392 | /* Each GPIO interrupt status register contains 31 GPIOs. */ | |
393 | for (i = 0; i < data->info->num_gpios; i += 31) { | |
394 | reg_offset = get_reg_offset(data, i); | |
395 | ||
396 | /* | |
397 | * Bit 0 is the write_en bit, bit 0 to 31 corresponds to 31 GPIOs. | |
398 | * When bit 0 is set to 0, write 1 to the other bits to clear the status. | |
399 | * When bit 0 is set to 1, write 1 to the other bits to set the status. | |
400 | */ | |
401 | status = readl_relaxed(data->irq_base + reg_offset); | |
402 | status &= ~BIT(0); | |
403 | writel_relaxed(status, data->irq_base + reg_offset); | |
404 | ||
405 | for_each_set_bit(j, &status, 32) { | |
406 | hwirq = i + j - 1; | |
407 | if (rtd_gpio_check_ie(data, hwirq)) { | |
408 | int girq = irq_find_mapping(domain, hwirq); | |
409 | u32 irq_type = irq_get_trigger_type(girq); | |
410 | ||
411 | if ((irq == data->irqs[1]) && (irq_type != IRQ_TYPE_EDGE_BOTH)) | |
412 | break; | |
413 | generic_handle_domain_irq(domain, hwirq); | |
414 | } | |
415 | } | |
416 | } | |
417 | ||
418 | chained_irq_exit(chip, desc); | |
419 | } | |
420 | ||
421 | static void rtd_gpio_enable_irq(struct irq_data *d) | |
422 | { | |
423 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
424 | struct rtd_gpio *data = gpiochip_get_data(gc); | |
425 | irq_hw_number_t hwirq = irqd_to_hwirq(d); | |
426 | ||
427 | /* Bit 0 is write_en and bit 1 to 31 is correspond to 31 GPIOs. */ | |
428 | u32 clr_mask = BIT(hwirq % 31) << 1; | |
429 | ||
430 | u32 ie_mask = BIT(hwirq % 32); | |
431 | int gpda_reg_offset; | |
432 | int gpa_reg_offset; | |
433 | int ie_reg_offset; | |
434 | u32 val; | |
435 | ||
436 | ie_reg_offset = rtd_gpio_ie_offset(data, hwirq); | |
437 | gpa_reg_offset = rtd_gpio_gpa_offset(data, hwirq); | |
438 | gpda_reg_offset = rtd_gpio_gpda_offset(data, hwirq); | |
439 | ||
440 | gpiochip_enable_irq(gc, hwirq); | |
441 | ||
442 | guard(raw_spinlock_irqsave)(&data->lock); | |
443 | ||
444 | writel_relaxed(clr_mask, data->irq_base + gpa_reg_offset); | |
445 | writel_relaxed(clr_mask, data->irq_base + gpda_reg_offset); | |
446 | ||
447 | val = readl_relaxed(data->base + ie_reg_offset); | |
448 | val |= ie_mask; | |
449 | writel_relaxed(val, data->base + ie_reg_offset); | |
450 | } | |
451 | ||
452 | static void rtd_gpio_disable_irq(struct irq_data *d) | |
453 | { | |
454 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
455 | struct rtd_gpio *data = gpiochip_get_data(gc); | |
456 | irq_hw_number_t hwirq = irqd_to_hwirq(d); | |
457 | u32 ie_mask = BIT(hwirq % 32); | |
458 | int ie_reg_offset; | |
459 | u32 val; | |
460 | ||
461 | ie_reg_offset = rtd_gpio_ie_offset(data, hwirq); | |
462 | ||
463 | scoped_guard(raw_spinlock_irqsave, &data->lock) { | |
464 | val = readl_relaxed(data->base + ie_reg_offset); | |
465 | val &= ~ie_mask; | |
466 | writel_relaxed(val, data->base + ie_reg_offset); | |
467 | } | |
468 | ||
469 | gpiochip_disable_irq(gc, hwirq); | |
470 | } | |
471 | ||
472 | static int rtd_gpio_irq_set_type(struct irq_data *d, unsigned int type) | |
473 | { | |
474 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
475 | struct rtd_gpio *data = gpiochip_get_data(gc); | |
476 | irq_hw_number_t hwirq = irqd_to_hwirq(d); | |
477 | u32 mask = BIT(hwirq % 32); | |
478 | int dp_reg_offset; | |
479 | bool polarity; | |
480 | u32 val; | |
481 | ||
482 | dp_reg_offset = rtd_gpio_dp_offset(data, hwirq); | |
483 | ||
484 | switch (type & IRQ_TYPE_SENSE_MASK) { | |
485 | case IRQ_TYPE_EDGE_RISING: | |
486 | polarity = 1; | |
487 | break; | |
488 | ||
489 | case IRQ_TYPE_EDGE_FALLING: | |
490 | polarity = 0; | |
491 | break; | |
492 | ||
493 | case IRQ_TYPE_EDGE_BOTH: | |
494 | polarity = 1; | |
495 | break; | |
496 | ||
497 | default: | |
498 | return -EINVAL; | |
499 | } | |
500 | ||
501 | scoped_guard(raw_spinlock_irqsave, &data->lock) { | |
502 | val = readl_relaxed(data->base + dp_reg_offset); | |
503 | if (polarity) | |
504 | val |= mask; | |
505 | else | |
506 | val &= ~mask; | |
507 | writel_relaxed(val, data->base + dp_reg_offset); | |
508 | } | |
509 | ||
510 | irq_set_handler_locked(d, handle_simple_irq); | |
511 | ||
512 | return 0; | |
513 | } | |
514 | ||
515 | static const struct irq_chip rtd_gpio_irq_chip = { | |
516 | .name = "rtd-gpio", | |
517 | .irq_enable = rtd_gpio_enable_irq, | |
518 | .irq_disable = rtd_gpio_disable_irq, | |
519 | .irq_set_type = rtd_gpio_irq_set_type, | |
520 | .flags = IRQCHIP_IMMUTABLE, | |
521 | }; | |
522 | ||
523 | static int rtd_gpio_probe(struct platform_device *pdev) | |
524 | { | |
525 | struct device *dev = &pdev->dev; | |
526 | struct gpio_irq_chip *irq_chip; | |
527 | struct rtd_gpio *data; | |
c8fb5a52 | 528 | int ret; |
eee636bf TC |
529 | |
530 | data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); | |
531 | if (!data) | |
532 | return -ENOMEM; | |
533 | ||
c8fb5a52 DC |
534 | ret = platform_get_irq(pdev, 0); |
535 | if (ret < 0) | |
536 | return ret; | |
537 | data->irqs[0] = ret; | |
eee636bf | 538 | |
c8fb5a52 DC |
539 | ret = platform_get_irq(pdev, 1); |
540 | if (ret < 0) | |
541 | return ret; | |
542 | data->irqs[1] = ret; | |
eee636bf TC |
543 | |
544 | data->info = device_get_match_data(dev); | |
545 | if (!data->info) | |
546 | return -EINVAL; | |
547 | ||
548 | raw_spin_lock_init(&data->lock); | |
549 | ||
550 | data->base = devm_platform_ioremap_resource(pdev, 0); | |
551 | if (IS_ERR(data->base)) | |
552 | return PTR_ERR(data->base); | |
553 | ||
554 | data->irq_base = devm_platform_ioremap_resource(pdev, 1); | |
555 | if (IS_ERR(data->irq_base)) | |
556 | return PTR_ERR(data->irq_base); | |
557 | ||
558 | data->gpio_chip.label = dev_name(dev); | |
559 | data->gpio_chip.base = -1; | |
560 | data->gpio_chip.ngpio = data->info->num_gpios; | |
561 | data->gpio_chip.request = gpiochip_generic_request; | |
562 | data->gpio_chip.free = gpiochip_generic_free; | |
563 | data->gpio_chip.get_direction = rtd_gpio_get_direction; | |
564 | data->gpio_chip.direction_input = rtd_gpio_direction_input; | |
565 | data->gpio_chip.direction_output = rtd_gpio_direction_output; | |
566 | data->gpio_chip.set = rtd_gpio_set; | |
567 | data->gpio_chip.get = rtd_gpio_get; | |
568 | data->gpio_chip.set_config = rtd_gpio_set_config; | |
569 | data->gpio_chip.parent = dev; | |
570 | ||
571 | irq_chip = &data->gpio_chip.irq; | |
572 | irq_chip->handler = handle_bad_irq; | |
573 | irq_chip->default_type = IRQ_TYPE_NONE; | |
574 | irq_chip->parent_handler = rtd_gpio_irq_handle; | |
575 | irq_chip->parent_handler_data = data; | |
576 | irq_chip->num_parents = 2; | |
577 | irq_chip->parents = data->irqs; | |
578 | ||
579 | gpio_irq_chip_set_chip(irq_chip, &rtd_gpio_irq_chip); | |
580 | ||
581 | return devm_gpiochip_add_data(dev, &data->gpio_chip, data); | |
582 | } | |
583 | ||
584 | static const struct of_device_id rtd_gpio_of_matches[] = { | |
585 | { .compatible = "realtek,rtd1295-misc-gpio", .data = &rtd1295_misc_gpio_info }, | |
586 | { .compatible = "realtek,rtd1295-iso-gpio", .data = &rtd1295_iso_gpio_info }, | |
587 | { .compatible = "realtek,rtd1395-iso-gpio", .data = &rtd1395_iso_gpio_info }, | |
588 | { .compatible = "realtek,rtd1619-iso-gpio", .data = &rtd1619_iso_gpio_info }, | |
589 | { .compatible = "realtek,rtd1319-iso-gpio", .data = &rtd_iso_gpio_info }, | |
590 | { .compatible = "realtek,rtd1619b-iso-gpio", .data = &rtd_iso_gpio_info }, | |
591 | { .compatible = "realtek,rtd1319d-iso-gpio", .data = &rtd_iso_gpio_info }, | |
592 | { .compatible = "realtek,rtd1315e-iso-gpio", .data = &rtd_iso_gpio_info }, | |
593 | { } | |
594 | }; | |
595 | MODULE_DEVICE_TABLE(of, rtd_gpio_of_matches); | |
596 | ||
597 | static struct platform_driver rtd_gpio_platform_driver = { | |
598 | .driver = { | |
599 | .name = "gpio-rtd", | |
600 | .of_match_table = rtd_gpio_of_matches, | |
601 | }, | |
602 | .probe = rtd_gpio_probe, | |
603 | }; | |
604 | module_platform_driver(rtd_gpio_platform_driver); | |
605 | ||
606 | MODULE_DESCRIPTION("Realtek DHC SoC gpio driver"); | |
607 | MODULE_LICENSE("GPL v2"); |