diff options
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/Kconfig | 2 | ||||
-rw-r--r-- | arch/mips/rb532/gpio.c | 228 |
2 files changed, 162 insertions, 68 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 1e06d233fa83..00a23a118492 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -568,7 +568,7 @@ config MIKROTIK_RB532 | |||
568 | select SYS_SUPPORTS_LITTLE_ENDIAN | 568 | select SYS_SUPPORTS_LITTLE_ENDIAN |
569 | select SWAP_IO_SPACE | 569 | select SWAP_IO_SPACE |
570 | select BOOT_RAW | 570 | select BOOT_RAW |
571 | select GENERIC_GPIO | 571 | select ARCH_REQUIRE_GPIOLIB |
572 | help | 572 | help |
573 | Support the Mikrotik(tm) RouterBoard 532 series, | 573 | Support the Mikrotik(tm) RouterBoard 532 series, |
574 | based on the IDT RC32434 SoC. | 574 | based on the IDT RC32434 SoC. |
diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c index b028779fedda..76a7fd96d564 100644 --- a/arch/mips/rb532/gpio.c +++ b/arch/mips/rb532/gpio.c | |||
@@ -27,20 +27,23 @@ | |||
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/gpio.h> | ||
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
32 | #include <linux/types.h> | 31 | #include <linux/types.h> |
33 | #include <linux/pci.h> | ||
34 | #include <linux/spinlock.h> | 32 | #include <linux/spinlock.h> |
35 | #include <linux/io.h> | ||
36 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
37 | 34 | #include <linux/gpio.h> | |
38 | #include <asm/addrspace.h> | ||
39 | 35 | ||
40 | #include <asm/mach-rc32434/rb.h> | 36 | #include <asm/mach-rc32434/rb.h> |
41 | 37 | #include <asm/mach-rc32434/gpio.h> | |
42 | struct rb532_gpio_reg __iomem *rb532_gpio_reg0; | 38 | |
43 | EXPORT_SYMBOL(rb532_gpio_reg0); | 39 | struct rb532_gpio_chip { |
40 | struct gpio_chip chip; | ||
41 | void __iomem *regbase; | ||
42 | void (*set_int_level)(struct gpio_chip *chip, unsigned offset, int value); | ||
43 | int (*get_int_level)(struct gpio_chip *chip, unsigned offset); | ||
44 | void (*set_int_status)(struct gpio_chip *chip, unsigned offset, int value); | ||
45 | int (*get_int_status)(struct gpio_chip *chip, unsigned offset); | ||
46 | }; | ||
44 | 47 | ||
45 | struct mpmc_device dev3; | 48 | struct mpmc_device dev3; |
46 | 49 | ||
@@ -108,108 +111,199 @@ unsigned char get_latch_u5(void) | |||
108 | } | 111 | } |
109 | EXPORT_SYMBOL(get_latch_u5); | 112 | EXPORT_SYMBOL(get_latch_u5); |
110 | 113 | ||
111 | int rb532_gpio_get_value(unsigned gpio) | 114 | /* |
115 | * Return GPIO level */ | ||
116 | static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
112 | { | 117 | { |
113 | return readl(&rb532_gpio_reg0->gpiod) & (1 << gpio); | 118 | u32 mask = 1 << offset; |
119 | struct rb532_gpio_chip *gpch; | ||
120 | |||
121 | gpch = container_of(chip, struct rb532_gpio_chip, chip); | ||
122 | return readl(gpch->regbase + GPIOD) & mask; | ||
114 | } | 123 | } |
115 | EXPORT_SYMBOL(rb532_gpio_get_value); | ||
116 | 124 | ||
117 | void rb532_gpio_set_value(unsigned gpio, int value) | 125 | /* |
126 | * Set output GPIO level | ||
127 | */ | ||
128 | static void rb532_gpio_set(struct gpio_chip *chip, | ||
129 | unsigned offset, int value) | ||
118 | { | 130 | { |
119 | unsigned tmp; | 131 | unsigned long flags; |
132 | u32 mask = 1 << offset; | ||
133 | u32 tmp; | ||
134 | struct rb532_gpio_chip *gpch; | ||
135 | void __iomem *gpvr; | ||
120 | 136 | ||
121 | tmp = readl(&rb532_gpio_reg0->gpiod) & ~(1 << gpio); | 137 | gpch = container_of(chip, struct rb532_gpio_chip, chip); |
122 | if (value) | 138 | gpvr = gpch->regbase + GPIOD; |
123 | tmp |= 1 << gpio; | ||
124 | 139 | ||
125 | writel(tmp, (void *)&rb532_gpio_reg0->gpiod); | 140 | local_irq_save(flags); |
141 | tmp = readl(gpvr); | ||
142 | if (value) | ||
143 | tmp |= mask; | ||
144 | else | ||
145 | tmp &= ~mask; | ||
146 | writel(tmp, gpvr); | ||
147 | local_irq_restore(flags); | ||
126 | } | 148 | } |
127 | EXPORT_SYMBOL(rb532_gpio_set_value); | ||
128 | 149 | ||
129 | int rb532_gpio_direction_input(unsigned gpio) | 150 | /* |
151 | * Set GPIO direction to input | ||
152 | */ | ||
153 | static int rb532_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
130 | { | 154 | { |
131 | writel(readl(&rb532_gpio_reg0->gpiocfg) & ~(1 << gpio), | 155 | unsigned long flags; |
132 | (void *)&rb532_gpio_reg0->gpiocfg); | 156 | u32 mask = 1 << offset; |
157 | u32 value; | ||
158 | struct rb532_gpio_chip *gpch; | ||
159 | void __iomem *gpdr; | ||
133 | 160 | ||
134 | return 0; | 161 | gpch = container_of(chip, struct rb532_gpio_chip, chip); |
135 | } | 162 | gpdr = gpch->regbase + GPIOCFG; |
136 | EXPORT_SYMBOL(rb532_gpio_direction_input); | ||
137 | 163 | ||
138 | int rb532_gpio_direction_output(unsigned gpio, int value) | 164 | local_irq_save(flags); |
139 | { | 165 | value = readl(gpdr); |
140 | gpio_set_value(gpio, value); | 166 | value &= ~mask; |
141 | writel(readl(&rb532_gpio_reg0->gpiocfg) | (1 << gpio), | 167 | writel(value, gpdr); |
142 | (void *)&rb532_gpio_reg0->gpiocfg); | 168 | local_irq_restore(flags); |
143 | 169 | ||
144 | return 0; | 170 | return 0; |
145 | } | 171 | } |
146 | EXPORT_SYMBOL(rb532_gpio_direction_output); | ||
147 | 172 | ||
148 | void rb532_gpio_set_int_level(unsigned gpio, int value) | 173 | /* |
174 | * Set GPIO direction to output | ||
175 | */ | ||
176 | static int rb532_gpio_direction_output(struct gpio_chip *chip, | ||
177 | unsigned offset, int value) | ||
149 | { | 178 | { |
150 | unsigned tmp; | 179 | unsigned long flags; |
180 | u32 mask = 1 << offset; | ||
181 | u32 tmp; | ||
182 | struct rb532_gpio_chip *gpch; | ||
183 | void __iomem *gpdr; | ||
184 | |||
185 | gpch = container_of(chip, struct rb532_gpio_chip, chip); | ||
186 | writel(mask, gpch->regbase + GPIOD); | ||
187 | gpdr = gpch->regbase + GPIOCFG; | ||
188 | |||
189 | local_irq_save(flags); | ||
190 | tmp = readl(gpdr); | ||
191 | tmp |= mask; | ||
192 | writel(tmp, gpdr); | ||
193 | local_irq_restore(flags); | ||
151 | 194 | ||
152 | tmp = readl(&rb532_gpio_reg0->gpioilevel) & ~(1 << gpio); | 195 | return 0; |
153 | if (value) | ||
154 | tmp |= 1 << gpio; | ||
155 | writel(tmp, (void *)&rb532_gpio_reg0->gpioilevel); | ||
156 | } | 196 | } |
157 | EXPORT_SYMBOL(rb532_gpio_set_int_level); | ||
158 | 197 | ||
159 | int rb532_gpio_get_int_level(unsigned gpio) | 198 | /* |
199 | * Set the GPIO interrupt level | ||
200 | */ | ||
201 | static void rb532_gpio_set_int_level(struct gpio_chip *chip, | ||
202 | unsigned offset, int value) | ||
160 | { | 203 | { |
161 | return readl(&rb532_gpio_reg0->gpioilevel) & (1 << gpio); | 204 | unsigned long flags; |
162 | } | 205 | u32 mask = 1 << offset; |
163 | EXPORT_SYMBOL(rb532_gpio_get_int_level); | 206 | u32 tmp; |
207 | struct rb532_gpio_chip *gpch; | ||
208 | void __iomem *gpil; | ||
164 | 209 | ||
165 | void rb532_gpio_set_int_status(unsigned gpio, int value) | 210 | gpch = container_of(chip, struct rb532_gpio_chip, chip); |
166 | { | 211 | gpil = gpch->regbase + GPIOILEVEL; |
167 | unsigned tmp; | ||
168 | 212 | ||
169 | tmp = readl(&rb532_gpio_reg0->gpioistat); | 213 | local_irq_save(flags); |
214 | tmp = readl(gpil); | ||
170 | if (value) | 215 | if (value) |
171 | tmp |= 1 << gpio; | 216 | tmp |= mask; |
172 | writel(tmp, (void *)&rb532_gpio_reg0->gpioistat); | 217 | else |
218 | tmp &= ~mask; | ||
219 | writel(tmp, gpil); | ||
220 | local_irq_restore(flags); | ||
173 | } | 221 | } |
174 | EXPORT_SYMBOL(rb532_gpio_set_int_status); | ||
175 | 222 | ||
176 | int rb532_gpio_get_int_status(unsigned gpio) | 223 | /* |
224 | * Get the GPIO interrupt level | ||
225 | */ | ||
226 | static int rb532_gpio_get_int_level(struct gpio_chip *chip, unsigned offset) | ||
177 | { | 227 | { |
178 | return readl(&rb532_gpio_reg0->gpioistat) & (1 << gpio); | 228 | u32 mask = 1 << offset; |
229 | struct rb532_gpio_chip *gpch; | ||
230 | |||
231 | gpch = container_of(chip, struct rb532_gpio_chip, chip); | ||
232 | return readl(gpch->regbase + GPIOILEVEL) & mask; | ||
179 | } | 233 | } |
180 | EXPORT_SYMBOL(rb532_gpio_get_int_status); | ||
181 | 234 | ||
182 | void rb532_gpio_set_func(unsigned gpio, int value) | 235 | /* |
236 | * Set the GPIO interrupt status | ||
237 | */ | ||
238 | static void rb532_gpio_set_int_status(struct gpio_chip *chip, | ||
239 | unsigned offset, int value) | ||
183 | { | 240 | { |
184 | unsigned tmp; | 241 | unsigned long flags; |
242 | u32 mask = 1 << offset; | ||
243 | u32 tmp; | ||
244 | struct rb532_gpio_chip *gpch; | ||
245 | void __iomem *gpis; | ||
246 | |||
247 | gpch = container_of(chip, struct rb532_gpio_chip, chip); | ||
248 | gpis = gpch->regbase + GPIOISTAT; | ||
185 | 249 | ||
186 | tmp = readl(&rb532_gpio_reg0->gpiofunc); | 250 | local_irq_save(flags); |
251 | tmp = readl(gpis); | ||
187 | if (value) | 252 | if (value) |
188 | tmp |= 1 << gpio; | 253 | tmp |= mask; |
189 | writel(tmp, (void *)&rb532_gpio_reg0->gpiofunc); | 254 | else |
255 | tmp &= ~mask; | ||
256 | writel(tmp, gpis); | ||
257 | local_irq_restore(flags); | ||
190 | } | 258 | } |
191 | EXPORT_SYMBOL(rb532_gpio_set_func); | ||
192 | 259 | ||
193 | int rb532_gpio_get_func(unsigned gpio) | 260 | /* |
261 | * Get the GPIO interrupt status | ||
262 | */ | ||
263 | static int rb532_gpio_get_int_status(struct gpio_chip *chip, unsigned offset) | ||
194 | { | 264 | { |
195 | return readl(&rb532_gpio_reg0->gpiofunc) & (1 << gpio); | 265 | u32 mask = 1 << offset; |
266 | struct rb532_gpio_chip *gpch; | ||
267 | |||
268 | gpch = container_of(chip, struct rb532_gpio_chip, chip); | ||
269 | return readl(gpch->regbase + GPIOISTAT) & mask; | ||
196 | } | 270 | } |
197 | EXPORT_SYMBOL(rb532_gpio_get_func); | 271 | |
272 | static struct rb532_gpio_chip rb532_gpio_chip[] = { | ||
273 | [0] = { | ||
274 | .chip = { | ||
275 | .label = "gpio0", | ||
276 | .direction_input = rb532_gpio_direction_input, | ||
277 | .direction_output = rb532_gpio_direction_output, | ||
278 | .get = rb532_gpio_get, | ||
279 | .set = rb532_gpio_set, | ||
280 | .base = 0, | ||
281 | .ngpio = 32, | ||
282 | }, | ||
283 | .get_int_level = rb532_gpio_get_int_level, | ||
284 | .set_int_level = rb532_gpio_set_int_level, | ||
285 | .get_int_status = rb532_gpio_get_int_status, | ||
286 | .set_int_status = rb532_gpio_set_int_status, | ||
287 | }, | ||
288 | }; | ||
198 | 289 | ||
199 | int __init rb532_gpio_init(void) | 290 | int __init rb532_gpio_init(void) |
200 | { | 291 | { |
201 | rb532_gpio_reg0 = ioremap_nocache(rb532_gpio_reg0_res[0].start, | 292 | struct resource *r; |
202 | rb532_gpio_reg0_res[0].end - | ||
203 | rb532_gpio_reg0_res[0].start); | ||
204 | 293 | ||
205 | if (!rb532_gpio_reg0) { | 294 | r = rb532_gpio_reg0_res; |
295 | rb532_gpio_chip->regbase = ioremap_nocache(r->start, r->end - r->start); | ||
296 | |||
297 | if (!rb532_gpio_chip->regbase) { | ||
206 | printk(KERN_ERR "rb532: cannot remap GPIO register 0\n"); | 298 | printk(KERN_ERR "rb532: cannot remap GPIO register 0\n"); |
207 | return -ENXIO; | 299 | return -ENXIO; |
208 | } | 300 | } |
209 | 301 | ||
210 | dev3.base = ioremap_nocache(rb532_dev3_ctl_res[0].start, | 302 | /* Register our GPIO chip */ |
211 | rb532_dev3_ctl_res[0].end - | 303 | gpiochip_add(&rb532_gpio_chip->chip); |
212 | rb532_dev3_ctl_res[0].start); | 304 | |
305 | r = rb532_dev3_ctl_res; | ||
306 | dev3.base = ioremap_nocache(r->start, r->end - r->start); | ||
213 | 307 | ||
214 | if (!dev3.base) { | 308 | if (!dev3.base) { |
215 | printk(KERN_ERR "rb532: cannot remap device controller 3\n"); | 309 | printk(KERN_ERR "rb532: cannot remap device controller 3\n"); |