X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=arch%2Fpowerpc%2Fsysdev%2Ffsl_soc.c;h=26f7d83c4be548c9e379f87d75f528468c0c93dc;hb=a2dd70a11d4c9cb8a4e4bb41f53a9b430e08559b;hp=3289fab01e9245a49919a61d5ecdc285a2a49810;hpb=40b42f1ebf653cd72c32eb1a1a0b9fea2dfbfd7d;p=linux-2.6 diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 3289fab01e..26f7d83c4b 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -22,7 +22,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -51,13 +54,21 @@ phys_addr_t get_immrbase(void) soc = of_find_node_by_type(NULL, "soc"); if (soc) { - unsigned int size; - const void *prop = of_get_property(soc, "reg", &size); + int size; + u32 naddr; + const u32 *prop = of_get_property(soc, "#address-cells", &size); + if (prop && size == 4) + naddr = *prop; + else + naddr = 2; + + prop = of_get_property(soc, "ranges", &size); if (prop) - immrbase = of_translate_address(soc, prop); + immrbase = of_translate_address(soc, prop + naddr); + of_node_put(soc); - }; + } return immrbase; } @@ -71,20 +82,31 @@ static u32 brgfreq = -1; u32 get_brgfreq(void) { struct device_node *node; + const unsigned int *prop; + int size; if (brgfreq != -1) return brgfreq; - node = of_find_node_by_type(NULL, "cpm"); + node = of_find_compatible_node(NULL, NULL, "fsl,cpm-brg"); if (node) { - unsigned int size; - const unsigned int *prop = of_get_property(node, - "brg-frequency", &size); + prop = of_get_property(node, "clock-frequency", &size); + if (prop && size == 4) + brgfreq = *prop; - if (prop) + of_node_put(node); + return brgfreq; + } + + /* Legacy device binding -- will go away when no users are left. */ + node = of_find_node_by_type(NULL, "cpm"); + if (node) { + prop = of_get_property(node, "brg-frequency", &size); + if (prop && size == 4) brgfreq = *prop; + of_node_put(node); - }; + } return brgfreq; } @@ -102,14 +124,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; } @@ -117,17 +139,51 @@ u32 get_baudrate(void) EXPORT_SYMBOL(get_baudrate); #endif /* CONFIG_CPM2 */ -static int __init gfar_mdio_of_init(void) +#ifdef CONFIG_FIXED_PHY +static int __init of_add_fixed_phys(void) { + int ret; struct device_node *np; - unsigned int i; + u32 *fixed_link; + struct fixed_phy_status status = {}; + + for_each_node_by_name(np, "ethernet") { + fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL); + if (!fixed_link) + continue; + + status.link = 1; + status.duplex = fixed_link[1]; + status.speed = fixed_link[2]; + status.pause = fixed_link[3]; + status.asym_pause = fixed_link[4]; + + ret = fixed_phy_add(PHY_POLL, fixed_link[0], &status); + if (ret) { + of_node_put(np); + return ret; + } + } + + return 0; +} +arch_initcall(of_add_fixed_phys); +#endif /* CONFIG_FIXED_PHY */ + +static int __init gfar_mdio_of_init(void) +{ + struct device_node *np = NULL; struct platform_device *mdio_dev; struct resource res; int ret; - for (np = NULL, i = 0; - (np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL; - i++) { + np = of_find_compatible_node(np, NULL, "fsl,gianfar-mdio"); + + /* try the deprecated version */ + if (!np) + np = of_find_compatible_node(np, "mdio", "gianfar"); + + if (np) { int k; struct device_node *child = NULL; struct gianfar_mdio_data mdio_data; @@ -166,11 +222,13 @@ static int __init gfar_mdio_of_init(void) goto unreg; } + of_node_put(np); return 0; unreg: platform_device_unregister(mdio_dev); err: + of_node_put(np); return ret; } @@ -180,7 +238,6 @@ static const char *gfar_tx_intr = "tx"; static const char *gfar_rx_intr = "rx"; static const char *gfar_err_intr = "error"; - static int __init gfar_of_init(void) { struct device_node *np; @@ -264,29 +321,43 @@ static int __init gfar_of_init(void) gfar_data.interface = PHY_INTERFACE_MODE_MII; ph = of_get_property(np, "phy-handle", NULL); - phy = of_find_node_by_phandle(*ph); + if (ph == NULL) { + u32 *fixed_link; - if (phy == NULL) { - ret = -ENODEV; - goto unreg; - } + fixed_link = (u32 *)of_get_property(np, "fixed-link", + NULL); + if (!fixed_link) { + ret = -ENODEV; + goto unreg; + } - mdio = of_get_parent(phy); + gfar_data.bus_id = 0; + gfar_data.phy_id = fixed_link[0]; + } else { + phy = of_find_node_by_phandle(*ph); + + if (phy == NULL) { + ret = -ENODEV; + goto unreg; + } + + mdio = of_get_parent(phy); + + id = of_get_property(phy, "reg", NULL); + ret = of_address_to_resource(mdio, 0, &res); + if (ret) { + of_node_put(phy); + of_node_put(mdio); + goto unreg; + } + + gfar_data.phy_id = *id; + gfar_data.bus_id = res.start; - id = of_get_property(phy, "reg", NULL); - ret = of_address_to_resource(mdio, 0, &res); - if (ret) { of_node_put(phy); of_node_put(mdio); - goto unreg; } - gfar_data.phy_id = *id; - gfar_data.bus_id = res.start; - - of_node_put(phy); - of_node_put(mdio); - ret = platform_device_add_data(gfar_dev, &gfar_data, sizeof(struct @@ -305,16 +376,83 @@ err: arch_initcall(gfar_of_init); +#ifdef CONFIG_I2C_BOARDINFO +#include +struct i2c_driver_device { + char *of_device; + char *i2c_driver; + char *i2c_type; +}; + +static struct i2c_driver_device i2c_devices[] __initdata = { + {"ricoh,rs5c372a", "rtc-rs5c372", "rs5c372a",}, + {"ricoh,rs5c372b", "rtc-rs5c372", "rs5c372b",}, + {"ricoh,rv5c386", "rtc-rs5c372", "rv5c386",}, + {"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",}, + {"dallas,ds1307", "rtc-ds1307", "ds1307",}, + {"dallas,ds1337", "rtc-ds1307", "ds1337",}, + {"dallas,ds1338", "rtc-ds1307", "ds1338",}, + {"dallas,ds1339", "rtc-ds1307", "ds1339",}, + {"dallas,ds1340", "rtc-ds1307", "ds1340",}, + {"stm,m41t00", "rtc-ds1307", "m41t00"}, + {"dallas,ds1374", "rtc-ds1374", "rtc-ds1374",}, +}; + +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; + 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) +{ + struct device_node *node = NULL; + + while ((node = of_get_next_child(adap_node, node))) { + struct i2c_board_info info = {}; + const u32 *addr; + int len; + + addr = of_get_property(node, "reg", &len); + if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) { + printk(KERN_WARNING "fsl_soc.c: invalid i2c device entry\n"); + continue; + } + + info.irq = irq_of_parse_and_map(node, 0); + if (info.irq == NO_IRQ) + info.irq = -1; + + if (of_find_i2c_driver(node, &info) < 0) + continue; + + info.addr = *addr; + + i2c_register_board_info(bus_num, &info, 1); + } +} + static int __init fsl_i2c_of_init(void) { struct device_node *np; - unsigned int i; + unsigned int i = 0; struct platform_device *i2c_dev; int ret; - for (np = NULL, i = 0; - (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL; - i++) { + for_each_compatible_node(np, NULL, "fsl-i2c") { struct resource r[2]; struct fsl_i2c_platform_data i2c_data; const unsigned char *flags = NULL; @@ -349,6 +487,8 @@ static int __init fsl_i2c_of_init(void) fsl_i2c_platform_data)); if (ret) goto unreg; + + of_register_i2c_devices(np, i++); } return 0; @@ -360,6 +500,7 @@ err: } arch_initcall(fsl_i2c_of_init); +#endif #ifdef CONFIG_PPC_83xx static int __init mpc83xx_wdt_init(void) @@ -443,14 +584,12 @@ static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) static int __init fsl_usb_of_init(void) { struct device_node *np; - unsigned int i; + unsigned int i = 0; struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL, *usb_dev_dr_client = NULL; int ret; - for (np = NULL, i = 0; - (np = of_find_compatible_node(np, "usb", "fsl-usb2-mph")) != NULL; - i++) { + for_each_compatible_node(np, NULL, "fsl-usb2-mph") { struct resource r[2]; struct fsl_usb2_platform_data usb_data; const unsigned char *prop = NULL; @@ -493,11 +632,10 @@ static int __init fsl_usb_of_init(void) fsl_usb2_platform_data)); if (ret) goto unreg_mph; + i++; } - for (np = NULL; - (np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL; - i++) { + for_each_compatible_node(np, NULL, "fsl-usb2-dr") { struct resource r[2]; struct fsl_usb2_platform_data usb_data; const unsigned char *prop = NULL; @@ -569,6 +707,7 @@ static int __init fsl_usb_of_init(void) fsl_usb2_platform_data)))) goto unreg_dr; } + i++; } return 0; @@ -586,6 +725,7 @@ err: arch_initcall(fsl_usb_of_init); +#ifndef CONFIG_PPC_CPM_NEW_BINDING #ifdef CONFIG_CPM2 extern void init_scc_ioports(struct fs_uart_platform_info*); @@ -1039,13 +1179,12 @@ arch_initcall(fs_enet_of_init); static int __init fsl_pcmcia_of_init(void) { - struct device_node *np = NULL; + struct device_node *np; /* * Register all the devices which type is "pcmcia" */ - while ((np = of_find_compatible_node(np, - "pcmcia", "fsl,pq-pcmcia")) != NULL) - of_platform_device_create(np, "m8xx-pcmcia", NULL); + for_each_compatible_node(np, "pcmcia", "fsl,pq-pcmcia") + of_platform_device_create(np, "m8xx-pcmcia", NULL); return 0; } @@ -1125,3 +1264,135 @@ err: arch_initcall(cpm_smc_uart_of_init); #endif /* CONFIG_8xx */ +#endif /* CONFIG_PPC_CPM_NEW_BINDING */ + +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; + + /* SPI controller is either clocked from QE or SoC clock */ + np = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!np) + np = of_find_node_by_type(NULL, "qe"); + + if (!np) + np = of_find_node_by_type(NULL, "soc"); + + 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); +} + +#if defined(CONFIG_PPC_85xx) || defined(CONFIG_PPC_86xx) +static __be32 __iomem *rstcr; + +static int __init setup_rstcr(void) +{ + struct device_node *np; + np = of_find_node_by_name(NULL, "global-utilities"); + if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) { + const u32 *prop = of_get_property(np, "reg", NULL); + if (prop) { + /* map reset control register + * 0xE00B0 is offset of reset control register + */ + rstcr = ioremap(get_immrbase() + *prop + 0xB0, 0xff); + if (!rstcr) + printk (KERN_EMERG "Error: reset control " + "register not mapped!\n"); + } + } else + printk (KERN_INFO "rstcr compatible register does not exist!\n"); + if (np) + of_node_put(np); + return 0; +} + +arch_initcall(setup_rstcr); + +void fsl_rstcr_restart(char *cmd) +{ + local_irq_disable(); + if (rstcr) + /* set reset control register */ + out_be32(rstcr, 0x2); /* HRESET_REQ */ + + while (1) ; +} +#endif