• OK335xS I2C device registe hacking


    /***************************************************************************
     *                 OK335xS I2C device registe hacking
     *  声明:
     *     1. 本文是对OK335xS Linux内核中I2C设备注册代码进行跟踪;
     *     2. 本人在文中采用函数调用线路图进行标记,方便阅读;
     *     3. 代码跟踪的用的是vim+ctags;
     *                                    2015-7-1 晴 深圳 南山平山村 曾剑锋
     **************************************************************************/
    
    
    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                                             |
                                                            |
    static void __init am335x_evm_init(void)   <------------+
    {                                                       
        ......                                              
        am33xx_mux_init(board_mux); --+ 
        omap_serial_init();           |
        am335x_evm_i2c_init();  ------*--------------------------------------+
        ......                        |                                      |
    }                                 |                                      |
                                      V                                      |
    static struct omap_board_mux board_mux[] __initdata = {                  |
        AM33XX_MUX(XDMA_EVENT_INTR0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT),--+ |
        AM33XX_MUX(I2C0_SDA, OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW |       | |
                AM33XX_INPUT_EN | AM33XX_PIN_OUTPUT),                      | |
        AM33XX_MUX(I2C0_SCL, OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW |       | |
                AM33XX_INPUT_EN | AM33XX_PIN_OUTPUT),                      | |
        { .reg_offset = OMAP_MUX_TERMINATOR },                             | |
    };            +--------------------------------------------------------+ |
                  V                                                          |
    #define AM33XX_MUX(mode0, mux_value)                                    |
    {                                                                       |
        // 若果mode0 = I2C0_SDA;                                            |
        // AM33XX_CONTROL_PADCONF_I2C0_SDA_OFFSET    ----------------------+ |
        .reg_offset = (AM33XX_CONTROL_PADCONF_##mode0##_OFFSET),          | |
        .value      = (((mux_value) & AM33XX_INPUT_EN) ? (mux_value)      | |
                    : ((mux_value) | AM33XX_PULL_DISA)),                  | |
    }                                                                      | |
                                                                           | |
    /**                                                                    | |
     * 参考文档:AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical     | |
     *    Reference Manual (Rev. H).pdf                                    | |
     * 参考文档:Sitara AM335x ARM Cortex-A8 Microprocessors (MPUs)        | |
     *    (Rev. F).pdf                                                     | |
     *  ------------------------------------------------------------------ | |
     *  | Offset | Acronym       | Register Description | Section        | | |
     *  +--------+---------------+----------------------|----------------+ | |
     *  | 988h   | conf_i2c0_sda |                      | Section 9.3.51 | | |
     */ ------------------------------------------------------------------ | |
    #define AM33XX_CONTROL_PADCONF_I2C0_SDA_OFFSET          0x0988   <-----+ |
                                                                             |
    static void __init am335x_evm_i2c_init(void)                <------------+
    {                                                            
        /* Initially assume General Purpose EVM Config */
        am335x_evm_id = GEN_PURP_EVM;
    
        evm_init_cpld();                         --------------+
                                                               |
        setup_pin_mux(pmic_irq_pin_mux);                       |
        omap_register_i2c_bus(1, 100, am335x_i2c0_boardinfo, --*--------+
                    ARRAY_SIZE(am335x_i2c0_boardinfo));        |        |
    }                                                          |        |
                                                               |        |
    static void evm_init_cpld(void)            <---------------+        |
    {                                                                   |
        i2c_add_driver(&cpld_reg_driver);                               |
    }                              |                                    |
                                   V                                    |
    static struct i2c_driver cpld_reg_driver = {                        |
        .driver = {                                                     |
            .name   = "cpld_reg",                                       |
        },                                                              |
        .probe      = cpld_reg_probe,    ---+                           |
        .remove     = cpld_reg_remove,      |                           |
        .id_table   = cpld_reg_id,          |                           |
    };                +---------------------+                           |
                      V                                                 |
    static int cpld_reg_probe(struct i2c_client *client,                |
            const struct i2c_device_id *id)                             |
    {                                                                   |
        cpld_client = client;                                           |
        return 0;                                                       |
    }                                                 +-----------------+
                                                      V                 |
    static struct i2c_board_info __initdata am335x_i2c0_boardinfo[] = { |
        {                                                               |
            /* Daughter Board EEPROM */                                 |
            I2C_BOARD_INFO("24c256", DAUG_BOARD_I2C_ADDR),              |
            .platform_data  = &am335x_daughter_board_eeprom_info,       |
        },                                                              |
        {                                                               |
            /* Baseboard board EEPROM */                                |
            I2C_BOARD_INFO("24c256", BASEBOARD_I2C_ADDR),               |
            .platform_data  = &am335x_baseboard_eeprom_info,            |
        },                                                              |
        {                                                               |
            I2C_BOARD_INFO("cpld_reg", 0x35),                           |
        },                                                              |
        {                                                               |
            I2C_BOARD_INFO("tlc59108", 0x40),                           |
        },                                                              |
        {                                                               |
            I2C_BOARD_INFO("tps65910", TPS65910_I2C_ID1),               |
            .platform_data  = &am335x_tps65910_info,                    |
        },                                                              |
        {                                                               |
            I2C_BOARD_INFO("tlv320aic3x", 0x1b),                        |
        },                                                              |
    };                    +---------------------------------------------+
                          V
    int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
                  struct i2c_board_info const *info,
                  unsigned len)
    {                
        int err;
    
        BUG_ON(bus_id < 1 || bus_id > omap_i2c_nr_ports());
    
        if (info) { 
            err = i2c_register_board_info(bus_id, info, len);    ---+
            if (err)                                                |
                return err;                                         |
        }                                                           |
                                                                    |
        if (!i2c_pdata[bus_id - 1].clkrate)                         |
            i2c_pdata[bus_id - 1].clkrate = clkrate;                |
                                                                    |
        i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;   |
                                                                    |
        return omap_i2c_add_bus(bus_id);        --------------------*----------+
    }                       +---------------------------------------+          |
                            V                                                  |
    int __init i2c_register_board_info(int busnum,                             |
        struct i2c_board_info const *info, unsigned len)                       |
    {                                                                          |
        int status;                                                            |
                                                                               |
        down_write(&__i2c_board_lock);                                         |
                                                                               |
        /* dynamic bus numbers will be assigned after the last static one */   |
        if (busnum >= __i2c_first_dynamic_bus_num)                             |
            __i2c_first_dynamic_bus_num = busnum + 1;                          |
                                                                               |
        for (status = 0; len; len--, info++) {                                 |
            struct i2c_devinfo  *devinfo;                                      |
                                                                               |
            devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);                   |
            if (!devinfo) {                                                    |
                pr_debug("i2c-core: can't register boardinfo!
    ");             |
                status = -ENOMEM;                                              |
                break;                                                         |
            }                                                                  |
                                                                               |
            devinfo->busnum = busnum;                                          |
            devinfo->board_info = *info;                                       |
            list_add_tail(&devinfo->list, &__i2c_board_list);                  |
        }                                                                      |
                                                                               |
        up_write(&__i2c_board_lock);                                           |
                                                                               |
        return status;                                                         |
    }                                                                          |
                                                                               |
    static int __init omap_i2c_add_bus(int bus_id)          <------------------+
    {       
        if (cpu_class_is_omap1())
            return omap1_i2c_add_bus(bus_id);
        else    
            return omap2_i2c_add_bus(bus_id);      ----------+
    }                                                        |
                                                             |
    static inline int omap2_i2c_add_bus(int bus_id)   <------+
    {
        int l;
        struct omap_hwmod *oh;
        struct platform_device *pdev;
        char oh_name[MAX_OMAP_I2C_HWMOD_NAME_LEN];
        struct omap_i2c_bus_platform_data *pdata;
        struct omap_i2c_dev_attr *dev_attr;
    
        if (!cpu_is_am33xx())
            omap2_i2c_mux_pins(bus_id);
    
        l = snprintf(oh_name, MAX_OMAP_I2C_HWMOD_NAME_LEN, "i2c%d", bus_id);
        WARN(l >= MAX_OMAP_I2C_HWMOD_NAME_LEN,
            "String buffer overflow in I2C%d device setup
    ", bus_id);
        oh = omap_hwmod_lookup(oh_name);      ---------------------------------+
        if (!oh) {                                                             |
                pr_err("Could not look up %s
    ", oh_name);                     |
                return -EEXIST;                                                |
        }                                                                      |
                                                                               |
        pdata = &i2c_pdata[bus_id - 1];                                        |
        /*                                                                     |
         * pass the hwmod class's CPU-specific knowledge of I2C IP revision in |
         * use, and functionality implementation flags, up to the OMAP I2C     |
         * driver via platform data                                            |
         */                                                                    |
        pdata->rev = oh->class->rev;                                           |
                                                                               |
        dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;                   |
        pdata->flags = dev_attr->flags;                                        |
                                                                               |
        /*                                                                     |
         * When waiting for completion of a i2c transfer, we need to           |
         * set a wake up latency constraint for the MPU. This is to            |
         * ensure quick enough wakeup from idle, when transfer                 |
         * completes.                                                          |
         * Only omap3 has support for constraints                              |
         */                                                                    |
        if (cpu_is_omap34xx())                                                 |
            pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;   |
                                                                               |
        pdata->device_reset = omap_device_reset;                               |
        pdev = omap_device_build(name, bus_id, oh, pdata,          ---------+  |
                sizeof(struct omap_i2c_bus_platform_data),                  |  |
                NULL, 0, 0);                                                |  |
        WARN(IS_ERR(pdev), "Could not build omap_device for %s
    ", name);   |  |
                                                                            |  |
        return PTR_RET(pdev);                                               |  |
    }                          +--------------------------------------------*--+
                               V                                            |
    struct omap_hwmod *omap_hwmod_lookup(const char *name)                  |
    {                                                                       |
        struct omap_hwmod *oh;                                              |
                                                                            |
        if (!name)                                                          |
            return NULL;                                                    |
                                                                            |
        oh = _lookup(name); -----+                                          |
                                 |                                          |
        return oh;               |                                          |
    }                            |                                          |
                                 V                                          |
    static struct omap_hwmod *_lookup(const char *name)                     |
    {                                                                       |
        struct omap_hwmod *oh, *temp_oh;                                    |
                                                                            |
        oh = NULL;                                                          |
                                                                            |
        list_for_each_entry(temp_oh, &omap_hwmod_list, node) {              |
            if (!strcmp(name, temp_oh->name)) {                             |
                oh = temp_oh;                                               |
                break;                                                      |
            }                                                               |
        }                           +---------------------------------------+
                                    |
        return oh;                  |
    }                               |
                                    V
    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);                                  |
    }                                  +-----------------------------------+
                                       V
    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)
    ", pdev_name, ret);   |  |
                                                                          |  |
        return ERR_PTR(ret);                                              |  |
    }                        +--------------------------------------------+  |
                             V                                               |
    static int omap_early_device_register(struct platform_device *pdev)      |
    {                                                                        |
        struct platform_device *devices[1];                                  |
                                                                             |
        devices[0] = pdev;                                                   |
        early_platform_add_devices(devices, 1);                              |
        return 0;                                                            |
    }             +----------------------------------------------------------+
                  V
    int omap_device_register(struct platform_device *pdev)
    {
        pr_debug("omap_device: %s: registering
    ", pdev->name);
    
        pdev->dev.parent = &omap_device_parent;
        pdev->dev.pm_domain = &omap_device_pm_domain;
        return platform_device_add(pdev);
    }
  • 相关阅读:
    光流法简单介绍
    learn something
    MOT
    jupyter notebook 启动出错
    SSD用测试集得到具体的检测结果
    百练_2677 肿瘤检测
    百练_2707 求一元二次方程的根
    百练_4022 买房子
    HDU2035 人见人爱A^B(快速幂)
    BestCoder Round #85 sum
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/4613343.html
Copyright © 2020-2023  润新知