Linux driver development study notes [4]: Automatically create device nodes + LED light driver that obtains register information through the device tree

table of Contents

Preface

1. Add led device tree node

Two, LED device tree node information acquisition


Preface

In  Punctual Atom Alpha Linux development board LED light driver development (automatically create device nodes) , although the function is realized, it directly defines the GPIO register address of the LED, and then the register for operation. This method is not recommended, and In Linux, the device tree is specifically used to describe the device information of the board, so it is completely possible to set the GPIO register information of the LED through the device tree, and then use the of function in the LED module driver to obtain the attribute information of the LED node in the device tree to To complete the driver writing

1. Add led device tree node

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

/*led节点*/
alphaled{
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "atkalpha-led";
    status = "okay";
    reg = <0X020C406C 0x04		/*CCM_CCGR1_BASE*/
           0X020E0068 0x04		/*SW_MUX_GPIO1_IO03_BASE*/
           0X020E02F4 0x04		/*SW_PAD_GPIO1_IO03_BASE*/
           0X0209C000 0x04		/*GPIO1_DR_BASE*/
           0X0209C004 0x04>;	/*GPIO1_GDIR_BASE*/
	};

Two, LED device tree node information acquisition

Add in dtsled_fops.dtsled_open to obtain device tree node information, obtain reg data, and then directly manipulate registers to set the multiplexing function of pin, electrical properties of GPIO, input and output, and default level

static int dtsled_open(struct inode *inode, struct file *file)
{
    int ret = 0, val;
    struct property *dtsled_prop = NULL;
    const char *str = NULL;
    uint32_t i, regdata[14];

    file->private_data = &dtsled;

    /*1、找到节点 alphaled,路径是 /alphaled */
    dtsled.nd = of_find_node_by_path("/alphaled");
    if (dtsled.nd == NULL){
        printk("alphaled node can not found!\r\n");
        return -EINVAL;
    } else {
        printk("alphaled node has been found!\r\n");
    }

    /*2、查找 兼容性属性*/
    dtsled_prop = of_find_property(dtsled.nd,"compatible",NULL);
    if (dtsled_prop == NULL){
        printk("compatible property find failed\r\n");
        return -EINVAL;
    } else {
        printk("compatible = %s\r\n", (char *)dtsled_prop->value);
    }
    /*3、查找 status 属性*/
    ret = of_property_read_string(dtsled.nd, "status", &str);
    if (ret < 0){
        printk("status read failed!\r\n");
        return -EINVAL;
    } else {
        printk("status = %s\r\n",str);
    }
    /*4、获取reg属性内容*/
    ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);
    if (ret < 0){
        printk("reg property read failed!\r\n");
    } else {
        printk("reg data:\r\n");
        for (i=0; i<10; i++){
            printk("%#X ", regdata[i]);
        }
        printk("\r\n");
    }

    /*初始化led,不能直接操作物理地址,需要地址重映射*/
    /*1、寄存器地址映射*/
#if 0
    IMX6U_CCM_CCGR1   = ioremap(regdata[0], regdata[1]);
    SW_MUX_GPIO1_IO03 = ioremap(regdata[2], regdata[3]);
    SW_PAD_GPIO1_IO03 = ioremap(regdata[4], regdata[5]);
    GPIO1_DR          = ioremap(regdata[6], regdata[7]);
    GPIO1_GDIR        = ioremap(regdata[8], regdata[9]);
#else
    IMX6U_CCM_CCGR1   = of_iomap(dtsled.nd, 0);
    SW_MUX_GPIO1_IO03 = of_iomap(dtsled.nd, 1);
    SW_PAD_GPIO1_IO03 = of_iomap(dtsled.nd, 2);
    GPIO1_DR          = of_iomap(dtsled.nd, 3);
    GPIO1_GDIR        = of_iomap(dtsled.nd, 4);
#endif

    /* 2、使能GPIO1时钟 */
	val = readl(IMX6U_CCM_CCGR1);
	val &= ~(3 << 26);	/* 清楚以前的设置 */
	val |= (3 << 26);	/* 设置新值 */
	writel(val, IMX6U_CCM_CCGR1);

	/* 3、设置GPIO1_IO03的复用功能,将其复用为
	 *    GPIO1_IO03,最后设置IO属性。
	 */
	writel(5, SW_MUX_GPIO1_IO03);
	
	/*寄存器SW_PAD_GPIO1_IO03设置IO属性
	 *bit 16:0 HYS关闭
	 *bit [15:14]: 00 默认下拉
     *bit [13]: 0 kepper功能
     *bit [12]: 1 pull/keeper使能
     *bit [11]: 0 关闭开路输出
     *bit [7:6]: 10 速度100Mhz
     *bit [5:3]: 110 R0/6驱动能力
     *bit [0]: 0 低转换率
	 */
	writel(0x10B0, SW_PAD_GPIO1_IO03);

	/* 4、设置GPIO1_IO03为输出功能 */
	val = readl(GPIO1_GDIR);
	val &= ~(1 << 3);	/* 清除以前的设置 */
	val |= (1 << 3);	/* 设置为输出 */
	writel(val, GPIO1_GDIR);

	/* 5、默认关闭LED */
	val = readl(GPIO1_DR);
	val |= (1 << 3);	
	writel(val, GPIO1_DR);

    return 0;
}

 

 

Guess you like

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