1. pwm驱动也是作为杂项设备注册的,同样为了防止并发造成的竞态,有个信号量保护。模块的初始化函数
- static int __init dev_init(void)
- {
- int ret;
-
- init_MUTEX(&lock);
- ret = misc_register(&misc);
-
- printk (DEVICE_NAME" initialized
");
- return ret;
- }
这个函数就是初始化了一个信号量,然后调用misc_register注册到杂项设备 2. 这个pwm驱动的基本功能体现在ioctl方法上
- static int s3c24xx_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
- {
- //printk("ioctl pwm: %x %lx
", cmd, arg);
- switch (cmd) {
- case PWM_IOCTL_SET_FREQ:
- if (arg == 0)
- return -EINVAL;
- PWM_Set_Freq(arg);
- break;
-
-
- case PWM_IOCTL_STOP:
- PWM_Stop();
- break;
- }
- return 0;
- }
可以看出,只提供两个选项,一个是设置频率(调用PWM_Set_Freq函数),一个是停止。其他的功能都没有,这充分体现驱动程序中 “提供机制而不是提供策略”的思想,驱动程序中只提供基本的功能实现,其他复杂的功能由应用程序提供。
3. PWM_Set_Freq(arg)函数分析
- static void PWM_Set_Freq( unsigned long freq )
- {
- unsigned long tcon;
- unsigned long tcnt;
- unsigned long tcfg1;
- unsigned long tcfg0;
-
-
- struct clk *clk_p;
- unsigned long pclk;
-
-
- //set GPB0 as tout0, pwm output
- s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
-
-
- tcon = __raw_readl(S3C2410_TCON);
- tcfg1 = __raw_readl(S3C2410_TCFG1);
- tcfg0 = __raw_readl(S3C2410_TCFG0);
-
-
- //prescaler = 50
- tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
- tcfg0 |= (50 - 1);
-
-
- //mux = 1/16
- tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
- tcfg1 |= S3C2410_TCFG1_MUX0_DIV16;
-
-
- __raw_writel(tcfg1, S3C2410_TCFG1);
- __raw_writel(tcfg0, S3C2410_TCFG0);
-
-
- clk_p = clk_get(NULL, "pclk");
- pclk = clk_get_rate(clk_p);
- tcnt = (pclk/50/16)/freq;
-
- __raw_writel(tcnt, S3C2410_TCNTB(0));
- __raw_writel(tcnt/2, S3C2410_TCMPB(0));
-
- tcon &= ~0x1f;
- tcon |= 0xb; //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0
- __raw_writel(tcon, S3C2410_TCON);
-
- tcon &= ~2; //clear manual update bit
- __raw_writel(tcon, S3C2410_TCON);
- }
主要是对操作pwm的寄存器进行设置,跟裸机的设置一样,但是可以看出,驱动程序中设置寄存器都是采用读修改写的方式进行的。 像S3C2410_TCON S3C2410_TCFG1_MUX0_MASK 都是在regs-timer.h中定义的,直接使用就可以了。