Buzzer driver source code in the/driver/char/buzzer/x210-buzzer.c file, the source code is as follows
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h># include <linux/init.h> #include <linux/delay.h> #include <linux/poll.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/interrupt.h> #include < asm/uaccess.h> #include <mach/hardware.h> #include <plat/regs-timer.h> #include <mach/regs-irq.h> #include <asm/mach/time.h> #include <linux/clk.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/miscdevice.h> #include <linux/gpio.h> #include <plat/gpio-cfg.h>//#include <plat/regs-clock.h>//#include <plat/regs-gpio.h>//#include <plat/gpio-bank-e.h>//#include <plat/gpio-bank-f.h >//#include <plat/gpio-bank-k.h> #define DEVICE_NAME "buzzer" # Define pwm_ioctl_seT_FREQ1#DEFINE&NBSP;PWM_IOCTL_STOP0STATIC&NBSP;STRUCT&NBSP;SEMAPHORE&NBSP;LOCK;//&NBSP;TCFG0 is set in Uboot and is not repeated here timer0 Input Frequency finput=pclk/(prescaler1+1)/mux1// =66M/16/16// TCFG0 = tcnt = (PCLK/16/16)/freq;// pwm0 output frequency foutput =finput/tcfg0= freqstatic void Pwm_set_freq ( unsigned long freq ) {unsigned long tcon;unsigned long tcnt;unsigned long tcfg1;struct clk *clk_p;unsigned long pclk;//unsigned tmp;//set Gpd0_2 to PWM output S3c_gpio_cfgpin (s5pv210_gpd0 (2), &NBSP;S3C_GPIO_SFN (2)); Tcon = __raw_readl ( S3c2410_tcon); Tcfg1 = __raw_readl (S3C2410_TCFG1);//mux = 1/16tcfg1 &= ~ (0xf <<8);tcfg1 |= (0x4<<8); __raw_writel (TCFG1,&NBSP;S3C2410_TCFG1); clk_p = clk_get (null, "PCLK");p Clk&nbsP; = clk_get_rate (clk_p);tcnt = (PCLK/16/16)/freq;__raw_writel (tcnt, S3C2410_ TCNTB (2)); __raw_writel (TCNT/2,&NBSP;S3C2410_TCMPB (2));//Duty ratio is 50%tcon &= ~ (0xf<<12); Tcon |= (0xb<<12);//disable deadzone, auto-reload, inv-off, update tcntb0 &tcmpb0, start timer 0__raw_writel (Tcon, s3c2410_tcon); tcon &= ~ (2< <12);//clear manual update bit__raw_writel (Tcon, s3c2410_tcon);} Void pwm_stop ( void ) {//Gpd0_2 set to Inputs3c_gpio_cfgpin (S5pv210_gpd0 (2), &NBSP;S3C_GPIO_SFN (0));} Static int x210_pwm_open (struct inode *inode, struct file *file) {if (! Down_trylock (&lock)) Return 0;elsereturn -ebusy;} Static int x210_pwm_close (Struct inode *inode, struct file *file) {Up (& lock); return 0;} pwm:gpf14->pwm0static int x210_pwm_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned Long arg) {switch (cmd) {case pwm_ioctl_set_freq:printk ("pwm_ioctl_set_freq:\r\n");if (arg == 0) return -einval; Pwm_set_freq (ARG); BREAK;CASE&NBSP;PWM_IOCTL_STOP:DEFAULT:PRINTK ("pwm_ioctl_stop:\r\n"); Pwm_stop (); break;} return 0;} static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = x210_pwm_open, .release = x210_pwm_close, .ioctl = x210_pwm_ioctl,};static struct miscdevice misc = {.minor = misc_dynamic_minor,.name = device_name,.fops = &dev_ Fops,};static int __init dev_init (void) {Int ret;init_MUTEX (&lock); Ret = misc_register (&misc);/* gpd0_2 (PWMTOUT2) */ret = gpio_request (s5pv210_gpd0 (2), "GPD0"), if (ret) PRINTK ("Buzzer-x210: request gpio gpd0 ( 2) fail "); S3c_gpio_setpull (S5pv210_gpd0 (2), s3c_gpio_pull_up); S3c_gpio_cfgpin (S5PV210_GPD0 (2), S3C_GPIO_SFN (1)); Gpio_set_value (S5pv210_gpd0 (2), 0);p rintk ("x210 " Device_name " Initialized\n "); return ret;} Static void __exit dev_exit (void) {misc_deregister (&MISC);} Module_init (Dev_init); Module_exit (Dev_exit); Module_license ("GPL"); Module_author ("www.9tripod.com"); Module_description ("X210 pwm driver");
The driver module code for the buzzer is as above. As with other driver module code, the function in Module_init is the function that runs when the driver module is loaded (INSMD), and the function in Module_exit is the function that runs when the driver module is unloaded (RMMOD).
First, look at the function Dev_init function executed when the Module_init driver is loaded, and the Code analysis is as follows
static int __init dev_init (void) {int Ret;init_mutex (&lock); ret = Misc_register (&MISC);/* Gpd0_2 (PWMTOUT2) */ ret = Gpio_request (s5pv210_gpd0 (2), "GPD0"), if (ret) PRINTK ("Buzzer-x210:request Gpio GPD0 (2) fail"); S3c_gpio_setpull ( S5PV210_GPD0 (2), s3c_gpio_pull_up), S3c_gpio_cfgpin (S5pv210_gpd0 (2), S3C_GPIO_SFN (1)); Gpio_set_value (S5PV210_GPD0 (2), 0);p rintk ("x210" Device_name "initialized\n"); return ret;}
Init_mutex in the above code (&LOCK), this lock is defined in this file globally, defined as follows, the INIT_MUTEXH function is the initialization of the semaphore, the semaphore count value is initialized to 1. The value of the count is initialized to 1 of the semaphore is actually a mutex, by this code can be known, the writer's intention is to use the mutex, but there may be no mutex at that time, only the signal volume, so with the signal to achieve the mutual exclusion lock. Because the semaphore count value is 1, it is similar to a mutex. Because the semaphore does not have the best mutual-exclusion lock optimization, the use of semaphores here is actually not the current mainstream.
static struct semaphore lock;
Struct semaphore is a semaphore structure with different semaphores and mutexes already mentioned. The contents of the structure are as follows
struct semaphore {spinlock_tlock;unsigned intcount;struct list_headwait_list; The waiting queue for semaphores};
In the Dev_init function, the next code is
ret = Misc_register (&MISC);
Misc_register is a function that registers a misc spurious device, and the parameter misc is a structure variable that is defined in the global and filled with the contents as follows
static struct Miscdevice misc = {//The MISCDEVICE structure is defined here and populated with three members, populated according to the actual situation. minor = Misc_dynamic_minor,//secondary device number minor members are assigned The value is the value of the Misc_dynamic_minor macro (255), which previously said that the value means let the kernel automatically assign the secondary device//number to us: name = device_name,//The Set Name, the device name is not as important as the name of the Platform platform bus mechanism (because it is used to macth function matching device and driver//). Here the name function is only used to record: FoPs = &dev_fops,//operation method of the device};
The FoPs member in the strcut miscdevice struct defined above is bound to Dev_fops,dev_fops is also defined in this file's global, the structure contains the operation of this driver and the method, the content is as follows
static struct File_operations Dev_fops = {. Owner = This_module,. Open = X210_pwm_open,//application-layer open operation of the device file The function that executes when the. Release = X210_pwm_close,//Application layer Close functions that are executed when the device file is manipulated. IOCTL = X210_PWM_IOCTL,//Application layer IOCTL executes when the device file is manipulated 's function};
After Misc_register (&MISC), the misc device and its driver operating methods are registered to complete the registration of spurious devices.
In the Dev_init function the next code is the buzzer hardware-related settings, according to the hardware schematic view of the buzzer corresponding GPIO, the operation is set as follows
/* gpd0_2 (PWMTOUT2) */ret = gpio_request (s5pv210_gpd0 (2), "GPD0"); //request the Gpiod0_2 PIN resource if (ret) PRINTK ("Buzzer-x210: request gpio gpd0 (2) fail") to the kernel; s3c _gpio_setpull (S5pv210_gpd0 (2), s3c_gpio_pull_up) //after applying to the kernel, set gpiod0_2 pin as pull-up S3C_GPIO _cfgpin (S5pv210_gpd0 (2), &NBSP;S3C_GPIO_SFN (1)), //sets the Gpiod0_2 pin's mode to S3C_GPIO_SFN (1) Mode (special Mode 1, according to manual is output //mode, details of the data sheet) Gpio_set_value (s5pv210_gpd0 (2), 0); // The initial output of this pin is set to 0 low because it is initialized to 0 low, so the buzzer will not start ringing. printk ("x210 " Device_name " initialized\n"); //device_name macros are device names, whichPrinting information, the compilation will print the string represented by the macro. return ret;
The above analysis has finished analyzing what happened when the buzzer driver module was loaded (Dev_init). The successful execution of the Dev_init function indicates that the driver has been installed and the driver code is in standby state. Wait for the application layer to operate.
When the application layer opens the buzzer device file with open, the corresponding driver execution function is X210_pwm_open, the code is as follows
static int X210_pwm_open (struct inode *inode, struct file *file) {if (!down_trylock (&lock))///Because the buzzer is a simple device, so the open function is Empty, here just performed a lockout operation to prevent the buzzer device from being opened multiple return 0; Use a non-blocking way to try to lock the elsereturn-ebusy;}
This article from "Whylinux" blog, declined reprint!
Linux Driver Development Buzzer driver Source analysis (i)