1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Coldfire generic GPIO support. |
4 | * |
5 | * (C) Copyright 2009, Steven King <sfking@fdwdc.com> |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> |
10 | #include <linux/init.h> |
11 | #include <linux/device.h> |
12 | #include <linux/gpio/driver.h> |
13 | |
14 | #include <linux/io.h> |
15 | #include <asm/coldfire.h> |
16 | #include <asm/mcfsim.h> |
17 | #include <asm/mcfgpio.h> |
18 | |
19 | int __mcfgpio_get_value(unsigned gpio) |
20 | { |
21 | return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio); |
22 | } |
23 | EXPORT_SYMBOL(__mcfgpio_get_value); |
24 | |
25 | void __mcfgpio_set_value(unsigned gpio, int value) |
26 | { |
27 | if (gpio < MCFGPIO_SCR_START) { |
28 | unsigned long flags; |
29 | MCFGPIO_PORTTYPE data; |
30 | |
31 | local_irq_save(flags); |
32 | data = mcfgpio_read(__mcfgpio_podr(gpio)); |
33 | if (value) |
34 | data |= mcfgpio_bit(gpio); |
35 | else |
36 | data &= ~mcfgpio_bit(gpio); |
37 | mcfgpio_write(data, __mcfgpio_podr(gpio)); |
38 | local_irq_restore(flags); |
39 | } else { |
40 | if (value) |
41 | mcfgpio_write(mcfgpio_bit(gpio), |
42 | MCFGPIO_SETR_PORT(gpio)); |
43 | else |
44 | mcfgpio_write(~mcfgpio_bit(gpio), |
45 | MCFGPIO_CLRR_PORT(gpio)); |
46 | } |
47 | } |
48 | EXPORT_SYMBOL(__mcfgpio_set_value); |
49 | |
50 | int __mcfgpio_direction_input(unsigned gpio) |
51 | { |
52 | unsigned long flags; |
53 | MCFGPIO_PORTTYPE dir; |
54 | |
55 | local_irq_save(flags); |
56 | dir = mcfgpio_read(__mcfgpio_pddr(gpio)); |
57 | dir &= ~mcfgpio_bit(gpio); |
58 | mcfgpio_write(dir, __mcfgpio_pddr(gpio)); |
59 | local_irq_restore(flags); |
60 | |
61 | return 0; |
62 | } |
63 | EXPORT_SYMBOL(__mcfgpio_direction_input); |
64 | |
65 | int __mcfgpio_direction_output(unsigned gpio, int value) |
66 | { |
67 | unsigned long flags; |
68 | MCFGPIO_PORTTYPE data; |
69 | |
70 | local_irq_save(flags); |
71 | data = mcfgpio_read(__mcfgpio_pddr(gpio)); |
72 | data |= mcfgpio_bit(gpio); |
73 | mcfgpio_write(data, __mcfgpio_pddr(gpio)); |
74 | |
75 | /* now set the data to output */ |
76 | if (gpio < MCFGPIO_SCR_START) { |
77 | data = mcfgpio_read(__mcfgpio_podr(gpio)); |
78 | if (value) |
79 | data |= mcfgpio_bit(gpio); |
80 | else |
81 | data &= ~mcfgpio_bit(gpio); |
82 | mcfgpio_write(data, __mcfgpio_podr(gpio)); |
83 | } else { |
84 | if (value) |
85 | mcfgpio_write(mcfgpio_bit(gpio), |
86 | MCFGPIO_SETR_PORT(gpio)); |
87 | else |
88 | mcfgpio_write(~mcfgpio_bit(gpio), |
89 | MCFGPIO_CLRR_PORT(gpio)); |
90 | } |
91 | local_irq_restore(flags); |
92 | return 0; |
93 | } |
94 | EXPORT_SYMBOL(__mcfgpio_direction_output); |
95 | |
96 | int __mcfgpio_request(unsigned gpio) |
97 | { |
98 | return 0; |
99 | } |
100 | EXPORT_SYMBOL(__mcfgpio_request); |
101 | |
102 | void __mcfgpio_free(unsigned gpio) |
103 | { |
104 | __mcfgpio_direction_input(gpio); |
105 | } |
106 | EXPORT_SYMBOL(__mcfgpio_free); |
107 | |
108 | #ifdef CONFIG_GPIOLIB |
109 | |
110 | static int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset) |
111 | { |
112 | return __mcfgpio_direction_input(offset); |
113 | } |
114 | |
115 | static int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset) |
116 | { |
117 | return !!__mcfgpio_get_value(offset); |
118 | } |
119 | |
120 | static int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset, |
121 | int value) |
122 | { |
123 | return __mcfgpio_direction_output(offset, value); |
124 | } |
125 | |
126 | static void mcfgpio_set_value(struct gpio_chip *chip, unsigned offset, |
127 | int value) |
128 | { |
129 | __mcfgpio_set_value(offset, value); |
130 | } |
131 | |
132 | static int mcfgpio_request(struct gpio_chip *chip, unsigned offset) |
133 | { |
134 | return __mcfgpio_request(offset); |
135 | } |
136 | |
137 | static void mcfgpio_free(struct gpio_chip *chip, unsigned offset) |
138 | { |
139 | __mcfgpio_free(offset); |
140 | } |
141 | |
142 | static int mcfgpio_to_irq(struct gpio_chip *chip, unsigned offset) |
143 | { |
144 | #if defined(MCFGPIO_IRQ_MIN) |
145 | if ((offset >= MCFGPIO_IRQ_MIN) && (offset < MCFGPIO_IRQ_MAX)) |
146 | #else |
147 | if (offset < MCFGPIO_IRQ_MAX) |
148 | #endif |
149 | return MCFGPIO_IRQ_VECBASE + offset; |
150 | else |
151 | return -EINVAL; |
152 | } |
153 | |
154 | static struct gpio_chip mcfgpio_chip = { |
155 | .label = "mcfgpio" , |
156 | .request = mcfgpio_request, |
157 | .free = mcfgpio_free, |
158 | .direction_input = mcfgpio_direction_input, |
159 | .direction_output = mcfgpio_direction_output, |
160 | .get = mcfgpio_get_value, |
161 | .set = mcfgpio_set_value, |
162 | .to_irq = mcfgpio_to_irq, |
163 | .base = 0, |
164 | .ngpio = MCFGPIO_PIN_MAX, |
165 | }; |
166 | |
167 | static int __init mcfgpio_sysinit(void) |
168 | { |
169 | return gpiochip_add_data(&mcfgpio_chip, NULL); |
170 | } |
171 | |
172 | core_initcall(mcfgpio_sysinit); |
173 | #endif |
174 | |