This patch adds support for IrDA on MPC8610HPCD. IrDA platfrom hook is
used to setup IR clocks and to manage the on-board transceiver.

(The original BSP patch comes with lots of Sign offs, providing them
here.)
Signed-off-by: Xianghua Xiao <[EMAIL PROTECTED]>
Signed-off-by: Jason Jin <[EMAIL PROTECTED]>
Signed-off-by: Timur Tabi <[EMAIL PROTECTED]>
Signed-off-by: York Sun <[EMAIL PROTECTED]>
Signed-off-by: Zhang Wei <[EMAIL PROTECTED]>
Signed-off-by: Anton Vorontsov <[EMAIL PROTECTED]>
---
 arch/powerpc/boot/dts/mpc8610_hpcd.dts     |   20 ++++
 arch/powerpc/platforms/86xx/Kconfig        |    1 +
 arch/powerpc/platforms/86xx/mpc8610_hpcd.c |  164 ++++++++++++++++++++++++++--
 3 files changed, 174 insertions(+), 11 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts 
b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
index fa9c297..6f550ef 100644
--- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts
+++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
@@ -171,6 +171,18 @@
                        interrupt-parent = <&mpic>;
                };
 
+               [EMAIL PROTECTED] {
+                       compatible = "fsl,mpc8610-irda";
+                       interrupt-parent = <&mpic>;
+                       interrupts = <73 2>;
+                       reg = <0x2d000 0x1000>;
+
+                       irda-transceiver {
+                               compatible = "vishay,tfdu6102";
+                               gpios = <&soc_gpio2 18 0>;
+                       };
+               };
+
                mpic: [EMAIL PROTECTED] {
                        clock-frequency = <0>;
                        interrupt-controller;
@@ -204,6 +216,14 @@
                        fsl,has-rstcr;
                };
 
+               soc_gpio2: [EMAIL PROTECTED] {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8610-gpio-bank",
+                                    "fsl,mpc8349-gpio-bank";
+                       reg = <0xf100 0x100>;
+                       gpio-controller;
+               };
+
                [EMAIL PROTECTED] {
                        compatible = "fsl,mpc8610-ssi";
                        cell-index = <0>;
diff --git a/arch/powerpc/platforms/86xx/Kconfig 
b/arch/powerpc/platforms/86xx/Kconfig
index 053f49a..f1d5d0f 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -21,6 +21,7 @@ config SBC8641D
 config MPC8610_HPCD
        bool "Freescale MPC8610 HPCD"
        select DEFAULT_UIMAGE
+       select FSL_MPC8349_GPIO
        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 eb16208..684e1ed 100644
--- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
+++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
@@ -22,7 +22,10 @@
 #include <linux/kdev_t.h>
 #include <linux/delay.h>
 #include <linux/seq_file.h>
+#include <linux/fsl_ir.h>
+#include <linux/gpio.h>
 #include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include <asm/system.h>
 #include <asm/time.h>
@@ -39,7 +42,144 @@
 #include <sysdev/fsl_pci.h>
 #include <sysdev/fsl_soc.h>
 
-static unsigned char *pixis_bdcfg0, *pixis_arch;
+#define PX_BRDCFG0_DVISEL      (1 << 3)
+#define PX_BRDCFG0_DLINK       (1 << 4)
+#define PX_BRDCFG0_DIU_MASK    (PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK)
+#define PX_BRDCFG0_IRDAEN      (1 << 5)
+
+static u8 __iomem *pixis_bdcfg0;
+static u8 __iomem *pixis_arch;
+static u32 __iomem *clkdvdr;
+static DEFINE_SPINLOCK(clkdvdr_lock);
+static u32 __iomem *ircr;
+static u32 __iomem *gpiocr;
+static int speed_gpio;
+
+/*
+ * FIXME: documentation says that bits are reserved. I just made up the
+ * names.
+ */
+#define CLKDVDR_IRCKEN         0x40000000
+#define CLKDVDR_IRCLK_MASK     0x0000FF00
+#define CLKDVDR_IRCLK(x)       (((x) << 8) & CLKDVDR_IRCLK_MASK)
+
+#define IRCR_IR1SEL            0x00000001
+
+static void mpc8610_set_ir_mode(struct fsl_ir *ir, u32 speed)
+{
+       if (speed > 115200) {
+               unsigned long flags;
+
+               /* FIR */
+               if (gpio_is_valid(speed_gpio))
+                       gpio_set_value(speed_gpio, 1);
+
+               spin_lock_irqsave(&clkdvdr_lock, flags);
+               if (speed == 4000000) {
+                       clrbits32(clkdvdr, CLKDVDR_IRCKEN);
+               } else {
+                       /* Using internal PLL for MIR clock */
+                       clrbits32(clkdvdr, CLKDVDR_IRCKEN |
+                                          CLKDVDR_IRCLK_MASK);
+                       setbits32(clkdvdr,
+                               CLKDVDR_IRCLK(ir->clock_in / 12 / speed - 1) |
+                               CLKDVDR_IRCKEN);
+               }
+               spin_unlock_irqrestore(&clkdvdr_lock, flags);
+
+               /* Set IR1 FIR mode in MPC8610 */
+               setbits32(ircr, IRCR_IR1SEL);
+       } else if (speed) {
+               /* SIR */
+               if (gpio_is_valid(speed_gpio))
+                       gpio_set_value(speed_gpio, 0);
+               /* Set IR1 SIR mode in MPC8610 */
+               clrbits32(ircr, IRCR_IR1SEL);
+       }
+}
+
+static struct fsl_ir_op mpc8610_ir_op = {
+       .set_ir_mode = mpc8610_set_ir_mode,
+};
+
+static int mpc8610_init_onboard_transceiver(void)
+{
+       struct device_node *np;
+       int ret;
+
+       if (!pixis_bdcfg0)
+               return -EINVAL;
+
+       np = of_find_compatible_node(NULL, NULL, "vishay,tfdu6102");
+       if (!np)
+               return -ENODEV;
+
+       /*
+        * Select IR1 in GPIO (GTM2_1 -- GPIO2[18:20]), and enable transceiver.
+        * Note: actually, this should be done in the firmware, but we support
+        * old firmwares too.
+        */
+       setbits32(gpiocr, 0x00020000);
+       clrbits32(gpiocr, 0x00800000);
+       clrbits8(pixis_bdcfg0, PX_BRDCFG0_IRDAEN);
+
+       speed_gpio = of_get_gpio(np, 0);
+       of_node_put(np);
+       if (!gpio_is_valid(speed_gpio))
+               return speed_gpio;
+
+       ret = gpio_request(speed_gpio, "irda-transceiver");
+       if (ret)
+               return ret;
+
+       ret = gpio_direction_output(speed_gpio, 0);
+       if (ret) {
+               gpio_free(speed_gpio);
+               return ret;
+       }
+       return 0;
+}
+
+static void mpc8610_ir_init(void)
+{
+       struct device_node *np;
+       struct device_node *irda;
+       static void __iomem *guts;
+
+       if (!clkdvdr)
+               return;
+
+       irda = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-irda");
+       if (!irda)
+               return;
+       irda->data = &mpc8610_ir_op;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
+       if (!np) {
+               pr_err("%s: can't find global utilities node\n", __func__);
+               goto err;
+       }
+
+       guts = of_iomap(np, 0);
+       of_node_put(np);
+       if (!guts) {
+               pr_err("%s: can't remap global utilities memory\n", __func__);
+               goto err;
+       }
+
+       gpiocr = guts + 0x30;
+       ircr = guts + 0x900;
+
+       if (mpc8610_init_onboard_transceiver()) {
+               pr_warning("%s: failed to initialize on-board transceiver, "
+                          "assuming external tranceiver.\n", __func__);
+       }
+       /* no of_node_put(irda) here -- we're using its ->data */
+       return;
+err:
+       irda->data = NULL;
+       of_node_put(irda);
+}
 
 static struct of_device_id __initdata mpc8610_ids[] = {
        { .compatible = "fsl,mpc8610-immr", },
@@ -49,6 +189,8 @@ static struct of_device_id __initdata mpc8610_ids[] = {
 
 static int __init mpc8610_declare_of_platform_devices(void)
 {
+       mpc8610_ir_init();
+
        /* Without this call, the SSI device driver won't get probed. */
        of_platform_bus_probe(NULL, mpc8610_ids, NULL);
 
@@ -218,10 +360,6 @@ void mpc8610hpcd_set_gamma_table(int monitor_port, char 
*gamma_table_base)
        }
 }
 
-#define PX_BRDCFG0_DVISEL      (1 << 3)
-#define PX_BRDCFG0_DLINK       (1 << 4)
-#define PX_BRDCFG0_DIU_MASK    (PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK)
-
 void mpc8610hpcd_set_monitor_port(int monitor_port)
 {
        static const u8 bdcfg[] = {
@@ -237,19 +375,16 @@ void mpc8610hpcd_set_monitor_port(int monitor_port)
 
 void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
 {
-       u32 __iomem *clkdvdr;
        u32 temp;
        /* variables for pixel clock calcs */
        ulong  bestval, bestfreq, speed_ccb, minpixclock, maxpixclock;
        ulong pixval;
        long err;
        int i;
+       unsigned long flags;
 
-       clkdvdr = ioremap(get_immrbase() + 0xe0800, sizeof(u32));
-       if (!clkdvdr) {
-               printk(KERN_ERR "Err: can't map clock divider register!\n");
+       if (!clkdvdr)
                return;
-       }
 
        /* Pixel Clock configuration */
        pr_debug("DIU: Bus Frequency = %d\n", get_busfreq());
@@ -296,12 +431,13 @@ void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
        pr_debug("DIU error = %ld\n NomPixClk ", err);
        pr_debug("DIU: Best Freq = %lx\n", bestfreq);
        /* Modify PXCLK in GUTS CLKDVDR */
+       spin_lock_irqsave(&clkdvdr_lock, flags);
        pr_debug("DIU: Current value of CLKDVDR = 0x%08x\n", (*clkdvdr));
        temp = (*clkdvdr) & 0x2000FFFF;
        *clkdvdr = temp;                /* turn off clock */
        *clkdvdr = temp | 0x80000000 | (((bestval) & 0x1F) << 16);
        pr_debug("DIU: Modified value of CLKDVDR = 0x%08x\n", (*clkdvdr));
-       iounmap(clkdvdr);
+       spin_unlock_irqrestore(&clkdvdr_lock, flags);
 }
 
 ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf)
@@ -354,6 +490,12 @@ static void __init mpc86xx_hpcd_setup_arch(void)
        diu_ops.set_sysfs_monitor_port  = mpc8610hpcd_set_sysfs_monitor_port;
 #endif
 
+       clkdvdr = ioremap(get_immrbase() + 0xe0800, sizeof(u32));
+       if (!clkdvdr) {
+               printk(KERN_ERR "Err: can't map clock divider register!\n");
+               return;
+       }
+
        np = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis");
        if (np) {
                of_address_to_resource(np, 0, &r);
-- 
1.5.5.1
_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to