Linux driver development study notes [6]: Automatically create device nodes + obtain register information through the device tree + pinctrl and gpio subsystem LED light driver

table of Contents

Preface

One, pinctrl subsystem adds pin information

Two, gpio subsystem node added

Three, drive modification


Preface

In punctual atom alpha Linux development boards LED lamp driver (device node is created automatically by the device information for the register + tree) based on the set pin multiplexing function by the device tree pinctrl subsystem (multiplexed with GPIO) and electrical properties ( Up/down, speed, drive capability, etc.), through the gpio subsystem to complete the configuration and reading and writing of the GPIO used by the LED.

One, pinctrl subsystem adds pin information

Add the following sub-nodes to the iomuxc node under the root node of the imx6ull-alientek-emmc.dts device tree

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

Two, gpio subsystem node added

Add the following sub-nodes under the root node of the imx6ull-alientek-emmc.dts device tree

/*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";
}

Three, drive modification

1, the device structure  gpioled_dev  increase in led_gpio field

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. Add to get device tree node information in gpioled_fops.gpioled_open, and set GPIO as output through gpio subsystem function. The multiplex function setting of pin and the electrical property setting of GPIO have been completed in the pinctrl subsystem, so there is no need to set it manually here.

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. Set the high and low level of GPIO through gpio_set_value in gpioled_fops.gpioled_write

 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;

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/m0_37845735/article/details/106976532