diff options
author | Jamie Iles <jamie@jamieiles.com> | 2011-05-20 02:40:19 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-05-20 02:40:19 -0400 |
commit | 280df6b3c3ad777a91f1011cd98d50df891bfef8 (patch) | |
tree | 31a03f7c9a8b2e1f4abf26f8fcf46e90c09ccb88 /drivers/gpio | |
parent | e849dc044af0939135c822833092bc9baf480222 (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/Kconfig | 6 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/basic_mmio_gpio.c | 317 |
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 | ||
71 | comment "Memory mapped GPIO drivers:" | 71 | comment "Memory mapped GPIO drivers:" |
72 | 72 | ||
73 | config GPIO_BASIC_MMIO_CORE | ||
74 | tristate | ||
75 | help | ||
76 | Provides core functionality for basic memory-mapped GPIO controllers. | ||
77 | |||
73 | config GPIO_BASIC_MMIO | 78 | config 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 | ||
7 | obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o | 7 | obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o |
8 | obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o | 8 | obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o |
9 | obj-$(CONFIG_GPIO_BASIC_MMIO_CORE) += basic_mmio_gpio.o | ||
9 | obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o | 10 | obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o |
10 | obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o | 11 | obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o |
11 | obj-$(CONFIG_GPIO_MAX730X) += max730x.o | 12 | obj-$(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 | ||
64 | struct 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 | |||
97 | static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc) | ||
98 | { | ||
99 | return container_of(gc, struct bgpio_chip, gc); | ||
100 | } | ||
101 | |||
102 | static void bgpio_write8(void __iomem *reg, unsigned long data) | 65 | static 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 | ||
287 | static void __iomem *bgpio_request_and_map(struct device *dev, | 250 | static 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 | |||
297 | static 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 | */ |
355 | static int bgpio_setup_io(struct platform_device *pdev, | 306 | static 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 | ||
410 | static int bgpio_setup_direction(struct platform_device *pdev, | 332 | static 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 | ||
441 | static int __devinit bgpio_probe(struct platform_device *pdev) | 354 | int __devexit bgpio_remove(struct bgpio_chip *bgc) |
355 | { | ||
356 | int err = gpiochip_remove(&bgc->gc); | ||
357 | |||
358 | kfree(bgc); | ||
359 | |||
360 | return err; | ||
361 | } | ||
362 | EXPORT_SYMBOL_GPL(bgpio_remove); | ||
363 | |||
364 | int __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); | 405 | EXPORT_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); | 409 | static 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 | ||
490 | static int __devexit bgpio_remove(struct platform_device *pdev) | 447 | static 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 | |||
509 | static 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 | ||
497 | static const struct platform_device_id bgpio_id_table[] = { | 516 | static 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 | ||
513 | static int __init bgpio_init(void) | 532 | static int __init bgpio_platform_init(void) |
514 | { | 533 | { |
515 | return platform_driver_register(&bgpio_driver); | 534 | return platform_driver_register(&bgpio_driver); |
516 | } | 535 | } |
517 | module_init(bgpio_init); | 536 | module_init(bgpio_platform_init); |
518 | 537 | ||
519 | static void __exit bgpio_exit(void) | 538 | static void __exit bgpio_platform_exit(void) |
520 | { | 539 | { |
521 | platform_driver_unregister(&bgpio_driver); | 540 | platform_driver_unregister(&bgpio_driver); |
522 | } | 541 | } |
523 | module_exit(bgpio_exit); | 542 | module_exit(bgpio_platform_exit); |
543 | |||
544 | #endif /* CONFIG_GPIO_BASIC_MMIO */ | ||
524 | 545 | ||
525 | MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers"); | 546 | MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers"); |
526 | MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); | 547 | MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); |