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 ...
随机推荐
- 部署showdoc
1.下载 https://github.com/star7th/showdoc 2.解压 sudo tar -zvxf ~/showdoc-2.4.5.tar.gz -C /home/wwwroot/ ...
- ActivityGroup实现tab功能
android.app包中含有一个ActivityGroup类,该类是Activity的容器,可以包含多个嵌套进来的 Activitys,这篇文章就是借助ActivityGroup可以嵌套Activi ...
- The Front-End Checklist
做个记录,摘自Front-End Performance Checklist HTML Minified HTML: The HTML code is minified, comments, whit ...
- 一个纯净的webpack4+angular5脚手架
该篇主要是结合刚发布不久的webpack4,搭建一个非cli的angular5的脚手架demo,主要分为以下几个方面阐述下脚手架结构: # 脚手架基础架构(根据angular5的新规范) /** * ...
- OpenGL入门程序一:绘制简单的矩形
#include <GL/glut.h> void MyDisplay(void); int main(int argc, char **argv) { //设置窗口的大小 glutIni ...
- Java基础八--构造函数
Java基础八--构造函数 一.子父类中构造函数的特点 1.1 为什么在子类构造对象时,发现,访问子类构造函数时,父类也运行了呢? 原因是:在子类的构造函数中第一行有一个默认的隐式语句. super( ...
- 微信小程序自定义模态框(字体图标)
组件已经传到github,自行下载:https://github.com/JinZhenZon/miniapp-customModel 支持如下配置: { outWidth <number&g ...
- LeetCode 22. Generate Parentheses(构造)
题目大意:给n个'(' 和 ')',构造出所有的长度为2*n并且有效的(可匹配的)字符串. 题目分析:这道题不难,可以直接搜索出所有可能的字符串,然后再逐一判断是否合法即可.但是还有更好的办法,实际上 ...
- ORA-14452:试图创建,更改或删除正在使用的临时表中的索引
因为表kol_xx_fin050_temp 为临时表,而且有其他session正在使用. select vs.* from v$session vs , v$lock vl , dba_objects ...
- zuul网关源码解析
zuul网关源码解析 zuul请求的生命周期 ZuulServlet ZuulServlet定义了对zuul整个过程的处理,如下: public void service(javax.servlet. ...