【調(diào)試筆記】韋東山:在100ask_imx6ull上移植內(nèi)核驅(qū)動使用六軸傳感器ICM20608

上次發(fā)了LCD調(diào)試筆記,大家很感興趣,所以這次再來一篇:六軸傳感器ICM20608驅(qū)動移植筆記,大家還需要什么移植筆記?可以留言。我們盡量滿足。

作者:韋東山
移植思路:
先找到驅(qū)動:也許內(nèi)核里已經(jīng)有,也許需要去網(wǎng)上查找。
打開http://bing.com,搜“ICM20608 linux driver”,發(fā)現(xiàn)這個網(wǎng)址:
https://github.com/torvalds/linux/blob/master/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
大膽假設(shè),在linux內(nèi)核中應(yīng)該也有驅(qū)動,找到:
$ cd? drivers/iio/imu/inv_mpu6050
$ grep "20608" * -nr
果然找到一堆驅(qū)動,比如:
inv_mpu_i2c.c:173:????? {"icm20608", INV_ICM20608},
inv_mpu_iio.h:75:?????? INV_ICM20608,
inv_mpu_iio.h:232:#define INV_ICM20608_WHOAMI_VALUE???????????? 0xAF
inv_mpu_spi.c:85:?????? {"icm20608", INV_ICM20608},
100ASK_IMX6ULL上使用SPI接口連接ICM20608,所以我們要找的驅(qū)動就是inv_mpu_spi.c。
這樣事情就好辦了。
接下來就是配置設(shè)備樹,
最后測試。
1.1 SPI驅(qū)動程序框架
我們需要弄清楚SPI驅(qū)動程序的結(jié)構(gòu),才能夠理解驅(qū)動程序,添加設(shè)備樹信息。
特別是對于ICM20608,在內(nèi)核的設(shè)備樹文檔Documentation/devicetree/bindings目錄下,找不到任何有用的信息。
那我們只能看源碼了,看源碼之前先弄清結(jié)構(gòu)。

我們需要閱讀源碼來確定設(shè)備樹的上述4點內(nèi)容。
1.2 ICM20608設(shè)備樹
100ASK_IMX6ULL開發(fā)板上,ICM20608接在哪一個SPI控制器上?

如上圖,接在ECSPI3這個SPI控制器上。
打開設(shè)備樹文件arch/arm/boot/dts/100ask_imx6ull-14x14.dts,可以看到如下代碼:
&ecspi3 {
??????? pinctrl-names = "default";
??????? pinctrl-0 = <&pinctrl_ecspi3>;
??????? cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
??????? status = "okay";
??????? spidev: icm20608@0{
??????????????? compatible = "invensense,icm20608";
??????????????? interrupt-parent = <&gpio1>;
??????????????? interrupts = <1 1>;
??????????????? spi-max-frequency = <8000000>;
??????????????? reg = <0>;
??????? };
};
這是我們同事寫出來的,具體過程就省略掉,看著挺簡單,寫的時候花了不少時間。
我們來研究一下,它位于ecspi3節(jié)點之下,ecspi3節(jié)點肯定就是SPI控制器之一。要找到它的compatible屬性,才能找到SPI控制器的驅(qū)動程序。
打開 imx6ull.dtsi,果然有:

把ecspi3節(jié)點和ICM20608節(jié)點合并起來,內(nèi)容如下:

1.3 SPI控制器驅(qū)動程序
1.3.1 找到驅(qū)動程序
根據(jù)上述設(shè)備樹信息,在Linux內(nèi)核源碼目錄下搜"fsl,imx6ul-ecspi",就可以找到SPI控制器的驅(qū)動程序:
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88/drivers$ grep "fsl,imx6ul-ecspi" * -nr
Binary file built-in.o matches
spi/spi-imx.c:782:????? { .compatible = "fsl,imx6ul-ecspi", .data = &imx6ul_ecspi_devtype_data, },
可見,spi/spi-imx.c就是我們要找的SPI控制器驅(qū)動程序。
1.3.2 我們能做的不多,只能在設(shè)備樹中指定片選
設(shè)備樹已經(jīng)在前面列出來了。
一個SPI控制器可以連接多個SPI設(shè)備,每個SPI設(shè)備使用都有單獨的片選信號,如下圖:

在SPI控制器驅(qū)動和設(shè)備樹中,我們最關(guān)心的是片選信號,其他信號我們無法修改。
閱讀spi-imx.c的spi_imx_probe函數(shù):

我們得找到設(shè)備樹的處理代碼,看看它是怎么從設(shè)備樹中設(shè)置cs_gpios的,搜“cs_gpios”,得到:

打開drivers/spi/spi.c第1846行,它確實是用來處理設(shè)備樹的:

of_spi_register_master函數(shù)的調(diào)用流程:
spi_imx_probe? (drivers/spi/spi-imx.c)
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
ret = spi_bitbang_start(&spi_imx->bitbang);?? (drivers/spi/spi-bitbang.c)
??????? ret = spi_register_master(spi_master_get(master));? (drivers/spi/spi.c)
???????????????? status = of_spi_register_master(master);? (drivers/spi/spi.c,就是它處理cs-gpios)
1.3 SPI設(shè)備驅(qū)動程序
設(shè)備樹已經(jīng)在前面列出來了。
SPI設(shè)備跟SPI控制器之間的硬件連接,能確定的也就3點,我們需要在設(shè)備樹中指定:
a. 接到哪個SPI控制器去?
IMX6ULL中有多個SPI控制器,在設(shè)備樹里,把SPI設(shè)備的節(jié)點放到某個SPI控制器節(jié)點之下就可以。
b. SPI設(shè)備有沒有中斷?用哪一個中斷?
我們的ICM20608如下設(shè)置:
interrupt-parent = <&gpio1>;
interrupts = <1 1>;
c. SPI設(shè)備使用哪個片選?
在SPI控制器節(jié)點里有cs-gpios屬性,里面定義有1個或多個片選。
在SPI設(shè)備的節(jié)點中,用reg屬性指定使用cs-gpios中的哪個片選(從0開始),如下:
reg = <0>;
你看,我們只關(guān)心設(shè)備樹,似乎沒怎么看驅(qū)動程序啊。
根據(jù)設(shè)備節(jié)點的compatible屬性可找到ICM20608的驅(qū)動程序為:
drivers\iio\imu\inv_mpu6050\inv_mpu_spi.c
打開drivers/iio/imu/inv_mpu6050/Makefile,其內(nèi)容如下:

上圖中的2個ko文件,都需要安裝。前一個要先安裝,它為后一個ko提供一些函數(shù)。
1.4 測試
ICM20608的驅(qū)動程序是基于IIO驅(qū)動來編寫的,我們還沒深入研究IIO。
所以本節(jié)只是簡單地講講怎么測試ICM20608,以后再深入研究。
首先,請確保你的設(shè)備樹文件arch/arm/boot/dts/100ask_imx6ull-14x14.dts中,ICM20608節(jié)點的屬性中含有cs-gpios,注意:不是cs-gpio。(我們曾經(jīng)提供一個補丁,它處理的是cs-gpio屬性,最新版本的內(nèi)核已經(jīng)去除了這個補丁,使用drivers/spi/spi.c處理的是cs-gpios屬性)
然后在開發(fā)板上安裝驅(qū)動程序:
[root@imx6ull:~]# insmod inv-mpu6050.ko
[root@imx6ull:~]# insmod inv-mpu6050-spi.ko
[?? 56.892312] inv-mpu6000-spi spi2.0: mounting matrix not found: using identity..
你就可以看到設(shè)備節(jié)點了:
[root@imx6ull:~]# ls /dev/iio*
/dev/iio:device0??? /dev/iio:device1
也可以看到/sys下創(chuàng)建了一些文件:
[root@imx6ull:~]# ls /sys/bus/iio/devices
iio:device0? iio:device1? trigger0
是iio:device0還是iio:device1對應(yīng)ICM20608?可以cat上述目錄里的name文件:
[root@imx6ull:~]# cat /sys/bus/iio/devices/iio\:device1/name
icm20608
然后就可以進(jìn)入/sys/bus/iio/devices/iio\:device1目錄,讀取里面的文件,同時轉(zhuǎn)動開發(fā)板,可以觀察到值在變化:
[root@imx6ull:~]# cd? /sys/bus/iio/devices/iio\:device1
[root@imx6ull:/sys/bus/iio/devices/iio:device1]# ls
buffer ???????????????????????in_anglvel_y_calibbias
current_timestamp_clock?????? in_anglvel_y_raw
dev?????????????????????????? in_anglvel_z_calibbias
in_accel_matrix?????????????? in_anglvel_z_raw
in_accel_mount_matrix???????? in_gyro_matrix
in_accel_scale??? ????????????in_temp_offset
in_accel_scale_available????? in_temp_raw
in_accel_x_calibbias????????? in_temp_scale
in_accel_x_raw??????????????? name
in_accel_y_calibbias????????? of_node
in_accel_y_raw??????????????? power
in_accel_z_calibbias????????? sampling_frequency
in_accel_z_raw??????????????? sampling_frequency_available
in_anglvel_mount_matrix?????? scan_elements
in_anglvel_scale????????????? subsystem
in_anglvel_scale_available??? trigger
in_anglvel_x_calibbias??? ????uevent
in_anglvel_x_raw
[root@imx6ull:/sys/bus/iio/devices/iio:device1]# cat in_accel_x_raw
-141
[root@imx6ull:/sys/bus/iio/devices/iio:device1]# cat in_accel_x_raw
-4652
[root@imx6ull:/sys/bus/iio/devices/iio:device1]# cat in_accel_x_raw
844
注意:我們對ICM20608并無深入研究,上述/sys目錄中各值有什么含義,留待你們?nèi)グl(fā)現(xiàn)。

我是韋東山,專注研究嵌入式linux+ARM 10多年,歡迎大家訂閱我的付費視頻:
100ask.taobao.com

還沒搞懂的同學(xué)可以加我同事微信13163769879加入交流群討論學(xué)習(xí)