📄 fsl_soc.c
字号:
/* * FSL SoC setup code * * Maintained by Kumar Gala (see MAINTAINERS for contact information) * * 2006 (c) MontaVista Software, Inc. * Vitaly Bordug <vbordug@ru.mvista.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */#include <linux/stddef.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/major.h>#include <linux/delay.h>#include <linux/irq.h>#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>#include <asm/system.h>#include <asm/atomic.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/time.h>#include <asm/prom.h>#include <sysdev/fsl_soc.h>#include <mm/mmu_decl.h>#include <asm/cpm2.h>extern void init_fcc_ioports(struct fs_platform_info*);extern void init_fec_ioports(struct fs_platform_info*);extern void init_smc_ioports(struct fs_uart_platform_info*);static phys_addr_t immrbase = -1;phys_addr_t get_immrbase(void){ struct device_node *soc; if (immrbase != -1) return immrbase; soc = of_find_node_by_type(NULL, "soc"); if (soc) { 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;}EXPORT_SYMBOL(get_immrbase);#if defined(CONFIG_CPM2) || defined(CONFIG_8xx)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_compatible_node(NULL, NULL, "fsl,cpm-brg"); if (node) { prop = of_get_property(node, "clock-frequency", &size); if (prop && size == 4) brgfreq = *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;}EXPORT_SYMBOL(get_brgfreq);static u32 fs_baudrate = -1;u32 get_baudrate(void){ struct device_node *node; if (fs_baudrate != -1) return fs_baudrate; node = of_find_node_by_type(NULL, "serial"); if (node) { 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;}EXPORT_SYMBOL(get_baudrate);#endif /* CONFIG_CPM2 */static int __init gfar_mdio_of_init(void){ struct device_node *np; unsigned int i; 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++) { int k; struct device_node *child = NULL; struct gianfar_mdio_data mdio_data; memset(&res, 0, sizeof(res)); memset(&mdio_data, 0, sizeof(mdio_data)); ret = of_address_to_resource(np, 0, &res); if (ret) goto err; mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", res.start, &res, 1); if (IS_ERR(mdio_dev)) { ret = PTR_ERR(mdio_dev); goto err; } for (k = 0; k < 32; k++) mdio_data.irq[k] = PHY_POLL; while ((child = of_get_next_child(np, child)) != NULL) { int irq = irq_of_parse_and_map(child, 0); if (irq != NO_IRQ) { const u32 *id = of_get_property(child, "reg", NULL); mdio_data.irq[*id] = irq; } } ret = platform_device_add_data(mdio_dev, &mdio_data, sizeof(struct gianfar_mdio_data)); if (ret) goto unreg; } return 0;unreg: platform_device_unregister(mdio_dev);err: return ret;}arch_initcall(gfar_mdio_of_init);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; unsigned int i; struct platform_device *gfar_dev; struct resource res; int ret; for (np = NULL, i = 0; (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; i++) { struct resource r[4]; struct device_node *phy, *mdio; struct gianfar_platform_data gfar_data; const unsigned int *id; const char *model; const char *ctype; const void *mac_addr; const phandle *ph; int n_res = 2; memset(r, 0, sizeof(r)); memset(&gfar_data, 0, sizeof(gfar_data)); ret = of_address_to_resource(np, 0, &r[0]); if (ret) goto err; of_irq_to_resource(np, 0, &r[1]); model = of_get_property(np, "model", NULL); /* If we aren't the FEC we have multiple interrupts */ if (model && strcasecmp(model, "FEC")) { r[1].name = gfar_tx_intr; r[2].name = gfar_rx_intr; of_irq_to_resource(np, 1, &r[2]); r[3].name = gfar_err_intr; of_irq_to_resource(np, 2, &r[3]); n_res += 2; } gfar_dev = platform_device_register_simple("fsl-gianfar", i, &r[0], n_res); if (IS_ERR(gfar_dev)) { ret = PTR_ERR(gfar_dev); goto err; } mac_addr = of_get_mac_address(np); if (mac_addr) memcpy(gfar_data.mac_addr, mac_addr, 6); if (model && !strcasecmp(model, "TSEC")) gfar_data.device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | FSL_GIANFAR_DEV_HAS_MULTI_INTR; if (model && !strcasecmp(model, "eTSEC")) gfar_data.device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | FSL_GIANFAR_DEV_HAS_MULTI_INTR | FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; ctype = of_get_property(np, "phy-connection-type", NULL); /* We only care about rgmii-id. The rest are autodetected */ if (ctype && !strcmp(ctype, "rgmii-id")) gfar_data.interface = PHY_INTERFACE_MODE_RGMII_ID; else gfar_data.interface = PHY_INTERFACE_MODE_MII; ph = of_get_property(np, "phy-handle", NULL); 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; of_node_put(phy); of_node_put(mdio); ret = platform_device_add_data(gfar_dev, &gfar_data, sizeof(struct gianfar_platform_data)); if (ret) goto unreg; } return 0;unreg: platform_device_unregister(gfar_dev);err: return ret;}arch_initcall(gfar_of_init);#ifdef CONFIG_I2C_BOARDINFO#include <linux/i2c.h>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; struct platform_device *i2c_dev; int ret; for (np = NULL, i = 0; (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL; i++) { struct resource r[2]; struct fsl_i2c_platform_data i2c_data; const unsigned char *flags = NULL; memset(&r, 0, sizeof(r)); memset(&i2c_data, 0, sizeof(i2c_data)); ret = of_address_to_resource(np, 0, &r[0]); if (ret) goto err; of_irq_to_resource(np, 0, &r[1]); i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2); if (IS_ERR(i2c_dev)) { ret = PTR_ERR(i2c_dev); goto err; } i2c_data.device_flags = 0; flags = of_get_property(np, "dfsrr", NULL); if (flags) i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR; flags = of_get_property(np, "fsl5200-clocking", NULL); if (flags) i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200; ret = platform_device_add_data(i2c_dev, &i2c_data, sizeof(struct fsl_i2c_platform_data)); if (ret) goto unreg; of_register_i2c_devices(np, i); } return 0;unreg: platform_device_unregister(i2c_dev);err: return ret;}arch_initcall(fsl_i2c_of_init);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -