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");