平台设备驱动程序

Linux android

Posted by LXG on March 29, 2022

Linux总线、设备、驱动模型探究

平台设备驱动程序

platform_driver

总线存在的目的就是把设备和对应的驱动绑定起来

设备

描述基地址、中断号、时钟、DMA、复位等信息


kernel/arch$ tree -L 1
.
├── alpha
├── arc
├── arm
├── arm64
├── avr32
├── blackfin
├── c6x
├── cris
├── frv
├── h8300
├── hexagon
├── ia64
├── Kconfig
├── m32r
├── m68k
├── metag
├── microblaze
├── mips
├── mn10300
├── nios2
├── openrisc
├── parisc
├── powerpc
├── s390
├── score
├── sh
├── sparc
├── tile
├── um
├── unicore32
├── x86
└── xtensa

驱动

kernel/drivers 完成外设的具体功能

总线

完成设备和驱动的关联

kernel/drivers/base/platform.c kernel/drivers$/pci

设备树

设备树的出现是为了解决内核中大量的板级文件代码,通过 DTS 可以像应用程序里的 XML 语言一样很方便的对硬件信息进行配置

arch/arm/boot/dts/rk3288-evb.dtsi


        compatible = "rockchip,rk3288-evb-android-rk808-edp", "rockchip,rk3288";

        chosen {
                bootargs = "earlycon=uart8250,mmio32,0xff690000 vmalloc=496M";
        };

        cpuinfo {
                compatible = "rockchip,cpuinfo";
                nvmem-cells = <&efuse_id>;
                nvmem-cell-names = "id";
        };

        lzt-ec20 {
                compatible = "rockchip,lzt-ec20";
                lte-power-gpios = <&gpio7 14 GPIO_ACTIVE_LOW>;
                led-power-gpios = <&gpio8 8 GPIO_ACTIVE_LOW>;
                wif-init-gpio = <&gpio8 7 IRQ_TYPE_LEVEL_LOW>;
                //fan-power-gpios = <&gpio8 9 GPIO_ACTIVE_LOW>;
                phone-ctl-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
                usb-power-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>;
                usb-5v-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
                status = "okay";
        };

        wireless-wlan {
                compatible = "wlan-platdata";
                rockchip,grf = <&grf>;
                wifi_chip_type = "ap6256";
                sdio_vref = <1800>;
                WIFI,host_wake_irq = <&gpio4 30 GPIO_ACTIVE_HIGH>;
                status = "okay";
        };

kernel_dts

设备信息

rk3288_interface

内核启动的时候是一层一层展开地去寻找设备,设备树之所以叫设备树也是因为设备在内核中的结构就像树一样,从根部一层一层的向外展开

soc_bus

大的圆圈中就是我们常说的 soc,里面包括 CPU 和各种控制器 A、B、I2C、SPI,soc 外面接了外设 E 和 F。IP 外设有具体的总线,如 I2C 总线、SPI 总线,对应的 I2C 设备和 SPI 设备就挂在各自的总线上,但是在 soc 内部只有系统总线,是没有具体总线的。

上图中可以看到红色字体标注的 simple-bus,这些就是连接各类控制器的总线,在内核里即为 platform 总线,挂载的设备为 platform 设备

ec20.c


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/circ_buf.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <asm/gpio.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/wakelock.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/wakelock.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/fs.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/timer.h>
#include <linux/sched.h>   
#include <linux/kthread.h>
MODULE_LICENSE("GPL");

#define DEBUG
#ifdef DEBUG
#define MODEMDBG(x...) printk(x)
#else
#define MODEMDBG(fmt,argss...)
#endif
#define SLEEP 1
#define READY 0
#define GPIO_LOW 0
#define GPIO_HIGH 1
int lte_power_gpios=-1;
int led_power_gpios=-1;

static int ec20_suspend(struct platform_device *pdev, pm_message_t state)
{
	
	return 0;
}
void ec20_init_gpio(struct platform_device *pdev){
	int ret;
	enum of_gpio_flags flags;
	pdev->dev.of_node = of_find_compatible_node(NULL, NULL, "rockchip,lzt-ec20");
	led_power_gpios = of_get_named_gpio_flags(pdev->dev.of_node, "led-power-gpios", 0, &flags);
	if(!gpio_is_valid(led_power_gpios)) {
		printk("led_power_gpios: %d is invalid\n", led_power_gpios);
		led_power_gpios = -1;
	}else {
		printk("led_power_gpios: %d is arrivable\n", led_power_gpios);
		ret = devm_gpio_request_one(&pdev->dev, led_power_gpios,GPIOF_DIR_OUT,NULL);
	}
	lte_power_gpios = of_get_named_gpio_flags(pdev->dev.of_node, "lte-power-gpios", 0, &flags);
	if(!gpio_is_valid(lte_power_gpios)) {
		printk("lte_power_gpios: %d is invalid\n", lte_power_gpios);
		lte_power_gpios = -1;
	}else {
		printk("lte_power_gpios: %d is arrivable\n", lte_power_gpios);
		ret = devm_gpio_request_one(&pdev->dev, lte_power_gpios,GPIOF_DIR_OUT,NULL);
	}

}
void power_on_ec20(int i){
	if(i==1)
	{
		printk("EC20 power 1\n");
		gpio_set_value(lte_power_gpios,GPIO_HIGH);
	}else{
		printk("EC20 power 0\n");
	        gpio_set_value(lte_power_gpios,GPIO_LOW);
	}
}

void power_on_led(int i){
	if(i==1)
	{
		//printk("EC20 power 1\n");
		gpio_set_value(led_power_gpios,GPIO_HIGH);
	}else{
		//printk("EC20 power 0\n");
	gpio_set_value(led_power_gpios,GPIO_LOW);
	}
}

static struct task_struct *poc_task = NULL;

int poc_thread(void *data){
    while (1)
	{
		power_on_led(1);
		msleep(1000);   
		power_on_led(0);	
		msleep(1000);		
    }
	
    return 0;
}
void send_sendkey_poc(void)
{
    poc_task = kthread_create(poc_thread, NULL, "poc_task");
    if(poc_task == NULL){
      printk("Accdet Unable to start poc_task thread. ");
      poc_task = NULL;
      return ;
    }
    wake_up_process(poc_task);
}

static int ec20_probe(struct platform_device *pdev)
{
	printk("ec20_probe\n");
	ec20_init_gpio(pdev);
	power_on_ec20(1);
	send_sendkey_poc();
	return 0;
}

static int ec20_resume(struct platform_device *pdev)
{
	
	return 0;
}

static const struct of_device_id ec20_of_match[] = {
	{.compatible = "rockchip,lzt-ec20"},
	{},
};

// 平台驱动程序必须实现probe函数
static struct platform_driver ec20_driver = {
	.probe	= ec20_probe,
	.suspend  	= ec20_suspend,
	.resume		= ec20_resume,
	.driver	= {
		.name	= "ec20",
		.owner	= THIS_MODULE,
		.of_match_table = ec20_of_match,
	},
};

static int __init ec20_init(void)
{
	printk("ec20_init\n");
	return platform_driver_register(&ec20_driver); // 内核中注册平台驱动程序
}

static void __exit ec20_exit(void)
{
	platform_driver_unregister(&ec20_driver);
}

module_init(ec20_init);

module_exit(ec20_exit);