[嵌入式Linux驅動]S5PV210的蜂鳴器Linux驅動
阿新 • • 發佈:2018-12-29
智慧家居報警器控制驅動程式:
1. 本驅動使用platform模型進行設計,分為Alarm_Beeper_device和Alarm_Beeper_driver兩個檔案
2. 註冊雜項裝置(misc),主裝置號固定是10(misc),從裝置號由系統自動分配,載入成功後使用lsmod可以看到: Alarm_Beeper_device
Alarm_Beeper_driver 3. 載入driver驅動模組之後自動對gpio進行初始化,初始化成功會輸出: [ 22.179372] Alarm_Beeper_dirver_probe: gpio init finished!!! //GPIO初始化成功
[ 22.191932] Alarm_Beeper_dirver_probe: timer0 init finished!!! //定時器初始化成功 初始化完成後會預設將蜂鳴器關掉。 4. 本驅動註冊成功後生成 /dev/smarthome_alarm_beeper 節點 5. 對 smarthome_alarm_beeper 裝置節點的操作主要有:
1)開啟操作open
2)關閉操作close
3)傳送命令ioctl:這裡使用了_IO的辦法對命令進行加密 #define MAGIC_WORD 'w' #define ALARM_BEEPER_OFF _IO(MAGIC_WORD,10) //關閉蜂鳴器
#define ALARM_BEEPER_ON _IO(MAGIC_WORD,11) //開啟蜂鳴器
#define ALARM_BEEPER_SPEED_UP _IO(MAGIC_WORD,12) //提高蜂鳴器頻率(大約提升1倍,最多提升7次)
#define ALARM_BEEPER_SPEED_DOWN _IO(MAGIC_WORD,13) //降低蜂鳴器頻率(大約降低1半,最多降低7次)
#define ALARM_BEEPER_SPEED_DEFAULT _IO(MAGIC_WORD,20) //恢復蜂鳴器預設頻率
注意:這裡僅僅是對蜂鳴器的頻率進行操作,對蜂鳴器鳴響的持續時間控制在使用者程式完成。 Alarm_Beeper_device.c
Makefile
2. 註冊雜項裝置(misc),主裝置號固定是10(misc),從裝置號由系統自動分配,載入成功後使用lsmod可以看到: Alarm_Beeper_device
Alarm_Beeper_driver 3. 載入driver驅動模組之後自動對gpio進行初始化,初始化成功會輸出: [ 22.179372] Alarm_Beeper_dirver_probe: gpio init finished!!! //GPIO初始化成功
[ 22.191932] Alarm_Beeper_dirver_probe: timer0 init finished!!! //定時器初始化成功 初始化完成後會預設將蜂鳴器關掉。 4. 本驅動註冊成功後生成 /dev/smarthome_alarm_beeper 節點 5. 對 smarthome_alarm_beeper 裝置節點的操作主要有:
1)開啟操作open
2)關閉操作close
3)傳送命令ioctl:這裡使用了_IO的辦法對命令進行加密 #define MAGIC_WORD 'w' #define ALARM_BEEPER_OFF _IO(MAGIC_WORD,10) //關閉蜂鳴器
#define ALARM_BEEPER_ON _IO(MAGIC_WORD,11) //開啟蜂鳴器
#define ALARM_BEEPER_SPEED_UP _IO(MAGIC_WORD,12) //提高蜂鳴器頻率(大約提升1倍,最多提升7次)
#define ALARM_BEEPER_SPEED_DOWN _IO(MAGIC_WORD,13) //降低蜂鳴器頻率(大約降低1半,最多降低7次)
#define ALARM_BEEPER_SPEED_DEFAULT _IO(MAGIC_WORD,20) //恢復蜂鳴器預設頻率
注意:這裡僅僅是對蜂鳴器的頻率進行操作,對蜂鳴器鳴響的持續時間控制在使用者程式完成。 Alarm_Beeper_device.c
Alarm_Beeper_driver.c#include <linux/platform_device.h> #include <linux/kernel.h> #include <linux/module.h> #include <asm/uaccess.h> #define S5PV210_GPD_BASE 0xe02000a0 //read the s5pv210 datasheet! #define S5PV210_TC_BASE 0xe2500000 #define GPD_SIZE 0x34 #define TC0_SIZE 0x14 void Alarm_Beeper_device_release(struct device * pdev); static struct resource Alarm_Beeper_resource[]={ [0] = { .start = S5PV210_GPD_BASE, .end = S5PV210_GPD_BASE + GPD_SIZE, .name = "GPD_BASE", .flags = IORESOURCE_MEM, }, [1] = { .start = S5PV210_TC_BASE, .end = S5PV210_TC_BASE + TC0_SIZE, .name = "TC0_BASE", .flags = IORESOURCE_MEM, }, }; struct platform_device Alarm_Beeper_device={ .name = "Alarm_Beeper_drv", .id = -1, .dev={ .release=Alarm_Beeper_device_release, }, .num_resources = ARRAY_SIZE(Alarm_Beeper_resource), .resource = Alarm_Beeper_resource, }; void Alarm_Beeper_device_release(struct device * pdev) { printk("entering %s\n",__FUNCTION__); } static int __init Alarm_Beeper_device_init(void) { printk("entering %s\n",__FUNCTION__); if(platform_device_register(&Alarm_Beeper_device)){ printk("%s: platform_device_register failed! \n",__FUNCTION__); return -EBUSY; } return 0; } static void __exit Alarm_Beeper_device_exit(void) { printk("entering %s\n",__FUNCTION__); platform_device_unregister(&Alarm_Beeper_device); } module_init(Alarm_Beeper_device_init); module_exit(Alarm_Beeper_device_exit); MODULE_AUTHOR("kinyanderson"); MODULE_DESCRIPTION("Alarm_Beeper_device,use for controlling the beeper"); MODULE_LICENSE("GPL");
app.c#include <asm/io.h> #include <asm/uaccess.h> #include <linux/fs.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/miscdevice.h> #define DEBUG 1 #define SINGLE_MODULE 1 #define MAGIC_WORD 'w' #define ALARM_BEEPER_OFF _IO(MAGIC_WORD,10) #define ALARM_BEEPER_ON _IO(MAGIC_WORD,11) #define ALARM_BEEPER_SPEED_UP _IO(MAGIC_WORD,12) #define ALARM_BEEPER_SPEED_DOWN _IO(MAGIC_WORD,13) #define ALARM_BEEPER_SPEED_DEFAULT _IO(MAGIC_WORD,20) struct Alarm_Beeper_Info{ unsigned int pclk_freq; unsigned int input_freq; unsigned int prescale_value; unsigned int mux_divide_value; unsigned int duty_cycle_numerator; unsigned int duty_cycle_denominator; unsigned int tcntb_value; unsigned short ALARM_BEEPER_status; }; #define ALARM_BEEPER_RUNNING 1 #define ALARM_BEEPER_STOPPED 0 /* 1-255 */ #define DEFAULT_PRESCALE_DIVIDE_VALUE 250 /* 1/1 1/2 1/4 1/8 1/16 */ #define DEFAULT_MUX_DIVIDE_VALUE 16 #define PCLK_FREQ 66000000 #define DEFAULT_INPUT_FREQ (66000000/DEFAULT_PRESCALE_DIVIDE_VALUE/DEFAULT_MUX_DIVIDE_VALUE) #define DEFAULT_TCNTB_VALUE DEFAULT_INPUT_FREQ #define DEFAULT_DUTY_CYCLE_NUMERATOR 1 #define DEFAULT_DUTY_CYCLE_DENOMINATOR 2 static struct Alarm_Beeper_Info alarm_beeper_info={ .pclk_freq = PCLK_FREQ, .input_freq = DEFAULT_INPUT_FREQ, .prescale_value = DEFAULT_PRESCALE_DIVIDE_VALUE, .mux_divide_value = DEFAULT_MUX_DIVIDE_VALUE, .tcntb_value = DEFAULT_TCNTB_VALUE, .duty_cycle_numerator = DEFAULT_DUTY_CYCLE_NUMERATOR, .duty_cycle_denominator = DEFAULT_DUTY_CYCLE_DENOMINATOR, .ALARM_BEEPER_status = ALARM_BEEPER_STOPPED, }; struct resource * platform_resource[2]; static volatile unsigned long * GPD0_BASE; static volatile unsigned long * TC0_BASE; #define TCFG0 (TC0_BASE + 0) #define TCFG1 (TC0_BASE + 1) #define TCON (TC0_BASE + 2) #define TCNTB0 (TC0_BASE + 3) #define TCMPB0 (TC0_BASE + 4) #define TCNTB_CURRENT 16500 #define TCNTB_MAX (TCNTB_CURRENT * 128) #define TCNTB_MIN (TCNTB_CURRENT / 128) //GPD0CON[3:0] = 0000 default input 0010 is TOUT0 #define GPD0_SET_INPUT(tmp) do{ \ tmp =ioread32(GPD0_BASE); \ tmp &= ~(0xf<<0); \ iowrite32(tmp,GPD0_BASE); \ }while(0) #define GPD0_SET_TOUT0(tmp) do{ \ tmp =ioread32(GPD0_BASE); \ tmp &= ~(0xf<<0); \ tmp |= (0x2<<0); \ iowrite32(tmp,GPD0_BASE); \ }while(0) #define TCNTB0_SET_VALUE(tmp,value) do{ \ tmp =ioread32(TCNTB0); \ tmp &= ~(0xffffffff<<0); \ tmp |= (value << 0); \ iowrite32(tmp,TCNTB0); \ }while(0) #define TIMER0_TCON_CLEAR(tmp) do{ \ tmp =ioread32(TCON); \ tmp &= ~(0xf<<0); \ iowrite32(tmp,TCON); \ }while(0) #define TIMER0_TCON_SET(tmp) do{ \ tmp =ioread32(TCON); \ tmp |= (0x1<<3)|(0x1<<2); \ iowrite32(tmp,TCON); \ }while(0) #define TIMER0_TCON_UPDATE(tmp) do{ \ tmp =ioread32(TCON); \ tmp |= (0x1<<1); \ iowrite32(tmp,TCON); \ udelay(5); \ tmp &= ~(0x1<<1); \ iowrite32(tmp,TCON); \ }while(0) #define TIMER0_START(tmp) do{ \ tmp =ioread32(TCON); \ tmp |= (0x1<<0); \ iowrite32(tmp,TCON); \ }while(0) #define TIMER0_STOP(tmp) do{ \ tmp =ioread32(TCON); \ tmp &= ~(0x1<<0); \ iowrite32(tmp,TCON); \ }while(0) /*** file_operation_function declare ****/ int Alarm_Beeper_driver_open (struct inode * inode_p, struct file *file_p); long Alarm_Beeper_driver_ioctl (struct file *file_p, unsigned int cmd, unsigned long arg); int Alarm_Beeper_driver_close (struct inode *inode_p, struct file *file_p); static int __devexit Alarm_Beeper_driver_remove(struct platform_device * pdev); static int __devinit Alarm_Beeper_dirver_probe(struct platform_device * pdev); /*** Struct declare ****/ static struct platform_driver Alarm_Beeper_driver={ .probe = Alarm_Beeper_dirver_probe, .remove = Alarm_Beeper_driver_remove, .driver = { .name = "Alarm_Beeper_drv", .owner = THIS_MODULE, }, }; static struct file_operations Alarm_Beeper_fop={ .open = Alarm_Beeper_driver_open, .unlocked_ioctl = Alarm_Beeper_driver_ioctl, .release = Alarm_Beeper_driver_close, }; static struct miscdevice Alarm_Beeper_miscdev = { .minor = MISC_DYNAMIC_MINOR, //dynamic .name = "smarthome_alarm_beeper", .fops = &Alarm_Beeper_fop, }; /*** file_operation_function implement ****/ int Alarm_Beeper_driver_open (struct inode * inode_p, struct file *file_p) { printk("entering %s\n",__FUNCTION__); unsigned int tmp; /* initing the gpio */ GPD0_SET_INPUT(tmp); printk("%s: gpio init finished!!!\n",__FUNCTION__); /* initing the timer0 */ //Timer Input Frequency = PCLK / ( {prescaler value + 1} ) / {divider value} //TCFG0[7:0] =249 (250) PCLK=66MHz tmp =ioread32(TCFG0); tmp &= ~(0xff<<0); tmp |= ((alarm_beeper_info.prescale_value- 1)<<0); //TCFG1[3:0] =0100 (1/16) 66M/250/16 = 16500 tmp =ioread32(TCFG1); tmp &= ~(0xf<<0); switch(alarm_beeper_info.mux_divide_value){ case 1: tmp |= (0x0<<0); break; case 2: tmp |= (0x1<<0); break; case 4: tmp |= (0x2<<0); break; case 8: tmp |= (0x3<<0); break; case 16: tmp |= (0x4<<0); break; default: tmp |= (0x5<<0); break; } iowrite32(tmp,TCFG1); TCNTB0_SET_VALUE(tmp,alarm_beeper_info.tcntb_value); tmp =ioread32(TCMPB0); tmp &= ~(0xffffffff<<0); tmp |=(alarm_beeper_info.input_freq - alarm_beeper_info.input_freq * alarm_beeper_info.duty_cycle_numerator / alarm_beeper_info.duty_cycle_denominator); iowrite32(tmp,TCMPB0); //TCON[3][2][1][0]=1110 [0]=0 default stop TIMER0_TCON_CLEAR(tmp); TIMER0_TCON_UPDATE(tmp); TIMER0_TCON_SET(tmp); alarm_beeper_info.ALARM_BEEPER_status = ALARM_BEEPER_STOPPED; printk("%s: timer0 init finished!!!\n",__FUNCTION__); return 0; } long Alarm_Beeper_driver_ioctl (struct file *file_p, unsigned int cmd, unsigned long arg) { printk("entering %s\n",__FUNCTION__); unsigned int tmp; if(_IOC_TYPE(cmd) != MAGIC_WORD) return -EINVAL; switch(cmd) { case ALARM_BEEPER_ON: if(alarm_beeper_info.ALARM_BEEPER_status == ALARM_BEEPER_RUNNING){ return 0; } GPD0_SET_TOUT0(tmp); TIMER0_START(tmp); alarm_beeper_info.ALARM_BEEPER_status=ALARM_BEEPER_RUNNING; break; case ALARM_BEEPER_SPEED_UP : if(alarm_beeper_info.tcntb_value<=TCNTB_MIN){ return 0; } alarm_beeper_info.tcntb_value /= 2; TIMER0_TCON_CLEAR(tmp); TCNTB0_SET_VALUE(tmp,alarm_beeper_info.tcntb_value); TIMER0_TCON_UPDATE(tmp); TIMER0_TCON_SET(tmp); TIMER0_START(tmp); alarm_beeper_info.ALARM_BEEPER_status=ALARM_BEEPER_RUNNING; break; case ALARM_BEEPER_SPEED_DOWN: if(alarm_beeper_info.tcntb_value>=TCNTB_MAX){ return 0; } alarm_beeper_info.tcntb_value *= 2; TIMER0_TCON_CLEAR(tmp); TCNTB0_SET_VALUE(tmp,alarm_beeper_info.tcntb_value); TIMER0_TCON_UPDATE(tmp); TIMER0_TCON_SET(tmp); TIMER0_START(tmp); alarm_beeper_info.ALARM_BEEPER_status=ALARM_BEEPER_RUNNING; break; case ALARM_BEEPER_SPEED_DEFAULT: alarm_beeper_info.tcntb_value = DEFAULT_TCNTB_VALUE; TIMER0_TCON_CLEAR(tmp); TCNTB0_SET_VALUE(tmp,alarm_beeper_info.tcntb_value); TIMER0_TCON_UPDATE(tmp); TIMER0_TCON_SET(tmp); TIMER0_START(tmp); alarm_beeper_info.ALARM_BEEPER_status=ALARM_BEEPER_RUNNING; break; case ALARM_BEEPER_OFF: if(alarm_beeper_info.ALARM_BEEPER_status == ALARM_BEEPER_STOPPED){ return 0; } TIMER0_STOP(tmp); GPD0_SET_INPUT(tmp); alarm_beeper_info.ALARM_BEEPER_status=ALARM_BEEPER_STOPPED; break; default: printk("%s: invalid command !!!\n",__FUNCTION__); break; } return 0; } int Alarm_Beeper_driver_close (struct inode *inode_p, struct file *file_p) { printk("entering %s\n",__FUNCTION__); unsigned int tmp; TIMER0_STOP(tmp); GPD0_SET_INPUT(tmp); alarm_beeper_info.ALARM_BEEPER_status=ALARM_BEEPER_STOPPED; return 0; } /*** driver_operation ****/ static int __devinit Alarm_Beeper_dirver_probe(struct platform_device * pdev) { printk("entering %s\n",__FUNCTION__); struct resource * pcheck; platform_resource[0]=platform_get_resource(pdev,IORESOURCE_MEM,0); if(NULL==platform_resource[0]){ printk("%s: platform_get_resource[0] failed!\n",__FUNCTION__); goto err1; } #if SINGLE_MODULE pcheck=request_mem_region(platform_resource[0]->start, platform_resource[0]->end - platform_resource[0]->start + 1, platform_resource[0]->name); if(NULL == pcheck){ printk("%s: request_mem_region failed!\n",__FUNCTION__); goto err1; //return device busy! } #endif GPD0_BASE=(unsigned long *)ioremap(platform_resource[0]->start, platform_resource[0]->end - platform_resource[0]->start + 1); platform_resource[1]=platform_get_resource(pdev,IORESOURCE_MEM,1); if(NULL == platform_resource[1]){ printk("%s: platform_get_resource[1] failed!\n",__FUNCTION__); goto err2; } #if SINGLE_MODULE pcheck=request_mem_region(platform_resource[1]->start, platform_resource[1]->end - platform_resource[1]->start + 1, platform_resource[1]->name); if(NULL == pcheck){ printk("%s: request_mem_region failed!\n",__FUNCTION__); goto err2; //return device busy! } #endif TC0_BASE=(unsigned long *)ioremap(platform_resource[1]->start, platform_resource[1]->end - platform_resource[1]->start + 1); #if DEBUG printk("%s: GPD0_BASE is %p \n",__FUNCTION__,GPD0_BASE); printk("%s: TC0_BASE is %p \n",__FUNCTION__,TC0_BASE); printk("%s: TCFG0 is %p \n",__FUNCTION__,TCFG0); printk("%s: TCFG1 is %p \n",__FUNCTION__,TCFG1); printk("%s: TCON is %p \n",__FUNCTION__,TCON); printk("%s: TCNTB0 is %p \n",__FUNCTION__,TCNTB0); printk("%s: TCMPB0 is %p \n",__FUNCTION__,TCMPB0); #endif if(misc_register(&Alarm_Beeper_miscdev)){ printk("%s: misc_register failed!\n",__FUNCTION__); goto err3; //release the memory! } return 0; err3: iounmap(TC0_BASE); #if SINGLE_MODULE release_mem_region(platform_resource[1]->start, platform_resource[1]->end - platform_resource[1]->start + 1); #endif err2: iounmap(GPD0_BASE); #if SINGLE_MODULE release_mem_region(platform_resource[0]->start, platform_resource[0]->end - platform_resource[0]->start + 1); #endif err1: return -EBUSY; } static int __devexit Alarm_Beeper_driver_remove(struct platform_device * pdev) { printk("entering %s\n",__FUNCTION__); iounmap(TC0_BASE); iounmap(GPD0_BASE); #if SINGLE_MODULE release_mem_region(platform_resource[1]->start, platform_resource[1]->end - platform_resource[1]->start + 1); release_mem_region(platform_resource[0]->start, platform_resource[0]->end - platform_resource[0]->start + 1); #endif if(misc_deregister(&Alarm_Beeper_miscdev)){ printk("%s:misc_deregister failed!\n",__FUNCTION__); return -EPERM; } return 0; } static int __init Alarm_Beeper_driver_init(void) { printk("entering %s\n",__FUNCTION__); if(platform_driver_register(&Alarm_Beeper_driver)){ printk("%s: driver_register failed!\n",__FUNCTION__); return -EBUSY; } return 0; } static void __exit Alarm_Beeper_driver_exit(void) { printk("entering %s\n",__FUNCTION__); platform_driver_unregister(&Alarm_Beeper_driver); } module_init(Alarm_Beeper_driver_init); module_exit(Alarm_Beeper_driver_exit); MODULE_AUTHOR("kinyanderson"); MODULE_DESCRIPTION("Alarm_Beeper_driver,use for controlling the beeper"); MODULE_LICENSE("GPL");
#include <stdio.h> #include <fcntl.h> #include <sys/ioctl.h> #define MAGIC_WORD 'w' #define ALARM_OFF _IO(MAGIC_WORD,10) #define ALARM_ON _IO(MAGIC_WORD,11) #define ALARM_SPEED_UP _IO(MAGIC_WORD,12) #define ALARM_SPEED_DOWN _IO(MAGIC_WORD,13) #define ALARM_SPEED_DEFAULT _IO(MAGIC_WORD,20) int main(int argc,char **argv) { int fd; int i; fd = open("/dev/smarthome_alarm_beeper",O_RDWR); if(fd < 0){ printf("can not open smarthome_alarm_beeper!!!\n"); return -1; } while(1) { ioctl(fd,ALARM_ON); sleep(5); ioctl(fd,ALARM_OFF); sleep(5); ioctl(fd,ALARM_ON); sleep(5); for(i=0;i<3;i++){ ioctl(fd,ALARM_SPEED_DOWN); sleep(5); } ioctl(fd,ALARM_SPEED_DEFAULT); sleep(5); for(i=0;i<3;i++){ ioctl(fd,ALARM_SPEED_UP); sleep(5); } ioctl(fd,ALARM_SPEED_DEFAULT); sleep(5); ioctl(fd,ALARM_OFF); sleep(10); } close(fd); printf("the app finished!!!\n"); return 0; }
Makefile
obj-m += Alarm_Beeper_device.o Alarm_Beeper_driver.o
KDIR := /home/kinyanderson/final_design/android-kernel-samsung-dev
modules:
make modules -C $(KDIR) M=`pwd`
arm-linux-gcc app.c -o app
clean:
make modules clean -C $(KDIR) M=`pwd`