diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2015-08-28 17:48:56 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-10-02 07:19:33 -0400 |
commit | 9f3538280301bb953bf159d5ce9fc1f41482aa4c (patch) | |
tree | 9ebcc34dc993f2a04a7bd250b45a7910eef1ddee /drivers/gpio/gpio-msm-v2.c | |
parent | fa9795d1121e18a6ee2d0f8b2e837f51d63d4b00 (diff) |
gpio: msm: Remove unused driver
Remove this driver now that Bjorn has introduced a pinctrl driver
for msm8660 and the dts files have been updated with the pinctrl
compatibles.
Cc: Andy Gross <agross@codeaurora.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpio-msm-v2.c')
-rw-r--r-- | drivers/gpio/gpio-msm-v2.c | 453 |
1 files changed, 0 insertions, 453 deletions
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c deleted file mode 100644 index 4b4222145f10..000000000000 --- a/drivers/gpio/gpio-msm-v2.c +++ /dev/null | |||
@@ -1,453 +0,0 @@ | |||
1 | /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
15 | * 02110-1301, USA. | ||
16 | * | ||
17 | */ | ||
18 | #define pr_fmt(fmt) "%s: " fmt, __func__ | ||
19 | |||
20 | #include <linux/bitmap.h> | ||
21 | #include <linux/bitops.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/gpio.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/irqchip/chained_irq.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/irqdomain.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/of_address.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/slab.h> | ||
35 | |||
36 | #define MAX_NR_GPIO 300 | ||
37 | |||
38 | /* Bits of interest in the GPIO_IN_OUT register. | ||
39 | */ | ||
40 | enum { | ||
41 | GPIO_IN = 0, | ||
42 | GPIO_OUT = 1 | ||
43 | }; | ||
44 | |||
45 | /* Bits of interest in the GPIO_INTR_STATUS register. | ||
46 | */ | ||
47 | enum { | ||
48 | INTR_STATUS = 0, | ||
49 | }; | ||
50 | |||
51 | /* Bits of interest in the GPIO_CFG register. | ||
52 | */ | ||
53 | enum { | ||
54 | GPIO_OE = 9, | ||
55 | }; | ||
56 | |||
57 | /* Bits of interest in the GPIO_INTR_CFG register. | ||
58 | * When a GPIO triggers, two separate decisions are made, controlled | ||
59 | * by two separate flags. | ||
60 | * | ||
61 | * - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS | ||
62 | * register for that GPIO will be updated to reflect the triggering of that | ||
63 | * gpio. If this bit is 0, this register will not be updated. | ||
64 | * - Second, INTR_ENABLE controls whether an interrupt is triggered. | ||
65 | * | ||
66 | * If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt | ||
67 | * can be triggered but the status register will not reflect it. | ||
68 | */ | ||
69 | enum { | ||
70 | INTR_ENABLE = 0, | ||
71 | INTR_POL_CTL = 1, | ||
72 | INTR_DECT_CTL = 2, | ||
73 | INTR_RAW_STATUS_EN = 3, | ||
74 | }; | ||
75 | |||
76 | /* Codes of interest in GPIO_INTR_CFG_SU. | ||
77 | */ | ||
78 | enum { | ||
79 | TARGET_PROC_SCORPION = 4, | ||
80 | TARGET_PROC_NONE = 7, | ||
81 | }; | ||
82 | |||
83 | /** | ||
84 | * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure | ||
85 | * | ||
86 | * @enabled_irqs: a bitmap used to optimize the summary-irq handler. By | ||
87 | * keeping track of which gpios are unmasked as irq sources, we avoid | ||
88 | * having to do readl calls on hundreds of iomapped registers each time | ||
89 | * the summary interrupt fires in order to locate the active interrupts. | ||
90 | * | ||
91 | * @wake_irqs: a bitmap for tracking which interrupt lines are enabled | ||
92 | * as wakeup sources. When the device is suspended, interrupts which are | ||
93 | * not wakeup sources are disabled. | ||
94 | * | ||
95 | * @dual_edge_irqs: a bitmap used to track which irqs are configured | ||
96 | * as dual-edge, as this is not supported by the hardware and requires | ||
97 | * some special handling in the driver. | ||
98 | */ | ||
99 | struct msm_gpio_dev { | ||
100 | struct gpio_chip gpio_chip; | ||
101 | DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); | ||
102 | DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO); | ||
103 | DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); | ||
104 | struct irq_domain *domain; | ||
105 | int summary_irq; | ||
106 | void __iomem *msm_tlmm_base; | ||
107 | }; | ||
108 | |||
109 | static struct msm_gpio_dev msm_gpio; | ||
110 | |||
111 | #define GPIO_INTR_CFG_SU(gpio) (msm_gpio.msm_tlmm_base + 0x0400 + \ | ||
112 | (0x04 * (gpio))) | ||
113 | #define GPIO_CONFIG(gpio) (msm_gpio.msm_tlmm_base + 0x1000 + \ | ||
114 | (0x10 * (gpio))) | ||
115 | #define GPIO_IN_OUT(gpio) (msm_gpio.msm_tlmm_base + 0x1004 + \ | ||
116 | (0x10 * (gpio))) | ||
117 | #define GPIO_INTR_CFG(gpio) (msm_gpio.msm_tlmm_base + 0x1008 + \ | ||
118 | (0x10 * (gpio))) | ||
119 | #define GPIO_INTR_STATUS(gpio) (msm_gpio.msm_tlmm_base + 0x100c + \ | ||
120 | (0x10 * (gpio))) | ||
121 | |||
122 | static DEFINE_SPINLOCK(tlmm_lock); | ||
123 | |||
124 | static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip) | ||
125 | { | ||
126 | return container_of(chip, struct msm_gpio_dev, gpio_chip); | ||
127 | } | ||
128 | |||
129 | static inline void set_gpio_bits(unsigned n, void __iomem *reg) | ||
130 | { | ||
131 | writel(readl(reg) | n, reg); | ||
132 | } | ||
133 | |||
134 | static inline void clear_gpio_bits(unsigned n, void __iomem *reg) | ||
135 | { | ||
136 | writel(readl(reg) & ~n, reg); | ||
137 | } | ||
138 | |||
139 | static int msm_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
140 | { | ||
141 | return readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN); | ||
142 | } | ||
143 | |||
144 | static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | ||
145 | { | ||
146 | writel(val ? BIT(GPIO_OUT) : 0, GPIO_IN_OUT(offset)); | ||
147 | } | ||
148 | |||
149 | static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
150 | { | ||
151 | unsigned long irq_flags; | ||
152 | |||
153 | spin_lock_irqsave(&tlmm_lock, irq_flags); | ||
154 | clear_gpio_bits(BIT(GPIO_OE), GPIO_CONFIG(offset)); | ||
155 | spin_unlock_irqrestore(&tlmm_lock, irq_flags); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int msm_gpio_direction_output(struct gpio_chip *chip, | ||
160 | unsigned offset, | ||
161 | int val) | ||
162 | { | ||
163 | unsigned long irq_flags; | ||
164 | |||
165 | spin_lock_irqsave(&tlmm_lock, irq_flags); | ||
166 | msm_gpio_set(chip, offset, val); | ||
167 | set_gpio_bits(BIT(GPIO_OE), GPIO_CONFIG(offset)); | ||
168 | spin_unlock_irqrestore(&tlmm_lock, irq_flags); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int msm_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
173 | { | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static void msm_gpio_free(struct gpio_chip *chip, unsigned offset) | ||
178 | { | ||
179 | return; | ||
180 | } | ||
181 | |||
182 | static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
183 | { | ||
184 | struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip); | ||
185 | struct irq_domain *domain = g_dev->domain; | ||
186 | |||
187 | return irq_create_mapping(domain, offset); | ||
188 | } | ||
189 | |||
190 | /* For dual-edge interrupts in software, since the hardware has no | ||
191 | * such support: | ||
192 | * | ||
193 | * At appropriate moments, this function may be called to flip the polarity | ||
194 | * settings of both-edge irq lines to try and catch the next edge. | ||
195 | * | ||
196 | * The attempt is considered successful if: | ||
197 | * - the status bit goes high, indicating that an edge was caught, or | ||
198 | * - the input value of the gpio doesn't change during the attempt. | ||
199 | * If the value changes twice during the process, that would cause the first | ||
200 | * test to fail but would force the second, as two opposite | ||
201 | * transitions would cause a detection no matter the polarity setting. | ||
202 | * | ||
203 | * The do-loop tries to sledge-hammer closed the timing hole between | ||
204 | * the initial value-read and the polarity-write - if the line value changes | ||
205 | * during that window, an interrupt is lost, the new polarity setting is | ||
206 | * incorrect, and the first success test will fail, causing a retry. | ||
207 | * | ||
208 | * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c. | ||
209 | */ | ||
210 | static void msm_gpio_update_dual_edge_pos(unsigned gpio) | ||
211 | { | ||
212 | int loop_limit = 100; | ||
213 | unsigned val, val2, intstat; | ||
214 | |||
215 | do { | ||
216 | val = readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN); | ||
217 | if (val) | ||
218 | clear_gpio_bits(BIT(INTR_POL_CTL), GPIO_INTR_CFG(gpio)); | ||
219 | else | ||
220 | set_gpio_bits(BIT(INTR_POL_CTL), GPIO_INTR_CFG(gpio)); | ||
221 | val2 = readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN); | ||
222 | intstat = readl(GPIO_INTR_STATUS(gpio)) & BIT(INTR_STATUS); | ||
223 | if (intstat || val == val2) | ||
224 | return; | ||
225 | } while (loop_limit-- > 0); | ||
226 | pr_err("%s: dual-edge irq failed to stabilize, " | ||
227 | "interrupts dropped. %#08x != %#08x\n", | ||
228 | __func__, val, val2); | ||
229 | } | ||
230 | |||
231 | static void msm_gpio_irq_ack(struct irq_data *d) | ||
232 | { | ||
233 | int gpio = d->hwirq; | ||
234 | |||
235 | writel(BIT(INTR_STATUS), GPIO_INTR_STATUS(gpio)); | ||
236 | if (test_bit(gpio, msm_gpio.dual_edge_irqs)) | ||
237 | msm_gpio_update_dual_edge_pos(gpio); | ||
238 | } | ||
239 | |||
240 | static void msm_gpio_irq_mask(struct irq_data *d) | ||
241 | { | ||
242 | unsigned long irq_flags; | ||
243 | int gpio = d->hwirq; | ||
244 | |||
245 | spin_lock_irqsave(&tlmm_lock, irq_flags); | ||
246 | writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio)); | ||
247 | clear_gpio_bits(BIT(INTR_RAW_STATUS_EN) | BIT(INTR_ENABLE), GPIO_INTR_CFG(gpio)); | ||
248 | __clear_bit(gpio, msm_gpio.enabled_irqs); | ||
249 | spin_unlock_irqrestore(&tlmm_lock, irq_flags); | ||
250 | } | ||
251 | |||
252 | static void msm_gpio_irq_unmask(struct irq_data *d) | ||
253 | { | ||
254 | unsigned long irq_flags; | ||
255 | int gpio = d->hwirq; | ||
256 | |||
257 | spin_lock_irqsave(&tlmm_lock, irq_flags); | ||
258 | __set_bit(gpio, msm_gpio.enabled_irqs); | ||
259 | set_gpio_bits(BIT(INTR_RAW_STATUS_EN) | BIT(INTR_ENABLE), GPIO_INTR_CFG(gpio)); | ||
260 | writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio)); | ||
261 | spin_unlock_irqrestore(&tlmm_lock, irq_flags); | ||
262 | } | ||
263 | |||
264 | static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) | ||
265 | { | ||
266 | unsigned long irq_flags; | ||
267 | int gpio = d->hwirq; | ||
268 | uint32_t bits; | ||
269 | |||
270 | spin_lock_irqsave(&tlmm_lock, irq_flags); | ||
271 | |||
272 | bits = readl(GPIO_INTR_CFG(gpio)); | ||
273 | |||
274 | if (flow_type & IRQ_TYPE_EDGE_BOTH) { | ||
275 | bits |= BIT(INTR_DECT_CTL); | ||
276 | irq_set_handler_locked(d, handle_edge_irq); | ||
277 | if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) | ||
278 | __set_bit(gpio, msm_gpio.dual_edge_irqs); | ||
279 | else | ||
280 | __clear_bit(gpio, msm_gpio.dual_edge_irqs); | ||
281 | } else { | ||
282 | bits &= ~BIT(INTR_DECT_CTL); | ||
283 | irq_set_handler_locked(d, handle_level_irq); | ||
284 | __clear_bit(gpio, msm_gpio.dual_edge_irqs); | ||
285 | } | ||
286 | |||
287 | if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)) | ||
288 | bits |= BIT(INTR_POL_CTL); | ||
289 | else | ||
290 | bits &= ~BIT(INTR_POL_CTL); | ||
291 | |||
292 | writel(bits, GPIO_INTR_CFG(gpio)); | ||
293 | |||
294 | if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) | ||
295 | msm_gpio_update_dual_edge_pos(gpio); | ||
296 | |||
297 | spin_unlock_irqrestore(&tlmm_lock, irq_flags); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * When the summary IRQ is raised, any number of GPIO lines may be high. | ||
304 | * It is the job of the summary handler to find all those GPIO lines | ||
305 | * which have been set as summary IRQ lines and which are triggered, | ||
306 | * and to call their interrupt handlers. | ||
307 | */ | ||
308 | static void msm_summary_irq_handler(struct irq_desc *desc) | ||
309 | { | ||
310 | unsigned long i; | ||
311 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
312 | |||
313 | chained_irq_enter(chip, desc); | ||
314 | |||
315 | for_each_set_bit(i, msm_gpio.enabled_irqs, MAX_NR_GPIO) { | ||
316 | if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS)) | ||
317 | generic_handle_irq(irq_find_mapping(msm_gpio.domain, | ||
318 | i)); | ||
319 | } | ||
320 | |||
321 | chained_irq_exit(chip, desc); | ||
322 | } | ||
323 | |||
324 | static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) | ||
325 | { | ||
326 | int gpio = d->hwirq; | ||
327 | |||
328 | if (on) { | ||
329 | if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO)) | ||
330 | irq_set_irq_wake(msm_gpio.summary_irq, 1); | ||
331 | set_bit(gpio, msm_gpio.wake_irqs); | ||
332 | } else { | ||
333 | clear_bit(gpio, msm_gpio.wake_irqs); | ||
334 | if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO)) | ||
335 | irq_set_irq_wake(msm_gpio.summary_irq, 0); | ||
336 | } | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static struct irq_chip msm_gpio_irq_chip = { | ||
342 | .name = "msmgpio", | ||
343 | .irq_mask = msm_gpio_irq_mask, | ||
344 | .irq_unmask = msm_gpio_irq_unmask, | ||
345 | .irq_ack = msm_gpio_irq_ack, | ||
346 | .irq_set_type = msm_gpio_irq_set_type, | ||
347 | .irq_set_wake = msm_gpio_irq_set_wake, | ||
348 | }; | ||
349 | |||
350 | static struct lock_class_key msm_gpio_lock_class; | ||
351 | |||
352 | static int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq, | ||
353 | irq_hw_number_t hwirq) | ||
354 | { | ||
355 | irq_set_lockdep_class(irq, &msm_gpio_lock_class); | ||
356 | irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, | ||
357 | handle_level_irq); | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static const struct irq_domain_ops msm_gpio_irq_domain_ops = { | ||
363 | .xlate = irq_domain_xlate_twocell, | ||
364 | .map = msm_gpio_irq_domain_map, | ||
365 | }; | ||
366 | |||
367 | static int msm_gpio_probe(struct platform_device *pdev) | ||
368 | { | ||
369 | int ret, ngpio; | ||
370 | struct resource *res; | ||
371 | |||
372 | if (of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio)) { | ||
373 | dev_err(&pdev->dev, "%s: ngpio property missing\n", __func__); | ||
374 | return -EINVAL; | ||
375 | } | ||
376 | |||
377 | if (ngpio > MAX_NR_GPIO) | ||
378 | WARN(1, "ngpio exceeds the MAX_NR_GPIO. Increase MAX_NR_GPIO\n"); | ||
379 | |||
380 | bitmap_zero(msm_gpio.enabled_irqs, MAX_NR_GPIO); | ||
381 | bitmap_zero(msm_gpio.wake_irqs, MAX_NR_GPIO); | ||
382 | bitmap_zero(msm_gpio.dual_edge_irqs, MAX_NR_GPIO); | ||
383 | |||
384 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
385 | msm_gpio.msm_tlmm_base = devm_ioremap_resource(&pdev->dev, res); | ||
386 | if (IS_ERR(msm_gpio.msm_tlmm_base)) | ||
387 | return PTR_ERR(msm_gpio.msm_tlmm_base); | ||
388 | |||
389 | msm_gpio.gpio_chip.ngpio = ngpio; | ||
390 | msm_gpio.gpio_chip.label = pdev->name; | ||
391 | msm_gpio.gpio_chip.dev = &pdev->dev; | ||
392 | msm_gpio.gpio_chip.base = 0; | ||
393 | msm_gpio.gpio_chip.direction_input = msm_gpio_direction_input; | ||
394 | msm_gpio.gpio_chip.direction_output = msm_gpio_direction_output; | ||
395 | msm_gpio.gpio_chip.get = msm_gpio_get; | ||
396 | msm_gpio.gpio_chip.set = msm_gpio_set; | ||
397 | msm_gpio.gpio_chip.to_irq = msm_gpio_to_irq; | ||
398 | msm_gpio.gpio_chip.request = msm_gpio_request; | ||
399 | msm_gpio.gpio_chip.free = msm_gpio_free; | ||
400 | |||
401 | ret = gpiochip_add(&msm_gpio.gpio_chip); | ||
402 | if (ret < 0) { | ||
403 | dev_err(&pdev->dev, "gpiochip_add failed with error %d\n", ret); | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | msm_gpio.summary_irq = platform_get_irq(pdev, 0); | ||
408 | if (msm_gpio.summary_irq < 0) { | ||
409 | dev_err(&pdev->dev, "No Summary irq defined for msmgpio\n"); | ||
410 | return msm_gpio.summary_irq; | ||
411 | } | ||
412 | |||
413 | msm_gpio.domain = irq_domain_add_linear(pdev->dev.of_node, ngpio, | ||
414 | &msm_gpio_irq_domain_ops, | ||
415 | &msm_gpio); | ||
416 | if (!msm_gpio.domain) | ||
417 | return -ENODEV; | ||
418 | |||
419 | irq_set_chained_handler(msm_gpio.summary_irq, msm_summary_irq_handler); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static const struct of_device_id msm_gpio_of_match[] = { | ||
425 | { .compatible = "qcom,msm-gpio", }, | ||
426 | { }, | ||
427 | }; | ||
428 | MODULE_DEVICE_TABLE(of, msm_gpio_of_match); | ||
429 | |||
430 | static int msm_gpio_remove(struct platform_device *dev) | ||
431 | { | ||
432 | gpiochip_remove(&msm_gpio.gpio_chip); | ||
433 | |||
434 | irq_set_handler(msm_gpio.summary_irq, NULL); | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static struct platform_driver msm_gpio_driver = { | ||
440 | .probe = msm_gpio_probe, | ||
441 | .remove = msm_gpio_remove, | ||
442 | .driver = { | ||
443 | .name = "msmgpio", | ||
444 | .of_match_table = msm_gpio_of_match, | ||
445 | }, | ||
446 | }; | ||
447 | |||
448 | module_platform_driver(msm_gpio_driver) | ||
449 | |||
450 | MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>"); | ||
451 | MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs"); | ||
452 | MODULE_LICENSE("GPL v2"); | ||
453 | MODULE_ALIAS("platform:msmgpio"); | ||