This patch implements support for PIXIS' GPIOs and adds appropriate
nodes to support MMC-over-SPI.

Signed-off-by: Anton Vorontsov <[EMAIL PROTECTED]>
---
 arch/powerpc/boot/dts/mpc8610_hpcd.dts     |   32 ++++++++
 arch/powerpc/platforms/86xx/Kconfig        |    2 +
 arch/powerpc/platforms/86xx/mpc8610_hpcd.c |  119 ++++++++++++++++++++++++++++
 3 files changed, 153 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts 
b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
index 44e9287..e3bf5e6 100644
--- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts
+++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
@@ -100,8 +100,18 @@
                };
 
                [EMAIL PROTECTED],0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        compatible = "fsl,fpga-pixis";
+                       ranges = <0 3 0 0x20>;
                        reg = <3 0 0x20>;
+
+                       sdcsr_pio: [EMAIL PROTECTED] {
+                               #gpio-cells = <2>;
+                               compatible = "fsl,fpga-pixis-pio";
+                               reg = <0xa 1>;
+                               gpio-controller;
+                       };
                };
        };
 
@@ -193,6 +203,28 @@
                        reg = <0xe4000 0x100>;
                };
 
+               [EMAIL PROTECTED] {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc8610-spi", "fsl,spi", "simple-bus";
+                       cell-index = <0>;
+                       reg = <0x7000 0x40>;
+                       interrupts = <59 2>;
+                       interrupt-parent = <&mpic>;
+                       mode = "cpu";
+                       /* gpios = <&sdcsr_pio 0 1>; */
+
+                       [EMAIL PROTECTED] {
+                               compatible = "linux,mmc-spi";
+                               linux,modalias = "mmc_spi";
+                               reg = <0>;
+                               max-speed = <50000000>;
+                               mmc,ocr-mask = <0x00200000>;
+                               gpios = <&sdcsr_pio 6 0   /*  WP */
+                                        &sdcsr_pio 7 1>; /* nCD */
+                       };
+               };
+
                [EMAIL PROTECTED] {
                        compatible = "fsl,mpc8610-ssi";
                        cell-index = <0>;
diff --git a/arch/powerpc/platforms/86xx/Kconfig 
b/arch/powerpc/platforms/86xx/Kconfig
index 39c02af..a7eb89c 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -22,6 +22,8 @@ config MPC8610_HPCD
        bool "Freescale MPC8610 HPCD"
        select DEFAULT_UIMAGE
        select FSL_ULI1575
+       select GENERIC_GPIO
+       select HAVE_GPIO_LIB
        help
          This option enables support for the MPC8610 HPCD board.
 
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c 
b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
index fe163d4..9c1a56b 100644
--- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
+++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
@@ -23,6 +23,9 @@
 #include <linux/delay.h>
 #include <linux/seq_file.h>
 #include <linux/of.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
 
 #include <asm/system.h>
 #include <asm/time.h>
@@ -42,6 +45,122 @@
 
 static unsigned char *pixis_bdcfg0, *pixis_arch;
 
+struct px_gpio_chip {
+       struct of_mm_gpio_chip mm_gc;
+       spinlock_t lock;
+
+       /* mask for active-low pins */
+       u8 active_low;
+};
+
+static inline struct px_gpio_chip *
+to_px_gpio_chip(struct of_mm_gpio_chip *mm_gc)
+{
+       return container_of(mm_gc, struct px_gpio_chip, mm_gc);
+}
+
+static int px_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct px_gpio_chip *px_gc = to_px_gpio_chip(mm_gc);
+       u8 __iomem *regs = mm_gc->regs;
+       u32 pin_mask = 1 << gpio;
+
+       return (in_8(regs) ^ px_gc->active_low) & pin_mask;
+}
+
+static void px_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct px_gpio_chip *px_gc = to_px_gpio_chip(mm_gc);
+       u8 __iomem *regs = mm_gc->regs;
+       unsigned long flags;
+       u32 pin_mask = 1 << gpio;
+
+       spin_lock_irqsave(&px_gc->lock, flags);
+
+       if (((!!val << gpio) ^ px_gc->active_low) & pin_mask)
+               setbits8(regs, pin_mask);
+       else
+               clrbits8(regs, pin_mask);
+
+       spin_unlock_irqrestore(&px_gc->lock, flags);
+}
+
+static int px_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+       return 0;
+}
+
+static int px_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       px_gpio_set(gc, gpio, val);
+       return 0;
+}
+
+#define PX_GPIO_FLAG_ACTIVE_LOW        (1 << 0)
+
+int px_gpio_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
+                 const void *gpio_spec)
+{
+       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(&of_gc->gc);
+       struct px_gpio_chip *px_gc = to_px_gpio_chip(mm_gc);
+       const u32 *gpio = gpio_spec;
+
+       if (*gpio > of_gc->gc.ngpio)
+               return -EINVAL;
+
+       if (gpio[1] & PX_GPIO_FLAG_ACTIVE_LOW)
+               px_gc->active_low |= 1 << *gpio;
+
+       return *gpio;
+}
+
+static int __init pixis_gpio_init(void)
+{
+       struct device_node *np;
+
+       for_each_compatible_node(np, NULL, "fsl,fpga-pixis-pio") {
+               int ret;
+               struct px_gpio_chip *px_gc;
+               struct of_mm_gpio_chip *mm_gc;
+               struct of_gpio_chip *of_gc;
+               struct gpio_chip *gc;
+
+               px_gc = kzalloc(sizeof(*px_gc), GFP_KERNEL);
+               if (!px_gc) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               spin_lock_init(&px_gc->lock);
+
+               mm_gc = &px_gc->mm_gc;
+               of_gc = &mm_gc->of_gc;
+               gc = &of_gc->gc;
+
+               of_gc->gpio_cells = 2;
+               of_gc->xlate = px_gpio_xlate;
+               gc->ngpio = 8;
+               gc->direction_input = px_gpio_dir_in;
+               gc->direction_output = px_gpio_dir_out;
+               gc->get = px_gpio_get;
+               gc->set = px_gpio_set;
+
+               ret = of_mm_gpiochip_add(np, mm_gc);
+               if (ret)
+                       goto err;
+               continue;
+err:
+               pr_err("%s: registration failed with status %d\n",
+                      np->full_name, ret);
+               kfree(px_gc);
+               /* try others anyway */
+       }
+       return 0;
+}
+machine_arch_initcall(mpc86xx_hpcd, pixis_gpio_init);
+
 static struct of_device_id __initdata mpc8610_ids[] = {
        { .compatible = "fsl,mpc8610-immr", },
        { .compatible = "simple-bus", },
-- 
1.5.5.1
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to