Android linux PWM驱动(s5pv210)
struct pwm_ctrl_dev{
struct cdev cdev;
struct pwm_device *pwm;
int freq;
unsigned int irq;
unsigned char value;
};
static struct pwm_ctrl_dev *pwm_dev;
struct class *pwm_class;
static int major = DEVICE_MAJOR;
static void pwm_set_freq(unsigned long freq) {
int period_ns = NS_IN_1HZ / freq;
pwm_config(pwm_dev->pwm, period_ns / 2, period_ns);
pwm_enable(pwm_dev->pwm);
}
static void pwm_on(void)
{
s3c_gpio_cfgpin(GPIO_DOUT, S3C_GPIO_SFN(2));
pwm_set_freq(pwm_dev->freq);
pwm_dev->value = 1;
}
static void pwm_off(void)
{
s3c_gpio_cfgpin(GPIO_DOUT, S3C_GPIO_SFN(0));
pwm_disable(pwm_dev->pwm);
pwm_dev->value = 0;
}
static int pwm_ctrl_open(struct inode *inode, struct file *filp)
{
try_module_get(THIS_MODULE);
return 0;
}
static int pwm_ctrl_release(struct inode *inode,struct file *filp)
{
module_put(THIS_MODULE);
return 0;
}
static long pwm_ctrl_ioctl(
struct file *filp, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case PWM_IOCTL_GET_STATE:
if(copy_to_user((int __user*)arg,&pwm_dev->value, 1))
return -ENOTTY;
case PWM_IOCTL_GET_FREQ:
if(copy_to_user((int __user*)arg,&pwm_dev->freq, sizeof(int)))
return -ENOTTY;
case PWM_IOCTL_SET_FREQ:
if (arg == 0){
pwm_off();
return 0;
}
pwm_on();
pwm_set_freq(arg);
break;
case PWM_IOCTL_STOP:
default:
pwm_off();
break;
}
return 0;
}
static ssize_t pwm_ctrl_read(
struct file *filp,char __user *buf,size_t size,loff_t *f_pos)
{
put_user(pwm_dev->value, buf);
return 0;
}
static ssize_t pwm_ctrl_write(struct file *filp,const char __user *buf,size_t size,loff_t *f_pos)
{
get_user(pwm_dev->value, buf);
if(pwm_dev->value) pwm_on();
else pwm_off();
return 0;
}
static struct file_operations pwm_ctrl_fops={
.owner = THIS_MODULE,
.read = pwm_ctrl_read,
.write = pwm_ctrl_write,
.unlocked_ioctl = pwm_ctrl_ioctl,
.open = pwm_ctrl_open,
.release = pwm_ctrl_release,
};
static void pwm_ctrl_setup_cdev(
struct pwm_ctrl_dev *dev,int minor,struct file_operations *fops)
{
int err, devno = MKDEV(major, minor);
cdev_init(&(dev->cdev), fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = fops;
err=cdev_add(&(dev->cdev), devno, 1);
if(err){
printk(KERN_NOTICE"erro %d adding %s %d\n",err,DEVICE_NAME,minor);
}
}
int __init pwm_ctrl_init(void){
int result;
dev_t devno=MKDEV(major,0);
if(major){
result = register_chrdev_region(devno, 1, DEVICE_NAME);
}
else{
result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
}
if(result < 0){
printk(KERN_WARNING"%s: unable to get major %d\n",DEVICE_NAME,major);
return result;
}
pwm_dev=kmalloc(sizeof(struct pwm_ctrl_dev),GFP_KERNEL);
if(!pwm_dev){
result=-ENOMEM;
goto fail_malloc;
}
pwm_class = class_create(THIS_MODULE, DEVICE_NAME);
device_create(pwm_class, NULL, MKDEV(DEVICE_MAJOR, 0), NULL, DEVICE_NAME);
pwm_ctrl_setup_cdev(pwm_dev, 0, &pwm_ctrl_fops);
pwm_dev->value = 0;
pwm_dev->freq = 1000;
result = gpio_request(GPIO_DOUT, DEVICE_NAME);
if (result) {
printk(KERN_INFO "[%s] request GPIO_DOUT for pwm failed\n",
__func__);
goto fail_malloc;
}
s3c_gpio_cfgpin(GPIO_DOUT, S3C_GPIO_SFN(1));
gpio_set_value(GPIO_DOUT, 0);
pwm_dev->pwm = pwm_request(BUZZER_PWM_ID, "buzzer");
if (IS_ERR(pwm_dev->pwm)){
printk(KERN_INFO "[%s] %s\n", __func__, "unable to request PWM for Buzzer\n");
goto fail_pwm;
}
pwm_off();
return 0;
fail_pwm:
pwm_free(pwm_dev->pwm);
kfree(pwm_dev);
fail_malloc:
unregister_chrdev_region(MKDEV(major,0),1);
return result;
}
void __exit pwm_ctrl_exit(void)
{
cdev_del(&pwm_dev->cdev);
device_destroy(pwm_class, MKDEV(major, 0));
class_destroy(pwm_class);
pwm_off();
pwm_free(pwm_dev->pwm);
gpio_free(GPIO_DOUT);
kfree(pwm_dev);
unregister_chrdev_region(MKDEV(major, 0), 1);
}
module_init(pwm_ctrl_init);
module_exit(pwm_ctrl_exit);
MODULE_AUTHOR("jvaemape");
MODULE_DESCRIPTION("S3C PWM Drive");
MODULE_LICENSE("Dual BSD/GPL");