linux驱动开发(imx6ull)-6_蜂鸣器

个人笔记

首先,我们要在设备树上添加设备信息。先在设备树 iomuxc 节点上添加pinctrl信息

		pinctrl_beep_1: beep-1{
			fsl,pins = <
				MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10b0
			>;
		};

MX6UL 是imx6ul-pinfunc.h头文件中定义的。

#define  MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01  0x000C 0x0050 0x0000 0x5 0x0

第一个 0x000C 代表mux_reg寄存器的偏移地址

第二个 0x0050 是conf_reg寄存器偏移地址。

第三个 0x0000 是input_reg寄存器的偏移地址

第四个 0x5 是 mux_reg 寄存器的值,也就是设置在 mux_reg 寄存器里面的值为 0x05 查数据手册能知道这是复用该端口作为 gpio 口。 

第五个 是 input_reg 的值 这里设为 0 没有用到。

跟在 MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01  后面的 0x10b0 就是电器属性的值 就是 conf_reg 的值。

注意 定义完着个 io 后你要看别的 io 有没有复用这个口,如果有那是用时就会失败,因为端口被别的设备复用了,我们写的这个就会使用不成功。所以要去把其他 MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01  给屏蔽掉。

然后添加设备节点信息:

	beep{
		compatible = "lakzhu,beep";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_beep_1>;
		beep-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
		status = "ok";
	};

pinctrl-0 链接着上面的 io 信息 led-gpios 表示 是 gpio5 的 1 号口, 高电平有效。设备信息添加完成。 

添加完成后 编译设备树写入开发板。

然后就是编写设备了。

首先写注册函数注册与卸载:

static int __init beep_init(void)
{
    int ret = 0;
    return 0;
}
static void __exit beep_exit(void)
{

}
//设备注册与卸载
module_init(beep_init);
module_exit(beep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lakzhu");

构建设备结构体

struct beep_dev{
    dev_t devid;
    struct cdev cdev;
    int major;
    int minor;
    struct class *class;
    struct device *device;
    struct device_node *nd;
    int beep_gpio;
};

struct beep_dev beep;

//操作函数
static const struct file_operations filp = {
    .owner = THIS_MODULE,
    .open = beep_open,
    .release = beep_release,
    .write = beep_write,
};

注册字符设备:

static int __init beep_init(void)
{
    int ret = 0;
    //注册字符设备
    beep.major = 0;
    if(beep.major){
        beep.devid = MKDEV(beep.major, 0);
        register_chrdev_region(beep.devid, BEEP_CNT, BEEP_NAME);
    }else{
        ret = alloc_chrdev_region(&beep.devid, 0, BEEP_CNT, BEEP_NAME);
        beep.major = MAJOR(beep.devid);
        beep.minor = MINOR(beep.devid);
    }
    printk("maj:%d   min:%d\r\n", beep.major, beep.minor);
    if(ret < 0){
        goto fail_devid;
    }
}
fail_devid:
    return ret;

初始化字符设备

  //初始化 dev
    beep.cdev.owner = THIS_MODULE;
    cdev_init(&beep.cdev, &filp);
    //cdev 添加到设备
    ret = cdev_add(&beep.cdev, beep.devid, BEEP_CNT);
    if(ret < 0){
        goto fail_cdev;
    }

fail_cdev:
    unregister_chrdev_region(beep.devid, BEEP_CNT);//失败了要把之前注册的设备号删除

创建类

    beep.class = class_create(THIS_MODULE, BEEP_NAME);
    if(IS_ERR(beep.class)){
        ret = PTR_ERR(beep.class);
        goto fail_class;
    }
fail_class:
    cdev_del(&beep.cdev);

 创建设备

    //创建设备
    beep.device = device_create(beep.class, NULL, beep.devid, NULL, BEEP_NAME);
    if(IS_ERR(beep.device)){
        ret = PTR_ERR(beep.device);
        goto fail_device;
    }
fail_device:
    class_destroy(beep.class);

通过 of 函数获取设备节点信息

    beep.nd = NULL;
    beep.nd = of_find_node_by_path("/beep");
    if(beep.nd == NULL){
        ret = -ENAVAIL;
        goto fail_nd;
    }
fail_node:
    device_destroy(beep.class, beep.devid);

获取对应的 led 信息:

    beep.beep_gpio = of_get_named_gpio(beep.nd, "beep-gpios", 0);
    if(beep.beep_gpio < 0){
        ret = -ENAVAIL;
        goto fail_GetGpio;
    }

fail_GetGpio:

申请io 申请了才能使用

    ret = gpio_request(beep.beep_gpio, "beep-gpios");
    if(ret){
        printk("can't request beep gpio \r\n");
        goto fail_request;
    }
fail_request:

使用io

    ret = gpio_direction_output(beep.beep_gpio, 0);
    if(ret < 0){
        goto fail_output;
    }
    gpio_set_value(beep.beep_gpio, 0);

    return ret;

fail_output:
    gpio_free(beep.beep_gpio);

函数退出,要把注册过的都注销掉


static void __exit beep_exit(void)
{
    gpio_set_value(beep.beep_gpio, 1);
   //注销字符驱动
    cdev_del(&beep.cdev);
    //删除设备号
    unregister_chrdev_region(beep.devid, BEEP_CNT);
    //摧毁驱动
    device_destroy(beep.class, beep.devid);
    //摧毁类
    class_destroy(beep.class);
    //销毁io
    gpio_free(beep.beep_gpio);
}

文件操作函数

static int beep_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &beep;
    return 0;
}

static int beep_release(struct inode *inode, struct file *filp)
{
    return 0;
}

static ssize_t beep_write(struct file *filp, const  char __user *buf, size_t count, loff_t *ppos)
{
    int ret;
    unsigned char data[1];
    struct beep_dev *dev = filp->private_data;
    ret = copy_from_user(data, buf, count);
    if(ret < 0)
        return -ENAVAIL;
    if(data[0] == DEEPON){
        gpio_set_value(dev->beep_gpio, DEEPON);
    }else if(data[0] == DEEPOFF){
        gpio_set_value(dev->beep_gpio, DEEPOFF);
    }
    return 0;
}

完整 的文件

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define BEEP_CNT     1
#define BEEP_NAME    "beep"

#define DEEPOFF          1
#define DEEPON           0

//gpio 设备结构体
struct beep_dev{
    dev_t devid;
    struct cdev cdev;
    int major;
    int minor;
    struct class *class;
    struct device *device;
    struct device_node *nd;
    int beep_gpio;
};

struct beep_dev beep;

static int beep_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &beep;
    return 0;
}

static int beep_release(struct inode *inode, struct file *filp)
{
    return 0;
}

static ssize_t beep_write(struct file *filp, const  char __user *buf, size_t count, loff_t *ppos)
{
    int ret;
    unsigned char data[1];
    struct beep_dev *dev = filp->private_data;
    ret = copy_from_user(data, buf, count);
    if(ret < 0)
        return -ENAVAIL;
    if(data[0] == DEEPON){
        gpio_set_value(dev->beep_gpio, DEEPON);
    }else if(data[0] == DEEPOFF){
        gpio_set_value(dev->beep_gpio, DEEPOFF);
    }
    return 0;
}

static const struct file_operations filp = {
    .owner = THIS_MODULE,
    .open = beep_open,
    .release = beep_release,
    .write = beep_write,
};
//入口出口
static int __init beep_init(void)
{
    int ret = 0;
    //注册字符设备
    beep.major = 0;
    if(beep.major){
        beep.devid = MKDEV(beep.major, 0);
        register_chrdev_region(beep.devid, BEEP_CNT, BEEP_NAME);
    }else{
        ret = alloc_chrdev_region(&beep.devid, 0, BEEP_CNT, BEEP_NAME);
        beep.major = MAJOR(beep.devid);
        beep.minor = MINOR(beep.devid);
    }
    printk("maj:%d   min:%d\r\n", beep.major, beep.minor);
    if(ret < 0){
        goto fail_devid;
    }

    //初始化 dev
    beep.cdev.owner = THIS_MODULE;
    cdev_init(&beep.cdev, &filp);
    //cdev 添加到设备
    ret = cdev_add(&beep.cdev, beep.devid, BEEP_CNT);
    if(ret < 0){
        goto fail_cdev;
    }

    //创建设备节点
    beep.class = class_create(THIS_MODULE, BEEP_NAME);
    if(IS_ERR(beep.class)){
        ret = PTR_ERR(beep.class);
        goto fail_class;
    }

    //创建设备
    beep.device = device_create(beep.class, NULL, beep.devid, NULL, BEEP_NAME);
    if(IS_ERR(beep.device)){
        ret = PTR_ERR(beep.device);
        goto fail_device;
    }
        printk("1");
    //获取设备节点
    beep.nd = NULL;
    beep.nd = of_find_node_by_path("/beep");
    if(beep.nd == NULL){
        ret = -ENAVAIL;
        goto fail_nd;
    }
    printk("2");
    //获取led的对应的gpio
    beep.beep_gpio = of_get_named_gpio(beep.nd, "beep-gpios", 0);
    if(beep.beep_gpio < 0){
        ret = -ENAVAIL;
        goto fail_GetGpio;
    }
    printk("3");
    //申请io 申请了才能使用
    ret = gpio_request(beep.beep_gpio, "beep-gpios");
    if(ret){
        printk("can't request beep gpio \r\n");
        goto fail_request;
    }
    printk("4");
    //使用io
    ret = gpio_direction_output(beep.beep_gpio, 0);
    if(ret < 0){
        goto fail_output;
    }
    gpio_set_value(beep.beep_gpio, 0);

    return ret;
fail_output:
    gpio_free(beep.beep_gpio);
fail_request:
fail_GetGpio:
fail_nd:
    device_destroy(beep.class, beep.devid);
fail_device:
    class_destroy(beep.class);
fail_class:
    cdev_del(&beep.cdev);
fail_cdev:
    unregister_chrdev_region(beep.devid, BEEP_CNT);
fail_devid:
    return ret;
}

static void __exit beep_exit(void)
{
    gpio_set_value(beep.beep_gpio, 1);
   //注销字符驱动
    cdev_del(&beep.cdev);
    //删除设备号
    unregister_chrdev_region(beep.devid, BEEP_CNT);
    //摧毁驱动
    device_destroy(beep.class, beep.devid);
    //摧毁类
    class_destroy(beep.class);
    //销毁io
    gpio_free(beep.beep_gpio);
}
//设备注册与卸载
module_init(beep_init);
module_exit(beep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lakzhu");

编译下载到板子上就能使用了。

有新设备 要是用 先 depmod  然后才能modpure 函数

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值