2006-01-13 10:19:13 -07:00
|
|
|
/*
|
|
|
|
* FSL SoC setup code
|
|
|
|
*
|
|
|
|
* Maintained by Kumar Gala (see MAINTAINERS for contact information)
|
|
|
|
*
|
2006-09-21 07:26:34 -06:00
|
|
|
* 2006 (c) MontaVista Software, Inc.
|
|
|
|
* Vitaly Bordug <vbordug@ru.mvista.com>
|
|
|
|
*
|
2006-01-13 10:19:13 -07:00
|
|
|
* 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/fsl_devices.h>
|
2006-09-21 07:26:34 -06:00
|
|
|
#include <linux/fs_enet_pd.h>
|
|
|
|
#include <linux/fs_uart_pd.h>
|
2006-01-13 10:19:13 -07:00
|
|
|
|
|
|
|
#include <asm/system.h>
|
|
|
|
#include <asm/atomic.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/irq.h>
|
2006-09-21 07:26:34 -06:00
|
|
|
#include <asm/time.h>
|
2006-01-13 10:19:13 -07:00
|
|
|
#include <asm/prom.h>
|
|
|
|
#include <sysdev/fsl_soc.h>
|
|
|
|
#include <mm/mmu_decl.h>
|
2006-09-21 07:26:34 -06:00
|
|
|
#include <asm/cpm2.h>
|
2006-01-13 10:19:13 -07:00
|
|
|
|
2006-09-21 12:38:05 -06:00
|
|
|
extern void init_fcc_ioports(struct fs_platform_info*);
|
2006-10-02 12:41:50 -06:00
|
|
|
extern void init_scc_ioports(struct fs_uart_platform_info*);
|
2006-01-13 10:19:13 -07:00
|
|
|
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");
|
2006-01-23 15:58:04 -07:00
|
|
|
if (soc) {
|
2006-01-13 10:19:13 -07:00
|
|
|
unsigned int size;
|
2006-07-11 23:35:54 -06:00
|
|
|
const void *prop = get_property(soc, "reg", &size);
|
2006-09-21 07:26:34 -06:00
|
|
|
|
|
|
|
if (prop)
|
|
|
|
immrbase = of_translate_address(soc, prop);
|
2006-01-13 10:19:13 -07:00
|
|
|
of_node_put(soc);
|
|
|
|
};
|
|
|
|
|
|
|
|
return immrbase;
|
|
|
|
}
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
EXPORT_SYMBOL(get_immrbase);
|
2006-01-13 10:19:13 -07:00
|
|
|
|
2006-09-21 07:26:34 -06:00
|
|
|
#ifdef CONFIG_CPM2
|
|
|
|
|
|
|
|
static u32 brgfreq = -1;
|
|
|
|
|
|
|
|
u32 get_brgfreq(void)
|
|
|
|
{
|
|
|
|
struct device_node *node;
|
|
|
|
|
|
|
|
if (brgfreq != -1)
|
|
|
|
return brgfreq;
|
|
|
|
|
|
|
|
node = of_find_node_by_type(NULL, "cpm");
|
|
|
|
if (node) {
|
|
|
|
unsigned int size;
|
|
|
|
const unsigned int *prop = get_property(node, "brg-frequency",
|
|
|
|
&size);
|
|
|
|
|
|
|
|
if (prop)
|
|
|
|
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) {
|
|
|
|
unsigned int size;
|
|
|
|
const unsigned int *prop = 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 */
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
static int __init gfar_mdio_of_init(void)
|
2006-01-13 10:19:13 -07:00
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
unsigned int i;
|
2006-01-23 15:58:04 -07:00
|
|
|
struct platform_device *mdio_dev;
|
2006-01-13 10:19:13 -07:00
|
|
|
struct resource res;
|
|
|
|
int ret;
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
for (np = NULL, i = 0;
|
|
|
|
(np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL;
|
|
|
|
i++) {
|
2006-01-13 10:19:13 -07:00
|
|
|
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)
|
2006-01-23 15:58:04 -07:00
|
|
|
goto err;
|
2006-01-13 10:19:13 -07:00
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
mdio_dev =
|
|
|
|
platform_device_register_simple("fsl-gianfar_mdio",
|
|
|
|
res.start, &res, 1);
|
2006-01-13 10:19:13 -07:00
|
|
|
if (IS_ERR(mdio_dev)) {
|
|
|
|
ret = PTR_ERR(mdio_dev);
|
2006-01-23 15:58:04 -07:00
|
|
|
goto err;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
for (k = 0; k < 32; k++)
|
|
|
|
mdio_data.irq[k] = -1;
|
|
|
|
|
|
|
|
while ((child = of_get_next_child(np, child)) != NULL) {
|
2006-09-21 07:26:34 -06:00
|
|
|
int irq = irq_of_parse_and_map(child, 0);
|
|
|
|
if (irq != NO_IRQ) {
|
|
|
|
const u32 *id = get_property(child, "reg", NULL);
|
|
|
|
mdio_data.irq[*id] = irq;
|
|
|
|
}
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
ret =
|
|
|
|
platform_device_add_data(mdio_dev, &mdio_data,
|
|
|
|
sizeof(struct gianfar_mdio_data));
|
2006-01-13 10:19:13 -07:00
|
|
|
if (ret)
|
2006-01-23 15:58:04 -07:00
|
|
|
goto unreg;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
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++) {
|
2006-01-13 10:19:13 -07:00
|
|
|
struct resource r[4];
|
|
|
|
struct device_node *phy, *mdio;
|
|
|
|
struct gianfar_platform_data gfar_data;
|
2006-07-11 23:35:54 -06:00
|
|
|
const unsigned int *id;
|
|
|
|
const char *model;
|
|
|
|
const void *mac_addr;
|
|
|
|
const phandle *ph;
|
2006-09-21 07:26:34 -06:00
|
|
|
int n_res = 2;
|
2006-01-13 10:19:13 -07:00
|
|
|
|
|
|
|
memset(r, 0, sizeof(r));
|
|
|
|
memset(&gfar_data, 0, sizeof(gfar_data));
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 0, &r[0]);
|
|
|
|
if (ret)
|
2006-01-23 15:58:04 -07:00
|
|
|
goto err;
|
2006-01-13 10:19:13 -07:00
|
|
|
|
2006-07-31 14:35:41 -06:00
|
|
|
r[1].start = r[1].end = irq_of_parse_and_map(np, 0);
|
2006-01-13 10:19:13 -07:00
|
|
|
r[1].flags = IORESOURCE_IRQ;
|
|
|
|
|
|
|
|
model = 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;
|
2006-07-31 14:35:41 -06:00
|
|
|
r[2].start = r[2].end = irq_of_parse_and_map(np, 1);
|
2006-01-13 10:19:13 -07:00
|
|
|
r[2].flags = IORESOURCE_IRQ;
|
|
|
|
|
|
|
|
r[3].name = gfar_err_intr;
|
2006-07-31 14:35:41 -06:00
|
|
|
r[3].start = r[3].end = irq_of_parse_and_map(np, 2);
|
2006-01-13 10:19:13 -07:00
|
|
|
r[3].flags = IORESOURCE_IRQ;
|
2006-07-31 14:35:41 -06:00
|
|
|
|
|
|
|
n_res += 2;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
gfar_dev =
|
|
|
|
platform_device_register_simple("fsl-gianfar", i, &r[0],
|
2006-09-21 07:26:34 -06:00
|
|
|
n_res);
|
2006-01-13 10:19:13 -07:00
|
|
|
|
|
|
|
if (IS_ERR(gfar_dev)) {
|
|
|
|
ret = PTR_ERR(gfar_dev);
|
2006-01-23 15:58:04 -07:00
|
|
|
goto err;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
2006-08-17 07:42:35 -06:00
|
|
|
mac_addr = get_property(np, "local-mac-address", NULL);
|
|
|
|
if (mac_addr == NULL)
|
|
|
|
mac_addr = get_property(np, "mac-address", NULL);
|
|
|
|
if (mac_addr == NULL) {
|
|
|
|
/* Obsolete */
|
|
|
|
mac_addr = get_property(np, "address", NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mac_addr)
|
|
|
|
memcpy(gfar_data.mac_addr, mac_addr, 6);
|
2006-01-13 10:19:13 -07:00
|
|
|
|
|
|
|
if (model && !strcasecmp(model, "TSEC"))
|
|
|
|
gfar_data.device_flags =
|
2006-01-23 15:58:04 -07:00
|
|
|
FSL_GIANFAR_DEV_HAS_GIGABIT |
|
|
|
|
FSL_GIANFAR_DEV_HAS_COALESCE |
|
|
|
|
FSL_GIANFAR_DEV_HAS_RMON |
|
|
|
|
FSL_GIANFAR_DEV_HAS_MULTI_INTR;
|
2006-01-13 10:19:13 -07:00
|
|
|
if (model && !strcasecmp(model, "eTSEC"))
|
|
|
|
gfar_data.device_flags =
|
2006-01-23 15:58:04 -07:00
|
|
|
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;
|
2006-01-13 10:19:13 -07:00
|
|
|
|
2006-07-11 23:35:54 -06:00
|
|
|
ph = get_property(np, "phy-handle", NULL);
|
2006-01-13 10:19:13 -07:00
|
|
|
phy = of_find_node_by_phandle(*ph);
|
|
|
|
|
|
|
|
if (phy == NULL) {
|
|
|
|
ret = -ENODEV;
|
2006-01-23 15:58:04 -07:00
|
|
|
goto unreg;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mdio = of_get_parent(phy);
|
|
|
|
|
2006-07-11 23:35:54 -06:00
|
|
|
id = get_property(phy, "reg", NULL);
|
2006-01-13 10:19:13 -07:00
|
|
|
ret = of_address_to_resource(mdio, 0, &res);
|
|
|
|
if (ret) {
|
|
|
|
of_node_put(phy);
|
|
|
|
of_node_put(mdio);
|
2006-01-23 15:58:04 -07:00
|
|
|
goto unreg;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gfar_data.phy_id = *id;
|
|
|
|
gfar_data.bus_id = res.start;
|
|
|
|
|
|
|
|
of_node_put(phy);
|
|
|
|
of_node_put(mdio);
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
ret =
|
|
|
|
platform_device_add_data(gfar_dev, &gfar_data,
|
|
|
|
sizeof(struct
|
|
|
|
gianfar_platform_data));
|
2006-01-13 10:19:13 -07:00
|
|
|
if (ret)
|
2006-01-23 15:58:04 -07:00
|
|
|
goto unreg;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
unreg:
|
2006-01-13 10:19:13 -07:00
|
|
|
platform_device_unregister(gfar_dev);
|
2006-01-23 15:58:04 -07:00
|
|
|
err:
|
2006-01-13 10:19:13 -07:00
|
|
|
return ret;
|
|
|
|
}
|
2006-01-23 15:58:04 -07:00
|
|
|
|
2006-01-13 10:19:13 -07:00
|
|
|
arch_initcall(gfar_of_init);
|
|
|
|
|
|
|
|
static int __init fsl_i2c_of_init(void)
|
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
unsigned int i;
|
|
|
|
struct platform_device *i2c_dev;
|
|
|
|
int ret;
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
for (np = NULL, i = 0;
|
|
|
|
(np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL;
|
|
|
|
i++) {
|
2006-01-13 10:19:13 -07:00
|
|
|
struct resource r[2];
|
|
|
|
struct fsl_i2c_platform_data i2c_data;
|
2006-07-11 23:35:54 -06:00
|
|
|
const unsigned char *flags = NULL;
|
2006-01-13 10:19:13 -07:00
|
|
|
|
|
|
|
memset(&r, 0, sizeof(r));
|
|
|
|
memset(&i2c_data, 0, sizeof(i2c_data));
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 0, &r[0]);
|
|
|
|
if (ret)
|
2006-01-23 15:58:04 -07:00
|
|
|
goto err;
|
2006-01-13 10:19:13 -07:00
|
|
|
|
2006-07-31 14:35:41 -06:00
|
|
|
r[1].start = r[1].end = irq_of_parse_and_map(np, 0);
|
2006-01-13 10:19:13 -07:00
|
|
|
r[1].flags = IORESOURCE_IRQ;
|
|
|
|
|
|
|
|
i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2);
|
|
|
|
if (IS_ERR(i2c_dev)) {
|
|
|
|
ret = PTR_ERR(i2c_dev);
|
2006-01-23 15:58:04 -07:00
|
|
|
goto err;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
i2c_data.device_flags = 0;
|
|
|
|
flags = get_property(np, "dfsrr", NULL);
|
|
|
|
if (flags)
|
|
|
|
i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
|
|
|
|
|
|
|
|
flags = get_property(np, "fsl5200-clocking", NULL);
|
|
|
|
if (flags)
|
|
|
|
i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
ret =
|
|
|
|
platform_device_add_data(i2c_dev, &i2c_data,
|
|
|
|
sizeof(struct
|
|
|
|
fsl_i2c_platform_data));
|
2006-01-13 10:19:13 -07:00
|
|
|
if (ret)
|
2006-01-23 15:58:04 -07:00
|
|
|
goto unreg;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
unreg:
|
2006-01-13 10:19:13 -07:00
|
|
|
platform_device_unregister(i2c_dev);
|
2006-01-23 15:58:04 -07:00
|
|
|
err:
|
2006-01-13 10:19:13 -07:00
|
|
|
return ret;
|
|
|
|
}
|
2006-01-23 15:58:04 -07:00
|
|
|
|
2006-01-13 10:19:13 -07:00
|
|
|
arch_initcall(fsl_i2c_of_init);
|
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_83xx
|
|
|
|
static int __init mpc83xx_wdt_init(void)
|
|
|
|
{
|
|
|
|
struct resource r;
|
|
|
|
struct device_node *soc, *np;
|
|
|
|
struct platform_device *dev;
|
2006-07-11 23:35:54 -06:00
|
|
|
const unsigned int *freq;
|
2006-01-13 10:19:13 -07:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt");
|
|
|
|
|
|
|
|
if (!np) {
|
|
|
|
ret = -ENODEV;
|
2006-01-23 15:58:04 -07:00
|
|
|
goto nodev;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
soc = of_find_node_by_type(NULL, "soc");
|
|
|
|
|
|
|
|
if (!soc) {
|
|
|
|
ret = -ENODEV;
|
2006-01-23 15:58:04 -07:00
|
|
|
goto nosoc;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
2006-07-11 23:35:54 -06:00
|
|
|
freq = get_property(soc, "bus-frequency", NULL);
|
2006-01-13 10:19:13 -07:00
|
|
|
if (!freq) {
|
|
|
|
ret = -ENODEV;
|
2006-01-23 15:58:04 -07:00
|
|
|
goto err;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&r, 0, sizeof(r));
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 0, &r);
|
|
|
|
if (ret)
|
2006-01-23 15:58:04 -07:00
|
|
|
goto err;
|
2006-01-13 10:19:13 -07:00
|
|
|
|
|
|
|
dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1);
|
|
|
|
if (IS_ERR(dev)) {
|
|
|
|
ret = PTR_ERR(dev);
|
2006-01-23 15:58:04 -07:00
|
|
|
goto err;
|
2006-01-13 10:19:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = platform_device_add_data(dev, freq, sizeof(int));
|
|
|
|
if (ret)
|
2006-01-23 15:58:04 -07:00
|
|
|
goto unreg;
|
2006-01-13 10:19:13 -07:00
|
|
|
|
|
|
|
of_node_put(soc);
|
|
|
|
of_node_put(np);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2006-01-23 15:58:04 -07:00
|
|
|
unreg:
|
2006-01-13 10:19:13 -07:00
|
|
|
platform_device_unregister(dev);
|
2006-01-23 15:58:04 -07:00
|
|
|
err:
|
2006-01-13 10:19:13 -07:00
|
|
|
of_node_put(soc);
|
2006-01-23 15:58:04 -07:00
|
|
|
nosoc:
|
2006-01-13 10:19:13 -07:00
|
|
|
of_node_put(np);
|
2006-01-23 15:58:04 -07:00
|
|
|
nodev:
|
2006-01-13 10:19:13 -07:00
|
|
|
return ret;
|
|
|
|
}
|
2006-01-23 15:58:04 -07:00
|
|
|
|
2006-01-13 10:19:13 -07:00
|
|
|
arch_initcall(mpc83xx_wdt_init);
|
|
|
|
#endif
|
2006-02-02 11:31:00 -07:00
|
|
|
|
2006-07-11 23:35:54 -06:00
|
|
|
static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
|
2006-02-02 11:31:00 -07:00
|
|
|
{
|
|
|
|
if (!phy_type)
|
|
|
|
return FSL_USB2_PHY_NONE;
|
|
|
|
if (!strcasecmp(phy_type, "ulpi"))
|
|
|
|
return FSL_USB2_PHY_ULPI;
|
|
|
|
if (!strcasecmp(phy_type, "utmi"))
|
|
|
|
return FSL_USB2_PHY_UTMI;
|
|
|
|
if (!strcasecmp(phy_type, "utmi_wide"))
|
|
|
|
return FSL_USB2_PHY_UTMI_WIDE;
|
|
|
|
if (!strcasecmp(phy_type, "serial"))
|
|
|
|
return FSL_USB2_PHY_SERIAL;
|
|
|
|
|
|
|
|
return FSL_USB2_PHY_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __init fsl_usb_of_init(void)
|
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
unsigned int i;
|
2006-04-11 09:07:16 -06:00
|
|
|
struct platform_device *usb_dev_mph = NULL, *usb_dev_dr = NULL;
|
2006-02-02 11:31:00 -07:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
for (np = NULL, i = 0;
|
|
|
|
(np = of_find_compatible_node(np, "usb", "fsl-usb2-mph")) != NULL;
|
|
|
|
i++) {
|
|
|
|
struct resource r[2];
|
|
|
|
struct fsl_usb2_platform_data usb_data;
|
2006-07-11 23:35:54 -06:00
|
|
|
const unsigned char *prop = NULL;
|
2006-02-02 11:31:00 -07:00
|
|
|
|
|
|
|
memset(&r, 0, sizeof(r));
|
|
|
|
memset(&usb_data, 0, sizeof(usb_data));
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 0, &r[0]);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
2006-07-31 14:35:41 -06:00
|
|
|
r[1].start = r[1].end = irq_of_parse_and_map(np, 0);
|
2006-02-02 11:31:00 -07:00
|
|
|
r[1].flags = IORESOURCE_IRQ;
|
|
|
|
|
2006-04-11 09:07:16 -06:00
|
|
|
usb_dev_mph =
|
|
|
|
platform_device_register_simple("fsl-ehci", i, r, 2);
|
|
|
|
if (IS_ERR(usb_dev_mph)) {
|
|
|
|
ret = PTR_ERR(usb_dev_mph);
|
2006-02-02 11:31:00 -07:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2006-04-11 09:07:16 -06:00
|
|
|
usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL;
|
|
|
|
usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask;
|
2006-02-02 11:31:00 -07:00
|
|
|
|
|
|
|
usb_data.operating_mode = FSL_USB2_MPH_HOST;
|
|
|
|
|
|
|
|
prop = get_property(np, "port0", NULL);
|
|
|
|
if (prop)
|
|
|
|
usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
|
|
|
|
|
|
|
|
prop = get_property(np, "port1", NULL);
|
|
|
|
if (prop)
|
|
|
|
usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
|
|
|
|
|
|
|
|
prop = get_property(np, "phy_type", NULL);
|
|
|
|
usb_data.phy_mode = determine_usb_phy(prop);
|
|
|
|
|
|
|
|
ret =
|
2006-04-11 09:07:16 -06:00
|
|
|
platform_device_add_data(usb_dev_mph, &usb_data,
|
2006-02-02 11:31:00 -07:00
|
|
|
sizeof(struct
|
|
|
|
fsl_usb2_platform_data));
|
|
|
|
if (ret)
|
2006-04-11 09:07:16 -06:00
|
|
|
goto unreg_mph;
|
2006-02-02 11:31:00 -07:00
|
|
|
}
|
|
|
|
|
2006-04-11 09:07:16 -06:00
|
|
|
for (np = NULL;
|
2006-02-02 11:31:00 -07:00
|
|
|
(np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL;
|
|
|
|
i++) {
|
|
|
|
struct resource r[2];
|
|
|
|
struct fsl_usb2_platform_data usb_data;
|
2006-07-11 23:35:54 -06:00
|
|
|
const unsigned char *prop = NULL;
|
2006-02-02 11:31:00 -07:00
|
|
|
|
|
|
|
memset(&r, 0, sizeof(r));
|
|
|
|
memset(&usb_data, 0, sizeof(usb_data));
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 0, &r[0]);
|
|
|
|
if (ret)
|
2006-04-11 09:07:16 -06:00
|
|
|
goto unreg_mph;
|
2006-02-02 11:31:00 -07:00
|
|
|
|
2006-07-31 14:35:41 -06:00
|
|
|
r[1].start = r[1].end = irq_of_parse_and_map(np, 0);
|
2006-02-02 11:31:00 -07:00
|
|
|
r[1].flags = IORESOURCE_IRQ;
|
|
|
|
|
2006-04-11 09:07:16 -06:00
|
|
|
usb_dev_dr =
|
|
|
|
platform_device_register_simple("fsl-ehci", i, r, 2);
|
|
|
|
if (IS_ERR(usb_dev_dr)) {
|
|
|
|
ret = PTR_ERR(usb_dev_dr);
|
2006-02-02 11:31:00 -07:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2006-04-11 09:07:16 -06:00
|
|
|
usb_dev_dr->dev.coherent_dma_mask = 0xffffffffUL;
|
|
|
|
usb_dev_dr->dev.dma_mask = &usb_dev_dr->dev.coherent_dma_mask;
|
2006-02-02 11:31:00 -07:00
|
|
|
|
|
|
|
usb_data.operating_mode = FSL_USB2_DR_HOST;
|
|
|
|
|
|
|
|
prop = get_property(np, "phy_type", NULL);
|
|
|
|
usb_data.phy_mode = determine_usb_phy(prop);
|
|
|
|
|
|
|
|
ret =
|
2006-04-11 09:07:16 -06:00
|
|
|
platform_device_add_data(usb_dev_dr, &usb_data,
|
2006-02-02 11:31:00 -07:00
|
|
|
sizeof(struct
|
|
|
|
fsl_usb2_platform_data));
|
|
|
|
if (ret)
|
2006-04-11 09:07:16 -06:00
|
|
|
goto unreg_dr;
|
2006-02-02 11:31:00 -07:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
2006-04-11 09:07:16 -06:00
|
|
|
unreg_dr:
|
|
|
|
if (usb_dev_dr)
|
|
|
|
platform_device_unregister(usb_dev_dr);
|
|
|
|
unreg_mph:
|
|
|
|
if (usb_dev_mph)
|
|
|
|
platform_device_unregister(usb_dev_mph);
|
2006-02-02 11:31:00 -07:00
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-04-11 09:07:16 -06:00
|
|
|
arch_initcall(fsl_usb_of_init);
|
2006-09-21 07:26:34 -06:00
|
|
|
|
|
|
|
#ifdef CONFIG_CPM2
|
|
|
|
|
|
|
|
static const char fcc_regs[] = "fcc_regs";
|
|
|
|
static const char fcc_regs_c[] = "fcc_regs_c";
|
|
|
|
static const char fcc_pram[] = "fcc_pram";
|
|
|
|
static char bus_id[9][BUS_ID_SIZE];
|
|
|
|
|
|
|
|
static int __init fs_enet_of_init(void)
|
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
unsigned int i;
|
|
|
|
struct platform_device *fs_enet_dev;
|
|
|
|
struct resource res;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
for (np = NULL, i = 0;
|
|
|
|
(np = of_find_compatible_node(np, "network", "fs_enet")) != NULL;
|
|
|
|
i++) {
|
|
|
|
struct resource r[4];
|
|
|
|
struct device_node *phy, *mdio;
|
|
|
|
struct fs_platform_info fs_enet_data;
|
2006-10-05 20:16:48 -06:00
|
|
|
const unsigned int *id, *phy_addr, *phy_irq;
|
2006-09-21 07:26:34 -06:00
|
|
|
const void *mac_addr;
|
|
|
|
const phandle *ph;
|
|
|
|
const char *model;
|
|
|
|
|
|
|
|
memset(r, 0, sizeof(r));
|
|
|
|
memset(&fs_enet_data, 0, sizeof(fs_enet_data));
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 0, &r[0]);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
r[0].name = fcc_regs;
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 1, &r[1]);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
r[1].name = fcc_pram;
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 2, &r[2]);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
r[2].name = fcc_regs_c;
|
2006-10-02 12:41:50 -06:00
|
|
|
fs_enet_data.fcc_regs_c = r[2].start;
|
2006-09-21 07:26:34 -06:00
|
|
|
|
|
|
|
r[3].start = r[3].end = irq_of_parse_and_map(np, 0);
|
|
|
|
r[3].flags = IORESOURCE_IRQ;
|
|
|
|
|
|
|
|
fs_enet_dev =
|
|
|
|
platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4);
|
|
|
|
|
|
|
|
if (IS_ERR(fs_enet_dev)) {
|
|
|
|
ret = PTR_ERR(fs_enet_dev);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
model = get_property(np, "model", NULL);
|
|
|
|
if (model == NULL) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto unreg;
|
|
|
|
}
|
|
|
|
|
|
|
|
mac_addr = get_property(np, "mac-address", NULL);
|
|
|
|
memcpy(fs_enet_data.macaddr, mac_addr, 6);
|
|
|
|
|
|
|
|
ph = get_property(np, "phy-handle", NULL);
|
|
|
|
phy = of_find_node_by_phandle(*ph);
|
|
|
|
|
|
|
|
if (phy == NULL) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto unreg;
|
|
|
|
}
|
|
|
|
|
|
|
|
phy_addr = get_property(phy, "reg", NULL);
|
|
|
|
fs_enet_data.phy_addr = *phy_addr;
|
|
|
|
|
2006-10-02 12:41:50 -06:00
|
|
|
phy_irq = get_property(phy, "interrupts", NULL);
|
|
|
|
|
2006-09-21 07:26:34 -06:00
|
|
|
id = get_property(np, "device-id", NULL);
|
|
|
|
fs_enet_data.fs_no = *id;
|
POWERPC: Bring the fs_no calculation to the relevant SoC enumeration
The fs_no mean used to be fs_enet driver driven, hence it was an
enumeration across all the possible fs_enet "users" in the SoC. Now, with
QE on the pipeline, and to make DTS descriptions more clear, fs_no features
relevant SoC part number, with additional field to describe the SoC type.
Another reason for that is now not only fs_enet is going to utilize those
stuff. There might be UART, HLDC, and even USB, so to prevent confusion and
be ready for upcoming OF_device transfer, fs_enet and cpm_uart drivers were
updated in that concern, as well as the relevant DTS.
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
2006-09-21 12:38:05 -06:00
|
|
|
strcpy(fs_enet_data.fs_type, model);
|
2006-09-21 07:26:34 -06:00
|
|
|
|
|
|
|
mdio = of_get_parent(phy);
|
|
|
|
ret = of_address_to_resource(mdio, 0, &res);
|
|
|
|
if (ret) {
|
|
|
|
of_node_put(phy);
|
|
|
|
of_node_put(mdio);
|
|
|
|
goto unreg;
|
|
|
|
}
|
|
|
|
|
2006-09-21 12:38:05 -06:00
|
|
|
fs_enet_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
|
|
|
|
fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
|
|
|
|
|
2006-09-21 07:26:34 -06:00
|
|
|
if (strstr(model, "FCC")) {
|
POWERPC: Bring the fs_no calculation to the relevant SoC enumeration
The fs_no mean used to be fs_enet driver driven, hence it was an
enumeration across all the possible fs_enet "users" in the SoC. Now, with
QE on the pipeline, and to make DTS descriptions more clear, fs_no features
relevant SoC part number, with additional field to describe the SoC type.
Another reason for that is now not only fs_enet is going to utilize those
stuff. There might be UART, HLDC, and even USB, so to prevent confusion and
be ready for upcoming OF_device transfer, fs_enet and cpm_uart drivers were
updated in that concern, as well as the relevant DTS.
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
2006-09-21 12:38:05 -06:00
|
|
|
int fcc_index = *id - 1;
|
2006-10-05 20:16:48 -06:00
|
|
|
const unsigned char *mdio_bb_prop;
|
2006-09-21 07:26:34 -06:00
|
|
|
|
POWERPC: Get rid of remapping the whole immr
The stuff below cleans up the code attempting to remap the whole cpm2_immr
early, as well as places happily assuming that fact. This is more like the 2.4
legacy stuff, and is at least confusing and unclear now.
To keep the world comfortable, a new mechanism is introduced: before accessing
specific immr register/register set, one needs to map it, using cpm2_map(<reg>),
for instance, access to CPM command register will look like
volatile cpm_cpm2_t *cp = cpm2_map(im_cpm);
keeping the code clear, yet without "already defined somewhere" cpm2_immr.
So far, unmapping code is not implemented, but it's not a big deal to add it,
if the whole idea makes sense.
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
2006-09-21 12:37:58 -06:00
|
|
|
fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0);
|
2006-09-21 07:26:34 -06:00
|
|
|
fs_enet_data.rx_ring = 32;
|
|
|
|
fs_enet_data.tx_ring = 32;
|
|
|
|
fs_enet_data.rx_copybreak = 240;
|
|
|
|
fs_enet_data.use_napi = 0;
|
|
|
|
fs_enet_data.napi_weight = 17;
|
|
|
|
fs_enet_data.mem_offset = FCC_MEM_OFFSET(fcc_index);
|
|
|
|
fs_enet_data.cp_page = CPM_CR_FCC_PAGE(fcc_index);
|
|
|
|
fs_enet_data.cp_block = CPM_CR_FCC_SBLOCK(fcc_index);
|
|
|
|
|
|
|
|
snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x",
|
|
|
|
(u32)res.start, fs_enet_data.phy_addr);
|
|
|
|
fs_enet_data.bus_id = (char*)&bus_id[(*id)];
|
2006-09-21 12:38:05 -06:00
|
|
|
fs_enet_data.init_ioports = init_fcc_ioports;
|
2006-09-21 07:26:34 -06:00
|
|
|
|
2006-10-02 12:41:50 -06:00
|
|
|
mdio_bb_prop = get_property(phy, "bitbang", NULL);
|
|
|
|
if (mdio_bb_prop) {
|
|
|
|
struct platform_device *fs_enet_mdio_bb_dev;
|
|
|
|
struct fs_mii_bb_platform_info fs_enet_mdio_bb_data;
|
|
|
|
|
|
|
|
fs_enet_mdio_bb_dev =
|
|
|
|
platform_device_register_simple("fsl-bb-mdio",
|
|
|
|
i, NULL, 0);
|
|
|
|
memset(&fs_enet_mdio_bb_data, 0,
|
|
|
|
sizeof(struct fs_mii_bb_platform_info));
|
|
|
|
fs_enet_mdio_bb_data.mdio_dat.bit =
|
|
|
|
mdio_bb_prop[0];
|
|
|
|
fs_enet_mdio_bb_data.mdio_dir.bit =
|
|
|
|
mdio_bb_prop[1];
|
|
|
|
fs_enet_mdio_bb_data.mdc_dat.bit =
|
|
|
|
mdio_bb_prop[2];
|
|
|
|
fs_enet_mdio_bb_data.mdio_port =
|
|
|
|
mdio_bb_prop[3];
|
|
|
|
fs_enet_mdio_bb_data.mdc_port =
|
|
|
|
mdio_bb_prop[4];
|
|
|
|
fs_enet_mdio_bb_data.delay =
|
|
|
|
mdio_bb_prop[5];
|
|
|
|
|
|
|
|
fs_enet_mdio_bb_data.irq[0] = phy_irq[0];
|
|
|
|
fs_enet_mdio_bb_data.irq[1] = -1;
|
|
|
|
fs_enet_mdio_bb_data.irq[2] = -1;
|
|
|
|
fs_enet_mdio_bb_data.irq[3] = phy_irq[0];
|
|
|
|
fs_enet_mdio_bb_data.irq[31] = -1;
|
|
|
|
|
|
|
|
fs_enet_mdio_bb_data.mdio_dat.offset =
|
|
|
|
(u32)&cpm2_immr->im_ioport.iop_pdatc;
|
|
|
|
fs_enet_mdio_bb_data.mdio_dir.offset =
|
|
|
|
(u32)&cpm2_immr->im_ioport.iop_pdirc;
|
|
|
|
fs_enet_mdio_bb_data.mdc_dat.offset =
|
|
|
|
(u32)&cpm2_immr->im_ioport.iop_pdatc;
|
|
|
|
|
|
|
|
ret = platform_device_add_data(
|
|
|
|
fs_enet_mdio_bb_dev,
|
|
|
|
&fs_enet_mdio_bb_data,
|
|
|
|
sizeof(struct fs_mii_bb_platform_info));
|
|
|
|
if (ret)
|
|
|
|
goto unreg;
|
|
|
|
}
|
|
|
|
|
|
|
|
of_node_put(phy);
|
|
|
|
of_node_put(mdio);
|
2006-09-21 07:26:34 -06:00
|
|
|
|
2006-10-02 12:41:50 -06:00
|
|
|
ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
|
|
|
|
sizeof(struct
|
|
|
|
fs_platform_info));
|
2006-10-05 20:16:48 -06:00
|
|
|
if (ret)
|
|
|
|
goto unreg;
|
|
|
|
}
|
2006-09-21 07:26:34 -06:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unreg:
|
|
|
|
platform_device_unregister(fs_enet_dev);
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
arch_initcall(fs_enet_of_init);
|
|
|
|
|
|
|
|
static const char scc_regs[] = "regs";
|
|
|
|
static const char scc_pram[] = "pram";
|
|
|
|
|
|
|
|
static int __init cpm_uart_of_init(void)
|
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
unsigned int i;
|
|
|
|
struct platform_device *cpm_uart_dev;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
for (np = NULL, i = 0;
|
|
|
|
(np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL;
|
|
|
|
i++) {
|
|
|
|
struct resource r[3];
|
|
|
|
struct fs_uart_platform_info cpm_uart_data;
|
|
|
|
const int *id;
|
POWERPC: Bring the fs_no calculation to the relevant SoC enumeration
The fs_no mean used to be fs_enet driver driven, hence it was an
enumeration across all the possible fs_enet "users" in the SoC. Now, with
QE on the pipeline, and to make DTS descriptions more clear, fs_no features
relevant SoC part number, with additional field to describe the SoC type.
Another reason for that is now not only fs_enet is going to utilize those
stuff. There might be UART, HLDC, and even USB, so to prevent confusion and
be ready for upcoming OF_device transfer, fs_enet and cpm_uart drivers were
updated in that concern, as well as the relevant DTS.
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
2006-09-21 12:38:05 -06:00
|
|
|
const char *model;
|
2006-09-21 07:26:34 -06:00
|
|
|
|
|
|
|
memset(r, 0, sizeof(r));
|
|
|
|
memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 0, &r[0]);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
r[0].name = scc_regs;
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 1, &r[1]);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
r[1].name = scc_pram;
|
|
|
|
|
|
|
|
r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
|
|
|
|
r[2].flags = IORESOURCE_IRQ;
|
|
|
|
|
|
|
|
cpm_uart_dev =
|
|
|
|
platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3);
|
|
|
|
|
|
|
|
if (IS_ERR(cpm_uart_dev)) {
|
|
|
|
ret = PTR_ERR(cpm_uart_dev);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
id = get_property(np, "device-id", NULL);
|
|
|
|
cpm_uart_data.fs_no = *id;
|
POWERPC: Bring the fs_no calculation to the relevant SoC enumeration
The fs_no mean used to be fs_enet driver driven, hence it was an
enumeration across all the possible fs_enet "users" in the SoC. Now, with
QE on the pipeline, and to make DTS descriptions more clear, fs_no features
relevant SoC part number, with additional field to describe the SoC type.
Another reason for that is now not only fs_enet is going to utilize those
stuff. There might be UART, HLDC, and even USB, so to prevent confusion and
be ready for upcoming OF_device transfer, fs_enet and cpm_uart drivers were
updated in that concern, as well as the relevant DTS.
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
2006-09-21 12:38:05 -06:00
|
|
|
|
|
|
|
model = (char*)get_property(np, "model", NULL);
|
|
|
|
strcpy(cpm_uart_data.fs_type, model);
|
|
|
|
|
2006-09-21 07:26:34 -06:00
|
|
|
cpm_uart_data.uart_clk = ppc_proc_freq;
|
|
|
|
|
|
|
|
cpm_uart_data.tx_num_fifo = 4;
|
|
|
|
cpm_uart_data.tx_buf_size = 32;
|
|
|
|
cpm_uart_data.rx_num_fifo = 4;
|
|
|
|
cpm_uart_data.rx_buf_size = 32;
|
2006-09-21 12:38:05 -06:00
|
|
|
cpm_uart_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
|
|
|
|
cpm_uart_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
|
2006-09-21 07:26:34 -06:00
|
|
|
|
|
|
|
ret =
|
|
|
|
platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
|
|
|
|
sizeof(struct
|
|
|
|
fs_uart_platform_info));
|
|
|
|
if (ret)
|
|
|
|
goto unreg;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unreg:
|
|
|
|
platform_device_unregister(cpm_uart_dev);
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
arch_initcall(cpm_uart_of_init);
|
|
|
|
#endif /* CONFIG_CPM2 */
|