aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorJamie Iles <jamie@jamieiles.com>2011-05-20 02:40:19 -0400
committerGrant Likely <grant.likely@secretlab.ca>2011-05-20 02:40:19 -0400
commit280df6b3c3ad777a91f1011cd98d50df891bfef8 (patch)
tree31a03f7c9a8b2e1f4abf26f8fcf46e90c09ccb88 /drivers/gpio
parente849dc044af0939135c822833092bc9baf480222 (diff)
basic_mmio_gpio: split into a gpio library and platform device
Allow GPIO_BASIC_MMIO_CORE to be used to provide an accessor library for implementing GPIO drivers whilst abstracting the register access detail. Based on a patch from Anton Vorontsov[1] and adapted to allow bgpio_chip to be embedded in another structure. Changes since v1: - Register the gpio_chip in the platform device probe 1. https://lkml.org/lkml/2011/4/19/401 Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com> Signed-off-by: Jamie Iles <jamie@jamieiles.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/basic_mmio_gpio.c317
3 files changed, 176 insertions, 148 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 44235bd4f9d..b57ec09af89 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -70,8 +70,14 @@ config GPIO_MAX730X
70 70
71comment "Memory mapped GPIO drivers:" 71comment "Memory mapped GPIO drivers:"
72 72
73config GPIO_BASIC_MMIO_CORE
74 tristate
75 help
76 Provides core functionality for basic memory-mapped GPIO controllers.
77
73config GPIO_BASIC_MMIO 78config GPIO_BASIC_MMIO
74 tristate "Basic memory-mapped GPIO controllers support" 79 tristate "Basic memory-mapped GPIO controllers support"
80 select GPIO_BASIC_MMIO_CORE
75 help 81 help
76 Say yes here to support basic memory-mapped GPIO controllers. 82 Say yes here to support basic memory-mapped GPIO controllers.
77 83
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 7b2bdceca08..d92ce3a62ae 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o
6 6
7obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o 7obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o
8obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o 8obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o
9obj-$(CONFIG_GPIO_BASIC_MMIO_CORE) += basic_mmio_gpio.o
9obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o 10obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o
10obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o 11obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o
11obj-$(CONFIG_GPIO_MAX730X) += max730x.o 12obj-$(CONFIG_GPIO_MAX730X) += max730x.o
diff --git a/drivers/gpio/basic_mmio_gpio.c b/drivers/gpio/basic_mmio_gpio.c
index b2ec45ffe44..8152e9f516b 100644
--- a/drivers/gpio/basic_mmio_gpio.c
+++ b/drivers/gpio/basic_mmio_gpio.c
@@ -45,6 +45,7 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
45 */ 45 */
46 46
47#include <linux/init.h> 47#include <linux/init.h>
48#include <linux/err.h>
48#include <linux/bug.h> 49#include <linux/bug.h>
49#include <linux/kernel.h> 50#include <linux/kernel.h>
50#include <linux/module.h> 51#include <linux/module.h>
@@ -61,44 +62,6 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
61#include <linux/mod_devicetable.h> 62#include <linux/mod_devicetable.h>
62#include <linux/basic_mmio_gpio.h> 63#include <linux/basic_mmio_gpio.h>
63 64
64struct bgpio_chip {
65 struct gpio_chip gc;
66
67 unsigned long (*read_reg)(void __iomem *reg);
68 void (*write_reg)(void __iomem *reg, unsigned long data);
69
70 void __iomem *reg_dat;
71 void __iomem *reg_set;
72 void __iomem *reg_clr;
73 void __iomem *reg_dir;
74
75 /* Number of bits (GPIOs): <register width> * 8. */
76 int bits;
77
78 /*
79 * Some GPIO controllers work with the big-endian bits notation,
80 * e.g. in a 8-bits register, GPIO7 is the least significant bit.
81 */
82 unsigned long (*pin2mask)(struct bgpio_chip *bgc, unsigned int pin);
83
84 /*
85 * Used to lock bgpio_chip->data. Also, this is needed to keep
86 * shadowed and real data registers writes together.
87 */
88 spinlock_t lock;
89
90 /* Shadowed data register to clear/set bits safely. */
91 unsigned long data;
92
93 /* Shadowed direction registers to clear/set direction safely. */
94 unsigned long dir;
95};
96
97static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
98{
99 return container_of(gc, struct bgpio_chip, gc);
100}
101
102static void bgpio_write8(void __iomem *reg, unsigned long data) 65static void bgpio_write8(void __iomem *reg, unsigned long data)
103{ 66{
104 writeb(data, reg); 67 writeb(data, reg);
@@ -284,20 +247,10 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
284 return 0; 247 return 0;
285} 248}
286 249
287static void __iomem *bgpio_request_and_map(struct device *dev, 250static int bgpio_setup_accessors(struct device *dev,
288 struct resource *res) 251 struct bgpio_chip *bgc,
289{ 252 bool be)
290 if (!devm_request_mem_region(dev, res->start, resource_size(res),
291 res->name ?: "mmio_gpio"))
292 return NULL;
293
294 return devm_ioremap(dev, res->start, resource_size(res));
295}
296
297static int bgpio_setup_accessors(struct platform_device *pdev,
298 struct bgpio_chip *bgc)
299{ 253{
300 const struct platform_device_id *platid = platform_get_device_id(pdev);
301 254
302 switch (bgc->bits) { 255 switch (bgc->bits) {
303 case 8: 256 case 8:
@@ -319,13 +272,11 @@ static int bgpio_setup_accessors(struct platform_device *pdev,
319 break; 272 break;
320#endif /* BITS_PER_LONG >= 64 */ 273#endif /* BITS_PER_LONG >= 64 */
321 default: 274 default:
322 dev_err(&pdev->dev, "unsupported data width %u bits\n", 275 dev_err(dev, "unsupported data width %u bits\n", bgc->bits);
323 bgc->bits);
324 return -EINVAL; 276 return -EINVAL;
325 } 277 }
326 278
327 bgc->pin2mask = strcmp(platid->name, "basic-mmio-gpio-be") ? 279 bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask;
328 bgpio_pin2mask : bgpio_pin2mask_be;
329 280
330 return 0; 281 return 0;
331} 282}
@@ -352,51 +303,22 @@ static int bgpio_setup_accessors(struct platform_device *pdev,
352 * - an input direction register (named "dirin") where a 1 bit indicates 303 * - an input direction register (named "dirin") where a 1 bit indicates
353 * the GPIO is an input. 304 * the GPIO is an input.
354 */ 305 */
355static int bgpio_setup_io(struct platform_device *pdev, 306static int bgpio_setup_io(struct bgpio_chip *bgc,
356 struct bgpio_chip *bgc) 307 void __iomem *dat,
308 void __iomem *set,
309 void __iomem *clr)
357{ 310{
358 struct resource *res_set;
359 struct resource *res_clr;
360 struct resource *res_dat;
361 resource_size_t dat_sz;
362 311
363 res_dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); 312 bgc->reg_dat = dat;
364 if (!res_dat)
365 return -EINVAL;
366
367 dat_sz = resource_size(res_dat);
368 if (!is_power_of_2(dat_sz))
369 return -EINVAL;
370
371 bgc->bits = dat_sz * 8;
372 if (bgc->bits > BITS_PER_LONG)
373 return -EINVAL;
374
375 bgc->reg_dat = bgpio_request_and_map(&pdev->dev, res_dat);
376 if (!bgc->reg_dat) 313 if (!bgc->reg_dat)
377 return -ENOMEM; 314 return -EINVAL;
378
379 res_set = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set");
380 res_clr = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr");
381 if (res_set && res_clr) {
382 if (resource_size(res_set) != resource_size(res_clr) ||
383 resource_size(res_set) != resource_size(res_dat))
384 return -EINVAL;
385
386 bgc->reg_set = bgpio_request_and_map(&pdev->dev, res_set);
387 bgc->reg_clr = bgpio_request_and_map(&pdev->dev, res_clr);
388 if (!bgc->reg_set || !bgc->reg_clr)
389 return -ENOMEM;
390 315
316 if (set && clr) {
317 bgc->reg_set = set;
318 bgc->reg_clr = clr;
391 bgc->gc.set = bgpio_set_with_clear; 319 bgc->gc.set = bgpio_set_with_clear;
392 } else if (res_set && !res_clr) { 320 } else if (set && !clr) {
393 if (resource_size(res_set) != resource_size(res_dat)) 321 bgc->reg_set = set;
394 return -EINVAL;
395
396 bgc->reg_set = bgpio_request_and_map(&pdev->dev, res_set);
397 if (!bgc->reg_set)
398 return -ENOMEM;
399
400 bgc->gc.set = bgpio_set_set; 322 bgc->gc.set = bgpio_set_set;
401 } else { 323 } else {
402 bgc->gc.set = bgpio_set; 324 bgc->gc.set = bgpio_set;
@@ -407,27 +329,18 @@ static int bgpio_setup_io(struct platform_device *pdev,
407 return 0; 329 return 0;
408} 330}
409 331
410static int bgpio_setup_direction(struct platform_device *pdev, 332static int bgpio_setup_direction(struct bgpio_chip *bgc,
411 struct bgpio_chip *bgc) 333 void __iomem *dirout,
334 void __iomem *dirin)
412{ 335{
413 struct resource *res_dirout; 336 if (dirout && dirin) {
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; 337 return -EINVAL;
421 } else if (res_dirout) { 338 } else if (dirout) {
422 bgc->reg_dir = bgpio_request_and_map(&pdev->dev, res_dirout); 339 bgc->reg_dir = dirout;
423 if (!bgc->reg_dir)
424 return -ENOMEM;
425 bgc->gc.direction_output = bgpio_dir_out; 340 bgc->gc.direction_output = bgpio_dir_out;
426 bgc->gc.direction_input = bgpio_dir_in; 341 bgc->gc.direction_input = bgpio_dir_in;
427 } else if (res_dirin) { 342 } else if (dirin) {
428 bgc->reg_dir = bgpio_request_and_map(&pdev->dev, res_dirin); 343 bgc->reg_dir = dirin;
429 if (!bgc->reg_dir)
430 return -ENOMEM;
431 bgc->gc.direction_output = bgpio_dir_out_inv; 344 bgc->gc.direction_output = bgpio_dir_out_inv;
432 bgc->gc.direction_input = bgpio_dir_in_inv; 345 bgc->gc.direction_input = bgpio_dir_in_inv;
433 } else { 346 } else {
@@ -438,60 +351,166 @@ static int bgpio_setup_direction(struct platform_device *pdev,
438 return 0; 351 return 0;
439} 352}
440 353
441static int __devinit bgpio_probe(struct platform_device *pdev) 354int __devexit bgpio_remove(struct bgpio_chip *bgc)
355{
356 int err = gpiochip_remove(&bgc->gc);
357
358 kfree(bgc);
359
360 return err;
361}
362EXPORT_SYMBOL_GPL(bgpio_remove);
363
364int __devinit bgpio_init(struct bgpio_chip *bgc,
365 struct device *dev,
366 unsigned long sz,
367 void __iomem *dat,
368 void __iomem *set,
369 void __iomem *clr,
370 void __iomem *dirout,
371 void __iomem *dirin,
372 bool big_endian)
442{ 373{
443 struct device *dev = &pdev->dev;
444 struct bgpio_pdata *pdata = dev_get_platdata(dev);
445 struct bgpio_chip *bgc;
446 int ret; 374 int ret;
447 int ngpio;
448 375
449 bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL); 376 if (!is_power_of_2(sz))
450 if (!bgc) 377 return -EINVAL;
451 return -ENOMEM;
452 378
453 ret = bgpio_setup_io(pdev, bgc); 379 bgc->bits = sz * 8;
380 if (bgc->bits > BITS_PER_LONG)
381 return -EINVAL;
382
383 spin_lock_init(&bgc->lock);
384 bgc->gc.dev = dev;
385 bgc->gc.label = dev_name(dev);
386 bgc->gc.base = -1;
387 bgc->gc.ngpio = bgc->bits;
388
389 ret = bgpio_setup_io(bgc, dat, set, clr);
454 if (ret) 390 if (ret)
455 return ret; 391 return ret;
456 392
457 ngpio = bgc->bits; 393 ret = bgpio_setup_accessors(dev, bgc, big_endian);
458 if (pdata) {
459 bgc->gc.base = pdata->base;
460 if (pdata->ngpio > 0)
461 ngpio = pdata->ngpio;
462 } else {
463 bgc->gc.base = -1;
464 }
465
466 ret = bgpio_setup_accessors(pdev, bgc);
467 if (ret) 394 if (ret)
468 return ret; 395 return ret;
469 396
470 spin_lock_init(&bgc->lock); 397 ret = bgpio_setup_direction(bgc, dirout, dirin);
471 ret = bgpio_setup_direction(pdev, bgc);
472 if (ret) 398 if (ret)
473 return ret; 399 return ret;
474 400
475 bgc->data = bgc->read_reg(bgc->reg_dat); 401 bgc->data = bgc->read_reg(bgc->reg_dat);
476 402
477 bgc->gc.ngpio = ngpio; 403 return ret;
478 bgc->gc.dev = dev; 404}
479 bgc->gc.label = dev_name(dev); 405EXPORT_SYMBOL_GPL(bgpio_init);
480 406
481 platform_set_drvdata(pdev, bgc); 407#ifdef CONFIG_GPIO_BASIC_MMIO
482 408
483 ret = gpiochip_add(&bgc->gc); 409static void __iomem *bgpio_map(struct platform_device *pdev,
484 if (ret) 410 const char *name,
485 dev_err(dev, "gpiochip_add() failed: %d\n", ret); 411 resource_size_t sane_sz,
412 int *err)
413{
414 struct device *dev = &pdev->dev;
415 struct resource *r;
416 resource_size_t start;
417 resource_size_t sz;
418 void __iomem *ret;
419
420 *err = 0;
421
422 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
423 if (!r)
424 return NULL;
425
426 sz = resource_size(r);
427 if (sz != sane_sz) {
428 *err = -EINVAL;
429 return NULL;
430 }
431
432 start = r->start;
433 if (!devm_request_mem_region(dev, start, sz, r->name)) {
434 *err = -EBUSY;
435 return NULL;
436 }
437
438 ret = devm_ioremap(dev, start, sz);
439 if (!ret) {
440 *err = -ENOMEM;
441 return NULL;
442 }
486 443
487 return ret; 444 return ret;
488} 445}
489 446
490static int __devexit bgpio_remove(struct platform_device *pdev) 447static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
448{
449 struct device *dev = &pdev->dev;
450 struct resource *r;
451 void __iomem *dat;
452 void __iomem *set;
453 void __iomem *clr;
454 void __iomem *dirout;
455 void __iomem *dirin;
456 unsigned long sz;
457 bool be;
458 int err;
459 struct bgpio_chip *bgc;
460 struct bgpio_pdata *pdata = dev_get_platdata(dev);
461
462 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
463 if (!r)
464 return -EINVAL;
465
466 sz = resource_size(r);
467
468 dat = bgpio_map(pdev, "dat", sz, &err);
469 if (!dat)
470 return err ? err : -EINVAL;
471
472 set = bgpio_map(pdev, "set", sz, &err);
473 if (err)
474 return err;
475
476 clr = bgpio_map(pdev, "clr", sz, &err);
477 if (err)
478 return err;
479
480 dirout = bgpio_map(pdev, "dirout", sz, &err);
481 if (err)
482 return err;
483
484 dirin = bgpio_map(pdev, "dirin", sz, &err);
485 if (err)
486 return err;
487
488 be = !strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be");
489
490 bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
491 if (!bgc)
492 return -ENOMEM;
493
494 err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, be);
495 if (err)
496 return err;
497
498 if (pdata) {
499 bgc->gc.base = pdata->base;
500 if (pdata->ngpio > 0)
501 bgc->gc.ngpio = pdata->ngpio;
502 }
503
504 platform_set_drvdata(pdev, bgc);
505
506 return gpiochip_add(&bgc->gc);
507}
508
509static int __devexit bgpio_pdev_remove(struct platform_device *pdev)
491{ 510{
492 struct bgpio_chip *bgc = platform_get_drvdata(pdev); 511 struct bgpio_chip *bgc = platform_get_drvdata(pdev);
493 512
494 return gpiochip_remove(&bgc->gc); 513 return bgpio_remove(bgc);
495} 514}
496 515
497static const struct platform_device_id bgpio_id_table[] = { 516static const struct platform_device_id bgpio_id_table[] = {
@@ -506,21 +525,23 @@ static struct platform_driver bgpio_driver = {
506 .name = "basic-mmio-gpio", 525 .name = "basic-mmio-gpio",
507 }, 526 },
508 .id_table = bgpio_id_table, 527 .id_table = bgpio_id_table,
509 .probe = bgpio_probe, 528 .probe = bgpio_pdev_probe,
510 .remove = __devexit_p(bgpio_remove), 529 .remove = __devexit_p(bgpio_pdev_remove),
511}; 530};
512 531
513static int __init bgpio_init(void) 532static int __init bgpio_platform_init(void)
514{ 533{
515 return platform_driver_register(&bgpio_driver); 534 return platform_driver_register(&bgpio_driver);
516} 535}
517module_init(bgpio_init); 536module_init(bgpio_platform_init);
518 537
519static void __exit bgpio_exit(void) 538static void __exit bgpio_platform_exit(void)
520{ 539{
521 platform_driver_unregister(&bgpio_driver); 540 platform_driver_unregister(&bgpio_driver);
522} 541}
523module_exit(bgpio_exit); 542module_exit(bgpio_platform_exit);
543
544#endif /* CONFIG_GPIO_BASIC_MMIO */
524 545
525MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers"); 546MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers");
526MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); 547MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");