656 lines
15 KiB
C
656 lines
15 KiB
C
|
/*
|
||
|
* gsc3280_pwm.c - driver for pwm in blx gsc3280 soc
|
||
|
*
|
||
|
* Copyright (C) 2012 BLX Corporation
|
||
|
*
|
||
|
* 2013-04-08
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <linux/miscdevice.h>
|
||
|
#include <linux/errno.h>
|
||
|
#include <linux/fs.h>
|
||
|
#include <asm/io.h>
|
||
|
#include <asm/uaccess.h>
|
||
|
#include <asm/ioctl.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/timer.h>
|
||
|
#include <linux/clk.h>
|
||
|
#include <linux/delay.h>
|
||
|
|
||
|
|
||
|
#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<<PWMEN0|1<<PWMEN1|edge<<PWMSEL0|valid<<POLA0|valid<<POLA1);
|
||
|
break;
|
||
|
case 1:
|
||
|
pwm_set_ctl( value|1<<PWMEN2|1<<PWMEN3|edge<<PWMSEL1|valid<<POLA2|valid<<POLA3);
|
||
|
break;
|
||
|
case 2:
|
||
|
pwm_set_ctl( value|1<<PWMEN4|1<<PWMEN5|edge<<PWMSEL2);
|
||
|
break;
|
||
|
default:
|
||
|
printk(KERN_ERR"no %x channel \n", channel);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int fini_clk_output(int channel, int edge, int valid)
|
||
|
{
|
||
|
|
||
|
int value = gsc3280_pwm_readl(PWMCTRL);
|
||
|
switch(channel){
|
||
|
case 0:
|
||
|
pwm_set_ctl(value & (~(1<<PWMEN0|1<<PWMEN1)));
|
||
|
break;
|
||
|
case 1:
|
||
|
pwm_set_ctl(value & (~(1<<PWMEN2|1<<PWMEN3)));
|
||
|
break;
|
||
|
case 2:
|
||
|
pwm_set_ctl(value & (~( 1<<PWMEN4|1<<PWMEN5)));
|
||
|
break;
|
||
|
default:
|
||
|
printk(KERN_ERR"no %x channel \n", channel);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#if 0 //for test
|
||
|
static void set_wave(int channel, int mr1, int mr2, int lim)
|
||
|
{
|
||
|
switch(channel){
|
||
|
case 0:
|
||
|
pwm_set_LIM(0,lim);
|
||
|
pwm_set_mr(0,0,mr1);
|
||
|
pwm_set_mr(0,1,mr2);
|
||
|
gsc3280_pwm_writel( 1<<LOAD_6|1<<LOAD_1|1<<LOAD_0, PWMLER);
|
||
|
break;
|
||
|
case 1:
|
||
|
pwm_set_LIM(1,lim);
|
||
|
pwm_set_mr(1,0,mr1);
|
||
|
pwm_set_mr(1,1,mr2);
|
||
|
gsc3280_pwm_writel( 1<<LOAD_7|1<<LOAD_2|1<<LOAD_3, PWMLER);
|
||
|
break;
|
||
|
case 2:
|
||
|
pwm_set_LIM(2,lim);
|
||
|
pwm_set_mr(2,0,mr1);
|
||
|
pwm_set_mr(2,1,mr2);
|
||
|
gsc3280_pwm_writel( 1<<LOAD_8|1<<LOAD_4|1<<LOAD_5, PWMLER);
|
||
|
break;
|
||
|
default:
|
||
|
printk(KERN_ERR"ctl is 0x%x\n", gsc3280_pwm_readl( PWMCTRL));
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static int gsc3280_pwm_open(struct inode *inode, struct file *file)
|
||
|
{
|
||
|
int err;
|
||
|
|
||
|
pwm0_clk = clk_get(&pwm_dev->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<<LOAD_6|1<<LOAD_1|1<<LOAD_0, PWMLER);
|
||
|
break;
|
||
|
case 1:
|
||
|
gsc3280_pwm_writel( 1<<LOAD_7|1<<LOAD_2|1<<LOAD_3, PWMLER);
|
||
|
break;
|
||
|
case 2:
|
||
|
gsc3280_pwm_writel( 1<<LOAD_8|1<<LOAD_4, PWMLER);
|
||
|
break;
|
||
|
default:
|
||
|
printk(KERN_ERR"ctl is 0x%x\n", gsc3280_pwm_readl( PWMCTRL));
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int pwm_stop(int channel)
|
||
|
{
|
||
|
fini_clk_output(channel,0,0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static long gsc3280_pwm_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
|
||
|
{
|
||
|
void __user *p = (void __user *)arg;
|
||
|
int renc_lim = 0;
|
||
|
#if DEBUG_PWM
|
||
|
printk(KERN_INFO"in intol before switch\n");
|
||
|
#endif
|
||
|
switch (cmd) {
|
||
|
|
||
|
case CMD_PWM0_START:
|
||
|
pwm_start(0);
|
||
|
break;
|
||
|
case CMD_PWM0_STOP:
|
||
|
pwm_stop(0);
|
||
|
break;
|
||
|
case CMD_PWM0_R0:
|
||
|
pwm_set_mr(0,0,arg);
|
||
|
break;
|
||
|
case CMD_PWM0_R1:
|
||
|
pwm_set_mr(0,1,arg);
|
||
|
break;
|
||
|
case CMD_PWM0_LIM:
|
||
|
pwm_set_LIM(0,arg);
|
||
|
break;
|
||
|
|
||
|
case CMD_PWM1_START:
|
||
|
pwm_start(1);
|
||
|
break;
|
||
|
case CMD_PWM1_STOP:
|
||
|
pwm_stop(1);
|
||
|
break;
|
||
|
case CMD_PWM1_R0:
|
||
|
pwm_set_mr(1,0,arg);
|
||
|
break;
|
||
|
case CMD_PWM1_R1:
|
||
|
pwm_set_mr(1,1,arg);
|
||
|
break;
|
||
|
case CMD_PWM1_LIM:
|
||
|
pwm_set_LIM(1,arg);
|
||
|
break;
|
||
|
|
||
|
case CMD_PWM2_START:
|
||
|
|
||
|
pwm_start(2);
|
||
|
|
||
|
|
||
|
#if DEBUG_PWM
|
||
|
printk(KERN_ALERT"0xbc105000 MODE=%x\n",*(volatile unsigned int*)0xbc105000);
|
||
|
printk(KERN_ALERT"0xbc105008 MCCTRL=%x\n",*(volatile unsigned int*)0xbc105008);
|
||
|
printk(KERN_ALERT"0xbc10500c CAPCTRL=%x\n",*(volatile unsigned int*)0xbc10500c);
|
||
|
printk(KERN_ALERT"0xbc105010 CNTCTRL=%x\n",*(volatile unsigned int*)0xbc105010);
|
||
|
printk(KERN_ALERT"0xbc105014 IR=%x\n",*(volatile unsigned int*)0xbc105014);
|
||
|
*(volatile unsigned int *)0xbc105014 = 0x1000;
|
||
|
//p = 0x1000;
|
||
|
printk(KERN_ALERT"0xbc105014 IR=%x\n",*(volatile unsigned int*)0xbc105014);
|
||
|
printk(KERN_ALERT"0xbc10505c DT=%x\n",*(volatile unsigned int*)0xbc10505c);
|
||
|
printk(KERN_ALERT"0xbc105068 RE_EN=%x\n",*(volatile unsigned int*)0xbc105068);
|
||
|
printk(KERN_ALERT"0xbc04a008 SYSCTL0=%x\n",*(volatile unsigned int*)0xbc04a008);
|
||
|
printk(KERN_ALERT"0xbc04a00c SYSCTL1=%x\n",*(volatile unsigned int*)0xbc04a00c);
|
||
|
printk(KERN_ALERT"0xbc04a0b0 IOMUX0=%x\n",*(volatile unsigned int*)0xbc04a0b0);
|
||
|
printk(KERN_ALERT"0xbc04a0b4 IOMUX1=%x\n",*(volatile unsigned int*)0xbc04a0b4);
|
||
|
printk(KERN_ALERT"0xbc105024 TC2=%x\n",*(volatile unsigned int*)0xbc105024);
|
||
|
printk(KERN_ALERT"0xbc105044 MR2_1=%x\n",*(volatile unsigned int*)0xbc105044);
|
||
|
printk(KERN_ALERT"0xbc105030 LIM=%x\n",*(volatile unsigned int*)0xbc105030);
|
||
|
printk(KERN_ALERT"0xbc105004 CTRL=%x\n",*(volatile unsigned int*)0xbc105004);
|
||
|
printk(KERN_ALERT"0xbc105064 LER=%x\n",*(volatile unsigned int*)0xbc105064);
|
||
|
printk(KERN_ALERT"0xbc105018 IER=%x\n",*(volatile unsigned int*)0xbc105018);
|
||
|
printk(KERN_ALERT"0xbc105000 MODE=%x\n",*(volatile unsigned int*)0xbc105000);
|
||
|
printk(KERN_ALERT"0xbc105010 CNTCTRL=%x\n",*(volatile unsigned int*)0xbc105010);
|
||
|
printk(KERN_ALERT"0xbc105058 MCR=%x\n",*(volatile unsigned int*)0xbc105058);
|
||
|
printk(KERN_ALERT"0xbc105024 TC2=%x\n",*(volatile unsigned int*)0xbc105024);
|
||
|
#endif
|
||
|
|
||
|
break;
|
||
|
case CMD_PWM2_STOP:
|
||
|
pwm_stop(2);
|
||
|
break;
|
||
|
case CMD_PWM2_R0:
|
||
|
#if DEBUG_PWM
|
||
|
printk(KERN_INFO"in CMD_PWM2_R0,value==%d\n",arg);
|
||
|
#endif
|
||
|
pwm_set_mr(2,0,arg);
|
||
|
break;
|
||
|
case CMD_PWM2_R1:
|
||
|
pwm_set_mr(2,1,arg);
|
||
|
break;
|
||
|
case CMD_PWM2_LIM:
|
||
|
#if DEBUG_PWM
|
||
|
printk(KERN_INFO"in CMD_PWM2_LIM,value==%d\n",arg);
|
||
|
#endif
|
||
|
pwm_set_LIM(2,arg);
|
||
|
break;
|
||
|
case CMD_SET_PWM_FREQ:
|
||
|
{
|
||
|
unsigned long rate;
|
||
|
copy_from_user(&rate, p, sizeof(rate));
|
||
|
if(pwm0_clk)
|
||
|
clk_set_rate(pwm0_clk, rate);
|
||
|
}
|
||
|
break;
|
||
|
case CMD_GET_PWM_FREQ:
|
||
|
{
|
||
|
unsigned long rate;
|
||
|
#if DEBUG_PWM
|
||
|
|
||
|
struct clk *pll_clk = (struct clk *)NULL;
|
||
|
struct clk *pclk_clk = NULL;
|
||
|
unsigned long pll_rate;
|
||
|
unsigned long pclk_rate;
|
||
|
int err;
|
||
|
pll_clk = clk_get(NULL, "pll");
|
||
|
if (IS_ERR(pll_clk)) {
|
||
|
err = PTR_ERR(pll_clk);
|
||
|
return err;
|
||
|
}
|
||
|
pll_rate = clk_get_rate(pll_clk);
|
||
|
printk(KERN_ALERT"pll rate is %ld\n", pll_rate);
|
||
|
|
||
|
pclk_clk = clk_get(NULL, "pclk");
|
||
|
if (IS_ERR(pclk_clk)) {
|
||
|
err = PTR_ERR(pclk_clk);
|
||
|
return err;
|
||
|
}
|
||
|
pclk_rate = clk_get_rate(pclk_clk);
|
||
|
printk(KERN_ALERT"pclk_rate is %ld\n", pclk_rate);
|
||
|
|
||
|
#endif
|
||
|
if(pwm0_clk)
|
||
|
{
|
||
|
rate = clk_get_rate(pwm0_clk);
|
||
|
|
||
|
#if DEBUG_PWM
|
||
|
printk(KERN_ALERT"pwm_rate=%ld\n",rate);
|
||
|
#endif
|
||
|
copy_to_user(p, &rate, sizeof(rate));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printk(KERN_ALERT"pwm_rate=NULL\n");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
case CMD_SET_RENC:
|
||
|
{
|
||
|
//copy_from_user(&renc_lim, p, sizeof(renc_lim));
|
||
|
renc_lim = p;
|
||
|
printk(KERN_ALERT"renc_lim is %d, p is %x\n",renc_lim, p);
|
||
|
break;
|
||
|
}
|
||
|
case CMD_GET_RENC:
|
||
|
{
|
||
|
#define RENC_EN 0x68
|
||
|
#define RENC_LIM 0x6c
|
||
|
#define RENC_M1 0x70
|
||
|
#define RENC_M2 0x74
|
||
|
#define RENC_M3 0x78
|
||
|
#define RENC_TC1 0x7C
|
||
|
#define RENC_TC2 0x80
|
||
|
#define RENC_TC3 0x84
|
||
|
#define RENC_STATE 0x88
|
||
|
|
||
|
struct rencs{
|
||
|
int direct;
|
||
|
int tc3;
|
||
|
int m1;
|
||
|
int m2;
|
||
|
int m3;
|
||
|
int fclk;
|
||
|
}renc;
|
||
|
|
||
|
gsc3280_pwm_writel(1,RENC_EN);
|
||
|
if(renc_lim)
|
||
|
gsc3280_pwm_writel(renc_lim, RENC_LIM);
|
||
|
else
|
||
|
gsc3280_pwm_writel(0xff00, RENC_LIM);
|
||
|
//gsc3280_pwm_writel(rarg[0], RENC_LIM);
|
||
|
|
||
|
while(!(gsc3280_pwm_readl(RENC_STATE) & 0x4)){
|
||
|
printk(KERN_ALERT"LIM is 0x%x\n",gsc3280_pwm_readl(RENC_LIM));
|
||
|
printk(KERN_ALERT"EN is 0x%x\n",gsc3280_pwm_readl(RENC_EN));
|
||
|
}
|
||
|
|
||
|
//udelay(200);
|
||
|
renc.direct =gsc3280_pwm_readl(RENC_STATE) & 0x3;
|
||
|
renc.tc3 = gsc3280_pwm_readl(RENC_TC3) & 0xffff;
|
||
|
renc.m1 = gsc3280_pwm_readl(RENC_M1) & 0xffff;
|
||
|
renc.m2 = gsc3280_pwm_readl(RENC_M2) & 0xffff;
|
||
|
renc.m3 = gsc3280_pwm_readl(RENC_M3) & 0xffff;
|
||
|
renc.fclk = clk_get_rate(pwmr_clk);
|
||
|
|
||
|
//renc[0] = 1; renc[1] = 2;
|
||
|
//copy_to_user(p, renc, sizeof(renc));
|
||
|
//printk(KERN_ALERT"before copy to user \n");
|
||
|
copy_to_user(p, &renc, sizeof(renc));
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct file_operations gsc3280_pwm_ops = {
|
||
|
.owner = THIS_MODULE,
|
||
|
.open = gsc3280_pwm_open,
|
||
|
.release = gsc3280_pwm_close,
|
||
|
.read = gsc3280_pwm_read,
|
||
|
.write = gsc3280_pwm_write,
|
||
|
.unlocked_ioctl = gsc3280_pwm_ioctl
|
||
|
};
|
||
|
|
||
|
static struct miscdevice gsc3280_pwm_miscdev = {
|
||
|
MISC_DYNAMIC_MINOR,
|
||
|
"pwm",
|
||
|
&gsc3280_pwm_ops,
|
||
|
};
|
||
|
|
||
|
static int gsc3280_pwm_getResourse(struct platform_device *pdev, unsigned int index)
|
||
|
{
|
||
|
struct resource *res1 = NULL;
|
||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, index);
|
||
|
|
||
|
if (res == NULL)
|
||
|
{
|
||
|
printk(KERN_ERR"Fail to get gsc3280_pwm_resource!\n");
|
||
|
return -ENOENT;
|
||
|
}
|
||
|
//printk("Resource start=0x%x, end = 0x%x\n", res->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");
|