am335x omap serial 驱动分析

  • am335x 自身的 uart 驱动集成在 kernel 的 arch/arm/mach-omap2/ 里面。

  • 文件是 arch/arm/mach-omap2/serial.c

    // 看到最底部 omap_serial_init  入口函数。
    void __init omap_serial_init(void)     
    {                                                 
        omap_serial_board_init(NULL);   // ---> 1.0
    }                  
  • 1.0 omap_serial_board_init

    void __init omap_serial_board_init(struct omap_uart_port_info *info)            
    {               
        struct omap_uart_state *uart;     // ---> 1.1
        struct omap_board_data bdata;     // ---> 1.1
        // 这里是轮询所有 uart ,并配置基本的属性一下
        // 在这里,我们主要要弄懂 uart_list 是怎么来的,在哪里被初始化
        list_for_each_entry(uart, &uart_list, node) {           
            bdata.id = uart->num;     
            bdata.flags = 0;   
            bdata.pads = NULL;  
            bdata.pads_cnt = 0;   
                             
            if (cpu_is_omap44xx() || (cpu_is_omap34xx() &&     
                                !cpu_is_am33xx()))  
                omap_serial_fill_default_pads(&bdata);  
                
            if (!info)  
                omap_serial_init_port(&bdata, NULL);   // ---> 2.0
            else        
                omap_serial_init_port(&bdata, &info[uart->num]);  
        }    
    }     
  • 1.1 struct omap_uart_state 和 struct omap_board_data

    //  arch/arm/mach-omap2/serial.c
    //  
    struct omap_uart_state {    
        int num;  
        int can_sleep;  
   
        struct list_head node;  
        struct omap_hwmod *oh;  
        struct platform_device *pdev;     
    }; 
    
    //  arch/arm/mach-omap2/mux.h   
    //  struct omap_board_data - board specific device data 
    struct omap_board_data { 
        int         id;   
        u32         flags;   
        struct omap_device_pad  *pads;    
        int         pads_cnt;        
    };   
  • 2.0 omap_serial_init_port

    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 = 0;                                                         
        char *name;                                                                 
        struct omap_uart_port_info omap_up;                                         
                                                                                
        if (WARN_ON(!bdata))                                                        
            return;                                                                 
        if (WARN_ON(bdata->id < 0))                                                 
            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 * 16;                                  
        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, 0, false);                                               
        WARN(IS_ERR(pdev), "Could not build omap_device for %s: %s.
",             
             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);                                   
    }                                                                               
原文地址:https://www.cnblogs.com/chenfulin5/p/7081287.html