调试加载PMU芯片驱动之后,除了逐步验证其功能是一种测试方法之外,写一个测试程序也是一种方法。下面是AXP18X的测试程序,通过基础的寄存器读写来控制测试。当然,除了PMU,其它模块也都可以通过类似方法验证。
(1)首先建立一个带main的可独立运行的axp18x_test.c文件,如下:
#include <stdio.h> #include <fcntl.h> main() { unsigned char arr[20]={0,0,}; int fd,status; char rw; int tmp=0; fd = open("/dev/pmic_axp18x", O_RDWR); //添加的设备都在dev下 if (fd < 0) { printf("/dev/pmic_axp18x open error!!/n"); return -1; } while(1) { printf(">"); //进入等待输入 scanf("%c",&rw); //获取字符,进入字符判断状态 if(rw!=0xa) getchar(); switch(rw) { case 'r': case 'R': printf("please enter reg(hex):"); fflush(stdin); //把printf输出到缓冲区的内容,刷新输出到屏幕上 scanf("%2x",&arr[0]); arr[1] = 0x00; status = read(fd, arr, 2); //调用device的read函数 if (status < 0){ printf("/dev/pmic_axp18x read reg 0x%x error!!/n",arr[0]); goto exit; } printf("read 0x%x success: 0x%x./n",arr[0],arr[1]); getchar(); break; case 'w': case 'W': printf("please enter reg(hex xx):"); fflush(stdin); scanf("%2x",&tmp); arr[0]=tmp; printf("please enter value(hex xx):"); fflush(stdin); scanf("%2x",&tmp); arr[1]=tmp; printf("write 0x%x to 0x%x.../n",arr[1],arr[0]); status =write(fd, arr , 2); if (status < 0) { printf("/dev/pmic_axp18x write 0x%x to reg 0x%x error!!/n",arr[1],arr[0]); goto exit; } printf("write 0x%x to 0x%x success./n",arr[1],arr[0]); getchar(); break; case 'q': case 'Q': goto exit; //退出,返回控制台 break; default: printf("support command:/n"); printf("r/R:read/n"); printf("w/W:write/n"); printf("q/Q:quit/n"); break; } printf("/n"); } exit: return 1; }
(2)该程序用gcc也可以编译,生成a.out。这种方式是用OS的gcc编译工具生成的,用file命令查看:
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped。用./a.out即可执行
(3)也用嵌入式交叉编译器编译,首先建立对应的makefile文件:
CROSS_COMPILE = /home/dsgsdg/gcc/arm-2008q3/bin/arm-linux- CC = $(CROSS_COMPILE)gcc axp18x_test: axp18x_test.c $(CC) -o axp18x_test axp18x_test.c -static
指定交叉编译器的makefile可以直接单独编译,另加上static选项,标识静态编译,就是包括库文件一起编译可以单独运行。需要注意的是:如果我用arm-eabi-4.4.3的交叉编译器执行make编译,就不会成功,提示头文件找不到。初步判断是交叉编译器的差别引起的,在编译器文件夹内也确实找不到所需的头文件,但ALPS一直是它来编的。
(4)在终端中切到内核的该目录下,运行make。生成了可执行文件axp18x_test。执行file axp18x_test,可以得到该可执行文件的格式和运行平台。如下:
axp18x_test: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.14, not stripped
如果不用这种方式编译,用gcc的话得到的是X86平台上的可执行文件,在ARM上是执行不了的。这样编译得到的文件需拷贝到平台上才可以运行。
(5)测试。拷贝axp18x_test到MID的sd卡,运行./axp18x_test提示权限不够。但是执行sudo.....又没有这个指令;执行chmod 777可以执行,但是用ls -l查看属性仍然没有改变,而且同样不能运行。所以打算拷贝到system目录下再改变属性运行,当执行cp和mov都是没有的,想到了用busybox cp来复制,呵呵完毕后,再chmod 777属性组就改变过来了。运行./axp18x_test,即进入输入字符的测试状态,输入r或者w即可测试验证功能。
*********************************************************************
HALL器件可用在手机等皮套的闭合控制上,在MTK上的驱动修改可以参照如下流程。
#define KPD_PWRKEY_USE_HALL_EINT KPD_YES //宏开关 #define CUST_EINT_POLARITY_LOW 0 //触发极性常量低电平 static u8 kpd_pwrkey_hall_state = CUST_EINT_POLARITY_LOW; //hall脚的for give a initial value,默认闭合 static unsigned int bl_brightness_hal = 102; //假定当前系统亮度的一个可读变量
中断初始化
mt_set_gpio_mode(GPIO_MHALL_EINT_PIN, GPIO_MHALL_EINT_PIN_M_GPIO); mt_set_gpio_dir(GPIO_MHALL_EINT_PIN, GPIO_DIR_IN); mt_set_gpio_pull_enable(GPIO_MHALL_EINT_PIN, GPIO_PULL_ENABLE); mt_set_gpio_pull_select(GPIO_MHALL_EINT_PIN, GPIO_PULL_UP); mt_eint_set_sens(CUST_EINT_MHALL_NUM, MT_LEVEL_SENSITIVE); //中断极性会不断改变,后面会设置 mt_eint_set_polarity(CUST_EINT_MHALL_NUM, CUST_EINT_POLARITY_HIGH); //闭合后触发极性高,打开后触发极性低。默认第一次是高触发 mt_eint_set_hw_debounce(CUST_EINT_MHALL_NUM, CUST_EINT_MHALL_DEBOUNCE_CN); mt_eint_registration(CUST_EINT_MHALL_NUM, CUST_EINT_MHALL_TYPE, kpd_pwrkey_eint_handler, 0); mt_eint_unmask(CUST_EINT_MHALL_NUM);中断处理调用过程
static void kpd_pwrkey_handler_hal2(unsigned long data); static DECLARE_TASKLET(kpd_pwrkey_tasklet, kpd_pwrkey_handler_hal2, 0); ............ static void kpd_pwrkey_eint_handler(void) { tasklet_schedule(&kpd_pwrkey_tasklet); }中断处理流程
static void kpd_pwrkey_handler_hal2(unsigned long data){ bool pressed; u8 old_state = kpd_pwrkey_hall_state; mt_eint_mask(CUST_EINT_MHALL_NUM); kpd_pwrkey_hall_state = !kpd_pwrkey_hall_state; //获取新状态。恰好闭合时低电平,触发极性是高电平;打开后相反 pressed = (kpd_pwrkey_hall_state == CUST_EINT_POLARITY_LOW); if (kpd_show_hw_keycode) { printk(KPD_SAY "(%s) HW keycode = using EINT\n", pressed ? "pressed" : "released"); } if((pressed == 1)&&(bl_brightness_hal != 0)) //如果当前闭合了,屏幕还是亮的 { input_report_key(kpd_input_dev, KPD_PWRKEY_MAP, 1); input_sync(kpd_input_dev); input_report_key(kpd_input_dev, KPD_PWRKEY_MAP, 0); input_sync(kpd_input_dev); //模拟一次电源键按下,报两次的目的就是避免上层会根据按下弹起的时间差判断是长按还是短按 } if((pressed == 0)&&(bl_brightness_hal == 0)) //如果当前打开了,屏幕还是灭的 { input_report_key(kpd_input_dev, KPD_PWRKEY_MAP, 1); input_sync(kpd_input_dev); input_report_key(kpd_input_dev, KPD_PWRKEY_MAP, 0); input_sync(kpd_input_dev); //也模拟一次电源键按下 } /* for detecting the return to old_state */ mt_eint_set_polarity(CUST_EINT_MHALL_NUM, old_state); //反转中断极性 mt_eint_unmask(CUST_EINT_MHALL_NUM); }