diff options
| author | Jochen Friedrich <jochen@scram.de> | 2008-07-02 12:18:23 -0400 |
|---|---|---|
| committer | Kumar Gala <galak@kernel.crashing.org> | 2008-07-28 08:42:09 -0400 |
| commit | dc2380ec8572fcd7f7e9579afc9fb223300d922f (patch) | |
| tree | ef83f9d7406aca65c87e84c38fadc6e6f0394f53 /arch/powerpc/sysdev | |
| parent | e193325e3e3de188ae2aa5207adc7129aacc5c9d (diff) | |
powerpc: implement GPIO LIB API on CPM1 Freescale SoC.
This patch implement GPIO LIB support for the CPM1 GPIOs.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/sysdev')
| -rw-r--r-- | arch/powerpc/sysdev/cpm1.c | 267 |
1 files changed, 262 insertions, 5 deletions
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 661df42830b9..4a04823e8423 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
| 31 | #include <linux/irq.h> | 31 | #include <linux/irq.h> |
| 32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
| 33 | #include <linux/spinlock.h> | ||
| 33 | #include <asm/page.h> | 34 | #include <asm/page.h> |
| 34 | #include <asm/pgtable.h> | 35 | #include <asm/pgtable.h> |
| 35 | #include <asm/8xx_immap.h> | 36 | #include <asm/8xx_immap.h> |
| @@ -42,6 +43,10 @@ | |||
| 42 | 43 | ||
| 43 | #include <asm/fs_pd.h> | 44 | #include <asm/fs_pd.h> |
| 44 | 45 | ||
| 46 | #ifdef CONFIG_8xx_GPIO | ||
| 47 | #include <linux/of_gpio.h> | ||
| 48 | #endif | ||
| 49 | |||
| 45 | #define CPM_MAP_SIZE (0x4000) | 50 | #define CPM_MAP_SIZE (0x4000) |
| 46 | 51 | ||
| 47 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ | 52 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ |
| @@ -290,20 +295,24 @@ struct cpm_ioport16 { | |||
| 290 | __be16 res[3]; | 295 | __be16 res[3]; |
| 291 | }; | 296 | }; |
| 292 | 297 | ||
| 293 | struct cpm_ioport32 { | 298 | struct cpm_ioport32b { |
| 294 | __be32 dir, par, sor; | 299 | __be32 dir, par, odr, dat; |
| 300 | }; | ||
| 301 | |||
| 302 | struct cpm_ioport32e { | ||
| 303 | __be32 dir, par, sor, odr, dat; | ||
| 295 | }; | 304 | }; |
| 296 | 305 | ||
| 297 | static void cpm1_set_pin32(int port, int pin, int flags) | 306 | static void cpm1_set_pin32(int port, int pin, int flags) |
| 298 | { | 307 | { |
| 299 | struct cpm_ioport32 __iomem *iop; | 308 | struct cpm_ioport32e __iomem *iop; |
| 300 | pin = 1 << (31 - pin); | 309 | pin = 1 << (31 - pin); |
| 301 | 310 | ||
| 302 | if (port == CPM_PORTB) | 311 | if (port == CPM_PORTB) |
| 303 | iop = (struct cpm_ioport32 __iomem *) | 312 | iop = (struct cpm_ioport32e __iomem *) |
| 304 | &mpc8xx_immr->im_cpm.cp_pbdir; | 313 | &mpc8xx_immr->im_cpm.cp_pbdir; |
| 305 | else | 314 | else |
| 306 | iop = (struct cpm_ioport32 __iomem *) | 315 | iop = (struct cpm_ioport32e __iomem *) |
| 307 | &mpc8xx_immr->im_cpm.cp_pedir; | 316 | &mpc8xx_immr->im_cpm.cp_pedir; |
| 308 | 317 | ||
| 309 | if (flags & CPM_PIN_OUTPUT) | 318 | if (flags & CPM_PIN_OUTPUT) |
| @@ -498,3 +507,251 @@ int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode) | |||
| 498 | 507 | ||
| 499 | return 0; | 508 | return 0; |
| 500 | } | 509 | } |
| 510 | |||
| 511 | /* | ||
| 512 | * GPIO LIB API implementation | ||
| 513 | */ | ||
| 514 | #ifdef CONFIG_8xx_GPIO | ||
| 515 | |||
| 516 | struct cpm1_gpio16_chip { | ||
| 517 | struct of_mm_gpio_chip mm_gc; | ||
| 518 | spinlock_t lock; | ||
| 519 | |||
| 520 | /* shadowed data register to clear/set bits safely */ | ||
| 521 | u16 cpdata; | ||
| 522 | }; | ||
| 523 | |||
| 524 | static inline struct cpm1_gpio16_chip * | ||
| 525 | to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc) | ||
| 526 | { | ||
| 527 | return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc); | ||
| 528 | } | ||
| 529 | |||
| 530 | static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc) | ||
| 531 | { | ||
| 532 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); | ||
| 533 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
| 534 | |||
| 535 | cpm1_gc->cpdata = in_be16(&iop->dat); | ||
| 536 | } | ||
| 537 | |||
| 538 | static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio) | ||
| 539 | { | ||
| 540 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 541 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
| 542 | u16 pin_mask; | ||
| 543 | |||
| 544 | pin_mask = 1 << (15 - gpio); | ||
| 545 | |||
| 546 | return !!(in_be16(&iop->dat) & pin_mask); | ||
| 547 | } | ||
| 548 | |||
| 549 | static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||
| 550 | { | ||
| 551 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 552 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); | ||
| 553 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
| 554 | unsigned long flags; | ||
| 555 | u16 pin_mask = 1 << (15 - gpio); | ||
| 556 | |||
| 557 | spin_lock_irqsave(&cpm1_gc->lock, flags); | ||
| 558 | |||
| 559 | if (value) | ||
| 560 | cpm1_gc->cpdata |= pin_mask; | ||
| 561 | else | ||
| 562 | cpm1_gc->cpdata &= ~pin_mask; | ||
| 563 | |||
| 564 | out_be16(&iop->dat, cpm1_gc->cpdata); | ||
| 565 | |||
| 566 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); | ||
| 567 | } | ||
| 568 | |||
| 569 | static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||
| 570 | { | ||
| 571 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 572 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
| 573 | u16 pin_mask; | ||
| 574 | |||
| 575 | pin_mask = 1 << (15 - gpio); | ||
| 576 | |||
| 577 | setbits16(&iop->dir, pin_mask); | ||
| 578 | |||
| 579 | cpm1_gpio16_set(gc, gpio, val); | ||
| 580 | |||
| 581 | return 0; | ||
| 582 | } | ||
| 583 | |||
| 584 | static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
| 585 | { | ||
| 586 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 587 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
| 588 | u16 pin_mask; | ||
| 589 | |||
| 590 | pin_mask = 1 << (15 - gpio); | ||
| 591 | |||
| 592 | clrbits16(&iop->dir, pin_mask); | ||
| 593 | |||
| 594 | return 0; | ||
| 595 | } | ||
| 596 | |||
| 597 | int cpm1_gpiochip_add16(struct device_node *np) | ||
| 598 | { | ||
| 599 | struct cpm1_gpio16_chip *cpm1_gc; | ||
| 600 | struct of_mm_gpio_chip *mm_gc; | ||
| 601 | struct of_gpio_chip *of_gc; | ||
| 602 | struct gpio_chip *gc; | ||
| 603 | |||
| 604 | cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); | ||
| 605 | if (!cpm1_gc) | ||
| 606 | return -ENOMEM; | ||
| 607 | |||
| 608 | spin_lock_init(&cpm1_gc->lock); | ||
| 609 | |||
| 610 | mm_gc = &cpm1_gc->mm_gc; | ||
| 611 | of_gc = &mm_gc->of_gc; | ||
| 612 | gc = &of_gc->gc; | ||
| 613 | |||
| 614 | mm_gc->save_regs = cpm1_gpio16_save_regs; | ||
| 615 | of_gc->gpio_cells = 2; | ||
| 616 | gc->ngpio = 16; | ||
| 617 | gc->direction_input = cpm1_gpio16_dir_in; | ||
| 618 | gc->direction_output = cpm1_gpio16_dir_out; | ||
| 619 | gc->get = cpm1_gpio16_get; | ||
| 620 | gc->set = cpm1_gpio16_set; | ||
| 621 | |||
| 622 | return of_mm_gpiochip_add(np, mm_gc); | ||
| 623 | } | ||
| 624 | |||
| 625 | struct cpm1_gpio32_chip { | ||
| 626 | struct of_mm_gpio_chip mm_gc; | ||
| 627 | spinlock_t lock; | ||
| 628 | |||
| 629 | /* shadowed data register to clear/set bits safely */ | ||
| 630 | u32 cpdata; | ||
| 631 | }; | ||
| 632 | |||
| 633 | static inline struct cpm1_gpio32_chip * | ||
| 634 | to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc) | ||
| 635 | { | ||
| 636 | return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc); | ||
| 637 | } | ||
| 638 | |||
| 639 | static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) | ||
| 640 | { | ||
| 641 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); | ||
| 642 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
| 643 | |||
| 644 | cpm1_gc->cpdata = in_be32(&iop->dat); | ||
| 645 | } | ||
| 646 | |||
| 647 | static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio) | ||
| 648 | { | ||
| 649 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 650 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
| 651 | u32 pin_mask; | ||
| 652 | |||
| 653 | pin_mask = 1 << (31 - gpio); | ||
| 654 | |||
| 655 | return !!(in_be32(&iop->dat) & pin_mask); | ||
| 656 | } | ||
| 657 | |||
| 658 | static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||
| 659 | { | ||
| 660 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 661 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); | ||
| 662 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
| 663 | unsigned long flags; | ||
| 664 | u32 pin_mask = 1 << (31 - gpio); | ||
| 665 | |||
| 666 | spin_lock_irqsave(&cpm1_gc->lock, flags); | ||
| 667 | |||
| 668 | if (value) | ||
| 669 | cpm1_gc->cpdata |= pin_mask; | ||
| 670 | else | ||
| 671 | cpm1_gc->cpdata &= ~pin_mask; | ||
| 672 | |||
| 673 | out_be32(&iop->dat, cpm1_gc->cpdata); | ||
| 674 | |||
| 675 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); | ||
| 676 | } | ||
| 677 | |||
| 678 | static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||
| 679 | { | ||
| 680 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 681 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
| 682 | u32 pin_mask; | ||
| 683 | |||
| 684 | pin_mask = 1 << (31 - gpio); | ||
| 685 | |||
| 686 | setbits32(&iop->dir, pin_mask); | ||
| 687 | |||
| 688 | cpm1_gpio32_set(gc, gpio, val); | ||
| 689 | |||
| 690 | return 0; | ||
| 691 | } | ||
| 692 | |||
| 693 | static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
| 694 | { | ||
| 695 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 696 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
| 697 | u32 pin_mask; | ||
| 698 | |||
| 699 | pin_mask = 1 << (31 - gpio); | ||
| 700 | |||
| 701 | clrbits32(&iop->dir, pin_mask); | ||
| 702 | |||
| 703 | return 0; | ||
| 704 | } | ||
| 705 | |||
| 706 | int cpm1_gpiochip_add32(struct device_node *np) | ||
| 707 | { | ||
| 708 | struct cpm1_gpio32_chip *cpm1_gc; | ||
| 709 | struct of_mm_gpio_chip *mm_gc; | ||
| 710 | struct of_gpio_chip *of_gc; | ||
| 711 | struct gpio_chip *gc; | ||
| 712 | |||
| 713 | cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); | ||
| 714 | if (!cpm1_gc) | ||
| 715 | return -ENOMEM; | ||
| 716 | |||
| 717 | spin_lock_init(&cpm1_gc->lock); | ||
| 718 | |||
| 719 | mm_gc = &cpm1_gc->mm_gc; | ||
| 720 | of_gc = &mm_gc->of_gc; | ||
| 721 | gc = &of_gc->gc; | ||
| 722 | |||
| 723 | mm_gc->save_regs = cpm1_gpio32_save_regs; | ||
| 724 | of_gc->gpio_cells = 2; | ||
| 725 | gc->ngpio = 32; | ||
| 726 | gc->direction_input = cpm1_gpio32_dir_in; | ||
| 727 | gc->direction_output = cpm1_gpio32_dir_out; | ||
| 728 | gc->get = cpm1_gpio32_get; | ||
| 729 | gc->set = cpm1_gpio32_set; | ||
| 730 | |||
| 731 | return of_mm_gpiochip_add(np, mm_gc); | ||
| 732 | } | ||
| 733 | |||
| 734 | static int cpm_init_par_io(void) | ||
| 735 | { | ||
| 736 | struct device_node *np; | ||
| 737 | |||
| 738 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-a") | ||
| 739 | cpm1_gpiochip_add16(np); | ||
| 740 | |||
| 741 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-b") | ||
| 742 | cpm1_gpiochip_add32(np); | ||
| 743 | |||
| 744 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-c") | ||
| 745 | cpm1_gpiochip_add16(np); | ||
| 746 | |||
| 747 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-d") | ||
| 748 | cpm1_gpiochip_add16(np); | ||
| 749 | |||
| 750 | /* Port E uses CPM2 layout */ | ||
| 751 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-e") | ||
| 752 | cpm2_gpiochip_add32(np); | ||
| 753 | return 0; | ||
| 754 | } | ||
| 755 | arch_initcall(cpm_init_par_io); | ||
| 756 | |||
| 757 | #endif /* CONFIG_8xx_GPIO */ | ||
