mini2440驱动分析之PWM
1. pwm驱动也是作为杂项设备注册的,同样为了防止并发造成的竞态,有个信号量保护。模块的初始化函数
这个函数就是初始化了一个信号量,然后调用misc_register注册到杂项设备
- static int __init dev_init(void)
- {
- int ret;
- init_MUTEX(&lock);
- ret = misc_register(&misc);
- printk (DEVICE_NAME"\tinitialized\n");
- return ret;
- }
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\n", 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;
- }
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);
- }