aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@openedhand.com>2008-06-20 05:02:19 -0400
committerSamuel Ortiz <samuel@sortiz.org>2008-07-20 13:52:38 -0400
commit6f2384c4bdd4be3dc1e5d22ed5e6f0c3076fda60 (patch)
tree2b2db76100b1e7420a661ca1491b67e7b5de79b0
parent5b664cb235e97afbf34db9c4d77f08ebd725335e (diff)
mfd: asic3 gpiolib support
ASIC3 is, among other things, a GPIO extender. We should thus have it supporting the current gpiolib API. Signed-off-by: Samuel Ortiz <sameo@openedhand.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
-rw-r--r--drivers/mfd/asic3.c224
-rw-r--r--include/linux/mfd/asic3.h24
2 files changed, 164 insertions, 84 deletions
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index ef8a492766a7..c70e7a5a5a90 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -9,7 +9,7 @@
9 * 9 *
10 * Copyright 2001 Compaq Computer Corporation. 10 * Copyright 2001 Compaq Computer Corporation.
11 * Copyright 2004-2005 Phil Blundell 11 * Copyright 2004-2005 Phil Blundell
12 * Copyright 2007 OpenedHand Ltd. 12 * Copyright 2007-2008 OpenedHand Ltd.
13 * 13 *
14 * Authors: Phil Blundell <pb@handhelds.org>, 14 * Authors: Phil Blundell <pb@handhelds.org>,
15 * Samuel Ortiz <sameo@openedhand.com> 15 * Samuel Ortiz <sameo@openedhand.com>
@@ -19,12 +19,26 @@
19#include <linux/version.h> 19#include <linux/version.h>
20#include <linux/kernel.h> 20#include <linux/kernel.h>
21#include <linux/irq.h> 21#include <linux/irq.h>
22#include <linux/gpio.h>
22#include <linux/io.h> 23#include <linux/io.h>
23#include <linux/spinlock.h> 24#include <linux/spinlock.h>
24#include <linux/platform_device.h> 25#include <linux/platform_device.h>
25 26
26#include <linux/mfd/asic3.h> 27#include <linux/mfd/asic3.h>
27 28
29struct asic3 {
30 void __iomem *mapping;
31 unsigned int bus_shift;
32 unsigned int irq_nr;
33 unsigned int irq_base;
34 spinlock_t lock;
35 u16 irq_bothedge[4];
36 struct gpio_chip gpio;
37 struct device *dev;
38};
39
40static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset);
41
28static inline void asic3_write_register(struct asic3 *asic, 42static inline void asic3_write_register(struct asic3 *asic,
29 unsigned int reg, u32 value) 43 unsigned int reg, u32 value)
30{ 44{
@@ -251,7 +265,7 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
251 edge &= ~bit; 265 edge &= ~bit;
252 } else if (type == IRQT_BOTHEDGE) { 266 } else if (type == IRQT_BOTHEDGE) {
253 trigger |= bit; 267 trigger |= bit;
254 if (asic3_gpio_get_value(asic, irq - asic->irq_base)) 268 if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base))
255 edge &= ~bit; 269 edge &= ~bit;
256 else 270 else
257 edge |= bit; 271 edge |= bit;
@@ -350,6 +364,107 @@ static void asic3_irq_remove(struct platform_device *pdev)
350} 364}
351 365
352/* GPIOs */ 366/* GPIOs */
367static int asic3_gpio_direction(struct gpio_chip *chip,
368 unsigned offset, int out)
369{
370 u32 mask = ASIC3_GPIO_TO_MASK(offset), out_reg;
371 unsigned int gpio_base;
372 unsigned long flags;
373 struct asic3 *asic;
374
375 asic = container_of(chip, struct asic3, gpio);
376 gpio_base = ASIC3_GPIO_TO_BASE(offset);
377
378 if (gpio_base > ASIC3_GPIO_D_Base) {
379 printk(KERN_ERR "Invalid base (0x%x) for gpio %d\n",
380 gpio_base, offset);
381 return -EINVAL;
382 }
383
384 spin_lock_irqsave(&asic->lock, flags);
385
386 out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_Direction);
387
388 /* Input is 0, Output is 1 */
389 if (out)
390 out_reg |= mask;
391 else
392 out_reg &= ~mask;
393
394 asic3_write_register(asic, gpio_base + ASIC3_GPIO_Direction, out_reg);
395
396 spin_unlock_irqrestore(&asic->lock, flags);
397
398 return 0;
399
400}
401
402static int asic3_gpio_direction_input(struct gpio_chip *chip,
403 unsigned offset)
404{
405 return asic3_gpio_direction(chip, offset, 0);
406}
407
408static int asic3_gpio_direction_output(struct gpio_chip *chip,
409 unsigned offset, int value)
410{
411 return asic3_gpio_direction(chip, offset, 1);
412}
413
414static int asic3_gpio_get(struct gpio_chip *chip,
415 unsigned offset)
416{
417 unsigned int gpio_base;
418 u32 mask = ASIC3_GPIO_TO_MASK(offset);
419 struct asic3 *asic;
420
421 asic = container_of(chip, struct asic3, gpio);
422 gpio_base = ASIC3_GPIO_TO_BASE(offset);
423
424 if (gpio_base > ASIC3_GPIO_D_Base) {
425 printk(KERN_ERR "Invalid base (0x%x) for gpio %d\n",
426 gpio_base, offset);
427 return -EINVAL;
428 }
429
430 return asic3_read_register(asic, gpio_base + ASIC3_GPIO_Status) & mask;
431}
432
433static void asic3_gpio_set(struct gpio_chip *chip,
434 unsigned offset, int value)
435{
436 u32 mask, out_reg;
437 unsigned int gpio_base;
438 unsigned long flags;
439 struct asic3 *asic;
440
441 asic = container_of(chip, struct asic3, gpio);
442 gpio_base = ASIC3_GPIO_TO_BASE(offset);
443
444 if (gpio_base > ASIC3_GPIO_D_Base) {
445 printk(KERN_ERR "Invalid base (0x%x) for gpio %d\n",
446 gpio_base, offset);
447 return;
448 }
449
450 mask = ASIC3_GPIO_TO_MASK(offset);
451
452 spin_lock_irqsave(&asic->lock, flags);
453
454 out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_Out);
455
456 if (value)
457 out_reg |= mask;
458 else
459 out_reg &= ~mask;
460
461 asic3_write_register(asic, gpio_base + ASIC3_GPIO_Out, out_reg);
462
463 spin_unlock_irqrestore(&asic->lock, flags);
464
465 return;
466}
467
353static inline u32 asic3_get_gpio(struct asic3 *asic, unsigned int base, 468static inline u32 asic3_get_gpio(struct asic3 *asic, unsigned int base,
354 unsigned int function) 469 unsigned int function)
355{ 470{
@@ -368,15 +483,6 @@ static void asic3_set_gpio(struct asic3 *asic, unsigned int base,
368 spin_unlock_irqrestore(&asic->lock, flags); 483 spin_unlock_irqrestore(&asic->lock, flags);
369} 484}
370 485
371#define asic3_get_gpio_a(asic, fn) \
372 asic3_get_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn)
373#define asic3_get_gpio_b(asic, fn) \
374 asic3_get_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn)
375#define asic3_get_gpio_c(asic, fn) \
376 asic3_get_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn)
377#define asic3_get_gpio_d(asic, fn) \
378 asic3_get_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn)
379
380#define asic3_set_gpio_a(asic, fn, bits, val) \ 486#define asic3_set_gpio_a(asic, fn, bits, val) \
381 asic3_set_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn, bits, val) 487 asic3_set_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn, bits, val)
382#define asic3_set_gpio_b(asic, fn, bits, val) \ 488#define asic3_set_gpio_b(asic, fn, bits, val) \
@@ -394,54 +500,6 @@ static void asic3_set_gpio(struct asic3 *asic, unsigned int base,
394 asic3_set_gpio_d((asic), fn, (bits), (pdata)->gpio_d.field); \ 500 asic3_set_gpio_d((asic), fn, (bits), (pdata)->gpio_d.field); \
395 } while (0) 501 } while (0)
396 502
397int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio)
398{
399 u32 mask = ASIC3_GPIO_bit(gpio);
400
401 switch (gpio >> 4) {
402 case ASIC3_GPIO_BANK_A:
403 return asic3_get_gpio_a(asic, Status) & mask;
404 case ASIC3_GPIO_BANK_B:
405 return asic3_get_gpio_b(asic, Status) & mask;
406 case ASIC3_GPIO_BANK_C:
407 return asic3_get_gpio_c(asic, Status) & mask;
408 case ASIC3_GPIO_BANK_D:
409 return asic3_get_gpio_d(asic, Status) & mask;
410 default:
411 printk(KERN_ERR "%s: invalid GPIO value 0x%x",
412 __func__, gpio);
413 return -EINVAL;
414 }
415}
416EXPORT_SYMBOL(asic3_gpio_get_value);
417
418void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val)
419{
420 u32 mask = ASIC3_GPIO_bit(gpio);
421 u32 bitval = 0;
422 if (val)
423 bitval = mask;
424
425 switch (gpio >> 4) {
426 case ASIC3_GPIO_BANK_A:
427 asic3_set_gpio_a(asic, Out, mask, bitval);
428 return;
429 case ASIC3_GPIO_BANK_B:
430 asic3_set_gpio_b(asic, Out, mask, bitval);
431 return;
432 case ASIC3_GPIO_BANK_C:
433 asic3_set_gpio_c(asic, Out, mask, bitval);
434 return;
435 case ASIC3_GPIO_BANK_D:
436 asic3_set_gpio_d(asic, Out, mask, bitval);
437 return;
438 default:
439 printk(KERN_ERR "%s: invalid GPIO value 0x%x",
440 __func__, gpio);
441 return;
442 }
443}
444EXPORT_SYMBOL(asic3_gpio_set_value);
445 503
446static int asic3_gpio_probe(struct platform_device *pdev) 504static int asic3_gpio_probe(struct platform_device *pdev)
447{ 505{
@@ -472,12 +530,14 @@ static int asic3_gpio_probe(struct platform_device *pdev)
472 alt_function); 530 alt_function);
473 } 531 }
474 532
475 return 0; 533 return gpiochip_add(&asic->gpio);
476} 534}
477 535
478static void asic3_gpio_remove(struct platform_device *pdev) 536static int asic3_gpio_remove(struct platform_device *pdev)
479{ 537{
480 return; 538 struct asic3 *asic = platform_get_drvdata(pdev);
539
540 return gpiochip_remove(&asic->gpio);
481} 541}
482 542
483 543
@@ -488,11 +548,13 @@ static int asic3_probe(struct platform_device *pdev)
488 struct asic3 *asic; 548 struct asic3 *asic;
489 struct resource *mem; 549 struct resource *mem;
490 unsigned long clksel; 550 unsigned long clksel;
491 int ret; 551 int ret = 0;
492 552
493 asic = kzalloc(sizeof(struct asic3), GFP_KERNEL); 553 asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
494 if (!asic) 554 if (asic == NULL) {
555 printk(KERN_ERR "kzalloc failed\n");
495 return -ENOMEM; 556 return -ENOMEM;
557 }
496 558
497 spin_lock_init(&asic->lock); 559 spin_lock_init(&asic->lock);
498 platform_set_drvdata(pdev, asic); 560 platform_set_drvdata(pdev, asic);
@@ -502,14 +564,15 @@ static int asic3_probe(struct platform_device *pdev)
502 if (!mem) { 564 if (!mem) {
503 ret = -ENOMEM; 565 ret = -ENOMEM;
504 printk(KERN_ERR "asic3: no MEM resource\n"); 566 printk(KERN_ERR "asic3: no MEM resource\n");
505 goto err_out_1; 567 goto out_free;
506 } 568 }
507 569
570
508 asic->mapping = ioremap(mem->start, PAGE_SIZE); 571 asic->mapping = ioremap(mem->start, PAGE_SIZE);
509 if (!asic->mapping) { 572 if (!asic->mapping) {
510 ret = -ENOMEM; 573 ret = -ENOMEM;
511 printk(KERN_ERR "asic3: couldn't ioremap\n"); 574 printk(KERN_ERR "asic3: couldn't ioremap\n");
512 goto err_out_1; 575 goto out_free;
513 } 576 }
514 577
515 asic->irq_base = pdata->irq_base; 578 asic->irq_base = pdata->irq_base;
@@ -525,9 +588,21 @@ static int asic3_probe(struct platform_device *pdev)
525 ret = asic3_irq_probe(pdev); 588 ret = asic3_irq_probe(pdev);
526 if (ret < 0) { 589 if (ret < 0) {
527 printk(KERN_ERR "asic3: couldn't probe IRQs\n"); 590 printk(KERN_ERR "asic3: couldn't probe IRQs\n");
528 goto err_out_2; 591 goto out_unmap;
592 }
593
594 asic->gpio.base = pdata->gpio_base;
595 asic->gpio.ngpio = ASIC3_NUM_GPIOS;
596 asic->gpio.get = asic3_gpio_get;
597 asic->gpio.set = asic3_gpio_set;
598 asic->gpio.direction_input = asic3_gpio_direction_input;
599 asic->gpio.direction_output = asic3_gpio_direction_output;
600
601 ret = asic3_gpio_probe(pdev);
602 if (ret < 0) {
603 printk(KERN_ERR "GPIO probe failed\n");
604 goto out_irq;
529 } 605 }
530 asic3_gpio_probe(pdev);
531 606
532 if (pdata->children) { 607 if (pdata->children) {
533 int i; 608 int i;
@@ -541,9 +616,13 @@ static int asic3_probe(struct platform_device *pdev)
541 616
542 return 0; 617 return 0;
543 618
544 err_out_2: 619 out_irq:
620 asic3_irq_remove(pdev);
621
622 out_unmap:
545 iounmap(asic->mapping); 623 iounmap(asic->mapping);
546 err_out_1: 624
625 out_free:
547 kfree(asic); 626 kfree(asic);
548 627
549 return ret; 628 return ret;
@@ -551,9 +630,12 @@ static int asic3_probe(struct platform_device *pdev)
551 630
552static int asic3_remove(struct platform_device *pdev) 631static int asic3_remove(struct platform_device *pdev)
553{ 632{
633 int ret;
554 struct asic3 *asic = platform_get_drvdata(pdev); 634 struct asic3 *asic = platform_get_drvdata(pdev);
555 635
556 asic3_gpio_remove(pdev); 636 ret = asic3_gpio_remove(pdev);
637 if (ret < 0)
638 return ret;
557 asic3_irq_remove(pdev); 639 asic3_irq_remove(pdev);
558 640
559 asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0); 641 asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0);
diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h
index 4ab2162db13b..06ef8165f406 100644
--- a/include/linux/mfd/asic3.h
+++ b/include/linux/mfd/asic3.h
@@ -16,16 +16,6 @@
16 16
17#include <linux/types.h> 17#include <linux/types.h>
18 18
19struct asic3 {
20 void __iomem *mapping;
21 unsigned int bus_shift;
22 unsigned int irq_nr;
23 unsigned int irq_base;
24 spinlock_t lock;
25 u16 irq_bothedge[4];
26 struct device *dev;
27};
28
29struct asic3_platform_data { 19struct asic3_platform_data {
30 struct { 20 struct {
31 u32 dir; 21 u32 dir;
@@ -41,18 +31,19 @@ struct asic3_platform_data {
41 31
42 unsigned int irq_base; 32 unsigned int irq_base;
43 33
34 unsigned int gpio_base;
35
44 struct platform_device **children; 36 struct platform_device **children;
45 unsigned int n_children; 37 unsigned int n_children;
46}; 38};
47 39
48int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio);
49void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val);
50
51#define ASIC3_NUM_GPIO_BANKS 4 40#define ASIC3_NUM_GPIO_BANKS 4
52#define ASIC3_GPIOS_PER_BANK 16 41#define ASIC3_GPIOS_PER_BANK 16
53#define ASIC3_NUM_GPIOS 64 42#define ASIC3_NUM_GPIOS 64
54#define ASIC3_NR_IRQS ASIC3_NUM_GPIOS + 6 43#define ASIC3_NR_IRQS ASIC3_NUM_GPIOS + 6
55 44
45#define ASIC3_TO_GPIO(gpio) (NR_BUILTIN_GPIO + (gpio))
46
56#define ASIC3_GPIO_BANK_A 0 47#define ASIC3_GPIO_BANK_A 0
57#define ASIC3_GPIO_BANK_B 1 48#define ASIC3_GPIO_BANK_B 1
58#define ASIC3_GPIO_BANK_C 2 49#define ASIC3_GPIO_BANK_C 2
@@ -73,6 +64,13 @@ void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val);
73#define ASIC3_GPIO_C_Base 0x0200 64#define ASIC3_GPIO_C_Base 0x0200
74#define ASIC3_GPIO_D_Base 0x0300 65#define ASIC3_GPIO_D_Base 0x0300
75 66
67#define ASIC3_GPIO_TO_BANK(gpio) ((gpio) >> 4)
68#define ASIC3_GPIO_TO_BIT(gpio) ((gpio) - \
69 (ASIC3_GPIOS_PER_BANK * ((gpio) >> 4)))
70#define ASIC3_GPIO_TO_MASK(gpio) (1 << ASIC3_GPIO_TO_BIT(gpio))
71#define ASIC3_GPIO_TO_BASE(gpio) (ASIC3_GPIO_A_Base + (((gpio) >> 4) * 0x0100))
72#define ASIC3_BANK_TO_BASE(bank) (ASIC3_GPIO_A_Base + ((bank) * 0x100))
73
76#define ASIC3_GPIO_Mask 0x00 /* R/W 0:don't mask */ 74#define ASIC3_GPIO_Mask 0x00 /* R/W 0:don't mask */
77#define ASIC3_GPIO_Direction 0x04 /* R/W 0:input */ 75#define ASIC3_GPIO_Direction 0x04 /* R/W 0:input */
78#define ASIC3_GPIO_Out 0x08 /* R/W 0:output low */ 76#define ASIC3_GPIO_Out 0x08 /* R/W 0:output low */