Android linux PWM驱动(s5pv210)

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


你可能感兴趣的:(c,android,linux,ARM)