1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * MPC52xx gpio driver |
4 | * |
5 | * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix |
6 | */ |
7 | |
8 | #include <linux/of.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/gpio/legacy-of-mm-gpiochip.h> |
12 | #include <linux/io.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/module.h> |
15 | |
16 | #include <asm/mpc52xx.h> |
17 | #include <sysdev/fsl_soc.h> |
18 | |
19 | static DEFINE_SPINLOCK(gpio_lock); |
20 | |
21 | struct mpc52xx_gpiochip { |
22 | struct of_mm_gpio_chip mmchip; |
23 | unsigned int shadow_dvo; |
24 | unsigned int shadow_gpioe; |
25 | unsigned int shadow_ddr; |
26 | }; |
27 | |
28 | /* |
29 | * GPIO LIB API implementation for wakeup GPIOs. |
30 | * |
31 | * There's a maximum of 8 wakeup GPIOs. Which of these are available |
32 | * for use depends on your board setup. |
33 | * |
34 | * 0 -> GPIO_WKUP_7 |
35 | * 1 -> GPIO_WKUP_6 |
36 | * 2 -> PSC6_1 |
37 | * 3 -> PSC6_0 |
38 | * 4 -> ETH_17 |
39 | * 5 -> PSC3_9 |
40 | * 6 -> PSC2_4 |
41 | * 7 -> PSC1_4 |
42 | * |
43 | */ |
44 | static int mpc52xx_wkup_gpio_get(struct gpio_chip *gc, unsigned int gpio) |
45 | { |
46 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
47 | struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs; |
48 | unsigned int ret; |
49 | |
50 | ret = (in_8(®s->wkup_ival) >> (7 - gpio)) & 1; |
51 | |
52 | pr_debug("%s: gpio: %d ret: %d\n" , __func__, gpio, ret); |
53 | |
54 | return ret; |
55 | } |
56 | |
57 | static inline void |
58 | __mpc52xx_wkup_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) |
59 | { |
60 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
61 | struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc); |
62 | struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs; |
63 | |
64 | if (val) |
65 | chip->shadow_dvo |= 1 << (7 - gpio); |
66 | else |
67 | chip->shadow_dvo &= ~(1 << (7 - gpio)); |
68 | |
69 | out_8(®s->wkup_dvo, chip->shadow_dvo); |
70 | } |
71 | |
72 | static void |
73 | mpc52xx_wkup_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) |
74 | { |
75 | unsigned long flags; |
76 | |
77 | spin_lock_irqsave(&gpio_lock, flags); |
78 | |
79 | __mpc52xx_wkup_gpio_set(gc, gpio, val); |
80 | |
81 | spin_unlock_irqrestore(lock: &gpio_lock, flags); |
82 | |
83 | pr_debug("%s: gpio: %d val: %d\n" , __func__, gpio, val); |
84 | } |
85 | |
86 | static int mpc52xx_wkup_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) |
87 | { |
88 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
89 | struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc); |
90 | struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs; |
91 | unsigned long flags; |
92 | |
93 | spin_lock_irqsave(&gpio_lock, flags); |
94 | |
95 | /* set the direction */ |
96 | chip->shadow_ddr &= ~(1 << (7 - gpio)); |
97 | out_8(®s->wkup_ddr, chip->shadow_ddr); |
98 | |
99 | /* and enable the pin */ |
100 | chip->shadow_gpioe |= 1 << (7 - gpio); |
101 | out_8(®s->wkup_gpioe, chip->shadow_gpioe); |
102 | |
103 | spin_unlock_irqrestore(lock: &gpio_lock, flags); |
104 | |
105 | return 0; |
106 | } |
107 | |
108 | static int |
109 | mpc52xx_wkup_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) |
110 | { |
111 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
112 | struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs; |
113 | struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc); |
114 | unsigned long flags; |
115 | |
116 | spin_lock_irqsave(&gpio_lock, flags); |
117 | |
118 | __mpc52xx_wkup_gpio_set(gc, gpio, val); |
119 | |
120 | /* Then set direction */ |
121 | chip->shadow_ddr |= 1 << (7 - gpio); |
122 | out_8(®s->wkup_ddr, chip->shadow_ddr); |
123 | |
124 | /* Finally enable the pin */ |
125 | chip->shadow_gpioe |= 1 << (7 - gpio); |
126 | out_8(®s->wkup_gpioe, chip->shadow_gpioe); |
127 | |
128 | spin_unlock_irqrestore(lock: &gpio_lock, flags); |
129 | |
130 | pr_debug("%s: gpio: %d val: %d\n" , __func__, gpio, val); |
131 | |
132 | return 0; |
133 | } |
134 | |
135 | static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) |
136 | { |
137 | struct mpc52xx_gpiochip *chip; |
138 | struct mpc52xx_gpio_wkup __iomem *regs; |
139 | struct gpio_chip *gc; |
140 | int ret; |
141 | |
142 | chip = devm_kzalloc(dev: &ofdev->dev, size: sizeof(*chip), GFP_KERNEL); |
143 | if (!chip) |
144 | return -ENOMEM; |
145 | |
146 | platform_set_drvdata(pdev: ofdev, data: chip); |
147 | |
148 | gc = &chip->mmchip.gc; |
149 | |
150 | gc->ngpio = 8; |
151 | gc->direction_input = mpc52xx_wkup_gpio_dir_in; |
152 | gc->direction_output = mpc52xx_wkup_gpio_dir_out; |
153 | gc->get = mpc52xx_wkup_gpio_get; |
154 | gc->set = mpc52xx_wkup_gpio_set; |
155 | |
156 | ret = of_mm_gpiochip_add_data(np: ofdev->dev.of_node, mm_gc: &chip->mmchip, data: chip); |
157 | if (ret) |
158 | return ret; |
159 | |
160 | regs = chip->mmchip.regs; |
161 | chip->shadow_gpioe = in_8(®s->wkup_gpioe); |
162 | chip->shadow_ddr = in_8(®s->wkup_ddr); |
163 | chip->shadow_dvo = in_8(®s->wkup_dvo); |
164 | |
165 | return 0; |
166 | } |
167 | |
168 | static void mpc52xx_gpiochip_remove(struct platform_device *ofdev) |
169 | { |
170 | struct mpc52xx_gpiochip *chip = platform_get_drvdata(pdev: ofdev); |
171 | |
172 | of_mm_gpiochip_remove(mm_gc: &chip->mmchip); |
173 | } |
174 | |
175 | static const struct of_device_id mpc52xx_wkup_gpiochip_match[] = { |
176 | { .compatible = "fsl,mpc5200-gpio-wkup" , }, |
177 | {} |
178 | }; |
179 | |
180 | static struct platform_driver mpc52xx_wkup_gpiochip_driver = { |
181 | .driver = { |
182 | .name = "mpc5200-gpio-wkup" , |
183 | .of_match_table = mpc52xx_wkup_gpiochip_match, |
184 | }, |
185 | .probe = mpc52xx_wkup_gpiochip_probe, |
186 | .remove_new = mpc52xx_gpiochip_remove, |
187 | }; |
188 | |
189 | /* |
190 | * GPIO LIB API implementation for simple GPIOs |
191 | * |
192 | * There's a maximum of 32 simple GPIOs. Which of these are available |
193 | * for use depends on your board setup. |
194 | * The numbering reflects the bit numbering in the port registers: |
195 | * |
196 | * 0..1 > reserved |
197 | * 2..3 > IRDA |
198 | * 4..7 > ETHR |
199 | * 8..11 > reserved |
200 | * 12..15 > USB |
201 | * 16..17 > reserved |
202 | * 18..23 > PSC3 |
203 | * 24..27 > PSC2 |
204 | * 28..31 > PSC1 |
205 | */ |
206 | static int mpc52xx_simple_gpio_get(struct gpio_chip *gc, unsigned int gpio) |
207 | { |
208 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
209 | struct mpc52xx_gpio __iomem *regs = mm_gc->regs; |
210 | unsigned int ret; |
211 | |
212 | ret = (in_be32(®s->simple_ival) >> (31 - gpio)) & 1; |
213 | |
214 | return ret; |
215 | } |
216 | |
217 | static inline void |
218 | __mpc52xx_simple_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) |
219 | { |
220 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
221 | struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc); |
222 | struct mpc52xx_gpio __iomem *regs = mm_gc->regs; |
223 | |
224 | if (val) |
225 | chip->shadow_dvo |= 1 << (31 - gpio); |
226 | else |
227 | chip->shadow_dvo &= ~(1 << (31 - gpio)); |
228 | out_be32(®s->simple_dvo, chip->shadow_dvo); |
229 | } |
230 | |
231 | static void |
232 | mpc52xx_simple_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) |
233 | { |
234 | unsigned long flags; |
235 | |
236 | spin_lock_irqsave(&gpio_lock, flags); |
237 | |
238 | __mpc52xx_simple_gpio_set(gc, gpio, val); |
239 | |
240 | spin_unlock_irqrestore(lock: &gpio_lock, flags); |
241 | |
242 | pr_debug("%s: gpio: %d val: %d\n" , __func__, gpio, val); |
243 | } |
244 | |
245 | static int mpc52xx_simple_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) |
246 | { |
247 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
248 | struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc); |
249 | struct mpc52xx_gpio __iomem *regs = mm_gc->regs; |
250 | unsigned long flags; |
251 | |
252 | spin_lock_irqsave(&gpio_lock, flags); |
253 | |
254 | /* set the direction */ |
255 | chip->shadow_ddr &= ~(1 << (31 - gpio)); |
256 | out_be32(®s->simple_ddr, chip->shadow_ddr); |
257 | |
258 | /* and enable the pin */ |
259 | chip->shadow_gpioe |= 1 << (31 - gpio); |
260 | out_be32(®s->simple_gpioe, chip->shadow_gpioe); |
261 | |
262 | spin_unlock_irqrestore(lock: &gpio_lock, flags); |
263 | |
264 | return 0; |
265 | } |
266 | |
267 | static int |
268 | mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) |
269 | { |
270 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
271 | struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc); |
272 | struct mpc52xx_gpio __iomem *regs = mm_gc->regs; |
273 | unsigned long flags; |
274 | |
275 | spin_lock_irqsave(&gpio_lock, flags); |
276 | |
277 | /* First set initial value */ |
278 | __mpc52xx_simple_gpio_set(gc, gpio, val); |
279 | |
280 | /* Then set direction */ |
281 | chip->shadow_ddr |= 1 << (31 - gpio); |
282 | out_be32(®s->simple_ddr, chip->shadow_ddr); |
283 | |
284 | /* Finally enable the pin */ |
285 | chip->shadow_gpioe |= 1 << (31 - gpio); |
286 | out_be32(®s->simple_gpioe, chip->shadow_gpioe); |
287 | |
288 | spin_unlock_irqrestore(lock: &gpio_lock, flags); |
289 | |
290 | pr_debug("%s: gpio: %d val: %d\n" , __func__, gpio, val); |
291 | |
292 | return 0; |
293 | } |
294 | |
295 | static int mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev) |
296 | { |
297 | struct mpc52xx_gpiochip *chip; |
298 | struct gpio_chip *gc; |
299 | struct mpc52xx_gpio __iomem *regs; |
300 | int ret; |
301 | |
302 | chip = devm_kzalloc(dev: &ofdev->dev, size: sizeof(*chip), GFP_KERNEL); |
303 | if (!chip) |
304 | return -ENOMEM; |
305 | |
306 | platform_set_drvdata(pdev: ofdev, data: chip); |
307 | |
308 | gc = &chip->mmchip.gc; |
309 | |
310 | gc->ngpio = 32; |
311 | gc->direction_input = mpc52xx_simple_gpio_dir_in; |
312 | gc->direction_output = mpc52xx_simple_gpio_dir_out; |
313 | gc->get = mpc52xx_simple_gpio_get; |
314 | gc->set = mpc52xx_simple_gpio_set; |
315 | |
316 | ret = of_mm_gpiochip_add_data(np: ofdev->dev.of_node, mm_gc: &chip->mmchip, data: chip); |
317 | if (ret) |
318 | return ret; |
319 | |
320 | regs = chip->mmchip.regs; |
321 | chip->shadow_gpioe = in_be32(®s->simple_gpioe); |
322 | chip->shadow_ddr = in_be32(®s->simple_ddr); |
323 | chip->shadow_dvo = in_be32(®s->simple_dvo); |
324 | |
325 | return 0; |
326 | } |
327 | |
328 | static const struct of_device_id mpc52xx_simple_gpiochip_match[] = { |
329 | { .compatible = "fsl,mpc5200-gpio" , }, |
330 | {} |
331 | }; |
332 | |
333 | static struct platform_driver mpc52xx_simple_gpiochip_driver = { |
334 | .driver = { |
335 | .name = "mpc5200-gpio" , |
336 | .of_match_table = mpc52xx_simple_gpiochip_match, |
337 | }, |
338 | .probe = mpc52xx_simple_gpiochip_probe, |
339 | .remove_new = mpc52xx_gpiochip_remove, |
340 | }; |
341 | |
342 | static struct platform_driver * const drivers[] = { |
343 | &mpc52xx_wkup_gpiochip_driver, |
344 | &mpc52xx_simple_gpiochip_driver, |
345 | }; |
346 | |
347 | static int __init mpc52xx_gpio_init(void) |
348 | { |
349 | return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); |
350 | } |
351 | |
352 | /* Make sure we get initialised before anyone else tries to use us */ |
353 | subsys_initcall(mpc52xx_gpio_init); |
354 | |
355 | static void __exit mpc52xx_gpio_exit(void) |
356 | { |
357 | platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); |
358 | } |
359 | module_exit(mpc52xx_gpio_exit); |
360 | |
361 | MODULE_DESCRIPTION("Freescale MPC52xx gpio driver" ); |
362 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de" ); |
363 | MODULE_LICENSE("GPL v2" ); |
364 | |
365 | |