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(, , 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 ; |
} +-----------------+
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 < || 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 - ].clkrate) |
i2c_pdata[bus_id - ].clkrate = clkrate; |
|
i2c_pdata[bus_id - ].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 + ; |
|
for (status = ; len; len--, info++) { |
struct i2c_devinfo *devinfo; |
|
devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); |
if (!devinfo) { |
pr_debug("i2c-core: can't register boardinfo!\n"); |
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\n", bus_id);
oh = omap_hwmod_lookup(oh_name); ---------------------------------+
if (!oh) { |
pr_err("Could not look up %s\n", oh_name); |
return -EEXIST; |
} |
|
pdata = &i2c_pdata[bus_id - ]; |
/* |
* 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, , ); | |
WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", 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, , 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 == || !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); | |
} +--------------------------------------------+ |
V |
static int omap_early_device_register(struct platform_device *pdev) |
{ |
struct platform_device *devices[]; |
|
devices[] = pdev; |
early_platform_add_devices(devices, ); |
return ; |
} +----------------------------------------------------------+
V
int omap_device_register(struct platform_device *pdev)
{
pr_debug("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);
}
OK335xS I2C device registe hacking的更多相关文章
- OK335xS UART device registe hacking
/************************************************************************* * OK335xS UART device reg ...
- OK335xS pwm device register hacking
/************************************************************************* * OK335xS pwm device regi ...
- I.MX6 Linux I2C device& driver hacking
/******************************************************************************************* * I.MX6 ...
- OK335xS CAN device register and deiver match hacking
/************************************************************************* * OK335xS CAN device regi ...
- OK335xS GPMC nand device register hacking
/********************************************************************************* * OK335xS GPMC na ...
- I.MX6 AD7606-4 device driver registe hacking
/********************************************************************** * I.MX6 AD7606-4 device driv ...
- OK335xS LAN8710 phy driver hacking
/******************************************************************** * OK335xS LAN8710 phy driver h ...
- OK335xS davinci mdio driver hacking
/******************************************************************************* * OK335xS davinci m ...
- OK335xS psplash make-image-header.sh hacking
/***************************************************************************** * OK335xS psplash mak ...
随机推荐
- Win7下怎么设置让远程桌面连接记住密码下次登录不需再输入
远程桌面连接功能想必大家都不会陌生吧,特别是使用VPS服务器的用户们经常会用到,为了服务器的安全每次都会把密码设置的很复制,但是这样也有一个麻烦,就是每次要桌面远程连接的时候都要输入这么复杂的密码,很 ...
- 在线客服 分享 qq 一键加好友 一键入群
1.在线客服 <a href="tencent://message/?uin=qqnum&Site=&menu=yes">qq客服</a> ...
- 音视频学习系列第(五)篇---MediaRecorder的使用
音视频系列 什么是MediaRecorder MediaRecorder是安卓提供的一个用于音视频采集的类 在前几篇文章中,我们已经介绍了如何进行音频和视频的采集,即通过AudioRecord采集音频 ...
- mysql--------四种索引类型
一.索引的类型 mysql索引的四种类型:主键索引.唯一索引.普通索引和全文索引.通过给字段添加索引可以提高数据的读取速度,提高项目的并发能力和抗压能力.索引优化时mysql中的一种优化方式.索引的作 ...
- 我理解的NODE
简介:NODE不是我们想象中的后台语言,它不是一门语言,它是一个和浏览器类似的工具或者平台,在NODE平台中,可以把我们写的JS代码解析出来,而且NODE和谷歌浏览器一样都是采用V8引擎渲染解析的. ...
- C++&C#外挂(内存修改)
大学时候因为主修C#语言(当然现在做的是javaweb开发),那时在网上学了用C#做外挂的教程,外挂嘛,大家都懂的.这里只是低级的修改内存,不涉及到截获数据包.如果是欺骗服务器,修改服务器数据,那就难 ...
- 43 HTML CSS
第一部分: 1.meta 标签中:meta 标签中 <meta http-equvi = "refresh" content="2;URL= https://www ...
- Ubuntu18.04配置静态ip遇到的报错
说明: 因为很多测试环境在这个Ubuntu系统上装着,却由于虚拟服务器的重启.断电,每次Ip发生变化,就得更新环境,所以需要把该环境的ip配置成静态的,一劳永逸. 根据以往配置Ubuntu静态ip的经 ...
- poj2686 状压dp入门
状压dp第一题:很多东西没看懂,慢慢来,状压dp主要运用了位运算,二进制处理 集合{0,1,2,3,....,n-1}的子集可以用下面的方法编码成整数 像这样,一些集合运算就可以用如下的方法来操作: ...
- python-day49--前端 css-层叠样式表
1.css功能: 对html标签的渲染和布局 2.CSS 要掌握的两方面: 1.查找标签 选择器 2.操作标签 (对属性进行操作) 3.CSS 语法 CSS 规则由两个主要的部分构成:选择器,以及一 ...