四、控制蜂鸣器
1.1、控制原理
蜂鸣器使用的是有缘蜂鸣器,所以其实也只需要设置引脚的高低电平即可驱动蜂鸣器。
最终原理还是驱动GPIO,参考上一篇的GPIO,修改对应的设备树引脚即可。
1.2、设备树添加GPIO节点
在对应的设备树pinctrl节点上添加驱动的GPIO信息。
pinctrl_beep:beepgrp{
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10b0
>;
};
之后在根/下面添加自己的gpio节点
gpiobeep{
#address-cells = <1>;
#size-cells = <1>;
compatible = "atkalpha-gpiobeep";
pinctrl-name = "default";
pinctrl-0=<&pinctrl_beep>;
beep-gpio = < &gpio5 1 GPIO_ACTIVE_LOW >; //低电平点亮
status = "okay";
};
1.3、驱动代码
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#define BEEP_NAME "beep"
#define BEEP_CT 1
#define BEEP_ON 1
#define BEEP_OFF 0
struct beep_struct{
int major;
int minor;
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *device;
struct device_node *nd;
int gpio_num;
};
struct beep_struct beep_dev;
static int beep_open(struct inode *inode, struct file *file)
{
file->private_data = &beep_dev;
return 0;
}
static int beep_release(struct inode *inode, struct file *file)
{
return 0;
}
ssize_t beep_write(struct file *file, const char __user *data,size_t len, loff_t *ppos)
{
struct beep_struct *dev = file->private_data;
unsigned char data_tmp = 0;
int ret = 0;
ret = copy_from_user(&data_tmp,data,1);
if(ret < 0){
printk("write data err\r\n");
return -1;
}
if(data_tmp == BEEP_ON){
gpio_set_value(dev->gpio_num,0);
}
else if(data_tmp == BEEP_OFF){
gpio_set_value(dev->gpio_num,1);
}
return 0;
}
ssize_t beep_read(struct file *file, char __user * buf,size_t len, loff_t * ppos)
{
return 0;
}
static const struct file_operations beep_fileope = {
.owner = THIS_MODULE,
.open = beep_open,
.write = beep_write,
.read = beep_read,
.release = beep_release,
};
static int beep_gpio_init(void)
{
int ret = 0;
beep_dev.nd = of_find_node_by_path("/gpiobeep");
if(beep_dev.nd == NULL){
printk("not find node\r\n");
return -1;
}
printk("get node\r\n");
beep_dev.gpio_num = of_get_named_gpio(beep_dev.nd,"beep-gpio",0);
if(beep_dev.gpio_num < 0){
printk("not get gpio\r\n");
return -2;
}
printk("gpio num:%d\r\n",beep_dev.gpio_num);
ret = gpio_direction_output(beep_dev.gpio_num,1);
if(ret < 0){
printk("gpio set err\r\n");
return -3;
}
return 0;
}
static int __init beep_init(void)
{
int ret = 0;
ret = beep_gpio_init();
if(ret < 0){
printk("beep gpio init err\r\n");
goto CHRDEV_ERR;
}
beep_dev.major = 0;
if(beep_dev.major){
beep_dev.devid = MKDEV(beep_dev.major,0);
ret = register_chrdev_region(beep_dev.devid,BEEP_CT,BEEP_NAME);
}
else{
ret = alloc_chrdev_region(&beep_dev.devid,0,BEEP_CT, BEEP_NAME);
beep_dev.major = MAJOR(beep_dev.devid);
}
if(ret < 0){
printk("chrdev err\r\n");
goto CHRDEV_ERR;
}
printk("beep major:%#x\r\n",beep_dev.major);
beep_dev.cdev.owner = THIS_MODULE;
cdev_init(&beep_dev.cdev, &beep_fileope);
ret = cdev_add(&beep_dev.cdev, beep_dev.devid, BEEP_CT);
if(ret < 0){
printk("cdev err\r\n");
goto CDEV_ERR;
}
beep_dev.class = class_create(THIS_MODULE, "bsr");
if (IS_ERR(beep_dev.class)) {
printk("class create err\r\n");
ret = PTR_ERR(beep_dev.class);
goto CLASS_ERR;
}
beep_dev.device = device_create(beep_dev.class,NULL,beep_dev.devid,NULL,BEEP_NAME);
if (IS_ERR(beep_dev.device)) {
printk("device create err\r\n");
ret = PTR_ERR(beep_dev.device);
goto DEVICE_ERR;
}
return 0;
DEVICE_ERR:
class_destroy(beep_dev.class);
CLASS_ERR:
cdev_del(&beep_dev.cdev);
CDEV_ERR:
unregister_chrdev_region(beep_dev.devid,BEEP_CT);
CHRDEV_ERR:
return ret;
}
static void __exit beep_exit(void)
{
device_destroy(beep_dev.class,beep_dev.devid);
class_destroy(beep_dev.class);
cdev_del(&beep_dev.cdev);
unregister_chrdev_region(beep_dev.devid,BEEP_CT);
}
module_init(beep_init);
module_exit(beep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("gale");