平台设备驱动程序
总线存在的目的就是把设备和对应的驱动绑定起来
设备
描述基地址、中断号、时钟、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";
};
设备信息
内核启动的时候是一层一层展开地去寻找设备,设备树之所以叫设备树也是因为设备在内核中的结构就像树一样,从根部一层一层的向外展开
大的圆圈中就是我们常说的 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);