zoukankan      html  css  js  c++  java
  • am335x uart分析

    /************************************************************
     *                  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[0].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 = 0; 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 = 0; 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, 0, 0},                                              |
    };                                                             |
                                                                   |
    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 = 0; 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, 0},
    };
    
    
    drivers/tty/serial/omap-serial.c
    static int __init serial_omap_init(void)
    {
        int ret;
    
        ret = uart_register_driver(&serial_omap_reg);              -------+
        if (ret != 0)                                                     |
            return ret;                                                   |
        ret = platform_driver_register(&serial_omap_driver);  --+         |
        if (ret != 0)                                           |         |
            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        = -1,                                     |
        .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 = 2;
        up->port.fifosize = 64;
        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 < 0) {                                                 |
            dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d
    ",       |
                                    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
    ");                         |
            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
    ", 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 = 1;                                                     |
            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 != 0)                                                         |  |
            goto do_release_region;                                           |  |
                                                                              |  |
        pm_runtime_put(&pdev->dev);                                           |  |
        platform_set_drvdata(pdev, up);                                       |  |
        return 0;                                                             |  |
    err:                                                                      |  |
        dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d
    ",                   |  |
                    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 = 0;
        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 = -1;
    
        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, 1);                                               |
            device_set_wakeup_enable(tty_dev, 0);                                         |
        } else                                                                            |
            printk(KERN_ERR "Cannot register tty device on line %d
    ",                    |
                   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[64];
        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).
    ", 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);
    }
  • 相关阅读:
    leetcode——33.搜索旋转排序数组
    leetcode——80.删除排序数组中的重复项2
    leetcode——26.删除排序数组中的重复项
    leetcode——18.四数之和
    leetcode——42.接雨水
    leetcode——11.盛最多水的容器
    leetcode——16.最接近的三数之和
    leetcode——15.三数之和
    leetcode——1002.查找常用字符
    004 linux学习:【第4篇】之nginx
  • 原文地址:https://www.cnblogs.com/helloworldtoyou/p/5452416.html
Copyright © 2011-2022 走看看