/************************************************************
* am335x uart分析
* 本文记录am335x uart驱动的注册过程。
* 参考:
* http://www.cnblogs.com/helloworldtoyou/p/5385595.html
* 涉及文件:
* arch/arm/mach-omap2/board-am335xevm.c
* drivers/tty/serial/omap-serial.c
*
* Tony Liu, 2016-5-2, Shenzhen
***********************************************************/ 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_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); daughter_brd_detected = false;
setup_xxx_xxxx(); --+
...... |
} |
|
V
static void setup_xxx_xxxx(void)
{
/*which doesn't have Write Protect pin LAN8710A_PHY_ID */
am335x_mmc[].gpio_wp = -EINVAL; int ret; //配置引脚复用
_configure_device(EVM_SK, xxx_xxxx_dev_cfg, PROFILE_NONE); -----+
| |
} | |
V |
static void _configure_device(int evm_id, struct evm_dev_cfg *dev_cfg, |
int profile) |
{ |
int i; |
|
am335x_evm_set_id(evm_id); |
|
if (profile == PROFILE_NONE) { |
for (i = ; dev_cfg->device_init != NULL; dev_cfg++) { |
if (dev_cfg->device_on == DEV_ON_BASEBOARD) |
dev_cfg->device_init(evm_id, profile); |
else if (daughter_brd_detected == true) |
dev_cfg->device_init(evm_id, profile); |
} |
} else { |
for (i = ; dev_cfg->device_init != NULL; dev_cfg++) { |
if (dev_cfg->profile & profile) { |
if (dev_cfg->device_on == DEV_ON_BASEBOARD) |
dev_cfg->device_init(evm_id, profile); |
else if (daughter_brd_detected == true) |
dev_cfg->device_init(evm_id, profile); |
} |
} |
} |
} |
|
static struct evm_dev_cfg xxx_xxxx_dev_cfg[] = { <--------+
......
{uart0_init, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed ---+
{uart1_init, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed |
{uart4_init, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed |
...... |
{NULL, , }, |
}; |
|
static void uart0_init(int evm_id, int profile) <---+
{
setup_pin_mux(uart0_pin_mux); ------+
return; | |
} | |
V |
static void setup_pin_mux(struct pinmux_config *pin_mux) |
{ |
int i; |
|
for (i = ; pin_mux->string_name != NULL; pin_mux++) |
omap_mux_init_signal(pin_mux->string_name, pin_mux->val); |
} |
|
static struct pinmux_config uart0_pin_mux[] = { <-----+
{"uart0_rxd.uart0_rxd", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"uart0_txd.uart0_txd", OMAP_MUX_MODE0 | AM33XX_PULL_ENBL},
{"uart0_ctsn.uart0_ctsn", OMAP_MUX_MODE0 | AM33XX_PULL_ENBL},
{NULL, },
}; drivers/tty/serial/omap-serial.c
static int __init serial_omap_init(void)
{
int ret; ret = uart_register_driver(&serial_omap_reg); -------+
if (ret != ) |
return ret; |
ret = platform_driver_register(&serial_omap_driver); --+ |
if (ret != ) | |
uart_unregister_driver(&serial_omap_reg); | |
return ret; | |
} | |
| |
static struct uart_driver serial_omap_reg = { | |
.owner = THIS_MODULE, | |
.driver_name = "OMAP-SERIAL", | |
.dev_name = OMAP_SERIAL_NAME, | |
.nr = OMAP_MAX_HSUART_PORTS, | |
.cons = OMAP_CONSOLE, | |
}; | |
| |
#define OMAP_SERIAL_NAME "ttyO" | |
#define OMAP_MAX_HSUART_PORTS 6 | |
| |
#define OMAP_CONSOLE (&serial_omap_console) | |
| |
static struct console serial_omap_console = { | <------+
.name = OMAP_SERIAL_NAME, |
.write = serial_omap_console_write, |
.device = uart_console_device, |
.setup = serial_omap_console_setup, |
.flags = CON_PRINTBUFFER, |
.index = -, |
.data = &serial_omap_reg, |
}; |
|
static struct platform_driver serial_omap_driver = { <--+
.probe = serial_omap_probe,
.remove = serial_omap_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
.of_match_table = of_match_ptr(omap_serial_of_match),
},
}; static int serial_omap_probe(struct platform_device *pdev)
{
struct uart_omap_port *up;
struct resource *mem, *irq, *dma_tx, *dma_rx;
struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
int ret = -ENOSPC; if (pdev->dev.of_node)
omap_up_info = of_get_uart_port_info(&pdev->dev); ......
up->pdev = pdev;
up->port.dev = &pdev->dev;
up->port.type = PORT_OMAP;
up->port.iotype = UPIO_MEM;
up->port.irq = irq->start; up->port.regshift = ;
up->port.fifosize = ;
up->port.ops = &serial_omap_pops; --------+
|
if (pdev->dev.of_node) |
up->port.line = of_alias_get_id(pdev->dev.of_node, "serial"); |
else |
up->port.line = pdev->id; |
|
if (up->port.line < ) { |
dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n", |
up->port.line); |
ret = -ENODEV; |
goto err; |
} |
|
sprintf(up->name, "OMAP UART%d", up->port.line); |
up->port.mapbase = mem->start; |
up->port.membase = ioremap(mem->start, resource_size(mem)); |
if (!up->port.membase) { |
dev_err(&pdev->dev, "can't ioremap UART\n"); |
ret = -ENOMEM; |
goto err; |
} |
|
up->port.flags = omap_up_info->flags; |
up->port.uartclk = omap_up_info->uartclk; |
if (!up->port.uartclk) { |
up->port.uartclk = DEFAULT_CLK_SPEED; |
dev_warn(&pdev->dev, "No clock speed specified: using default:" |
"%d\n", DEFAULT_CLK_SPEED); |
} |
up->uart_dma.uart_base = mem->start; |
up->errata = omap_up_info->errata; |
|
if (omap_up_info->dma_enabled) { |
up->uart_dma.uart_dma_tx = dma_tx->start; |
up->uart_dma.uart_dma_rx = dma_rx->start; |
up->use_dma = ; |
up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size; |
up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout; |
up->uart_dma.rx_poll_rate = omap_up_info->dma_rx_poll_rate; |
spin_lock_init(&(up->uart_dma.tx_lock)); |
spin_lock_init(&(up->uart_dma.rx_lock)); |
up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; |
up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; |
} |
|
up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; |
up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; |
pm_qos_add_request(&up->pm_qos_request, |
PM_QOS_CPU_DMA_LATENCY, up->latency); |
serial_omap_uart_wq = create_singlethread_workqueue(up->name); |
INIT_WORK(&up->qos_work, serial_omap_uart_qos_work); |
|
pm_runtime_use_autosuspend(&pdev->dev); |
pm_runtime_set_autosuspend_delay(&pdev->dev, |
omap_up_info->autosuspend_timeout); |
|
pm_runtime_irq_safe(&pdev->dev); |
pm_runtime_enable(&pdev->dev); |
pm_runtime_get_sync(&pdev->dev); |
|
ui[up->port.line] = up; |
serial_omap_add_console_port(up); |
|
ret = uart_add_one_port(&serial_omap_reg, &up->port); --------------+ |
if (ret != ) | |
goto do_release_region; | |
| |
pm_runtime_put(&pdev->dev); | |
platform_set_drvdata(pdev, up); | |
return ; | |
err: | |
dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", | |
pdev->id, __func__, ret); | |
do_release_region: | |
release_mem_region(mem->start, resource_size(mem)); | |
return ret; | |
} | |
| |
static struct uart_ops serial_omap_pops = { <--------|--+
.tx_empty = serial_omap_tx_empty, |
.set_mctrl = serial_omap_set_mctrl, |
.get_mctrl = serial_omap_get_mctrl, |
.stop_tx = serial_omap_stop_tx, |
.start_tx = serial_omap_start_tx, |
.stop_rx = serial_omap_stop_rx, |
.enable_ms = serial_omap_enable_ms, |
.break_ctl = serial_omap_break_ctl, |
.startup = serial_omap_startup, |
.shutdown = serial_omap_shutdown, |
.set_termios = serial_omap_set_termios, |
.pm = serial_omap_pm, |
.type = serial_omap_type, |
.release_port = serial_omap_release_port, |
.request_port = serial_omap_request_port, |
.config_port = serial_omap_config_port, |
.verify_port = serial_omap_verify_port, |
#ifdef CONFIG_CONSOLE_POLL |
.poll_put_char = serial_omap_poll_put_char, |
.poll_get_char = serial_omap_poll_get_char, |
#endif |
}; |
|
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) <-+
{
struct uart_state *state;
struct tty_port *port;
int ret = ;
struct device *tty_dev; BUG_ON(in_interrupt()); if (uport->line >= drv->nr)
return -EINVAL; state = drv->state + uport->line;
port = &state->port; mutex_lock(&port_mutex);
mutex_lock(&port->mutex);
if (state->uart_port) {
ret = -EINVAL;
goto out;
} state->uart_port = uport;
state->pm_state = -; uport->cons = drv->cons;
uport->state = state; /*
* If this port is a console, then the spinlock is already
* initialised.
*/
if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
spin_lock_init(&uport->lock);
lockdep_set_class(&uport->lock, &port_lock_key);
} uart_configure_port(drv, state, uport); /*
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); -----+
if (likely(!IS_ERR(tty_dev))) { |
device_init_wakeup(tty_dev, ); |
device_set_wakeup_enable(tty_dev, ); |
} else |
printk(KERN_ERR "Cannot register tty device on line %d\n", |
uport->line); |
|
/* |
* Ensure UPF_DEAD is not set. |
*/ |
uport->flags &= ~UPF_DEAD; |
|
out: |
mutex_unlock(&port->mutex); |
mutex_unlock(&port_mutex); |
|
return ret; |
} |
|
struct device *tty_register_device(struct tty_driver *driver, unsigned index, <---+
struct device *device)
{
char name[];
dev_t dev = MKDEV(driver->major, driver->minor_start) + index; if (index >= driver->num) {
printk(KERN_ERR "Attempt to register invalid tty line number "
" (%d).\n", index);
return ERR_PTR(-EINVAL);
} if (driver->type == TTY_DRIVER_TYPE_PTY)
pty_line_name(driver, index, name);
else
tty_line_name(driver, index, name); ---+
|
return device_create(tty_class, device, dev, NULL, name); |
} |
// 设备名 |
static void tty_line_name(struct tty_driver *driver, int index, char *p) <--+
{
sprintf(p, "%s%d", driver->name, index + driver->name_base);
}

am335x uart分析的更多相关文章

  1. am335x i2c分析

    /***************************************************************************** * am335x i2c分析 * i2c驱 ...

  2. z-stack协议uart分析(DMA)

    1.从ZMain里面的main函数开始分析 2.进入int main( void ); HalDriverInit();   //硬件相关初始化,有DMA初始化和UART初始化 3.进入HalDriv ...

  3. am335x gpio分析

    /************************************************************************ * am335x_gpio * 本文主要记录am33 ...

  4. imx6 uart分析

    本文主要记录: 1.uart设备注册 2.uart驱动注册 3.上层应用调用有些地方理解的还不是很透彻,希望指正. 1.uart设备注册过程 MACHINE_START(MX6Q_SABRESD, & ...

  5. AM335X UBOOT(以UART为例分析UBOOT主要流程)

    UBOOT2016.05 UART初始化及设置 SPL阶段 第一部分C函数 |- s_init //(arch/arm/cpu/armv7/am33xx/board.c) |- set_uart_mu ...

  6. am335x uboot启动流程分析

    基本指令含义 .globl _start .globl指示告诉汇编器,_start这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号 b,bl b是不带返回的跳转  bl带返回的跳 ...

  7. [tty与uart]3.tty驱动分析

    转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tt ...

  8. [uart]3.tty驱动分析

    转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tt ...

  9. am335x omap serial 驱动分析

    am335x 自身的 uart 驱动集成在 kernel 的 arch/arm/mach-omap2/ 里面. 文件是 arch/arm/mach-omap2/serial.c // 看到最底部 om ...

随机推荐

  1. codeforces#254DIV2解题报告

    今天简直大爆发啊... 吃了顿烧烤竟然这么管事. . . .. 本弱渣竟然做出来了3道,并且B题是我第一次在CF中用到算法..(曾经最多也就是贪心. . . ). 题目地址:codeforces#22 ...

  2. C++拷贝函数的小结,关于变量的作用域等---ShinePans

    #include <iostream> using namespace std; class circle { private: double r0; public: circle(dou ...

  3. WinForm开发,窗体显示和窗体传值相关知识总结

    主窗体中代码: public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void b ...

  4. cocos2dx CallFunc注意事项

     CCDelayTime*delay=CCDelayTime::create(2); auto act = CallFunc::create([=](){   //func body ...  }); ...

  5. POI导出

    public void export(){try {String columns = getPara("nameArray");List<Record> list = ...

  6. 《Effective Java》读书笔记五(枚举和注解)

    No30 用enum代替int常量 一:综述 int枚举模式,示范: // The int enum pattern - severely deficient! public static final ...

  7. Oracle学习笔记之五,Oracle 11g的PL/SQL入门

    1. PL/SQL概述 PL/SQL(Procedural Language/SQL)是Oracle的专用语言,是对标准SQL语言的扩展,它允许在其内部嵌套普通的SQL语句,还可以定义变量和常量,允许 ...

  8. [na]pc加入域认证细节

    这也是以前好奇,因为学生时候,经常机房上网, 对一些譬如.. 现在看来很low了. 是小作坊式的技术, 真正上不了台面的.扛不住生产的压力. ftp共享 计算机统一管理等 无盘/网克等特别好奇 计算机 ...

  9. Centos7安装TensorFlow

    TensorFlow也火了一段时间,想想既然要研究NLP.为什么不好好应用一下Google开源的Deep Learning平台呢,一切还是先从搭建好开发环境開始. 非常多大神们也做了这方面的工作.汲取 ...

  10. #pragma GCC system_header用法

    在看公司公共库的头文件中发现了:#pragma GCC system_header一行,以前没有见过这种用法,在网上查了一下,解释如下: 从#pragma GCC system_header直到文件结 ...