平台总线介绍
总线代表着同类设备需要共同遵循的工作时序,不同的总线对于物理电平的要求是不一样的,对于每个比特的电平维持宽度也是不一样的,总线上传递的命令也会有自己的格式约束。
在Linux系统中总线可分为两种,
1、一种是实际存在的总线(例如I2C、SPI、USB等总线)。
2、另一种是虚拟存在的总线(platform总线)。
1.linux 设备驱动程序的演变
简单不易扩展,需重新编译,不同的引脚要写不同的驱动。
1.2 总线设备驱动
2.案例:平台总线驱动和设备树匹配
参考:http://wiki.t-firefly.com/zh_CN/AIO-3399J/driver_gpio.html
myled_ctrl {status = "okay";compatible = "rk3399_led2_green";gpio_led = <&gpio1 23 GPIO_ACTIVE_HIGH>; /* GPIO1_C7 */};
保存然后编译内核 :
make ARCH=arm64 nanopi4-images -j4
将内核镜像烧录到开发板
运行开发板,验证是否成功。
root@SOM-RK3399v2:~# cd /sys/firmware/devicetree/base/root@SOM-RK3399v2:/sys/firmware/devicetree/base# lsroot@SOM-RK3399v2:/sys/firmware/devicetree/base# cd myled_ctrl/root@SOM-RK3399v2:/sys/firmware/devicetree/base/myled_ctrl# lscompatible gpio_led name statusroot@SOM-RK3399v2:/sys/firmware/devicetree/base/myled_ctrl#cat compatiblerk3399_led2_greenroot@SOM-RK3399v2:/sys/firmware/devicetree/base/myled_ctrl#
root@SOM-RK3399v2:/drv_code# ls
led_drv.koroot@SOM-RK3399v2:/drv_code# insmod led_drv.ko[ 1250.159618] led_drv: loading out-of-tree module taints kernel.[ 1250.160868] <xyd> call led_driver_init()[ 1250.161925] <xyd> call led_driver_probe()root@SOM-RK3399v2:/drv_code#
[rootrk3399:/sys/devices/platform]# ls myled_ctrl/driver driver_override modalias of_node power subsystem uevent[rootrk3399:/sys/devices/platform]#
3.在 probe 函数中对 DTS 所添加的资源进行解析
验证配置结果:
root@SOM-RK3399v2:/drv_code# lsled_drv.koroot@SOM-RK3399v2:/drv_code# insmod led_drv.ko[ 1039.449461] led_drv: loading out-of-tree module taints kernel.[ 1039.453253] <xyd> call led_driver_init()[ 1039.454847] <xyd> call led_driver_probe() # 平台驱动匹配上 DTS 节点root@SOM-RK3399v2:/# cd /sys/bus/platformroot@SOM-RK3399v2:/sys/bus/platform# lsdevices drivers drivers_autoprobe drivers_probe uevent# 平台设备和驱动保存这个目录下root@SOM-RK3399v2: /sys/bus/platform/drivers/myled# ls –al # 查看平台驱动total 0drwxr-xr-x 2 root root 0 Jun 7 07:43 .drwxr-xr-x 120 root root 0 Jun 7 07:26 ..--w------- 1 root root 4096 Jun 7 07:51 bindlrwxrwxrwx 1 root root 0 Jun 7 07:51 module -> ../../../../module/led_drvlrwxrwxrwx 1 root root 0 Jun 7 07:51 myled_ctrl -> ../../../../devices/platform/myled_ctrl#myled_ctrl 是 DTS 的节点 现在被转换为 platform_device--w------- 1 root root 4096 Jun 7 07:43 uevent--w------- 1 root root 4096 Jun 7 07:51 unbindroot@SOM-RK3399v2:/sys/bus/platform/devices/myled_ctrl# ls –al # 查看平台设备就是 DTS 节点转换的total 0drwxr-xr-x 3 root root 0 Jun 7 07:26 .drwxr-xr-x 155 root root 0 Jun 7 07:26 ..lrwxrwxrwx 1 root root 0 Jun 7 07:46 driver -> ../../../bus/platform/drivers/myled# 和 myled 是匹配-rw-r--r-- 1 root root 4096 Jun 7 07:46 driver_override-r--r--r-- 1 root root 4096 Jun 7 07:46 modaliaslrwxrwxrwx 1 root root 0 Jun 7 07:46 of_node -> ../../../firmware/devicetree/base/myled_ctrl#myled_ctrl 平台设备是来自于 DTS 节点的drwxr-xr-x 2 root root 0 Jun 7 07:46 powerlrwxrwxrwx 1 root root 0 Jun 7 07:26 subsystem -> ../../../bus/platform-rw-r--r-- 1 root root 4096 Jun 7 07:26 uevent
设备树节点指定资源,platform_driver 获得资源:
4.内核对设备树的处理
哪些设备树节点会被转换为 platform_device:
1) 根节点下含有 compatible 属性的子节点;
2) 含有特定 compatible 属性的节点的子节点;
如果一个节点的compatible属性,它的值是这三者之一:
"simple-bus","simple-mfd","isa","arm,amba-bus"
那么它的子节点(需含 compatible 属性)也可转换为 platform_device.
3) 总线 I2C,SPI 节点下的子节点,不转换为 platform_device.
某个总线下子节点,应该交给对应的总线驱动程序来处理,它们不应该转换为platform_device.
struct platform_device {const char *name;int id;bool id_auto;struct device dev; // 父类的成员 名字叫 devu32 num_resources;struct resource *resource;const struct platform_device_id *id_entry;char *driver_override; /* Driver name to force a match *//* MFD cell pointer */struct mfd_cell *mfd_cell;/* arch specific additions */struct pdev_archdata archdata;};
struct device {struct device *parent;..../* arch specific additions */struct dev_archdata archdata;struct device_node *of_node; /* associated device tree node */struct fwnode_handle *fwnode; /* firmware device node */......dev_t devt; /* dev_t, creates the sysfs "dev" */u32 id; /* device instance */};
static int platform_match(struct device *dev, struct device_driver *drv){struct platform_device *pdev = to_platform_device(dev);struct platform_driver *pdrv = to_platform_driver(drv);/* When driver_override is set, only bind to the matching driver */if (pdev->driver_override)return !strcmp(pdev->driver_override, drv->name);/* Attempt an OF style match first */if ( of_driver_match_device (dev, drv)) // 使用设备树来匹配return 1;/* Then try ACPI style match */if (acpi_driver_match_device(dev, drv))return 1;/* Then try to match against the id table */if (pdrv->id_table) // 使用 id_table 匹配return platform_match_id(pdrv->id_table, pdev) != NULL;/* fall-back to driver name match */return (strcmp(pdev->name, drv->name) == 0); // 使用名字匹配}
gpio-leds {compatible = "xyd-leds";status = "okay";led2-green {//led2-greengpios = <&gpio1 23 GPIO_ACTIVE_HIGH>; //GPIO_ACTIVE_LOWlabel = "green_led2";};led2-orange {//led2-orangegpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;label = "green_led2";};};
root@SOM-RK3399v2:/sys/firmware/devicetree/base# ls gpio-leds/compatible led2-green name pinctrl-0 statusled@1 led2-orange phandle pinctrl-namesroot@SOM-RK3399v2:/sys/firmware/devicetree/base#