/*************************************************************************
* OK335xS UART device registe hacking
* 声明:
* 1. 本文是对OK335xS Linux内核中UART设备注册代码进行跟踪;
* 2. 本人在文中采用函数调用线路图进行标记,方便阅读;
* 3. 代码跟踪的用的是vim+ctags;
*
* 2015-6-30 晴 深圳 南山平山村 曾剑锋
************************************************************************/ \\\\\\\\\\\-*- 目录 -*-/////////
| 一、板级文件:
| 二、跟踪am33xx_init_early:
| 三、跟踪am335x_evm_init:
\\\\\\\\\\\\\\\\\////////////// 一、板级文件:
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 二、跟踪am33xx_init_early:
void __init am33xx_init_early(void)
{
omap2_set_globals_am33xx();
omap3xxx_check_revision();
am33xx_check_features();
omap_common_init_early();
am33xx_voltagedomains_init();
omap44xx_prminst_init();
am33xx_powerdomains_init();
omap44xx_cminst_init();
am33xx_clockdomains_init();
am33xx_hwmod_init(); ---->--------+
omap_hwmod_init_postsetup(); |
omap3xxx_clk_init(); |
} |
|
int __init am33xx_hwmod_init(void) <---+
{
return omap_hwmod_register(am33xx_hwmods); -------------+
} | |
V |
static __initdata struct omap_hwmod *am33xx_hwmods[] = { |
...... |
/* uart class */ |
&am33xx_uart1_hwmod, ----+ |
&am33xx_uart2_hwmod, | |
&am33xx_uart3_hwmod, | |
&am33xx_uart4_hwmod, | |
&am33xx_uart5_hwmod, | |
&am33xx_uart6_hwmod, | |
...... | |
} | |
V |
static struct omap_hwmod am33xx_uart1_hwmod = { |
.name = "uart1", // 后续注册设备时会用到name |
.class = &uart_class, ->----+ |
.clkdm_name = "l4_wkup_clkdm", | |
.mpu_irqs = am33xx_uart1_irqs, -*-------+ |
.main_clk = "uart1_fck", | | |
.sdma_reqs = uart1_edma_reqs, --*-------*----------+ |
...... | | | |
}; | | | |
V | | |
static struct omap_hwmod_class uart_class = { | | |
.name = "uart", | | |
.sysc = &uart_sysc, | | |
}; | | |
| | |
/* uart1 */ V | |
static struct omap_hwmod_dma_info uart1_edma_reqs[] = { | |
{ .name = "tx", .dma_req = , }, | |
{ .name = "rx", .dma_req = , }, | |
{ .dma_req = - } +--------------+ |
}; | |
V |
static struct omap_hwmod_irq_info am33xx_uart1_irqs[] = { |
{ .irq = }, |
{ .irq = - } |
}; |
|
int __init omap_hwmod_register(struct omap_hwmod **ohs) <------+
{
int r, i; if (!ohs)
return ; i = ;
do {
r = _register(ohs[i]); ------------------------------------+
WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name, |
r); |
} while (ohs[++i]); |
|
return ; |
} |
|
static int __init _register(struct omap_hwmod *oh) <---------------------+
{
int ms_id; if (!oh || !oh->name || !oh->class || !oh->class->name ||
(oh->_state != _HWMOD_STATE_UNKNOWN))
return -EINVAL; pr_debug("omap_hwmod: %s: registering\n", oh->name); if (_lookup(oh->name))
return -EEXIST; ms_id = _find_mpu_port_index(oh);
if (!IS_ERR_VALUE(ms_id))
oh->_mpu_port_index = ms_id;
else
oh->_int_flags |= _HWMOD_NO_MPU_PORT; list_add_tail(&oh->node, &omap_hwmod_list); spin_lock_init(&oh->_lock); oh->_state = _HWMOD_STATE_REGISTERED; /*
* XXX Rather than doing a strcmp(), this should test a flag
* set in the hwmod data, inserted by the autogenerator code.
*/
if (!strcmp(oh->name, MPU_INITIATOR_NAME))
mpu_oh = oh; return ;
} 三、跟踪am335x_evm_init:
static void __init am335x_evm_init(void)
{
am33xx_cpuidle_init();
am33xx_mux_init(board_mux);
omap_serial_init(); ------------------------------------------+
am335x_evm_i2c_init(); |
omap_sdrc_init(NULL, NULL); |
usb_musb_init(&musb_board_data); |
omap_board_config = am335x_evm_config; |
omap_board_config_size = ARRAY_SIZE(am335x_evm_config); |
/* Create an alias for icss clock */ |
if (clk_add_alias("pruss", NULL, "pruss_uart_gclk", NULL)) |
pr_warn("failed to create an alias: icss_uart_gclk --> pruss\n"); |
/* Create an alias for gfx/sgx clock */ |
if (clk_add_alias("sgx_ck", NULL, "gfx_fclk", NULL)) |
pr_warn("failed to create an alias: gfx_fclk --> sgx_ck\n"); |
|
printk("zengjf test code 1.\n"); |
} |
|
void __init omap_serial_init(void) <---------------------------------+
{
omap_serial_board_init(NULL); -------+
} +-----------------+
V
void __init omap_serial_board_init(struct omap_uart_port_info *info)
{
struct omap_uart_state *uart;
struct omap_board_data bdata; list_for_each_entry(uart, &uart_list, node) {
bdata.id = uart->num; ^---------------------------------+
bdata.flags = ; |
bdata.pads = NULL; |
bdata.pads_cnt = ; |
|
if (cpu_is_omap44xx() || (cpu_is_omap34xx() && |
!cpu_is_am33xx())) |
omap_serial_fill_default_pads(&bdata); |
|
if (!info) |
omap_serial_init_port(&bdata, NULL); -------------------*---+
else | |
omap_serial_init_port(&bdata, &info[uart->num]); | |
} | |
} | |
| |
static int __init omap_serial_early_init(void) | |
{ | |
do { | |
...... | |
snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN, | |
"uart%d", num_uarts + ); | |
oh = omap_hwmod_lookup(oh_name); ----------------------+ | |
if (!oh) | | |
break; | | |
| | |
uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);| | |
if (WARN_ON(!uart)) | | |
return -ENODEV; | | |
| | |
uart->oh = oh; | | |
uart->num = num_uarts++; | | |
list_add_tail(&uart->node, &uart_list); <------*--+ |
...... | | |
} while (); | | |
| | |
return ; | | |
} // 这里很重要 | | |
core_initcall(omap_serial_early_init); <------*--+ |
| |
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
void __init omap_serial_init_port(struct omap_board_data *bdata,
struct omap_uart_port_info *info)
{
struct omap_uart_state *uart;
struct omap_hwmod *oh;
struct platform_device *pdev;
void *pdata = NULL;
u32 pdata_size = ;
char *name;
struct omap_uart_port_info omap_up; if (WARN_ON(!bdata))
return;
if (WARN_ON(bdata->id < ))
return;
if (WARN_ON(bdata->id >= num_uarts))
return; list_for_each_entry(uart, &uart_list, node)
if (bdata->id == uart->num)
break;
if (!info)
info = omap_serial_default_info; oh = uart->oh;
name = DRIVER_NAME; omap_up.dma_enabled = info->dma_enabled;
omap_up.uartclk = OMAP24XX_BASE_BAUD * ;
omap_up.flags = UPF_BOOT_AUTOCONF;
omap_up.get_context_loss_count = omap_pm_get_dev_context_loss_count;
omap_up.set_forceidle = omap_uart_set_forceidle;
omap_up.set_noidle = omap_uart_set_noidle;
omap_up.enable_wakeup = omap_uart_enable_wakeup;
omap_up.dma_rx_buf_size = info->dma_rx_buf_size;
omap_up.dma_rx_timeout = info->dma_rx_timeout;
omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
omap_up.autosuspend_timeout = info->autosuspend_timeout; /* Enable the MDR1 Errata i202 for OMAP2430/3xxx/44xx */
if (!cpu_is_omap2420() && !cpu_is_ti816x())
omap_up.errata |= UART_ERRATA_i202_MDR1_ACCESS; /* Enable DMA Mode Force Idle Errata i291 for omap34xx/3630 */
if ((cpu_is_omap34xx() || cpu_is_omap3630()) && !cpu_is_am33xx())
omap_up.errata |= UART_ERRATA_i291_DMA_FORCEIDLE; pdata = &omap_up;
pdata_size = sizeof(struct omap_uart_port_info); if (WARN_ON(!oh))
return; pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size, ------+
NULL, , false); |
WARN(IS_ERR(pdev), "Could not build omap_device for %s: %s.\n", |
name, oh->name); |
|
if ((console_uart_id == bdata->id) && no_console_suspend) |
omap_device_disable_idle_on_suspend(pdev); |
|
oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt); |
|
uart->pdev = pdev; |
|
oh->dev_attr = uart; |
|
if (((cpu_is_omap34xx() || cpu_is_omap44xx()) && bdata->pads) |
&& !uart_debug) |
device_init_wakeup(&pdev->dev, true); |
} +------------------------------------------+
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); | |
} | |
| |
| |
static int omap_early_device_register(struct platform_device *pdev) <--+ |
{ |
struct platform_device *devices[]; |
|
devices[] = pdev; |
early_platform_add_devices(devices, ); |
return ; |
} |
|
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 UART device registe hacking的更多相关文章

  1. OK335xS I2C device registe hacking

    /*************************************************************************** * OK335xS I2C device re ...

  2. OK335xS pwm device register hacking

    /************************************************************************* * OK335xS pwm device regi ...

  3. OK335xS CAN device register and deiver match hacking

    /************************************************************************* * OK335xS CAN device regi ...

  4. OK335xS GPMC nand device register hacking

    /********************************************************************************* * OK335xS GPMC na ...

  5. I.MX6 AD7606-4 device driver registe hacking

    /********************************************************************** * I.MX6 AD7606-4 device driv ...

  6. OK335xS LAN8710 phy driver hacking

    /******************************************************************** * OK335xS LAN8710 phy driver h ...

  7. OK335xS davinci mdio driver hacking

    /******************************************************************************* * OK335xS davinci m ...

  8. OK335xS psplash make-image-header.sh hacking

    /***************************************************************************** * OK335xS psplash mak ...

  9. OK335xS U-boot GPIO control hacking

    /**************************************************************************************** * OK335xS ...

随机推荐

  1. Phpstorm配置scss不生成缓存

    --no-cache 加上这个,就不会生成 .sass-cache 文件夹了.

  2. 安装gcc4.8.5

    安装gcc4.8.51. g++ --version, 4.4.7不支持c++112. 升级gcc-c++, 下载gcc    https://gcc.gnu.org/ 官网,镜像下载地址https: ...

  3. TimeZone 时区 (JS .NET JSON MYSQL) + work week 闰年

    来源参考 : http://www.cnblogs.com/qiuyi21/archive/2008/03/04/1089456.html 来源参考 : http://walkingice.blogs ...

  4. 生成全球唯一标识GUID

    有时候我们操作数据的时候需要给这些数据一些编码,而这些编码又希望永远不会重复!这个时候微软的C#给了我们一个函数,这个函数产生的编码全球唯一,永远不会重复! 方法如下: 1.C#生成方式 string ...

  5. putty xming gnome-session

    在windows里远程连接linux的最好方法. 比VNC方式好多了 1) xming启动一个窗口 2) putty 设置完X11 forwarding之后,远程登录 3) 在putty 里启动 gn ...

  6. javascript之非构造函数的继承

    这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现"继承". 今天是最后一个部分,介绍不使用构造函数实现"继承". 一.什么是 ...

  7. 2月9日 Time and Date(Ruby基础) \n 2月10日 ,使用Proc,block对象化。

    20.1Time类 ,Data类 Time.now或者Time.new:获取当前时间. 相关Method: year, month, hour, min ,sec, wday: 一周中的第几天,返回整 ...

  8. 使用与不使用@RequestBody注解的区别

    1. 如果使用@RequestBody接受页面参数: public Map<String,Object> insertBudget(@ApiParam(required = true,na ...

  9. VS2015新建项目时,左侧面板空白的解决方法

    解决办法是: 1.进入"C:\Users\当前用户名(一般为administrator)\AppData\Local\Microsoft\VisualStudio\14.0" 2. ...

  10. c#将Excel数据导入到数据库的实现代码

    这篇文章主要介绍了c#将Excel数据导入到数据库的实现代码,有需要的朋友可以参考一下 假如Excel中的数据如下: 数据库建表如下: 其中Id为自增字段: 代码: 代码如下: using Syste ...