OK335xS CAN device register and deiver match hacking

/*************************************************************************
* OK335xS CAN device register and deiver match hacking
* 声明:
* 本文主要是跟踪CAN设备的注册、和驱动的匹配方式,了解CAN的注册流程。
*
* 2015-9-7 晴 深圳 南山平山村 曾剑锋
************************************************************************/
MACHINE_START(AM335XEVM, "am335xevm")
/* Maintainer: Texas Instruments */
.atag_offset = 0x100,
.map_io = am335x_evm_map_io,
.init_early = am33xx_init_early,
.init_irq = ti81xx_init_irq,
.handle_irq = omap3_intc_handle_irq,
.timer = &omap3_am33xx_timer,
.init_machine = am335x_evm_init, ------+
MACHINE_END |
|
MACHINE_START(AM335XIAEVM, "am335xiaevm") |
/* Maintainer: Texas Instruments */ |
.atag_offset = 0x100, |
.map_io = am335x_evm_map_io, |
.init_irq = ti81xx_init_irq, |
.init_early = am33xx_init_early, |
.timer = &omap3_am33xx_timer, |
.init_machine = am335x_evm_init, ------+
MACHINE_END |
|
static void __init am335x_evm_init(void) <-----+
{
setup_ok335xs(); ------+
} |
|
static void setup_ok335xs(void) <-----+
{
pr_info("The board is a ok335xs.\n"); /* Starter Kit has Micro-SD slot which doesn't have Write Protect pin */
am335x_mmc[].gpio_wp = -EINVAL; _configure_device(EVM_SK, ok335xs_dev_cfg, PROFILE_NONE);
^------------------------------------+
am33xx_cpsw_init(AM33XX_CPSW_MODE_RGMII, NULL, NULL); |
/* Atheros Tx Clk delay Phy fixup */ |
phy_register_fixup_for_uid(AM335X_EVM_PHY_ID, AM335X_EVM_PHY_MASK, |
am33xx_evm_tx_clk_dly_phy_fixup); |
} |
|
/*ok335xs*/ |
static struct evm_dev_cfg ok335xs_dev_cfg[] = { <-----------------+
{mmc0_init, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed
#if defined(CONFIG_ANDROID)
{mfd_tscadc_init, DEV_ON_BASEBOARD, PROFILE_ALL},
#endif
{rgmii1_init, DEV_ON_BASEBOARD, PROFILE_ALL},
{rgmii2_init, DEV_ON_BASEBOARD, PROFILE_ALL},
{lcdc_init, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed
{i2c1_init, DEV_ON_BASEBOARD, PROFILE_ALL},
{buzzer_init, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed
{enable_ecap2, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed
{usb0_init, DEV_ON_BASEBOARD, PROFILE_ALL},
{usb1_init, DEV_ON_BASEBOARD, PROFILE_ALL},
{evm_nand_init,DEV_ON_BASEBOARD, PROFILE_ALL},//fixed
{mcasp1_init, DEV_ON_BASEBOARD, PROFILE_NONE},//fixed
{gpio_keys_init_forlinx_s, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed
{gpio_led_init_s, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed
{uart2_init_s, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed
{spi1_init_s, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed
{d_can_init, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed ------+
{sgx_init, DEV_ON_BASEBOARD, PROFILE_ALL}, |
{NULL, , }, |
}; |
|
static void d_can_init(int evm_id, int profile) <-----------+
{
//setup_pin_mux(d_can0_pin_mux);
setup_pin_mux(d_can_gp_pin_mux); ---------------------------------+
am33xx_d_can_init(); | ---------------------------------*-+
} | | |
V | |
static struct pinmux_config d_can_gp_pin_mux[] = { | |
{"uart0_ctsn.d_can1_tx", OMAP_MUX_MODE2 | AM33XX_PULL_ENBL}, | |
{"uart0_rtsn.d_can1_rx", OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP}, | |
{NULL, }, | |
}; | |
| |
static void setup_pin_mux(struct pinmux_config *pin_mux) <-----------+ |
{ |
int i; |
|
for (i = ; pin_mux->string_name != NULL; pin_mux++) |
omap_mux_init_signal(pin_mux->string_name, pin_mux->val); ------+ |
| |
} | |
| |
int __init omap_mux_init_signal(const char *muxname, int val) <-----+ |
{ |
struct omap_mux_partition *partition = NULL; |
struct omap_mux *mux = NULL; |
u16 old_mode; |
int mux_mode; |
|
mux_mode = omap_mux_get_by_name(muxname, &partition, &mux); |
if (mux_mode < ) |
return mux_mode; |
|
old_mode = omap_mux_read(partition, mux->reg_offset); |
mux_mode |= val; |
pr_debug("%s: Setting signal %s 0x%04x -> 0x%04x\n", |
__func__, muxname, old_mode, mux_mode); |
omap_mux_write(partition, mux_mode, mux->reg_offset); |
|
return ; |
} |
|
void am33xx_d_can_init(unsigned int instance) <--------------------+
{
struct omap_hwmod *oh;
struct platform_device *pdev;
char oh_name[L3_MODULES_MAX_LEN]; /* Copy string name to oh_name buffer */
snprintf(oh_name, L3_MODULES_MAX_LEN, "d_can%d", instance); oh = omap_hwmod_lookup(oh_name);
if (!oh) {
pr_err("could not find %s hwmod data\n", oh_name);
return;
} pdev = omap_device_build("d_can", instance, oh, &am33xx_dcan_info, ----------+
sizeof(am33xx_dcan_info), NULL, , ); |
if (IS_ERR(pdev)) |
pr_err("could not build omap_device for %s\n", oh_name); |
} |
|
struct platform_device *omap_device_build(const char *pdev_name, int pdev_id, <---+
struct omap_hwmod *oh, void *pdata,
int pdata_len,
struct omap_device_pm_latency *pm_lats,
int pm_lats_cnt, int is_early_device)
{
struct omap_hwmod *ohs[] = { oh }; if (!oh)
return ERR_PTR(-EINVAL); return omap_device_build_ss(pdev_name, pdev_id, ohs, , pdata, ----------+
pdata_len, pm_lats, pm_lats_cnt, |
is_early_device); |
} |
|
struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id, <--+
struct omap_hwmod **ohs, int oh_cnt,
void *pdata, int pdata_len,
struct omap_device_pm_latency *pm_lats,
int pm_lats_cnt, int is_early_device)
{
int ret = -ENOMEM;
struct platform_device *pdev;
struct omap_device *od; if (!ohs || oh_cnt == || !pdev_name)
return ERR_PTR(-EINVAL); if (!pdata && pdata_len > )
return ERR_PTR(-EINVAL); pdev = platform_device_alloc(pdev_name, pdev_id);
if (!pdev) {
ret = -ENOMEM;
goto odbs_exit;
} /* Set the dev_name early to allow dev_xxx in omap_device_alloc */
if (pdev->id != -)
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
else
dev_set_name(&pdev->dev, "%s", pdev->name); od = omap_device_alloc(pdev, ohs, oh_cnt, pm_lats, pm_lats_cnt);
if (!od)
goto odbs_exit1; ret = platform_device_add_data(pdev, pdata, pdata_len);
if (ret)
goto odbs_exit2; if (is_early_device)
ret = omap_early_device_register(pdev);
else
ret = omap_device_register(pdev); -------------------+
if (ret) |
goto odbs_exit2; |
|
return pdev; |
|
odbs_exit2: |
omap_device_delete(od); |
odbs_exit1: |
platform_device_put(pdev); |
odbs_exit: |
|
pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret); |
|
return ERR_PTR(ret); |
} |
|
int omap_device_register(struct platform_device *pdev) <-----------+
{
pr_debug("omap_device: %s: registering\n", pdev->name);
printk("omap_device: %s: registering\n", pdev->name); pdev->dev.parent = &omap_device_parent;
pdev->dev.pm_domain = &omap_device_pm_domain;
return platform_device_add(pdev); ------------+
} |
|
int platform_device_add(struct platform_device *pdev) <-----------+
{
int i, ret = ; if (!pdev)
return -EINVAL; if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus; pdev->dev.bus = &platform_bus_type; -------------------+
|
if (pdev->id != -) |
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); |
else |
dev_set_name(&pdev->dev, "%s", pdev->name); |
|
for (i = ; i < pdev->num_resources; i++) { |
struct resource *p, *r = &pdev->resource[i]; |
|
if (r->name == NULL) |
r->name = dev_name(&pdev->dev); |
|
p = r->parent; |
if (!p) { |
if (resource_type(r) == IORESOURCE_MEM) |
p = &iomem_resource; |
else if (resource_type(r) == IORESOURCE_IO) |
p = &ioport_resource; |
} |
|
if (p && insert_resource(p, r)) { |
printk(KERN_ERR |
"%s: failed to claim resource %d\n", |
dev_name(&pdev->dev), i); |
ret = -EBUSY; |
goto failed; |
} |
} |
|
pr_debug("Registering platform device '%s'. Parent at %s\n", |
dev_name(&pdev->dev), dev_name(pdev->dev.parent)); |
|
ret = device_add(&pdev->dev); |
if (ret == ) |
return ret; |
|
failed: |
while (--i >= ) { |
struct resource *r = &pdev->resource[i]; |
unsigned long type = resource_type(r); |
|
if (type == IORESOURCE_MEM || type == IORESOURCE_IO) |
release_resource(r); |
} |
|
return ret; |
} |
EXPORT_SYMBOL_GPL(platform_device_add); |
|
struct bus_type platform_bus_type = { <----------------------+
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match, -------------------------------+
.uevent = platform_uevent, |
.pm = &platform_dev_pm_ops, |
}; |
EXPORT_SYMBOL_GPL(platform_bus_type); |
|
static int platform_match(struct device *dev, struct device_driver *drv) <--+
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv); /* Attempt an OF style match first */
if (of_driver_match_device(dev, drv)) -------------+
return ; |
|
/* Then try to match against the id table */ |
if (pdrv->id_table) |
return platform_match_id(pdrv->id_table, pdev) != NULL; |
^------------------------------------------|-+
/* fall-back to driver name match */ | |
// canbus use this for match | |
return (strcmp(pdev->name, drv->name) == ); | |
} | |
| |
static inline int of_driver_match_device(struct device *dev, <---+ |
const struct device_driver *drv) |
{ |
return of_match_device(drv->of_match_table, dev) != NULL; |
} |
|
static const struct platform_device_id *platform_match_id( <-----+
const struct platform_device_id *id,
struct platform_device *pdev)
{
while (id->name[]) {
if (strcmp(pdev->name, id->name) == ) {
pdev->id_entry = id;
return id;
}
id++;
}
return NULL;
} cat drivers/net/can/d_can/d_can_platform.c
static struct platform_driver d_can_plat_driver = { <-----+
.driver = { |
.name = D_CAN_DRV_NAME, ---------------*-+
.owner = THIS_MODULE, | |
}, | |
.probe = d_can_plat_probe, ---------------*-*-----+
.remove = __devexit_p(d_can_plat_remove), | | |
.suspend = d_can_suspend, | | |
.resume = d_can_resume, | | |
}; | | |
| | |
static int __init d_can_plat_init(void) <------------+ | | |
{ | | | |
printk(KERN_INFO D_CAN_DRV_DESC "\n"); | | | |
return platform_driver_register(&d_can_plat_driver);--*-- | |
} | | |
module_init(d_can_plat_init); ----------------------------+ | |
| |
static void __exit d_can_plat_exit(void) | |
{ | |
printk(KERN_INFO D_CAN_DRV_DESC " unloaded\n"); | |
platform_driver_unregister(&d_can_plat_driver); | |
} | |
module_exit(d_can_plat_exit); | |
| |
MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>"); | |
MODULE_LICENSE("GPL v2"); | |
MODULE_VERSION(D_CAN_VERSION); | |
MODULE_DESCRIPTION(D_CAN_DRV_DESC); | |
| |
#define D_CAN_DRV_NAME "d_can" <----------------+ |
v-------------------------------------+
static int __devinit d_can_plat_probe(struct platform_device *pdev)
{
int ret = ;
void __iomem *addr;
struct net_device *ndev;
struct d_can_priv *priv;
struct resource *mem;
struct d_can_platform_data *pdata;
struct clk *fck; printk("zengjf check can plat probed.\n");
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "No platform data\n");
goto exit;
} /* allocate the d_can device */
ndev = alloc_d_can_dev(pdata->num_of_msg_objs);
if (!ndev) {
ret = -ENOMEM;
dev_err(&pdev->dev, "alloc_d_can_dev failed\n");
goto exit;
} priv = netdev_priv(ndev);
fck = clk_get(&pdev->dev, "fck");
if (IS_ERR(fck)) {
dev_err(&pdev->dev, "fck is not found\n");
ret = -ENODEV;
goto exit_free_ndev;
} /* get the platform data */
mem = platform_get_resource(pdev, IORESOURCE_MEM, );
if (!mem) {
ret = -ENODEV;
dev_err(&pdev->dev, "No mem resource\n");
goto exit_clk_put;
} if (!request_mem_region(mem->start, resource_size(mem),
D_CAN_DRV_NAME)) {
dev_err(&pdev->dev, "resource unavailable\n");
ret = -EBUSY;
goto exit_clk_put;
} addr = ioremap(mem->start, resource_size(mem));
if (!addr) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
goto exit_release_mem;
} /* IRQ specific to Error and status & can be used for Message Object */
ndev->irq = platform_get_irq_byname(pdev, "d_can_ms");
if (!ndev->irq) {
dev_err(&pdev->dev, "No irq0 resource\n");
goto exit_iounmap;
} /* IRQ specific for Message Object */
priv->irq_obj = platform_get_irq_byname(pdev, "d_can_mo");
if (!priv->irq_obj) {
dev_err(&pdev->dev, "No irq1 resource\n");
goto exit_iounmap;
} pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
priv->pdev = pdev;
priv->base = addr;
priv->can.clock.freq = clk_get_rate(fck);
priv->ram_init = pdata->ram_init;
priv->opened = false; platform_set_drvdata(pdev, ndev);
SET_NETDEV_DEV(ndev, &pdev->dev); ret = register_d_can_dev(ndev);
if (ret) {
dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
D_CAN_DRV_NAME, ret);
goto exit_free_device;
} /* Initialize DCAN RAM */
d_can_reset_ram(priv, pdev->id, ); dev_info(&pdev->dev, "device registered (irq=%d, irq_obj=%d)\n",
ndev->irq, priv->irq_obj); return ; exit_free_device:
platform_set_drvdata(pdev, NULL);
pm_runtime_disable(&pdev->dev);
exit_iounmap:
iounmap(addr);
exit_release_mem:
release_mem_region(mem->start, resource_size(mem));
exit_clk_put:
clk_put(fck);
exit_free_ndev:
free_d_can_dev(ndev);
exit:
dev_err(&pdev->dev, "probe failed\n"); return ret;
}
上一篇:Fine报表权限流程分析记录


下一篇:WPF MVVM 验证