天天看點

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

一、驅動挂載與解除安裝

加載子產品之後,檢視完整的系統日志:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

1. 子產品加載與解除安裝

WK2124使用spi總線通信,是以在子產品加載的時候向核心注冊spi驅動。

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

2. 驅動挂載與解除安裝

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

可以看到spi驅動相容性是"wkmic,wk2124spi",驅動挂載函數probe,解除安裝函數remove。Linux 5.4核心中spi驅動架構沒有resume,是以注釋resume函數實作:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

3. SPI讀寫函數

以 wk2xxx_read_global_reg 為例,基于SPI驅動架構,實作如下:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

二、probe函數略讀

1. 測試SPI通信是否正常

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

對應日志為,能讀到寄存器資料,說明SPI通信正常:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

2. 解析中斷引腳

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

函數實作如下,傳回irq編号:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

對應日志為:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

3. 注冊uart驅動

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

uart_drriver實作為wk2xxx_uart_driver,使用​

​uart_register_driver​

​ API注冊進核心,後面進行剖析。

4. 注冊uart端口

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

uart端口使用 ​

​uart_add_one_port​

​ 注冊進核心,這些端口的操作函數集為wk2xxx_pops,後面進行剖析。

三、uart驅動架構實作

關于Linux驅動架構,參考文章:​​i.MX6ULL驅動開發 | 15 - Linux UART 驅動架構​​。

1. uart_driver結構體實作

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

需要注意,dev_name 将會是後續注冊的裝置節點名稱,每個注冊的uart端口都會對應一個節點,名稱為ttysWKx。

2. uart_port_ops實作

注冊uart_port的時候,最重要的是端口的操作函數集,也就是 uart_ops 成員中的函數,Linux核心最終調用的都是其中的函數。

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

其實整個驅動的目的就是實作這些函數,但沒有逐個分析的必要,主要看一下序列槽發送流程和序列槽接收流程。

四、設定序列槽波特率流程

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

1. enable_ms

enable_ms用于啟用modem狀态中斷:

enable_ms(port)
  Enable the modem status interrupts.
  
  This method may be called multiple times.  Modem status
  interrupts should be disabled when the shutdown      

wk2124沒有對應的控制線,是以實作為空:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

2. set_termios

set_termios用于設定序列槽屬性,比如更改波特率。

對于波特率是經過了轉碼的:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

而且驅動中最大支援到230400,這點在使用者态設定的時候需要注意:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

在所有設定參數都準備好之後,調用該函數設定到WK2124中每個子序列槽對應的寄存器中:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

其中設定寄存器的代碼如下:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

WK2124寄存器如下:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析
RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

五、序列槽發送資料流程

printk級别要改為 7 4 1 7
RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

1. enable_ms

2. set_termios

3. start_tx(重點)

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

其中的核心是 workqueue 機制,将發送的内容使用queue_work送出到工作隊列中:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析
RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

工作隊列實際的處理函數為wk2xxx_work,在其中實際操作wk2124寄存器去完成資料的發送,如下:

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

六、序列槽接收資料

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

1. enable_ms

2. set_termios

3. irq中斷函數

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析

4. wk2xxxirq_app

在接收流程的work處理函數wk2xxx_work中,主要調用 wk2xxxirq_app 函數,其中完成一系列與WK2124晶片的操作。

(1)讀取GIFR寄存器

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析
wk2xxx_read_global_reg(s->spi_wk,WK2XXX_GIFR ,dat);
gifr = dat[0];      

讀取之後判斷子序列槽是否确實發生了中斷,如果沒有發生則直接return。

(2)讀取子序列槽SIFR寄存器

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析
RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析
wk2xxx_read_slave_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,dat);
sifr = dat[0];      

(3)讀取子序列槽SIER寄存器

RK3399驅動開發 | 04 - WK2124序列槽晶片驅動淺析
wk2xxx_read_slave_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,dat);
sier = dat[0];      

5. wk2xxx_rx_chars

wk2xxx_read_slave_reg(s->spi_wk,s->port.iobase,WK2XXX_FDAT,dat);
ch = (int)dat[0];      

繼續閱讀