且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

OK335xS CAN device register and deiver match hacking

更新时间:2022-08-12 20:28:31

/*************************************************************************
 *        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;
}