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[0].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, 0, 0}, | }; | | 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(1); | ---------------------------------*-+ } | | | 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, 0}, | | }; | | | | static void setup_pin_mux(struct pinmux_config *pin_mux) <-----------+ | { | int i; | | for (i = 0; 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 < 0) | 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 0; | } | | 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, 0, 0); | 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, 1, 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 == 0 || !pdev_name) return ERR_PTR(-EINVAL); if (!pdata && pdata_len > 0) 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 != -1) 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 = 0; if (!pdev) return -EINVAL; if (!pdev->dev.parent) pdev->dev.parent = &platform_bus; pdev->dev.bus = &platform_bus_type; -------------------+ | if (pdev->id != -1) | dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); | else | dev_set_name(&pdev->dev, "%s", pdev->name); | | for (i = 0; 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 == 0) | return ret; | | failed: | while (--i >= 0) { | 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 1; | | /* 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) == 0); | | } | | | | 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[0]) { if (strcmp(pdev->name, id->name) == 0) { 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 = 0; 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, 0); 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, 1); dev_info(&pdev->dev, "device registered (irq=%d, irq_obj=%d)\n", ndev->irq, priv->irq_obj); return 0; 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; }