一、蜂鸣器驱动说明
蜂鸣器与GPIO点灯程序相差无几,本节实验重点编写代码,回顾通过修改设备树添加pinctrl与gpio结点信息来快速驱动Buzzer。
由原理图如下,想要驱动buzzer,使用GPIO1_19引脚的输出,使用高电平驱动蜂鸣器,使得三极管导通,2边通到GND。
二、程序
二话不说,有了前面的经验,现在gpio驱动buzzer可以说是小case。
1、添加设备树结点信息
注意,除此之外还要注意,不能有重复的IO配置。
/{
buzzer{
#address-cells = <1>;
#size-cells = <1>;
compatible = "pintitus,buzzer";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_buzzer>;
buzzer-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>;
status = "okay";
};
};
&iomuxc {
pinctrl-names = "default";
imx6ul-evk {
pinctrl_buzzer:buzzergrp{
fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x10b0
>;
};
};
};
2.驱动程序
/*设备结构体*/
struct gpio_buzzer{
dev_t devid; /*设备号*/
int major; /*主设备号*/
int minor; /*次设备号*/
struct cdev cdev; /*字符设备*/
struct class *class; /*设备的类*/
struct device *device;/*设备*/
struct device_node *nd;/*设备结点*/
int buzzer_gpio; /*IO的编号*/
char name[13]; /*IO申请名称*/
};
struct gpio_buzzer buzzer;
/*
注册与注销设备
*/
static int __init buzzer_init(void){
int ret = 0;
/* 注册字符设备 */
if(buzzer.major){
buzzer.devid = MKDEV(buzzer.major , 0);
ret = register_chrdev_region(buzzer.devid , BUZZER_CNT , BUZZER_NAME);
}else{
ret = alloc_chrdev_region(&buzzer.devid , 0 , BUZZER_CNT , BUZZER_NAME);
buzzer.major = MAJOR(buzzer.devid);
buzzer.minor = MINOR(buzzer.devid);
}
if(ret < 0){
goto failed_devid;
}
printk("buzzer.major = %d , buzzer.minor = %d \r\n" ,buzzer.major , buzzer.minor );
/* 添加字符设备 */
buzzer.cdev.owner = THIS_MODULE;
cdev_init( &buzzer.cdev , &buzzer_fops);
ret = cdev_add(&buzzer.cdev , buzzer.devid , BUZZER_CNT);
if(ret < 0){
goto failed_cdev;
}
/* 自动创建设备结点 */
/* 创建设备的类 */
buzzer.class = class_create(THIS_MODULE , BUZZER_NAME);
if(IS_ERR(buzzer.class)){
ret = PTR_ERR(buzzer.class);
goto failed_class;
}
/* 创建设备 */
buzzer.device = device_create(buzzer.class , NULL , buzzer.devid , NULL ,BUZZER_NAME);
if(IS_ERR(buzzer.device)){
ret = PTR_ERR(buzzer.device);
goto failed_device;
}
/* 1.获取设备结点 */
buzzer.nd = of_find_node_by_path("/buzzer");
if(buzzer.nd == NULL){
ret = -EINVAL;
goto failed_findnd;
}
/* 2.获取buzzer对应的GPIO */
buzzer.buzzer_gpio= of_get_named_gpio(buzzer.nd , "buzzer-gpios" , 0);
if(buzzer.buzzer_gpio < 0){
printk("buzzer.buzzer_gpio < 0\r\n");
ret = -EINVAL;
goto failed_findnd;
}
printk("buzzer.buzzer_gpio = %d\r\n" ,buzzer.buzzer_gpio );
/* 3.申请IO */
buzzer.name[0]="------------";
sprintf(buzzer.name, "buzzer-gpios");
printk("%s\r\n" , buzzer.name);
ret = gpio_request(buzzer.buzzer_gpio, buzzer.name);
if (ret) {
printk("failed to request GPIO for buzzer\n");
ret = -EINVAL;
goto failed_findnd;
}
/* 4.使用IO,设置为输出 */
ret = gpio_direction_output(buzzer.buzzer_gpio ,0 );
if(ret < 0){
goto failed_setio;
}
/* 5.输出电平 ,buzzer */
gpio_set_value(buzzer.buzzer_gpio , 0);
return 0;
failed_setio:
gpio_free(buzzer.buzzer_gpio);
printk("failed_request\r\n");
failed_findnd:
device_destroy(buzzer.class , buzzer.devid);
printk("failed_findnd\r\n");
failed_device:
class_destroy(buzzer.class);
printk("failed_device\r\n");
failed_class:
cdev_del(&buzzer.cdev);
printk("failed_class\r\n");
failed_cdev:
unregister_chrdev_region(buzzer.devid , BUZZER_CNT);
printk("failed_cdev\r\n");
failed_devid:
return ret;
}
static void __exit buzzer_exit(void){
cdev_del(&buzzer.cdev);
unregister_chrdev_region(buzzer.devid , BUZZER_CNT);
device_destroy(buzzer.class , buzzer.devid);
class_destroy(buzzer.class);
/*IO释放*/
gpio_free(buzzer.buzzer_gpio);
}
module_init(buzzer_init);
module_exit(buzzer_exit);
MODULE_LICENSE("GPL");
\