zoukankan      html  css  js  c++  java
  • Android驱动笔记(1)——LED驱动

    一、Android源自Linux

     Android驱动实际就是linux驱动和封装,内核通过驱动与底层硬件“交互”并为framework层提供统一接口。linux中诸如进程管理、内存管理、中断管理、虚拟文件系统(vfs)、网络管理等内容的都是差别不大的。但在驱动构成上存在下面的差异。

    驱动构成的差异:
    Linux:内核 + 文件系统 + rootfs
    Android:内核 + 文件系统 + rootfs + android文件系统挂载到system

     怎么理解这个“android文件系统挂载到system”?需要了解Android系统源代码目录结构:

    abi *:应用程序二进制接口
    bionic *:基础的库的源代码
    bootloader/legacy *:启动引导相关代码
    build *:存放编译系统的.mk文件
    development *:程序开发需要的模板和工具
    device *:设备相关代码
    framworks *:核心框架——java和C++语言,是Android应用程序的框架
    hardware *:主要是硬件适配层HAL代码
    out *:编译完成全部img文件
    packages *:Android的各种系统级应用程序
    system *:Android根文件系统相关源码
    

     而基本上一般的Linux文件系统没有system这个目录。

    二、一个LED驱动

     指示灯在Android设备上主要作用就是显示手机状态,高通平台通常情况下默认的RGB接口连接指示灯,个别用户会选择外接的LED芯片控制灯效。Android的LED驱动和Linux下的LED驱动没有太大区别。Android的LED驱动基本位于Kernel目录下。详细的led驱动可以参考drivers/leds/目录下的代码。

    1. 通常在dts中搜索指示灯关键字red可以找到平台默认相关配置。
    2. 对应的_deconfig文件中打开相应的配置宏 CONFIG_LEDS_QTI_TRI_LED –高通平台默认参考驱动模式不同选择的宏不同,根据平台以及硬件连接项目需要配置,无特殊情况选择默认配置即可。
    3. 确认对应的makefile文件Drivers/leds/makefile中有CONFIG_LEDS_QTI_TRI_LED宏配置
    4. 检查驱动代码 根据配置的宏查到对应的源文件,查看驱动代码Driver/leds/leds-qti-tri-led.c
    5. 检查dts配置 :arch/arm64/boot/dts/qcom/***.dtsi。dts相关配置参数说明可以查看: Documentation/devicetree/bingdings/leds/leds-qti-tri-led.txt.

    2.0、LED的硬件原理

     LED的原理图非常简单,一般采用平台默认的GPIO引脚,通过高低电平控制LED亮灭,同时可以调节占空比来调节LED电流。

    2.1、如何编写一个驱动?

     按照内核为某个设备提供的框架去编写,驱动编写分为四步:为结构体分配空间、设置结构体、硬件的相关操作、注册。为了给应用程序提供统一的接口,驱动采用分层的思想,其中核心层是内核为设备提供的框架,除此以外还有设备驱动层。

    参考代码:/drivers/leds/led-class.c

     实际操作依旧按照:为结构体分配空间、设置结构体、硬件的相关操作、注册来执行。

    2.2、驱动源码

    # Makefile
    KERNELDIR  :=/home/linux/fspad_733/lichee/linux-3.4
    test:
    	make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -C $(KERNELDIR) M=$(shell  pwd) modules
    clean:
    	make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -C $(KERNELDIR) M=$(shell  pwd) clean
    obj-m += fspad_leds.o
    
    /*own led*/
    #include <linux/module.h>
    #include <linux/slab.h>
    #include <linux/leds.h>
    #include <asm/io.h>
    #define FSPAD733_GPFCON 0x01C208B4
    #define FSPAD733_GPFDAT 0x01C208C4
    
    unsigned int *gpfcon;
    unsigned int *gpfdat;
    
    struct led_classdev  *led_dev; //led_dev结构体声明
    
    //step3:实现结构体中定义的操作(设置LED初始值)
    void fspad_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness){
    	if(brightness == LED_OFF) {
    		writel(readl(gpfdat)|(0x1 << 2),gpfdat); //led off
    	}else{
    		writel(readl(gpfdat)&~(0x1 << 2),gpfdat); //led on
    	}
    }
    
    //step2:驱动初始化函数
    int fspad_leds_init(void){
    	int  ret;
    	//1、为结构体分配空间,kzalloc分配空间,初始化结构体成员为0,必须要手动释放空间
    	if(NULL == (led_dev  = kzalloc(sizeof(struct led_classdev),GFP_KERNEL)))
    		return  -ENOMEM;
    
    	//2、设置结构体
    	led_dev->name  = "led0";
    	led_dev->flags = LED_CORE_SUSPENDRESUME;
    	led_dev->brightness_set = fspad_brightness_set;
    
    	//3、硬件相关的操作
    	gpfcon = ioremap(FSPAD733_GPFCON,0x4); //将物理地址映射到一个虚拟地址上
    	gpfdat = ioremap(FSPAD733_GPFDAT,0x4);
    	writel((readl(gpfcon)&~(0xf << 8))|(0x1 << 8),gpfcon);
        //led init:gpfcon的8~11位先清零,再在第8位写1
    	writel(readl(gpfdat)&~(0x1 << 2),gpfdat);
        //led on
    
    	//4、注册
    	ret = led_classdev_register(NULL, led_dev);
    	if(ret < 0)
    		return  ret;
    	return  0;
    }
    
    //step4:驱动注销
    void  fspad_leds_exit(void)
    {
    	led_classdev_unregister(led_dev);
    	iounmap(gpfcon);
    	iounmap(gpfdat);
    	kfree(led_dev);
    }
    
    //step1:初始化模块三要素
    module_init(fspad_leds_init);
    module_exit(fspad_leds_exit);
    MODULE_LICENSE("GPL");
    

    2.3、驱动编译和执行

     在编译uboot和内核的过程中,采用的是外部传参的方式进行编译,Makefile的写法见上文。另外需要执行:

    #sudo vi /etc/bash.bashrc
    export PATH=$PATH:/home/linux/lichee/out/sun8iw5p1/android/common/buildroot/external-toolchain/bin
    

     指定输出目录并使其立即生效:

    # source /etc/bash.bashrc
    

     insmod own_leds.ko将led驱动加载进内核,会在/sys/class/leds/led0/下生成led节点,进而可对led进行控制。

    2.4、LED上层简介

    1.framwork 层: LightsService.java 提供java调用jni层方法。一般作为service启动。
    2、jni 层: com_android_server_LightsService.cpp
    3 hardware层: Lights.c 通过节点控制led状态。

    2.5、调试方法

    1.通过节点来调整led状态,配合万用表测量对应pin脚输出状态。
    2 常用节点,设备注册成功后 会在/sys/class/leds/目录下生成对应的red blue green对应的目录。

    # cd sys/class/leds/red/
    # ls
    blink brightness device fusion led_time max_brightness power subsystem trigger uevent
    # echo 255 > brightness --打开点亮led
    # echo 0 > brightness --关闭led
    
  • 相关阅读:
    <context-param>与<init-param>的区别与作用(转自青春乐园)(
    使用Derby ij客户端工具
    转载 Ofbiz 入门教程
    数据库中插入和读取图片
    事务的使用
    存储过程
    触发器 的使用
    JS面试题及答案
    课程主页面三个接口开发
    增加media文件配置
  • 原文地址:https://www.cnblogs.com/hansenn/p/12714181.html
Copyright © 2011-2022 走看看