smart210驱动(9)蜂鸣器

buzzer_drv.c

/*
* linux-3.10.27
* arm-linux-gcc-4.5.1
*
* @ buzzer driver (gpio func)
*/

#include <linux/module.h>
#include <linux/init.h>   /* module_init, ... */
#include <linux/kernel.h> /* everything */

#include <linux/cdev.h>   /* cdev_init, ... */
#include <linux/fs.h>     /* file_operations,  */
#include <linux/device.h>  /* class_create,... */
#include <linux/platform_device.h>
#include <linux/slab.h>   /* kmalloc, ... */
#include <asm/io.h>       /* ioremap,... */

#include <linux/uaccess.h>   /* copy_from_user, ... */

#include <linux/gpio.h>
#include <linux/timer.h>

/*
* GPD0_0 : buzzer  (XpwmTOUT[0]  GPD0[0]     TOUT_0)           high->on
* GPD0_1 : lcd-blacklight (XpwmTOUT[1] GPD0[1] TOUT_1)     
*/

#define DEF_DEVICE_NAME		"myBuzzer"
#define DEF_MAJOR			0
struct priv_data
{
	char *name;
	int major;

	dev_t dev;
	struct cdev *cdev;
	struct class *cls;
};

static struct priv_data *priv_data;

#define BUZZER_OFF		0
#define BUZZER_ON		1


struct buzzer_dev 
{
	int gpio;
	char *name;
	int state;    /* 1 : on, 0 : off , else fliker  */

	void (* power_on)(struct buzzer_dev *dev);
	void (* power_off)(struct buzzer_dev *dev);
	void (* last)(struct buzzer_dev *dev, int nms);
};


static void smart210_buzzer_poweron(struct buzzer_dev *dev)
{
	gpio_set_value(dev->gpio, BUZZER_ON);
	dev->state = 1;
}

static void smart210_buzzer_poweroff(struct buzzer_dev *dev)
{
	gpio_set_value(dev->gpio, BUZZER_OFF);
	dev->state = 0;
}

static void buzzer_timer_callback(unsigned long data)
{
	pr_info("%s called.\n", __func__);
	
	struct buzzer_dev *dev = (struct buzzer_dev *)data;

	pr_info("dev : %s .\n", dev->name);
	
	gpio_set_value(dev->gpio, BUZZER_OFF);
}

static struct timer_list buzzer_timer;
static void smart210_buzzer_last(struct buzzer_dev *dev, int nms)
{
	gpio_set_value(dev->gpio, BUZZER_ON);
	mod_timer(&buzzer_timer, jiffies + nms * HZ / 1000);
}



static struct buzzer_dev buzzers[] = {
	{S5PV210_GPD0(0), "mybuzzer", BUZZER_OFF, smart210_buzzer_poweron, 
		smart210_buzzer_poweroff, smart210_buzzer_last},
};

#if 0
static 	ssize_t buzzer_show(struct device *dev, struct device_attribute *attr,
			char *buf)
{
	return 0;
}

static ssize_t buzzer_store(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t count)
{
	return 0;
}

static DEVICE_ATTR(buzzer, 0644, buzzer_show, buzzer_store);
#endif

static int smart210_buzzer_open (struct inode *inode, struct file *pfile)
{
	pr_info("%s called.\n", __func__);
	
	return 0;
}

static int smart210_buzzer_close (struct inode *inode, struct file *pfile)
{
	int i  = 0;
	pr_info("%s called.\n", __func__);

	//for(i = 0; i < ARRAY_SIZE(buzzers);i++){
	//	gpio_set_value(buzzers[i].gpio, BUZZER_OFF);
	//}
	
	return 0;
}

static ssize_t smart210_buzzer_write (struct file *file, 
	const char __user *usrbuff, size_t len, loff_t *offset)
{
	char recvbuf[8] = {0};
	char cmd, opt, last, i;

	if(copy_from_user(recvbuf, usrbuff, len)){
		return -EINVAL;
	}

	for(i = 0; i < 8; i++){
		printk(KERN_NOTICE "%d ", recvbuf[i]);
	}
	printk(KERN_NOTICE "\n");

	cmd = recvbuf[0];
    opt = recvbuf[1];
	last = recvbuf[2];
	printk(KERN_NOTICE "cmd : %d opt : %d last : %d \n", cmd, opt, last);
	if(opt > 0)
		return EINVAL;

	switch(cmd){
		case 0:
			buzzers[opt].power_off(&buzzers[opt]);
			break;

		case 1:
			buzzers[opt].power_on(&buzzers[opt]);
			break;

		default:
			buzzers[opt].last(&buzzers[opt], recvbuf[2] * 1000);
			break;
	}
	
	return 0;
}

const struct file_operations fops = 
{
	.owner = THIS_MODULE,
	.open = smart210_buzzer_open,
	.release = smart210_buzzer_close,
	.write = smart210_buzzer_write,
};

static int __init buzzer_drv_init(void)
{
	int ret = 0, i = 0;
	pr_info("%s called.\n", __func__);

	priv_data = kmalloc(sizeof(struct priv_data), GFP_KERNEL);
	if(!priv_data){
		pr_err("no mem.\n");
		return -ENOMEM;
	}

	priv_data->name = DEF_DEVICE_NAME;
	priv_data->major = DEF_MAJOR;

	if(priv_data->major){
		priv_data->dev = MKDEV(priv_data->major, 0);
		ret = register_chrdev_region(priv_data->dev, 1, priv_data->name);
	}else{
		ret = alloc_chrdev_region(&priv_data->dev, 1, 1, priv_data->name);
		priv_data->major = MAJOR(priv_data->dev);
	}

	if(ret){
		pr_err("chrdev register err.\n");
		goto err0;
	}

	/* add cdev */
	priv_data->cdev = cdev_alloc();
	if(!priv_data->cdev){
		pr_err("cdev alloc err.\n");
		goto err1;
	}

	cdev_init(priv_data->cdev, &fops);
	priv_data->cdev->owner = THIS_MODULE;
	priv_data->cdev->ops = &fops;
	cdev_add(priv_data->cdev, priv_data->dev, 1);

	/* add class */
	priv_data->cls = class_create(THIS_MODULE, priv_data->name);
	if(!priv_data->cls){
		pr_err("class create err.\n");
		goto err2;
	}
	device_create(priv_data->cls, NULL, priv_data->dev, NULL, priv_data->name);

	for(i = 0; i < ARRAY_SIZE(buzzers);i++){
		ret = gpio_request(buzzers[i].gpio, buzzers[i].name);
		if(ret){
			pr_err("gpio request fail.\n");
			goto err3;
		}
		gpio_direction_output(buzzers[i].gpio, buzzers[i].state);
		gpio_set_value(buzzers[i].gpio, BUZZER_OFF);
	}

	setup_timer(&buzzer_timer, buzzer_timer_callback, (unsigned long)&buzzers[0]);

	return 0;

err3:
	device_destroy(priv_data->cls, priv_data->dev);
	class_destroy(priv_data->cls);
err2:
	cdev_del(priv_data->cdev);
err1:
	unregister_chrdev_region(priv_data->dev, 1);
err0:
	kfree(priv_data);
	return -EINVAL;
}

static void __exit buzzer_drv_exit(void)
{
	int i = 0;
	pr_info("%s called.\n", __func__);
	
	for(i = 0; i < ARRAY_SIZE(buzzers); i++){
		gpio_free(buzzers[i].gpio);
	}

	
	device_destroy(priv_data->cls, priv_data->dev);
	class_destroy(priv_data->cls);
	cdev_del(priv_data->cdev);
	unregister_chrdev_region(priv_data->dev, 1);
	kfree(priv_data);
}

module_init(buzzer_drv_init);
module_exit(buzzer_drv_exit);
MODULE_LICENSE("GPL");

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值