Linux驱动开发学习笔记【6】:自动创建设备节点+通过设备树获取寄存器信息+pinctrl和gpio子系统的LED灯驱动

目录

前言

一、pinctrl子系统添加pin信息

二、gpio子系统节点添加

三、驱动修改


前言

正点原子阿尔法Linux开发板LED灯驱动开发(自动创建设备节点+通过设备树获取寄存器信息)基础上,通过设备树 pinctrl子系统来设置pin的复用功能(复用为GPIO)和电气属性(上 /下拉、速度、驱动能力等),通过gpio子系统来完成led所用GPIO的配置和读写。

一、pinctrl子系统添加pin信息

在 imx6ull-alientek-emmc.dts 设备树的根节点下 iomuxc 节点中 添加如下子节点

&iomuxc {
    ...
    pinctrl_gpio_leds: gpio-leds {
        fsl,pins = <
            MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0
        >;
    };
    ...
};

二、gpio子系统节点添加

在 imx6ull-alientek-emmc.dts 设备树的根节点下 添加如下子节点

/*led节点(通过pinctrl子系统和GPIO子系统)*/
gpioled{
    compatible = "alientek-gpioled";
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_gpio_leds>;/*pinctrl子系统*/
    led-gpio  = <&gpio1 3 GPIO_ACTIVE_LOW>;/*GPIO子系统*/
    status = "okay";
}

三、驱动修改

1、在设备结构体 gpioled_dev 中增加 led_gpio 字段

struct gpioled_dev
{
    struct cdev cdev;   /*字符设备*/
    struct class *class;/*类*/
    struct device *device;/*设备*/

    dev_t devid;        /*设备号*/
    int major;          /*主设备号*/
    int minor;          /*次设备号*/

    struct device_node *nd; /*设备节点*/

    int led_gpio; /*led所使用的GPIO编号*/
};

2、在 gpioled_fops.gpioled_open 中添加获取设备树节点信息,通过gpio子系统函数设置GPIO为输出。pin的复用功能设置和GPIO的电气属性设置已经在pinctrl子系统中完成了,所以这里不再需要手动再设置了

static int gpioled_open(struct inode *inode, struct file *file)
{
     int ret = 0;

    file->private_data = &gpioled;

    /*1、找到节点 gpioled,路径是 /gpioled */
    gpioled.nd = of_find_node_by_path("/gpioled");
    if (gpioled.nd == NULL){
        printk("gpioled node can not found!\r\n");
        return -EINVAL;
    } else {
        printk("gpioled node has been found!\r\n");
    }
    
    /*2、获取设备树中的gpio属性,得到LED所使用的LED编号*/
    gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0);
    if (gpioled.led_gpio < 0){
        printk("can't  get led-gpio \r\n");
        return -EINVAL;
    }
    printk("led-gpio num = %d \r\n", gpioled.led_gpio);

    /*3、设置GPIO_IO03为输出,并且输出高电平,默认关闭LED灯*/
    ret = gpio_direction_output(gpioled.led_gpio, 1);
    if (ret < 0){
        printk("can't set gpio \r\n");
    }

    return ret;
}

3、在 gpioled_fops.gpioled_write 中通过 gpio_set_value 设置GPIO的高低电平

 int ret = 0;
    uint8_t data[1], ledsta;
    struct gpioled_dev *dev = file->private_data;

    ret = copy_from_user(data, buf, count);
    if (ret < 0){
        printk("kernel write failed!\r\n");
        return -EFAULT;
    }

    ledsta = data[0];
    if (ledsta == LEDOFF){
        gpio_set_value(dev->led_gpio, 0);
    } 
    else if (ledsta == LEDON){
        gpio_set_value(dev->led_gpio, 1);
    }
    else
        printk("led para error\r\n");
    
    return ret;

猜你喜欢

转载自blog.csdn.net/m0_37845735/article/details/106976532