]> err.no Git - linux-2.6/blobdiff - arch/powerpc/sysdev/fsl_soc.c
[POWERPC] fsl_soc: add support for fsl_spi
[linux-2.6] / arch / powerpc / sysdev / fsl_soc.c
index 727453d3e8b919cac9d5d435a5980842abc46cbd..d028e8da027b1e479e6b6c151befb63499ff8aa9 100644 (file)
@@ -22,7 +22,9 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
 #include <linux/phy.h>
+#include <linux/spi/spi.h>
 #include <linux/fsl_devices.h>
 #include <linux/fs_enet_pd.h>
 #include <linux/fs_uart_pd.h>
@@ -51,13 +53,13 @@ phys_addr_t get_immrbase(void)
 
        soc = of_find_node_by_type(NULL, "soc");
        if (soc) {
-               unsigned int size;
+               int size;
                const void *prop = of_get_property(soc, "reg", &size);
 
                if (prop)
                        immrbase = of_translate_address(soc, prop);
                of_node_put(soc);
-       };
+       }
 
        return immrbase;
 }
@@ -75,16 +77,23 @@ u32 get_brgfreq(void)
        if (brgfreq != -1)
                return brgfreq;
 
-       node = of_find_node_by_type(NULL, "cpm");
+       node = of_find_compatible_node(NULL, NULL, "fsl,cpm1");
+       if (!node)
+               node = of_find_compatible_node(NULL, NULL, "fsl,cpm2");
+       if (!node)
+               node = of_find_node_by_type(NULL, "cpm");
        if (node) {
-               unsigned int size;
-               const unsigned int *prop = of_get_property(node,
-                                       "brg-frequency", &size);
+               int size;
+               const unsigned int *prop;
 
-               if (prop)
+               prop = of_get_property(node, "fsl,brg-frequency", &size);
+               if (!prop)
+                       prop = of_get_property(node, "brg-frequency", &size);
+               if (prop && size == 4)
                        brgfreq = *prop;
+
                of_node_put(node);
-       };
+       }
 
        return brgfreq;
 }
@@ -102,14 +111,14 @@ u32 get_baudrate(void)
 
        node = of_find_node_by_type(NULL, "serial");
        if (node) {
-               unsigned int size;
+               int size;
                const unsigned int *prop = of_get_property(node,
                                "current-speed", &size);
 
                if (prop)
                        fs_baudrate = *prop;
                of_node_put(node);
-       };
+       }
 
        return fs_baudrate;
 }
@@ -320,21 +329,26 @@ static struct i2c_driver_device i2c_devices[] __initdata = {
        {"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",},
 };
 
-static int __init of_find_i2c_driver(struct device_node *node, struct i2c_board_info *info)
+static int __init of_find_i2c_driver(struct device_node *node,
+                                    struct i2c_board_info *info)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
                if (!of_device_is_compatible(node, i2c_devices[i].of_device))
                        continue;
-               strncpy(info->driver_name, i2c_devices[i].i2c_driver, KOBJ_NAME_LEN);
-               strncpy(info->type, i2c_devices[i].i2c_type, I2C_NAME_SIZE);
+               if (strlcpy(info->driver_name, i2c_devices[i].i2c_driver,
+                           KOBJ_NAME_LEN) >= KOBJ_NAME_LEN ||
+                   strlcpy(info->type, i2c_devices[i].i2c_type,
+                           I2C_NAME_SIZE) >= I2C_NAME_SIZE)
+                       return -ENOMEM;
                return 0;
        }
        return -ENODEV;
 }
 
-static void __init of_register_i2c_devices(struct device_node *adap_node, int bus_num)
+static void __init of_register_i2c_devices(struct device_node *adap_node,
+                                          int bus_num)
 {
        struct device_node *node = NULL;
 
@@ -1186,3 +1200,89 @@ err:
 arch_initcall(cpm_smc_uart_of_init);
 
 #endif /* CONFIG_8xx */
+
+int __init fsl_spi_init(struct spi_board_info *board_infos,
+                       unsigned int num_board_infos,
+                       void (*activate_cs)(u8 cs, u8 polarity),
+                       void (*deactivate_cs)(u8 cs, u8 polarity))
+{
+       struct device_node *np;
+       unsigned int i;
+       const u32 *sysclk;
+
+       np = of_find_node_by_type(NULL, "qe");
+       if (!np)
+               return -ENODEV;
+
+       sysclk = of_get_property(np, "bus-frequency", NULL);
+       if (!sysclk)
+               return -ENODEV;
+
+       for (np = NULL, i = 1;
+            (np = of_find_compatible_node(np, "spi", "fsl_spi")) != NULL;
+            i++) {
+               int ret = 0;
+               unsigned int j;
+               const void *prop;
+               struct resource res[2];
+               struct platform_device *pdev;
+               struct fsl_spi_platform_data pdata = {
+                       .activate_cs = activate_cs,
+                       .deactivate_cs = deactivate_cs,
+               };
+
+               memset(res, 0, sizeof(res));
+
+               pdata.sysclk = *sysclk;
+
+               prop = of_get_property(np, "reg", NULL);
+               if (!prop)
+                       goto err;
+               pdata.bus_num = *(u32 *)prop;
+
+               prop = of_get_property(np, "mode", NULL);
+               if (prop && !strcmp(prop, "cpu-qe"))
+                       pdata.qe_mode = 1;
+
+               for (j = 0; j < num_board_infos; j++) {
+                       if (board_infos[j].bus_num == pdata.bus_num)
+                               pdata.max_chipselect++;
+               }
+
+               if (!pdata.max_chipselect)
+                       goto err;
+
+               ret = of_address_to_resource(np, 0, &res[0]);
+               if (ret)
+                       goto err;
+
+               ret = of_irq_to_resource(np, 0, &res[1]);
+               if (ret == NO_IRQ)
+                       goto err;
+
+               pdev = platform_device_alloc("mpc83xx_spi", i);
+               if (!pdev)
+                       goto err;
+
+               ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+               if (ret)
+                       goto unreg;
+
+               ret = platform_device_add_resources(pdev, res,
+                                                   ARRAY_SIZE(res));
+               if (ret)
+                       goto unreg;
+
+               ret = platform_device_register(pdev);
+               if (ret)
+                       goto unreg;
+
+               continue;
+unreg:
+               platform_device_del(pdev);
+err:
+               continue;
+       }
+
+       return spi_register_board_info(board_infos, num_board_infos);
+}