diff options
author | Jamie Iles <jamie@jamieiles.com> | 2011-05-20 02:40:17 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-05-20 02:40:17 -0400 |
commit | 31029116ebc1f2481bd2380437e9f7a18f18dca5 (patch) | |
tree | 09f616736afbc6ffefc88a7662c3bd1871e58f9d /drivers/gpio/basic_mmio_gpio.c | |
parent | dd86a0cc5e35161538c10e35eb85e2ad0adfe14d (diff) |
basic_mmio_gpio: support direction registers
Most controllers require the direction of a GPIO to be set by writing to
a direction register. Add support for either an input direction
register or an output direction register.
Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/gpio/basic_mmio_gpio.c')
-rw-r--r-- | drivers/gpio/basic_mmio_gpio.c | 114 |
1 files changed, 112 insertions, 2 deletions
diff --git a/drivers/gpio/basic_mmio_gpio.c b/drivers/gpio/basic_mmio_gpio.c index 6b99489e0ebb..f4afd96303c1 100644 --- a/drivers/gpio/basic_mmio_gpio.c +++ b/drivers/gpio/basic_mmio_gpio.c | |||
@@ -70,6 +70,7 @@ struct bgpio_chip { | |||
70 | void __iomem *reg_dat; | 70 | void __iomem *reg_dat; |
71 | void __iomem *reg_set; | 71 | void __iomem *reg_set; |
72 | void __iomem *reg_clr; | 72 | void __iomem *reg_clr; |
73 | void __iomem *reg_dir; | ||
73 | 74 | ||
74 | /* Number of bits (GPIOs): <register width> * 8. */ | 75 | /* Number of bits (GPIOs): <register width> * 8. */ |
75 | int bits; | 76 | int bits; |
@@ -88,6 +89,9 @@ struct bgpio_chip { | |||
88 | 89 | ||
89 | /* Shadowed data register to clear/set bits safely. */ | 90 | /* Shadowed data register to clear/set bits safely. */ |
90 | unsigned long data; | 91 | unsigned long data; |
92 | |||
93 | /* Shadowed direction registers to clear/set direction safely. */ | ||
94 | unsigned long dir; | ||
91 | }; | 95 | }; |
92 | 96 | ||
93 | static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc) | 97 | static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc) |
@@ -203,15 +207,80 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) | |||
203 | spin_unlock_irqrestore(&bgc->lock, flags); | 207 | spin_unlock_irqrestore(&bgc->lock, flags); |
204 | } | 208 | } |
205 | 209 | ||
210 | static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
211 | { | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio, | ||
216 | int val) | ||
217 | { | ||
218 | gc->set(gc, gpio, val); | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
206 | static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) | 223 | static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) |
207 | { | 224 | { |
225 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | ||
226 | unsigned long flags; | ||
227 | |||
228 | spin_lock_irqsave(&bgc->lock, flags); | ||
229 | |||
230 | bgc->dir &= ~bgc->pin2mask(bgc, gpio); | ||
231 | bgc->write_reg(bgc->reg_dir, bgc->dir); | ||
232 | |||
233 | spin_unlock_irqrestore(&bgc->lock, flags); | ||
234 | |||
208 | return 0; | 235 | return 0; |
209 | } | 236 | } |
210 | 237 | ||
211 | static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | 238 | static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) |
212 | { | 239 | { |
240 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | ||
241 | unsigned long flags; | ||
242 | |||
243 | gc->set(gc, gpio, val); | ||
244 | |||
245 | spin_lock_irqsave(&bgc->lock, flags); | ||
246 | |||
247 | bgc->dir |= bgc->pin2mask(bgc, gpio); | ||
248 | bgc->write_reg(bgc->reg_dir, bgc->dir); | ||
249 | |||
250 | spin_unlock_irqrestore(&bgc->lock, flags); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio) | ||
256 | { | ||
257 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | ||
258 | unsigned long flags; | ||
259 | |||
260 | spin_lock_irqsave(&bgc->lock, flags); | ||
261 | |||
262 | bgc->dir |= bgc->pin2mask(bgc, gpio); | ||
263 | bgc->write_reg(bgc->reg_dir, bgc->dir); | ||
264 | |||
265 | spin_unlock_irqrestore(&bgc->lock, flags); | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) | ||
271 | { | ||
272 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | ||
273 | unsigned long flags; | ||
274 | |||
213 | gc->set(gc, gpio, val); | 275 | gc->set(gc, gpio, val); |
214 | 276 | ||
277 | spin_lock_irqsave(&bgc->lock, flags); | ||
278 | |||
279 | bgc->dir &= ~bgc->pin2mask(bgc, gpio); | ||
280 | bgc->write_reg(bgc->reg_dir, bgc->dir); | ||
281 | |||
282 | spin_unlock_irqrestore(&bgc->lock, flags); | ||
283 | |||
215 | return 0; | 284 | return 0; |
216 | } | 285 | } |
217 | 286 | ||
@@ -274,6 +343,14 @@ static int bgpio_setup_accessors(struct platform_device *pdev, | |||
274 | * by clearing a bit. For the set clr pair, this drives a 1 by setting a bit | 343 | * by clearing a bit. For the set clr pair, this drives a 1 by setting a bit |
275 | * in the set register and clears it by setting a bit in the clear register. | 344 | * in the set register and clears it by setting a bit in the clear register. |
276 | * The configuration is detected by which resources are present. | 345 | * The configuration is detected by which resources are present. |
346 | * | ||
347 | * For setting the GPIO direction, there are three supported configurations: | ||
348 | * | ||
349 | * - simple bidirection GPIO that requires no configuration. | ||
350 | * - an output direction register (named "dirout") where a 1 bit | ||
351 | * indicates the GPIO is an output. | ||
352 | * - an input direction register (named "dirin") where a 1 bit indicates | ||
353 | * the GPIO is an input. | ||
277 | */ | 354 | */ |
278 | static int bgpio_setup_io(struct platform_device *pdev, | 355 | static int bgpio_setup_io(struct platform_device *pdev, |
279 | struct bgpio_chip *bgc) | 356 | struct bgpio_chip *bgc) |
@@ -330,6 +407,37 @@ static int bgpio_setup_io(struct platform_device *pdev, | |||
330 | return 0; | 407 | return 0; |
331 | } | 408 | } |
332 | 409 | ||
410 | static int bgpio_setup_direction(struct platform_device *pdev, | ||
411 | struct bgpio_chip *bgc) | ||
412 | { | ||
413 | struct resource *res_dirout; | ||
414 | struct resource *res_dirin; | ||
415 | |||
416 | res_dirout = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
417 | "dirout"); | ||
418 | res_dirin = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirin"); | ||
419 | if (res_dirout && res_dirin) { | ||
420 | return -EINVAL; | ||
421 | } else if (res_dirout) { | ||
422 | bgc->reg_dir = bgpio_request_and_map(&pdev->dev, res_dirout); | ||
423 | if (!bgc->reg_dir) | ||
424 | return -ENOMEM; | ||
425 | bgc->gc.direction_output = bgpio_dir_out; | ||
426 | bgc->gc.direction_input = bgpio_dir_in; | ||
427 | } else if (res_dirin) { | ||
428 | bgc->reg_dir = bgpio_request_and_map(&pdev->dev, res_dirin); | ||
429 | if (!bgc->reg_dir) | ||
430 | return -ENOMEM; | ||
431 | bgc->gc.direction_output = bgpio_dir_out_inv; | ||
432 | bgc->gc.direction_input = bgpio_dir_in_inv; | ||
433 | } else { | ||
434 | bgc->gc.direction_output = bgpio_simple_dir_out; | ||
435 | bgc->gc.direction_input = bgpio_simple_dir_in; | ||
436 | } | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
333 | static int __devinit bgpio_probe(struct platform_device *pdev) | 441 | static int __devinit bgpio_probe(struct platform_device *pdev) |
334 | { | 442 | { |
335 | struct device *dev = &pdev->dev; | 443 | struct device *dev = &pdev->dev; |
@@ -360,11 +468,13 @@ static int __devinit bgpio_probe(struct platform_device *pdev) | |||
360 | return ret; | 468 | return ret; |
361 | 469 | ||
362 | spin_lock_init(&bgc->lock); | 470 | spin_lock_init(&bgc->lock); |
471 | ret = bgpio_setup_direction(pdev, bgc); | ||
472 | if (ret) | ||
473 | return ret; | ||
474 | |||
363 | bgc->data = bgc->read_reg(bgc->reg_dat); | 475 | bgc->data = bgc->read_reg(bgc->reg_dat); |
364 | 476 | ||
365 | bgc->gc.ngpio = ngpio; | 477 | bgc->gc.ngpio = ngpio; |
366 | bgc->gc.direction_input = bgpio_dir_in; | ||
367 | bgc->gc.direction_output = bgpio_dir_out; | ||
368 | bgc->gc.dev = dev; | 478 | bgc->gc.dev = dev; |
369 | bgc->gc.label = dev_name(dev); | 479 | bgc->gc.label = dev_name(dev); |
370 | 480 | ||