中断深入-->休眠唤醒(通用)

在此之前

中断里面 休眠唤醒,poll,异步… 等等都是为了读取该驱动的应用不占用那么多cpu资源
相对来说,对原来的驱动的中断函数没有太多调整,而是在驱动其他地方进行改进处理,给应用程序更好调用
并且 休眠唤醒有一个巨大的缺点,如果没有数据就会一直睡下去,app不执行其他事情

休眠流程

当app读取时候,有数据可以读取

在这里插入图片描述

app读取时候没有数据,进入休眠

在这里插入图片描述

  1. 先创建一个等待队列 waitqueue
  2. 同时app->read,调用了驱动的read, 在驱动的read里,把进程放进等待队列
  3. app读取的时候没有数据,先进入休眠
  4. 当有按键产生,会执行写好的 handle程序
  5. 在handle程序的最后,会唤醒等待队列告诉app :有数据了,可以继续运行了

代码构思

对于该驱动的几种写法

1. 设备树里只指定gpio

在驱动里面从设备树里提取出gpio , 驱动里使用 gpio_to_irq 转为中断
eg:
struct device_node *node = pdev->dev.of_node;//当probe成功后,把platform_device 变成设备树 node节点
gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag); //从node节点得到gpio编号
gpio_keys_100ask[i].irq = gpio_to_irq(gpio_keys_100ask[i].gpio); //把gpio变为中断引脚

request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, “100ask_gpio_key”, &gpio_keys_100ask[i]); //注册中断

2. 设备树里有 interrupts

在设备树里有interrupts eg:

xxx_eint {
        compatible = "mediatek, xxx-eint";                                                                                                     
        interrupt-parent = <&eintc>;
        interrupts = <79 IRQ_TYPE_EDGE_FALLING>;//79是gpio号
        debounce = <79 1000>;
        status = "okay";
};

在驱动中我们
node = of_find_compatible_node(NULL, NULL, “mediatek, xxx-eint”); //获取中断对应的compatible的节点
of_property_read_u32_array(node, “debounce”, ints, ARRAY_SIZE(ints)); //获取节点中debounce的内容
debounce = ints[1]; //debounce = 1000
gpiopin = ints[0]; //gpio = 79
irqnum = irq_of_parse_and_map(node, 0); //获取节点中关于interrupt中gpio对应的中断号
//(此接口可以根据device tree中描述的中断信息来分析出此节点中interrupts中gpio对应的中断号),获取中断号后,就可调用request_irq来申请中断。

3. 前两种基础上增加环形缓冲区

有时候app还没人工加载,但是已经有中断发生了,后面运行的app只能获取最近一次的数据
这时候我们用一个环形缓冲区,有中断的时候先保存在驱动里,
后面人为加载的app可以一次性把之前的数据都取出来

在之前的基础上面加

static int r=0,w=0; //一个读位置,一个写位置
#define NEXT_POS(x) ((x+1)% BUF_LEN) //让当前位置+1

static int is_key_buf_empty(void)  //判断当前是否有新数据,在app读驱动时调用 wait_event_interruptible 使用
{
	if(r == w)
		return 0;
	else
		return 1;
}

static void put_key(int key) // 存入数据
{
	g_key[w] = key;
	w = NEXT_POS(w);
}

static int get_key(void) //取出数据
{
	int key =0;
	key = g_key[r];
	r = NEXT_POS(r);
	return key;
}

完整代码

设备树
/*
 * Copyright (C) 2016 Freescale Semiconductor, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

/dts-v1/;

#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"

/ {
    model = "Freescale i.MX6 ULL 14x14 EVK Board";
    compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";

    chosen {
        stdout-path = &uart1;
    };

    memory {
        reg = <0x80000000 0x20000000>;
    };

    reserved-memory {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;

        linux,cma {
            compatible = "shared-dma-pool";
            reusable;
            size = <0x14000000>;
            linux,cma-default;
        };
    };

    backlight {
        compatible = "pwm-backlight";
        pwms = <&pwm1 0 1000>;
        brightness-levels = <0 1 2 3 4 5 6 8 10>;
        default-brightness-level = <8>;
        status = "okay";
    };

    pxp_v4l2 {
        compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2";
        status = "okay";
    };

    regulators {
        compatible = "simple-bus";
        #address-cells = <1>;
        #size-cells = <0>;

        reg_can_3v3: regulator@0 {
            compatible = "regulator-fixed";
            reg = <0>;
            regulator-name = "can-3v3";
            regulator-min-microvolt = <3300000>;
            regulator-max-microvolt = <3300000>;
        };

        reg_usb_ltemodule: regulator@1 {
            compatible = "regulator-fixed";
            regulator-name = "ltemodule-pwr";
            regulator-min-microvolt = <3800000>;
            regulator-max-microvolt = <3800000>;
            gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>;
            enable-active-high;
            regulator-boot-on;
        };

        reg_gpio_wifi: regulator@2 {
            compatible = "regulator-fixed";
            regulator-name = "wifi-pwr";
            regulator-min-microvolt = <3300000>;
            regulator-max-microvolt = <3300000>;
            gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
            regulator-boot-on;
        };

    };

    leds {
        compatible = "gpio-leds";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_leds>;
        
        status = "disabled";

        led0: cpu {
            label = "cpu";
            gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
            default-state = "on";
            linux,default-trigger = "heartbeat";
        };
    };

    gpio_keys_100ask {
		status = "okay";
        compatible = "100ask,gpio_key";
	gpios = <&gpio5 1 GPIO_ACTIVE_HIGH
		 &gpio4 14 GPIO_ACTIVE_LOW>;
        pinctrl-names = "default";
        pinctrl-0 = <&key1_100ask &key2_100ask>;
		interrupt-parent = <&gpio1>;
		interrupts = <74 IRQ_TYPE_EDGE_FALLING>;
    };
	
	gpio_keys_100ask {
		status = "disabled";
        compatible = "100ask,gpio_key";
	gpios = <&gpio5 1 GPIO_ACTIVE_HIGH
		 &gpio4 14 GPIO_ACTIVE_LOW>;
		
        pinctrl-names = "default";
        pinctrl-0 = <&key1_100ask &key2_100ask>;
    };
	

    gpio-keys {
        compatible = "gpio-keys";
        pinctrl-names = "default";
	status = "disabled";

        user1 {
            label = "User1 Button";
            gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
            gpio-key,wakeup;
            linux,code = <KEY_1>;
        };
        
        user2 {
            label = "User2 Button";
            gpios = <&gpio4 14 GPIO_ACTIVE_LOW>;
            gpio-key,wakeup;
            linux,code = <KEY_2>;
        };
    };
    sound {
            compatible = "fsl,imx6ul-evk-wm8960",
                     "fsl,imx-audio-wm8960";
            model = "wm8960-audio";
            cpu-dai = <&sai2>;
            audio-codec = <&codec>;
            asrc-controller = <&asrc>;
            codec-master;
            gpr = <&gpr 4 0x100000 0x100000>;
            hp-det = <3 0>;
            /*hp-det-gpios = <&gpio5 4 0>;
            mic-det-gpios = <&gpio5 4 0>;*/
            audio-routing =
                "Headphone Jack", "HP_L",
                "Headphone Jack", "HP_R",
                "Ext Spk", "SPK_LP",
                "Ext Spk", "SPK_LN",
                "Ext Spk", "SPK_RP",
                "Ext Spk", "SPK_RN",
                "LINPUT2", "Mic Jack",
                "LINPUT3", "Mic Jack",
                "RINPUT1", "Main MIC",
                "RINPUT2", "Main MIC",  
                "Mic Jack", "MICB",
                "Main MIC", "MICB",
                "CPU-Playback", "ASRC-Playback",
                "Playback", "CPU-Playback",
                "ASRC-Capture", "CPU-Capture",
                "CPU-Capture", "Capture";
                status = "okay";
        };
    
    spi4 {
        compatible = "spi-gpio";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_spi4>;
        pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
        status = "okay";
        gpio-sck = <&gpio5 11 0>;
        gpio-mosi = <&gpio5 10 0>;
        cs-gpios = <&gpio5 7 0>;
        num-chipselects = <1>;
        #address-cells = <1>;
        #size-cells = <0>;

        gpio_spi: gpio_spi@0 {
            compatible = "fairchild,74hc595";
            gpio-controller;
            #gpio-cells = <2>;
            reg = <0>;
            registers-number = <1>;
            registers-default = /bits/ 8 <0x57>;
            spi-max-frequency = <10000>;
        };
    };
    
    sii902x_reset: sii902x-reset {
            compatible = "gpio-reset";
            reset-gpios = <&gpio_spi 1 GPIO_ACTIVE_LOW>;
            reset-delay-us = <100000>;
            #reset-cells = <0>;
            status = "okay";
        };

};

&gpmi{
    status = "disabled";
};
&cpu0 {
    arm-supply = <&reg_arm>;
    soc-supply = <&reg_soc>;
};

&clks {
    assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
    assigned-clock-rates = <786432000>;
};

&fec1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_enet1>;
    phy-mode = "rmii";
    phy-handle = <&ethphy0>;
    phy-reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
    phy-reset-duration = <26>;
    status = "okay";
};

&fec2 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_enet2>;
    phy-mode = "rmii";
    phy-handle = <&ethphy1>;
    phy-reset-gpios = <&gpio5 6 GPIO_ACTIVE_LOW>;
    phy-reset-duration = <26>;
    status = "okay";

    mdio {
        #address-cells = <1>;
        #size-cells = <0>;

        ethphy0: ethernet-phy@0 {
            compatible = "ethernet-phy-ieee802.3-c22";
            smsc,disable-energy-detect;
            reg = <0>;
        };
        ethphy1: ethernet-phy@1 {
            compatible = "ethernet-phy-ieee802.3-c22";
            smsc,disable-energy-detect;
            reg = <1>;
        };
    };
};

&flexcan1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_flexcan1>;
    xceiver-supply = <&reg_can_3v3>;
    status = "okay";
};
&gpc {
    fsl,cpu_pupscr_sw2iso = <0x1>;
    fsl,cpu_pupscr_sw = <0x0>;
    fsl,cpu_pdnscr_iso2sw = <0x1>;
    fsl,cpu_pdnscr_iso = <0x1>;
    fsl,ldo-bypass = <0>; /* DCDC, ldo-enable */
};

&i2c1 {
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c1>;
    status = "okay";
};

&i2c2 {
    clock_frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c2>;
    status = "okay";

    codec: wm8960@1a {
        compatible = "wlf,wm8960";
        reg = <0x1a>;
        clocks = <&clks IMX6UL_CLK_SAI2>;
        clock-names = "mclk";
        wlf,shared-lrclk;
        };
         sii902x: sii902x@39 {
                 compatible = "SiI,sii902x";
                 pinctrl-names = "default";
                 reset-names="sii902x";
                 pinctrl-0 = <&pinctrl_sii902x>;
                 resets = <&sii902x_reset>;
                 interrupt-parent = <&gpio1>;
                 interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
                 mode_str ="1280x720M@60";
                 bits-per-pixel = <16>;
                 reg = <0x39>;
                 status = "okay";    
         };


        gt9xx@5d {
                compatible = "goodix,gt9xx";
                reg = <0x5d>;
                status = "okay";
                interrupt-parent = <&gpio1>;
                interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_tsc_reset &pinctrl_touchscreen_int>;
                /*pinctrl-1 = <&pinctrl_tsc_irq>;*/
                /*pinctrl-names = "default", "int-output-low", "int-output-high", "int-input";
                pinctrl-0 = <&ts_int_default>;
                pinctrl-1 = <&ts_int_output_low>;
                pinctrl-2 = <&ts_int_output_high>;
                pinctrl-3 = <&ts_int_input>;
                */
                reset-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
                irq-gpios = <&gpio1 5 IRQ_TYPE_EDGE_FALLING>;
                irq-flags = <2>;                /*1:rising 2: falling*/

                touchscreen-max-id = <1>;
                touchscreen-size-x = <800>;
                touchscreen-size-y = <480>;
                touchscreen-max-w = <1024>;
                touchscreen-max-p = <1024>;
                /*touchscreen-key-map = <172>, <158>;*/ /*KEY_HOMEPAGE, KEY_BACK*/

                goodix,type-a-report = <0>;
                goodix,driver-send-cfg = <0>;
                goodix,create-wr-node = <1>;
                goodix,wakeup-with-reset = <0>;
                goodix,resume-in-workqueue = <0>;
                goodix,int-sync = <0>;
                goodix,swap-x2y = <0>;
                goodix,esd-protect = <0>;
                goodix,pen-suppress-finger = <0>;
                goodix,auto-update = <0>;
                goodix,auto-update-cfg = <0>;
                goodix,power-off-sleep = <0>;

                /*7*/
                goodix,cfg-group0 = [
                6b 00 04 58 02 05 0d 00 01 0f 
                28 0f 50 32 03 05 00 00 00 00 
                00 00 00 00 00 00 00 8a 2a 0c 
                45 47 0c 08 00 00 00 40 03 2c 
                00 01 00 00 00 03 64 32 00 00 
                00 28 64 94 d5 02 07 00 00 04 
                95 2c 00 8b 34 00 82 3f 00 7d 
                4c 00 7a 5b 00 7a 00 00 00 00 
                00 00 00 00 00 00 00 00 00 00 
                00 00 00 00 00 00 00 00 00 00 
                00 00 00 00 00 00 00 00 00 00 
                00 00 18 16 14 12 10 0e 0c 0a 
                08 06 04 02 ff ff 00 00 00 00 
                00 00 00 00 00 00 00 00 00 00 
                00 00 16 18 1c 1d 1e 1f 20 21 
                22 24 13 12 10 0f 0a 08 06 04 
                02 00 ff ff ff ff ff ff 00 00 
                00 00 00 00 00 00 00 00 00 00 
                00 00 00 00 79 01
                ];

                /*4.3*/
                goodix,cfg-group1 = [
                97 E0 01 10 01 05 0D 00 01 00
                00 05 5A 46 53 11 00 00 11 11
                14 14 14 22 0A 04 00 00 00 00
                00 00 53 00 14 00 00 84 00 00
                3C 00 00 64 1E 28 87 27 08 32
                34 05 0D 20 33 60 11 02 24 00
                00 64 80 80 14 02 00 00 54 89
                68 85 6D 82 72 80 76 7D 7B 7B
                00 00 00 00 00 00 00 F0 50 3C
                FF FF 07 00 00 00 02 14 14 03
                04 00 21 64 0A 00 00 00 00 00
                00 00 00 00 00 00 00 00 00 00
                00 00 00 00 00 00 00 00 00 00
                32 20 50 3C 3C 00 00 00 00 00
                0D 06 0C 05 0B 04 0A 03 FF FF
                FF FF FF FF 00 01 02 03 04 05
                06 07 08 09 0A 0B 0C 0D FF FF
                FF FF FF FF FF FF FF FF FF FF
                00 00 00 00 00 00 00 00 00 00
                00 00 00 00 3C 00 05 1E 00 02
                2A 1E 19 14 02 00 03 0A 05 00
                00 00 00 00 00 00 01 FF FF 86
                22 03 00 00 33 00 0F 00 00 00
                50 3C 50 00 00 00 00 2A 01
                ];

                /*5*/
                goodix,cfg-group2 = [
                00 20 03 E0 01 05 3C 00 01 08
                28 0C 50 32 03 05 00 00 00 00
                00 00 00 17 19 1E 14 8B 2B 0D
                33 35 0C 08 00 00 00 9A 03 11
                00 01 00 00 00 00 00 32 00 00
                00 20 58 94 C5 02 00 00 00 04
                B0 23 00 93 2B 00 7B 35 00 69
                41 00 5B 4F 00 5B 00 00 00 00
                00 00 00 00 00 00 00 00 00 00
                00 00 00 00 00 00 00 00 00 00
                00 00 00 00 00 00 00 00 00 00
                00 00 02 04 06 08 0A 0C 0E 10
                12 14 16 18 1A FF 00 00 00 00
                00 00 00 00 00 00 00 00 00 00
                00 00 00 02 04 06 08 0A 0C 0F
                10 12 13 16 18 1C 1D 1E 1F 20
                21 22 24 26 FF FF FF FF 00 00
                00 FF FF FF FF FF FF FF FF FF
                FF FF FF FF 48 01
                ];

        };


};

&iomuxc {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_hog_1>;
    imx6ul-evk {
        key2_100ask: key2_100ask {                /*!< Function assigned for the core: Cortex-A7[ca7] */
            fsl,pins = <
                MX6UL_PAD_NAND_CE1_B__GPIO4_IO14           0x000010B0
            >;
        };

        pinctrl_hog_1: hoggrp-1 {
            fsl,pins = <
                MX6UL_PAD_UART1_RTS_B__GPIO1_IO19   0x17059 /* SD1 CD */
                MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID    0x17059 /* USB OTG1 ID */
                // MX6UL_PAD_CSI_DATA07__GPIO4_IO28           0x000010B0
                MX6ULL_PAD_SNVS_TAMPER5__GPIO5_IO05        0x000110A0
            >;
        };
                pinctrl_sii902x: hdmigrp {
                fsl,pins = <
                        MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0x59
                            >;
            };
                pinctrl_touchscreen_int: lcdif_tsc_int {
                fsl,pins = <
                        MX6UL_PAD_GPIO1_IO05__GPIO1_IO05 0x000010B0
                            >;
                        };
        pinctrl_enet1: enet1grp {
            fsl,pins = <
            >;
        };

        pinctrl_enet2: enet2grp {
            fsl,pins = <
                MX6UL_PAD_GPIO1_IO06__ENET2_MDIO    0x1b0b0
                MX6UL_PAD_GPIO1_IO07__ENET2_MDC     0x1b0b0
                MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN  0x1b0b0
                MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER  0x1b0b0
                MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
                MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
                MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN  0x1b0b0
                MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
                MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
                MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2  0x4001b031
                MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN  0x1b0b0
                MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER  0x1b0b0
                MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
                MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
                MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN  0x1b0b0
                MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
                MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
                MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1  0x4001b031
            >;
        };

        pinctrl_flexcan1: flexcan1grp{
            fsl,pins = <
                MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX         0x000010B0
                MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX         0x000010B0
            >;
        };

        pinctrl_i2c1: i2c1grp {
            fsl,pins = <
                MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
                MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
            >;
        };

        pinctrl_i2c2: i2c2grp {
            fsl,pins = <
                MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
                MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
            >;
        };

        pinctrl_ecspi3: ecspi3 {              
                    fsl,pins = <
                MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI         0x000010B0
                MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO         0x000010B0
                MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK       0x000010B0
                //MX6UL_PAD_UART2_TX_DATA__ECSPI3_SS0        0x000010B0
                MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20        0x000010B0
                MX6UL_PAD_GPIO1_IO01__GPIO1_IO01           0x000010B0
            >;
        };

        pinctrl_ecspi1: ecspi1 {
                     fsl,pins = <
                 MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK         0x000010B0
                 MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI         0x000010B0
                 MX6UL_PAD_CSI_DATA07__ECSPI1_MISO         0x000010B0
                 MX6UL_PAD_CSI_DATA05__GPIO4_IO26          0x000010B0
                 MX6UL_PAD_CSI_DATA03__GPIO4_IO24          0x000010B0
             >;
         };

        pinctrl_uart3: uart3grp {
            fsl,pins = <
                MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX   0x1b0b1
                MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX   0x1b0b1
            >;
        };
        
        pinctrl_uart1: uart1grp {
            fsl,pins = <
                MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
                MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
            >;
        };

        pinctrl_uart6: uart6grp {
             fsl,pins = <
                 MX6UL_PAD_CSI_MCLK__UART6_DCE_TX      0x1b0b1
                 MX6UL_PAD_CSI_PIXCLK__UART6_DCE_RX    0x1b0b1
             >;
         };


        pinctrl_sai2: sai2grp {
            fsl,pins = <
                MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK    0x17088
                MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC    0x17088
                MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA 0x11088
                MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA    0x11088
                MX6UL_PAD_JTAG_TMS__SAI2_MCLK       0x17088
            >;
        };

        pinctrl_tsc: tscgrp {
            fsl,pins = <
                MX6UL_PAD_GPIO1_IO01__GPIO1_IO01    0xb0
                MX6UL_PAD_GPIO1_IO02__GPIO1_IO02    0xb0
                MX6UL_PAD_GPIO1_IO03__GPIO1_IO03    0xb0
                MX6UL_PAD_GPIO1_IO04__GPIO1_IO04    0xb0
            >;
        };

        pinctrl_usdhc1: usdhc1grp {
            fsl,pins = <
                MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x17059
                MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x10071
                MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059
                MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059
                MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059
                MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059
            >;
        };

        pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
            fsl,pins = <
                MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x170b9
                MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x100b9
                MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
                MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
                MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
                MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9
            >;
        };

        pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
            fsl,pins = <
                MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x170f9
                MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x100f9
                MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
                MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
                MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
                MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
            >;
        };

        pinctrl_usdhc2: usdhc2grp {
            fsl,pins = <
                MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x10069
                MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x17059
                MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
                MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
                MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
                MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
            >;
        };

        pinctrl_usdhc2_8bit: usdhc2grp_8bit {
            fsl,pins = <
                MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x10069
                MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x17059
                MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
                MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
                MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
                MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
                MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x17059
                MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x17059
                MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x17059
                MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x17059
            >;
        };

        pinctrl_usdhc2_8bit_100mhz: usdhc2grp_8bit_100mhz {
            fsl,pins = <
                MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x100b9
                MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x170b9
                MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170b9
                MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170b9
                MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170b9
                MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170b9
                MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170b9
                MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170b9
                MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170b9
                MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170b9
            >;
        };

        pinctrl_usdhc2_8bit_200mhz: usdhc2grp_8bit_200mhz {
            fsl,pins = <
                MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x100f9
                MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x170f9
                MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170f9
                MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170f9
                MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170f9
                MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170f9
                MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170f9
                MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170f9
                MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170f9
                MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170f9
            >;
        };
        pinctrl_lcdif_dat: lcdifdatgrp {
            fsl,pins = <
                MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x79
                MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x79
                MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x79
                MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x79
                MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x79
                MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x79
                MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x79
                MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x79
                MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x79
                MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x79
                MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x79
                MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x79
                MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x79
                MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x79
                MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x79
                MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x79
                MX6UL_PAD_LCD_DATA16__LCDIF_DATA16  0x79
                MX6UL_PAD_LCD_DATA17__LCDIF_DATA17  0x79
                MX6UL_PAD_LCD_DATA18__LCDIF_DATA18  0x79
                MX6UL_PAD_LCD_DATA19__LCDIF_DATA19  0x79
                MX6UL_PAD_LCD_DATA20__LCDIF_DATA20  0x79
                MX6UL_PAD_LCD_DATA21__LCDIF_DATA21  0x79
                MX6UL_PAD_LCD_DATA22__LCDIF_DATA22  0x79
                MX6UL_PAD_LCD_DATA23__LCDIF_DATA23  0x79
            >;
        };

        pinctrl_lcdif_dat_16bits: lcdifdatgrp_16bits {
            fsl,pins = <
                MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x79
                MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x79
                MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x79
                MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x79
                MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x79
                MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x79
                MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x79
                MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x79
                MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x79
                MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x79
                MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x79
                MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x79
                MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x79
                MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x79
                MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x79
                MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x79
            >;
        };

        pinctrl_lcdif_ctrl: lcdifctrlgrp {
            fsl,pins = <
                MX6UL_PAD_LCD_CLK__LCDIF_CLK        0x79
                MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x79
                MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x79
                MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x79
            >;
        };
        pinctrl_pwm1: pwm1grp {
            fsl,pins = <
                MX6UL_PAD_GPIO1_IO08__PWM1_OUT   0x110b0
            >;
        };
        pinctrl_lcdif_reset: lcdifresetgrp {
            fsl,pins = <
                MX6UL_PAD_LCD_RESET__GPIO3_IO04     0x1b0b0
            >;
        };

        pinctrl_adc1: adc1grp {
            fsl,pins = <
                MX6UL_PAD_GPIO1_IO03__GPIO1_IO03          0x000010B1
                MX6UL_PAD_GPIO1_IO04__GPIO1_IO04          0x000010B1
                >;
        };

    };
};

&iomuxc_snvs {
    pinctrl-names = "default_snvs";
    pinctrl-0 = <&pinctrl_hog_2>;
    imx6ul-evk {
        key1_100ask: key1_100ask {        /*!< Function assigned for the core: Cortex-A7[ca7] */
            fsl,pins = <
                MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01        0x000110A0
            >;
        };

        pinctrl_hog_2: hoggrp-2 {
            fsl,pins = <
                MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09     0x1b0b0 /* enet1 reset */
                MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06     0x1b0b0 /* enet2 reset */
                MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01     0x000110A0 /*key 1*/
            >;
        };

         pinctrl_tsc_reset: tscresetgrp  {        /*!< Function assigned for the core: Cortex-A7[ca7] */
            fsl,pins = <
                MX6ULL_PAD_SNVS_TAMPER2__GPIO5_IO02        0x000110A0
            >;
        };

        pinctrl_spi4: spi4grp {
            fsl,pins = <
                MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10        0x70a1
                MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11        0x70a1
                MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07      0x70a1
                MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08      0x80000000
            >;
        };

        pinctrl_leds: ledgrp {
            fsl,pins = <
                  MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03        0x000110A0
            >;
        };

        pinctrl_485_ctl: uart3_rs485 {
            fsl,pins = <
            MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00     0x1b0b0
            >;
        };
        
    };
};

&lcdif {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_lcdif_dat
             &pinctrl_lcdif_ctrl
             &pinctrl_lcdif_reset>; 
    display = <&display0>;
    status = "okay";
    reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>; /* 100ask */

    display0: display {
        bits-per-pixel = <24>;
        bus-width = <24>;

        display-timings {
            native-mode = <&timing0>;

             timing0: timing0_1024x768 {
             clock-frequency = <50000000>;
             hactive = <1024>;
             vactive = <600>;
             hfront-porch = <160>;
             hback-porch = <140>;
             hsync-len = <20>;
             vback-porch = <20>;
             vfront-porch = <12>;
             vsync-len = <3>;

             hsync-active = <0>;
             vsync-active = <0>;
             de-active = <1>;
             pixelclk-active = <0>;
             };

        };
    };
};

&pwm1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_pwm1>;
    status = "okay";
};

&pxp {
    status = "okay";
};
&ecspi3 { 
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_ecspi3>;
    cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
    status = "okay";
    
    
    spidev: icm20608@0{
        compatible = "invensense,icm20608";
        interrupt-parent = <&gpio1>;
        interrupts = <1 1>;
        spi-max-frequency = <8000000>; 
        reg = <0>; 
    };
};

&sai2 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_sai2>;

    assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>,
              <&clks IMX6UL_CLK_SAI2>;
    assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
    assigned-clock-rates = <0>, <12288000>;

    status = "okay";
};

&tsc {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_tsc>;
    xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
    measure-delay-time = <0xfffff>;
    pre-charge-time = <0xffff>;
    status = "okay";
};

&uart1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_uart1>;
    status = "okay";
};
&uart3 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_uart3
             &pinctrl_485_ctl>;
    //pinctrl-0 = <&pinctrl_uart3>;
    //fsl,rs485-gpio-txen = <&gpio5 0 GPIO_ACTIVE_HIGH>;
    //rts-gpio = <&gpio5 0 GPIO_ACTIVE_HIGH>;
    rs485-rts-active-high;
    //rs485-rts-active-high;
        rs485-rx-during-tx;
        rs485-rts-delay = <100 100>;
        linux,rs485-enabled-at-boot-time;
    status = "okay";
};
 
&uart6 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_uart6>;
    status = "okay";
};


&usbotg1 {
    dr_mode = "otg";
    srp-disable;
    hnp-disable;
    adp-disable;
    status = "okay";
};

&usbotg2 {
    dr_mode = "host";
    disable-over-current;
    status = "okay";
};

&usbphy1 {
    tx-d-cal = <0x5>;
};

&usbphy2 {
    tx-d-cal = <0x5>;
};

&usdhc1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_usdhc1>;
    cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
    keep-power-in-suspend;
    enable-sdio-wakeup;
    bus-width = <4>;
    status = "okay";
};

&usdhc2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2_8bit>;
        bus-width = <8>;
        non-removable;
        status = "okay";
};

&wdog1 {
    status = "okay";
};

&adc1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_adc1>;
    num-channels = <5>;
    vref-supply = <&reg_can_3v3>;
    status = "okay";
};

&ecspi1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_ecspi1>;
    
    fsl,spi-num-chipselects = <2>;
    cs-gpio = <&gpio4 26 GPIO_ACTIVE_LOW>, <&gpio4 24 GPIO_ACTIVE_LOW>;
    status = "okay";
    /*   
    spidev0: spi@0 {
        compatible = "rohm,dh2228fv";
        reg = <0>;
        spi-max-frequency = <5000000>;
    };
    
    spidev1: spi@1 {
        compatible = "rohm,dh2228fv";
        reg = <1>;
        spi-max-frequency = <5000000>;
    };
    */
    
};


1. 设备树里只指定gpio c驱动
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>


struct gpio_key{
	int gpio;
	struct gpio_desc *gpiod;
	int flag;
	int irq;
} ;

static struct gpio_key *gpio_keys_100ask;

/* 主设备号                                                                 */
static int major = 0;
static struct class *gpio_key_class;

static int g_key = 0;

static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);

/* 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	int err;
	
	wait_event_interruptible(gpio_key_wait, g_key);
	err = copy_to_user(buf, &g_key, 4);
	g_key = 0;
	
	return 4;
}


/* 定义自己的file_operations结构体                                              */
static struct file_operations gpio_key_drv = {
	.owner	 = THIS_MODULE,
	.read    = gpio_key_drv_read,
};


static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
	struct gpio_key *gpio_key = dev_id;
	int val;
	val = gpiod_get_value(gpio_key->gpiod);
	

	printk("key %d %d\n", gpio_key->gpio, val);
	g_key = (gpio_key->gpio << 8) | val;
	wake_up_interruptible(&gpio_key_wait);
	
	return IRQ_HANDLED;
}

/* 1. 从platform_device获得GPIO
 * 2. gpio=>irq
 * 3. request_irq
 */
static int gpio_key_probe(struct platform_device *pdev)
{
	int err;
	struct device_node *node = pdev->dev.of_node;
	int count;
	int i;
	enum of_gpio_flags flag;
		
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	count = of_gpio_count(node);
	if (!count)
	{
		printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
		return -1;
	}

	gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);
	for (i = 0; i < count; i++)
	{
		gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag);
		if (gpio_keys_100ask[i].gpio < 0)
		{
			printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);
			return -1;
		}
		gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio);
		gpio_keys_100ask[i].flag = flag & OF_GPIO_ACTIVE_LOW;
		gpio_keys_100ask[i].irq  = gpio_to_irq(gpio_keys_100ask[i].gpio);
	}

	for (i = 0; i < count; i++)
	{
		err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_keys_100ask[i]);
	}

	/* 注册file_operations 	*/
	major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv);  /* /dev/100ask_gpio_key */

	gpio_key_class = class_create(THIS_MODULE, "100ask_gpio_key_class");
	if (IS_ERR(gpio_key_class)) {
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		unregister_chrdev(major, "100ask_gpio_key");
		return PTR_ERR(gpio_key_class);
	}

	device_create(gpio_key_class, NULL, MKDEV(major, 0), NULL, "100ask_gpio_key"); /* /dev/100ask_gpio_key */
        
    return 0;
    
}

static int gpio_key_remove(struct platform_device *pdev)
{
	//int err;
	struct device_node *node = pdev->dev.of_node;
	int count;
	int i;

	device_destroy(gpio_key_class, MKDEV(major, 0));
	class_destroy(gpio_key_class);
	unregister_chrdev(major, "100ask_gpio_key");

	count = of_gpio_count(node);
	for (i = 0; i < count; i++)
	{
		free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);
	}
	kfree(gpio_keys_100ask);
    return 0;
}


static const struct of_device_id ask100_keys[] = {
    { .compatible = "100ask,gpio_key" },
    { },
};

/* 1. 定义platform_driver */
static struct platform_driver gpio_keys_driver = {
    .probe      = gpio_key_probe,
    .remove     = gpio_key_remove,
    .driver     = {
        .name   = "100ask_gpio_key",
        .of_match_table = ask100_keys,
    },
};

/* 2. 在入口函数注册platform_driver */
static int __init gpio_key_init(void)
{
    int err;
    
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	
    err = platform_driver_register(&gpio_keys_driver); 
	
	return err;
}

/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
 *     卸载platform_driver
 */
static void __exit gpio_key_exit(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

    platform_driver_unregister(&gpio_keys_driver);
}


/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */

module_init(gpio_key_init);
module_exit(gpio_key_exit);

MODULE_LICENSE("GPL");



2. 设备树里只指定gpio 再增加环形缓冲区 c驱动
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>


struct gpio_key{
	int gpio;
	struct gpio_desc *gpiod;
	int flag;
	int irq;
} ;

static struct gpio_key *gpio_keys_100ask;

/* 主设备号                                                                 */
static int major = 0;
static struct class *gpio_key_class;

#define BUF_LEN 128
static int g_key[BUF_LEN];
static int r=0,w=0;
#define NEXT_POS(x) ((x+1)% BUF_LEN)

static int is_key_buf_empty(void)
{
	if(r == w)
		return 0;
	else
		return 1;
}

static void put_key(int key)
{
	g_key[w] = key;
	w = NEXT_POS(w);
}

static int get_key(void)
{
	int key =0;
	key = g_key[r];
	r = NEXT_POS(r);
	return key;
}



static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);

/* 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	int err;
	printk(KERN_EMERG"111111111\n");
	wait_event_interruptible(gpio_key_wait, is_key_buf_empty() );
	int return_val = get_key();
	printk(KERN_EMERG"the return val is %d\n",return_val);
	err = copy_to_user(buf, &return_val, 4);
	
	return 4;
}


/* 定义自己的file_operations结构体                                              */
static struct file_operations gpio_key_drv = {
	.owner	 = THIS_MODULE,
	.read    = gpio_key_drv_read,
};


static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
	struct gpio_key *gpio_key = dev_id;
	int val;
	val = gpiod_get_value(gpio_key->gpiod);
	
	printk(KERN_EMERG"222222222222222\n");
	printk("key %d %d\n", gpio_key->gpio, val);
	put_key((gpio_key->gpio << 8) | val);
	printk(KERN_EMERG"the val is %d\n",(gpio_key->gpio << 8) | val);
	printk(KERN_EMERG"now r is %d w is %d\n",r,w);
	wake_up_interruptible(&gpio_key_wait);
	
	return IRQ_HANDLED;
}

/* 1. 从platform_device获得GPIO
 * 2. gpio=>irq
 * 3. request_irq
 */
static int gpio_key_probe(struct platform_device *pdev)
{
	int err;
	struct device_node *node = pdev->dev.of_node;
	int count;
	int i;
	enum of_gpio_flags flag;
		
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	count = of_gpio_count(node);
	if (!count)
	{
		printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
		return -1;
	}

	gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);
	for (i = 0; i < count; i++)
	{
		gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag);
		if (gpio_keys_100ask[i].gpio < 0)
		{
			printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);
			return -1;
		}
		gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio);
		gpio_keys_100ask[i].flag = flag & OF_GPIO_ACTIVE_LOW;
		gpio_keys_100ask[i].irq  = gpio_to_irq(gpio_keys_100ask[i].gpio);
	}
	
	for (i = 0; i < count; i++)
	{
		err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_keys_100ask[i]);
	}

	/* 注册file_operations 	*/
	major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv);  /* /dev/100ask_gpio_key */

	gpio_key_class = class_create(THIS_MODULE, "100ask_gpio_key_class");
	if (IS_ERR(gpio_key_class)) {
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		unregister_chrdev(major, "100ask_gpio_key");
		return PTR_ERR(gpio_key_class);
	}

	device_create(gpio_key_class, NULL, MKDEV(major, 0), NULL, "100ask_gpio_key"); /* /dev/100ask_gpio_key */
        
    return 0;
    
}

static int gpio_key_remove(struct platform_device *pdev)
{
	//int err;
	struct device_node *node = pdev->dev.of_node;
	int count;
	int i;

	device_destroy(gpio_key_class, MKDEV(major, 0));
	class_destroy(gpio_key_class);
	unregister_chrdev(major, "100ask_gpio_key");

	count = of_gpio_count(node);
	for (i = 0; i < count; i++)
	{
		free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);
	}
	kfree(gpio_keys_100ask);
    return 0;
}


static const struct of_device_id ask100_keys[] = {
    { .compatible = "100ask,gpio_key" },
    { },
};

/* 1. 定义platform_driver */
static struct platform_driver gpio_keys_driver = {
    .probe      = gpio_key_probe,
    .remove     = gpio_key_remove,
    .driver     = {
        .name   = "100ask_gpio_key",
        .of_match_table = ask100_keys,
    },
};

/* 2. 在入口函数注册platform_driver */
static int __init gpio_key_init(void)
{
    int err;
    
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	
    err = platform_driver_register(&gpio_keys_driver); 
	
	return err;
}

/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
 *     卸载platform_driver
 */
static void __exit gpio_key_exit(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

    platform_driver_unregister(&gpio_keys_driver);
}


/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */

module_init(gpio_key_init);
module_exit(gpio_key_exit);

MODULE_LICENSE("GPL");



app 代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

/*
 * ./button_test /dev/100ask_button0
 *
 */
int main(int argc, char **argv)
{
	int fd;
	int val;
	
	/* 1. 判断参数 */
	if (argc != 2) 
	{
		printf("Usage: %s <dev>\n", argv[0]);
		return -1;
	}

	/* 2. 打开文件 */
	fd = open(argv[1], O_RDWR);
	if (fd == -1)
	{
		printf("can not open file %s\n", argv[1]);
		return -1;
	}

	while (1)
	{
		/* 3. 读文件 */
		read(fd, &val, 4);
		printf("get button : 0x%x\n", val);
	}
	
	close(fd);
	
	return 0;
}



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的esp32-idf和sx1268的休眠唤醒代码示例: ```c #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/gpio.h" #include "driver/spi_master.h" #include "sx126x.h" #define SX126X_SPI_HOST HSPI_HOST #define SX126X_PIN_CS GPIO_NUM_15 #define SX126X_PIN_BUSY GPIO_NUM_27 #define SX126X_PIN_RESET GPIO_NUM_33 spi_device_handle_t spi_handle; void sx126x_sleep(sx126x_t * sx126x) { // Set sleep mode sx126x_set_sleep(sx126x, SX126X_SLEEP_CFG_RC); // Configure RTC timer to wake up sx126x after 10 seconds sx126x_rtc_set_alarm(sx126x, 10 * SX126X_RTC_TICKS_PER_SECOND); // Disable spi spi_bus_remove_device(spi_handle); spi_bus_free(SX126X_SPI_HOST); // Enter deep sleep mode esp_deep_sleep_start(); } void sx126x_wakeup(sx126x_t * sx126x) { // Initialize spi spi_bus_config_t spi_bus_cfg = { .mosi_io_num = GPIO_NUM_23, .miso_io_num = GPIO_NUM_19, .sclk_io_num = GPIO_NUM_18, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 0, .flags = SPICOMMON_BUSFLAG_MASTER }; spi_device_interface_config_t spi_dev_cfg = { .clock_speed_hz = 10 * 1000 * 1000, .mode = 0, .spics_io_num = SX126X_PIN_CS, .queue_size = 1, .flags = SPI_DEVICE_NO_DUMMY, .command_bits = 8, .address_bits = 0, }; spi_bus_initialize(SX126X_SPI_HOST, &spi_bus_cfg, 1); spi_bus_add_device(SX126X_SPI_HOST, &spi_dev_cfg, &spi_handle); // Send wakeup command to sx126x sx126x_set_standby(sx126x); vTaskDelay(10 / portTICK_PERIOD_MS); sx126x_set_fs(sx126x); vTaskDelay(1 / portTICK_PERIOD_MS); // Wait for sx126x to complete wakeup while (gpio_get_level(SX126X_PIN_BUSY) == 1) { vTaskDelay(1 / portTICK_PERIOD_MS); } // Re-enable spi spi_bus_remove_device(spi_handle); spi_bus_free(SX126X_SPI_HOST); spi_bus_initialize(SX126X_SPI_HOST, &spi_bus_cfg, 1); spi_bus_add_device(SX126X_SPI_HOST, &spi_dev_cfg, &spi_handle); } void app_main(void) { // Initialize sx126x sx126x_t sx126x = { .spi_host = SX126X_SPI_HOST, .spi_cs = SX126X_PIN_CS, .spi_handle = spi_handle, .busy_pin = SX126X_PIN_BUSY, .reset_pin = SX126X_PIN_RESET, }; sx126x_init(&sx126x); // Put sx126x to sleep sx126x_sleep(&sx126x); // Wake up sx126x sx126x_wakeup(&sx126x); // Do something with sx126x // ... } ``` 注意,上述代码仅供参考,具体的实现可能会因为不同的硬件和软件环境而有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值