/* * gsc3280_pwm.c - driver for pwm in blx gsc3280 soc * * Copyright (C) 2012 BLX Corporation * * 2013-04-08 */ #include #include #include #include #include #include #include #include #include #include #define PWMODE 0x0 #define PWMCTRL 0x4 #define MCPWMCTRL 0x8 #define PWMCAPCTRL 0xc #define PWMCNTCTRL 0x10 #define PWMIR 0x14 #define PWMIER 0x18 #define PWMTC0 0x1c #define PWMTC1 0x20 #define PWMTC2 0x24 #define PWMLIM0 0x28 #define PWMLIM1 0x2C #define PWMLIM2 0x30 #define PWMMR0_1 0x34 #define PWMMR0_2 0x38 #define PWMMR1_1 0x3c #define PWMMR1_2 0x40 #define PWMMR2_1 0x44 #define PWMMR2_2 0x48 #define PWMCAP0 0x4c #define PWMCAP1 0x50 #define PWMCAP2 0x54 #define PWMMCR 0x58 #define PWMDT 0x5c #define PWMCPR 0x60 #define PWMLER 0x64 #define LOAD_11 11 #define LOAD_10 10 #define LOAD_9 9 #define LOAD_8 8 #define LOAD_7 7 #define LOAD_6 6 #define LOAD_5 5 #define LOAD_4 4 #define LOAD_3 3 #define LOAD_2 2 #define LOAD_1 1 #define LOAD_0 0 #define SINGLE 15 #define POLA5 14 #define POLA4 13 #define POLA3 12 #define POLA2 11 #define POLA1 10 #define POLA0 9 #define PWMSEL2 8 #define PWMSEL1 7 #define PWMSEL0 6 #define PWMEN5 5 #define PWMEN4 4 #define PWMEN3 3 #define PWMEN2 2 #define PWMEN1 1 #define PWMEN0 0 #define CMD_PWM0_START 0x01 #define CMD_PWM0_STOP 0x02 #define CMD_PWM0_R0 0x03 #define CMD_PWM0_R1 0x04 #define CMD_PWM0_LIM 0x05 #define CMD_PWM1_START 0x11 #define CMD_PWM1_STOP 0x12 #define CMD_PWM1_R0 0x13 #define CMD_PWM1_R1 0x14 #define CMD_PWM1_LIM 0x15 #define CMD_PWM2_START 0x21 #define CMD_PWM2_STOP 0x22 #define CMD_PWM2_R0 0x23 #define CMD_PWM2_R1 0x24 #define CMD_PWM2_LIM 0x25 #define CMD_SET_PWM_FREQ 0x31 #define CMD_GET_PWM_FREQ 0x32 #define CMD_SET_RENC 0x40 #define CMD_GET_RENC 0x41 #define DEBUG_PWM 0 static unsigned char __iomem *pwm_base = NULL; struct resource *res; static int gsc3280_pwm_probe(struct platform_device *pdev); struct platform_device *pwm_dev; static struct clk *pwm0_clk = NULL; static struct clk *pwm1_clk = NULL; static struct clk *pwm2_clk = NULL; static struct clk *pwmr_clk = NULL; static struct platform_driver gsc3280_pwm_driver = { .probe = gsc3280_pwm_probe, .driver = { .name = "gsc3280-pwm", }, }; static inline void gsc3280_pwm_writel( unsigned int val, unsigned int off) { __raw_writel(val, pwm_base + off); #if DEBUG_PWM printk(KERN_ALERT"in write pwm_base=%lx",pwm_base); printk(KERN_ALERT"in write val=%d",val); printk(KERN_ALERT"in write off=%x",off); #endif #if DEBUG_PWM volatile unsigned int *p = pwm_base+off; volatile unsigned int *sysctl = 0xbc04a008; volatile unsigned int *iomux = 0xbc04a0b0; volatile unsigned int *pwm_r2=0xbc105044; printk(KERN_ALERT"in write sysctl=%x\n",*sysctl); printk(KERN_ALERT"in write iomux=%x\n",*iomux); printk(KERN_ALERT"in write iomux=%x\n",*iomux); printk(KERN_ALERT"in write pwm_r2=%x\n",*pwm_r2); #endif /* *iomux=(*iomux & ~(1<<10)); *pwm_r2=11111; *(volatile unsigned int*)0xbc105064 = 0xfff; printk(KERN_ALERT"in write pwm_r2=%x\n",*pwm_r2); *(volatile unsigned int*)0xbc105000 = 1; printk(KERN_ALERT"0xbc105000 is 0x%x\n", *(volatile unsigned int*)0xbc105000); *p=val; printk(KERN_ALERT"in write data=%d",*p); *p=10; printk(KERN_ALERT"in write data=%d",*p);*/ } static inline unsigned int gsc3280_pwm_readl( unsigned int off) { return __raw_readl(pwm_base + off); } static void pwm_set_ctl(int value) { gsc3280_pwm_writel(value,PWMCTRL); } static void pwm_set_LIM(int channel, int value){ switch(channel){ case 0: gsc3280_pwm_writel(value,PWMLIM0); break; case 1: gsc3280_pwm_writel(value,PWMLIM1); break; case 2: gsc3280_pwm_writel(value,PWMLIM2); #if DEBUG_PWM unsigned long *p; p=pwm_base+PWMLIM2; printk(KERN_ALERT"value==%d\n",value); printk(KERN_ALERT"PWMLIM2==%ld\n",*p); printk(KERN_ALERT"PWMLIM2_ADDR==%x\n",p); #endif break; default: printk(KERN_ERR"no channel %d\n", channel); } } static void pwm_set_mr(int channel, int regno, int value) { switch(channel){ case 0: if(regno == 0){ gsc3280_pwm_writel(value,PWMMR0_1); }else if(regno == 1){ gsc3280_pwm_writel(value,PWMMR0_2); }else{ printk(KERN_ERR"no reg %d\n", regno); } break; case 1: if(regno == 0){ gsc3280_pwm_writel(value,PWMMR1_1); }else if(regno == 1){ gsc3280_pwm_writel(value,PWMMR1_2); }else{ printk(KERN_ERR"no reg %d\n", regno); } break; case 2: if(regno == 0){ gsc3280_pwm_writel(value,PWMMR2_1); }else if(regno == 1){ gsc3280_pwm_writel(value,PWMMR2_2); }else{ printk(KERN_ERR"no reg %d\n", regno); } break; default: printk(KERN_ERR"no channel %d\n", channel); } } static int init_clk_output(int channel, int edge, int valid) { int value = gsc3280_pwm_readl(PWMCTRL); switch(channel){ case 0: pwm_set_ctl( value|1<dev, "pwm0"); if (IS_ERR(pwm0_clk)) { err = PTR_ERR(pwm0_clk); return err; } clk_enable(pwm0_clk); pwm1_clk = clk_get(&pwm_dev->dev, "pwm1"); if (IS_ERR(pwm1_clk)) { err = PTR_ERR(pwm1_clk); return err; } clk_enable(pwm1_clk); pwm2_clk = clk_get(&pwm_dev->dev, "pwm2"); if (IS_ERR(pwm2_clk)) { err = PTR_ERR(pwm2_clk); return err; } clk_enable(pwm2_clk); pwmr_clk = clk_get(&pwm_dev->dev, "pwmr"); if (IS_ERR(pwmr_clk)) { err = PTR_ERR(pwmr_clk); return err; } //clk_set_rate(pwmr_clk,5555555); clk_set_rate(pwmr_clk,20000000); clk_enable(pwmr_clk); return 0; } static int gsc3280_pwm_close(struct inode *inode, struct file *file) { clk_disable(pwm0_clk); clk_disable(pwm1_clk); clk_disable(pwm2_clk); clk_disable(pwmr_clk); clk_put(pwm0_clk); clk_put(pwm1_clk); clk_put(pwm2_clk); clk_put(pwmr_clk); return 0; } static ssize_t gsc3280_pwm_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) { return 0; } static ssize_t gsc3280_pwm_write(struct file *file, const char __user *buf, size_t count, loff_t *ptr) { return 0; } static int pwm_start(int channel) { init_clk_output(channel,0,1); switch(channel){ case 0: gsc3280_pwm_writel( 1<start, res->end); if (res1 != NULL) { release_mem_region(res->start, 0x0f); } res1 = request_mem_region(res->start, resource_size(res), "gsc3280-pwm"); if (res1 == NULL) { printk(KERN_ERR"Fail to request gsc3280_pwm region!\n"); return -ENOENT; } pwm_base = ioremap(res->start, res->end - res->start + 1); if (pwm_base == NULL) { printk(KERN_ERR"Fail to ioremap gsc3280_pwm resource!\n"); return -EINVAL; } return 0; } static int __devinit gsc3280_pwm_probe(struct platform_device *pdev) { pwm_dev = pdev; return gsc3280_pwm_getResourse(pdev, 0); } static int __init gsc3280_pwm_init(void) { if (misc_register(&gsc3280_pwm_miscdev)) { printk(KERN_WARNING "pwm: Couldn't register device 0, %d.\n", 255); return -EBUSY; } return platform_driver_register(&gsc3280_pwm_driver); } static void __exit gsc3280_pwm_exit(void) { misc_deregister(&gsc3280_pwm_miscdev); release_mem_region(res->start, 0x20); platform_driver_unregister(&gsc3280_pwm_driver); } module_init(gsc3280_pwm_init); module_exit(gsc3280_pwm_exit); MODULE_LICENSE("GPL");