Bootstrap

第五十七讲 GPIO子系统

第五十七讲 GPIO子系统

一、前言

很抱歉,前面都没怎么更新!!!

二、GPIO 子系统

1、GPIO

上图是在 ebf_linux_kernel/arch/arm/boot/dts/imx6ull.dtsi 文件里面截取的一段代码。aliases 的翻译过来是别名的意思,这里以 gpio0 为例,将 gpio0 取别名为 gpio1。

gpio1: gpio@209c000 {
    compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
    reg = <0x209c000 0x4000>;
    interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
    <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clks IMX6UL_CLK_GPIO1>;
    gpio-controller;
    #gpio-cells = <2>;
    interrupt-controller;
    #interrupt-cells = <2>;
    gpio-ranges = <&iomuxc  0 23 10>, <&iomuxc 10 17 6>,
    <&iomuxc 16 33 16>;
};

上面是 gpio1 的一些属性,这个有跟 gpio 子系统做匹配的作用。

  • compatible 属性是操作系统用来决定绑定设备驱动的关键因素,它是一个字符串列表,格式为 <制造商>,<型号>。其余的字符串表示与之兼容的设备。
  • reg 属性是寄存器组,gpio1 的起始地址为 0x209c000
  • interrupts 描述 gpio 中断相关内容
  • clocks 初始化 gpio 时钟
  • gpio-controller 表明 gpio1 是 gpio 的控制器
  • #gpio-cells = <2> 表示用两个 cell 描述一个 gpio 引脚
  • interrupt-controller 表示 gpio1 节点是个中断控制器
  • gpio-ranges gpio 编号转换为 pin 编号

2、新增一个 gpio 节点

rgb_led{
#address-cells = <1>;
#size-cells = <1>;
pinctrl-names = "default";
compatible = "fire,rgb-led";
pinctrl-0 = <&pinctrl_rgb_led>;
rgb_led_red = <&gpio1 4 GPIO_ACTIVE_LOW>;
rgb_led_green = <&gpio4 20 GPIO_ACTIVE_LOW>;
rgb_led_blue = <&gpio4 19 GPIO_ACTIVE_LOW>;
status = "okay";
};
  • compatible:属性值,与 led 平台驱动做匹配
  • pinctrl-0:指定 RGB 灯的引脚 pinctrl 信息
  • rgb_led_red:自定义属性
  • &gpio1 4:表示GPIO_PIN4(gpio1 表示 GPIO组 4表示GPIO编号)
  • GPIO_ACTIVE_LOW:低电平有效

注意:

以上这一段依赖另外一段代码,如果加上报错误

Reference to non-existent node or label "pinctrl_rgb_led"

需要加上

pinctrl_rgb_led:rgb_led{
		fsl,pins=<
			MX6UL_PAD_GPIO1_IO04__GPIO1_IO04    0x000010B1
			MX6UL_PAD_CSI_HSYNC__GPIO4_IO20     0x000010B1
			MX6UL_PAD_CSI_VSYNC__GPIO4_IO19     0x000010B1
		>;
	};

3、常用 API 讲解

  • 获取 GPIO 编号函数 of_get_named_gpio

    gpio 子系统有很多函数会用到 gpio 编号,可以通过 of_get_named_gpio 函数获取

    /**
     * of_get_named_gpio() - Get a GPIO number to use with GPIO API
     * @np:		device node to get GPIO from
     * @propname:	Name of property containing gpio specifier(s)
     * @index:	index of the GPIO
     *
     * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
     * value on the error condition.
     */
    static inline int of_get_named_gpio(struct device_node *np,
                                       const char *propname, int index)
    
  • GPIO 申请函数 gpio_request

    申请 GPIO

    /* 参数:
    • gpio: 要申请的 GPIO 编号,该值是函数 of_get_named_gpio 的返回值。
    • label: 引脚名字,相当于为申请得到的引脚取了个别名。
    返回值:
    • 成功: 返回 0,
    • 失败: 返回负数。
    */
    static inline int gpio_request(unsigned gpio, const char *label);
    
  • GPIO 释放函数

/*
gpio_free 函数与 gpio_request 是一对相反的函数,一个申请,一个释放。一个 GPIO 只能被申请
一次,当不再使用某一个引脚时记得将其释放掉。
参数:
• gpio:要释放的 GPIO 编号。
返回值:无
*/
static inline void gpio_free(unsigned gpio);

注意:摘自 /ebf_linux_kernel/Documentation/translations/zh_CN/gpio.txt

(这里仅摘抄了部分,更多的可以查阅文档,里面介绍的很详细)

声明和释放 GPIO
----------------------------
为了有助于捕获系统配置错误,定义了两个函数。

	/* 申请 GPIO, 返回 0 或负的错误代码.
	 * 非空标签可能有助于诊断.
	 */
	int gpio_request(unsigned gpio, const char *label);

	/* 释放之前声明的 GPIO */
	void gpio_free(unsigned gpio);

将无效的 GPIO 编码传递给 gpio_request()会导致失败,申请一个已使用这个
函数声明过的 GPIO 也会失败。gpio_request()的返回值必须检查。你应该在
进程上下文中调用这些函数。然而,对于自旋锁安全的 GPIO,在板子启动的早期、
进入进程之前是可以申请的。

这个函数完成两个基本的目标。一是标识那些实际上已作为 GPIO 使用的信号线,
这样便于更好地诊断;系统可能需要服务几百个可用的 GPIO,但是对于任何一个
给定的电路板通常只有一些被使用。另一个目的是捕获冲突,查明错误:如两个或
更多驱动错误地认为他们已经独占了某个信号线,或是错误地认为移除一个管理着
某个已激活信号的驱动是安全的。也就是说,申请 GPIO 的作用类似一种锁机制。

某些平台可能也使用 GPIO 作为电源管理激活信号(例如通过关闭未使用芯片区和
简单地关闭未使用时钟)。

对于 GPIO 使用 pinctrl 子系统已知的引脚,子系统应该被告知其使用情况;
一个 gpiolib 驱动的 .request()操作应调用 pinctrl_gpio_request(),
而 gpiolib 驱动的 .free()操作应调用 pinctrl_gpio_free()。pinctrl
子系统允许 pinctrl_gpio_request()在某个引脚或引脚组以复用形式“属于”
一个设备时都成功返回。

任何须将 GPIO 信号导向适当引脚的引脚复用硬件的编程应该发生在 GPIO
驱动的 .direction_input()或 .direction_output()函数中,以及
任何输出 GPIO 值的设置之后。这样可使从引脚特殊功能到 GPIO 的转换
不会在引脚产生毛刺波形。有时当用一个 GPIO 实现其信号驱动一个非 GPIO
硬件模块的解决方案时,就需要这种机制。

某些平台允许部分或所有 GPIO 信号使用不同的引脚。类似的,GPIO 或引脚的
其他方面也需要配置,如上拉/下拉。平台软件应该在对这些 GPIO 调用
gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映射表,
使得 GPIO 的用户无须关注这些细节。

还有一个值得注意的是在释放 GPIO 前,你必须停止使用它。
  • GPIO 输出设置函数 gpio_direction_output

    用于将引脚设置为输出模式

    /*
    函数参数:
    • gpio: 要设置的 GPIO 的编号。
    • value: 输出值,1,表示高电平。0 表示低电平。
    返回值:
    • 成功: 返回 0
    • 失败: 返回负数
    */
    static inline int gpio_direction_output(unsigned gpio , int value);
    
  • GPIO 输入设置函数 gpio_direction_input

    用于将引脚设置为输入模式

    /*
    函数参数:
    • gpio: 要设置的 GPIO 的编号。
    返回值:
    • 成功: 返回 0
    • 失败: 返回负数。
    */
    static inline int gpio_direction_input(unsigned gpio)
    
  • 获取 GPIO 引脚值函数 gpio_get_value

    用于获取引脚的当前状态。无论引脚被设置为输出或者输入都可以用该函数获取引脚的当前状
    态。

    /*
    函数参数:
    • gpio: 要获取的 GPIO 的编号。
    返回值:
    • 成功: 获取得到的引脚状态
    • 失败: 返回负数
    */
    static inline int gpio_get_value(unsigned gpio)
    
  • 设置 GPIO 输出值 gpio_set_value

    该函数只用于那些设置为输出模式的 GPIO.

    /*
    函数参数
    • gpio:设置的 GPIO 的编号。
    • value:设置的输出值,为 1 输出高电平,为 0 输出低电平。
    返回值:
    • 成功: 返回 0
    • 失败: 返回负数
    */
    static inline int gpio_set_value(unsigned gpio, int value)
    

三、 GPIO 子系统实验

1、设备树编译

  • 在文件 imx6ull-mmc-npi.dts 添加以下代码
	rgb_led{
		#address-cells = <1>;
		#size-cells = <1>;
		pinctrl-names = "default";
		compatible = "fire,rgb-led";
		pinctrl-0 = <&pinctrl_rgb_led>;
		rgb_led_red = <&gpio1 4 GPIO_ACTIVE_LOW>;
		rgb_led_green = <&gpio4 20 GPIO_ACTIVE_LOW>;
		rgb_led_blue = <&gpio4 19 GPIO_ACTIVE_LOW>;
		status = "okay";
	};
  • 增加 pinctl 节点

    pinctrl_rgb_led:rgb_led{
    		fsl,pins=<
    			MX6UL_PAD_GPIO1_IO04__GPIO1_IO04    0x000010B1
    			MX6UL_PAD_CSI_HSYNC__GPIO4_IO20     0x000010B1
    			MX6UL_PAD_CSI_VSYNC__GPIO4_IO19     0x000010B1
    		>;
    	};
    
  • 编译设备树

    make ARCH=arm -j1 CROSS_COMPILE=arm-linux-gnueabihf- dtbs

  • 将编译好的 debo 移动到开发板上面

  • 替换开发板上面的 imx6ull-mmc-npi.dtbo 文件

    sudo mv imx6ull-mmc-npi.dtb /usr/lib/linux-image-4.19.35-imx6/

  • 重新启动开发板

    sudo reboot

2、 编写测试代码

Makefile
KERNEL_DIR=../../ebf_linux_kernel_6ull_depth1/build_image/build/

ARCH=arm
CROSS_COMPILE=arm-linux-gnueabihf-
export  ARCH  CROSS_COMPILE

obj-m := rgb_led.o

all:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules

.PHONE:clean copy

clean:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean	
rgb_led.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include "rgb_led.h"

int led_red_name, led_green_name, led_blue_name;

int rgbLedOpen (struct inode *node, struct file *file)
{
	printk("\n open form driver \n");
	return 0;
}
ssize_t rgbLedWrite (struct file *file, const char __user *usr, size_t size, loff_t *loff)
{
	char lRecvBuf[10] = {0};

	printk("<1> Led write");
	if(size >= 10)
	{
		printk("<1> size error!");
		return -1;
	}
	
	if(copy_from_user(lRecvBuf, usr, size) < 0)
	{
		printk("<1> copy error!");
		return -1;
	}
	printk("<1> recv is %s", lRecvBuf);
	
	if(strstr(lRecvBuf, "red on") != NULL)
	{
		gpio_set_value(led_red_name, 0);
	}
	else if(strstr(lRecvBuf, "red off") != NULL)
	{
		gpio_set_value(led_red_name, 1);
	}
	else if(strstr(lRecvBuf, "green on") != NULL)
	{
		gpio_set_value(led_green_name, 0);
	}
	else if(strstr(lRecvBuf, "green off") != NULL)
	{
		gpio_set_value(led_green_name, 1);
	}
	else if(strstr(lRecvBuf, "blue on") != NULL)
	{
		gpio_set_value(led_blue_name, 0);
	}
	else if(strstr(lRecvBuf, "blue off") != NULL)
	{
		gpio_set_value(led_blue_name, 1);
	}
	else
	{
		printk("error data %s", lRecvBuf);
		gpio_set_value(led_red_name, 1);
		gpio_set_value(led_green_name, 1);
		gpio_set_value(led_blue_name, 1);

	}
	return size;
}
struct cdev gRGBLedCdev = 
{
	.owner = THIS_MODULE,
};
struct file_operations gRGBLedFp = 
{
	.owner = THIS_MODULE,
	.open = rgbLedOpen,
	.write = rgbLedWrite,
};

/**
 * @brief Get the Gpio Named object
 * 
 * @param vDeviceNode 
 * @return int 
 */
int GetGpioNamed(struct device_node *vDeviceNode){
	// get name
	led_red_name = of_get_named_gpio(vDeviceNode, "rgb_led_red", 0);
	if(led_red_name < 0){
		printk("<1> of_get_named_gpio rgb_led_red failed! \n");
        return -1;
	}

	led_blue_name = of_get_named_gpio(vDeviceNode, "rgb_led_blue", 0);
	if(led_red_name < 0){
		printk("<1> of_get_named_gpio rgb_led_blue failed! \n");
        return -1;
	}

	led_green_name = of_get_named_gpio(vDeviceNode, "rgb_led_green", 0);
	if(led_red_name < 0){
		printk("<1> of_get_named_gpio rgb_led_green failed! \n");
        return -1;
	}
	return 0;
}

static int rgbProbe(struct platform_device *pdv)
{
    struct device_node *pRGBLedDeviceNode;

    /*查找设备树节点*/
	printk("<1> path is rgb_led");
    pRGBLedDeviceNode = of_find_node_by_path("/rgb_led");
    if(pRGBLedDeviceNode == NULL)
    {
        printk("<1> Find node by path failed!  \n");
        return -1;
    }

	// get name
	// if(0 != GetGpioNamed(pRGBLedDeviceNode)){
	// 	printk("<1> of_get_named_gpio failed!\n");
	// 	return -1;
	// }
	led_red_name = of_get_named_gpio(pRGBLedDeviceNode, "rgb_led_red", 0);
	if(led_red_name < 0){
		printk("<1> of_get_named_gpio rgb_led_red failed! \n");
        return -1;
	}

	led_blue_name = of_get_named_gpio(pRGBLedDeviceNode, "rgb_led_blue", 0);
	if(led_red_name < 0){
		printk("<1> of_get_named_gpio rgb_led_blue failed! \n");
        return -1;
	}

	led_green_name = of_get_named_gpio(pRGBLedDeviceNode, "rgb_led_green", 0);
	if(led_red_name < 0){
		printk("<1> of_get_named_gpio rgb_led_green failed! \n");
        return -1;
	}

	// request gpio
	// int nRet = gpio_request(led_red_name, "rgb_red");
	// if(0 != nRet){
	// 	printk("Request red gpio failed! %d\n", nRet);
	// 	return -1;
	// }

	// if(0 != gpio_request(led_blue_name, "rgb_blue")){
	// 	printk("Request blue gpio failed!\n");
	// 	gpio_free(led_red_name);
	// 	return -1;
	// }

	// if(0 != gpio_request(led_green_name, "rgb_green")){
	// 	printk("Request green gpio failed!\n");
	// 	gpio_free(led_red_name);
	// 	gpio_free(led_blue_name);
	// 	return -1;
	// }

	// set gpio direction
	if(0 != gpio_direction_output(led_red_name, 1)){
		printk("Set red direction failed!");
	}

	if(0 != gpio_direction_output(led_blue_name, 1)){
		printk("Set blue direction failed!");
	}

	if(0 != gpio_direction_output(led_green_name, 1)){
		printk("Set green direction failed!");
	}


    if( alloc_chrdev_region(&rgbDev, 0, 1, DEVICE_NAME) < 0)
	{
		printk("<1> alloc_chrdev_region failed \n");
		return -1;
	} 

	cdev_init(&gRGBLedCdev, &gRGBLedFp);

	cdev_add(&gRGBLedCdev, rgbDev, 1);

	rgbClass = class_create(THIS_MODULE, DEVICE_NAME);

	device_create(rgbClass, NULL, rgbDev, NULL, DEVICE_NAME);
	return 0;
}

static const struct of_device_id rgbLed[] = 
{
	{.compatible = "fire,rgb-led"},
	{/* sentinel */}
};
struct platform_driver rgbPlatformDriver = 
{
    .probe = rgbProbe,
    .driver = 
    {
        .name = "rgb_led_platform",
        .owner = THIS_MODULE,
        .of_match_table = rgbLed,
    },
    
};
static __init int RGBInit(void)
{
    int driverState;
	driverState = platform_driver_register(&rgbPlatformDriver);
	printk(KERN_ALERT "\tDriverState is %d\n", driverState);
	return 0;
}

static __exit void RGBExit(void)
{
	
}

module_init(RGBInit);
module_exit(RGBExit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yeyu");
MODULE_DESCRIPTION("RGBModule");
MODULE_ALIAS("RGBModule");
rgb_led.h
/*
 * @LastEditors: 夜雨
 * @Date: 2022-03-17 22:41:17
 * @LastEditTime: 2022-03-19 12:23:54
 * @FilePath: \code\kernel\012rgb_led\rgb_led.h
 */
#include <linux/of.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/of_gpio.h>
#include <linux/io.h>
#include <linux/of_address.h>

#define DEVICE_NAME     "rgb_led"

typedef struct  
{
    struct device_node *device_node;
    void __iomem *virtual_CCM_CCGR;
	void __iomem *virtual_IOMUXC_SW_MUX_CTL_PAD;
	void __iomem *virtual_IOMUXC_SW_PAD_CTL_PAD;
	void __iomem *virtual_DR;
	void __iomem *virtual_GDIR;
}rgbLedStr;

dev_t rgbDev;
struct class * rgbClass;
rgbLedStr gRGBLedStr[3];
步骤
  • 编译代码

    make

  • 将 rgb_led.ko 移动到开发板上面

  • 加载模块

    sudo insmod rgb_led.ko

  • 查看模块是否加载成功(出现 rgb_led 代表成功)

    debian@npi:~/ftp$ ls /dev/r
    ram0     ram11    ram14    ram3     ram6     ram9     rtc
    ram1     ram12    ram15    ram4     ram7     random   rtc0
    ram10    ram13    ram2     ram5     ram8     rgb_led
    
    

3、点灯

红灯亮
debian@npi:~/ftp$ sudo sh -c "echo 'red on'>/dev/rgb_led"
[  754.806648]
[  754.806648]  open form driver
[  754.813186] <1> Led write
[  754.813208] <1> recv is red on

红灯灭
debian@npi:~/ftp$ sudo sh -c "echo 'red off'>/dev/rgb_led"
[  801.206930]
[  801.206930]  open form driver
[  801.211582] <1> Led write
[  801.211595] <1> recv is red off

蓝灯亮
debian@npi:~/ftp$ sudo sh -c "echo 'blue on'>/dev/rgb_led"
[ 1007.684984]
[ 1007.684984]  open form driver
[ 1007.689639] <1> Led write
[ 1007.689651] <1> recv is blue on

蓝灯灭
debian@npi:~/ftp$ sudo sh -c "echo 'blue off'>/dev/rgb_led"
[  890.756871] <1> size error!
[  995.945819]
[  995.945819]  open form driver
[  995.953263] <1> Led write
[  995.953276] <1> recv is blue off

最后再说一句

这里绿灯灭的实验做不了,无法让绿灯灭

debian@npi:~/ftp$ sudo sh -c "echo 'green off'>/dev/rgb_led"
[ 1065.208778]
[ 1065.208778]  open form driver
[ 1065.213431] <1> Led write
sh: 1: echo: echo: I/O error

猜测是冲突了

还有就是调用 gpio_request 会报错误 16

感兴趣的同学可以找找原因,但是这里就不多说了,不影响整体实验。

四、附录1(imx6ull-mmc-npi.dts)

/*
 * 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 = "Embedfire i.MX6ULL Board";
	compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";

	aliases {
		pwm0 = &pwm1;
		pwm1 = &pwm2;
		pwm2 = &pwm3;
		pwm3 = &pwm4;
	};
	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;
		};
	};

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


		reg_sd1_vmmc: regulator@1 {
			compatible = "regulator-fixed";
			regulator-name = "VSD_3V3";
			regulator-min-microvolt = <3300000>;
			regulator-max-microvolt = <3300000>;
			gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
			off-on-delay = <20000>;
			enable-active-high;
		};
/*
		reg_gpio_dvfs: regulator-gpio {
			compatible = "regulator-gpio";
			pinctrl-names = "default";
			pinctrl-0 = <&pinctrl_dvfs>;
			regulator-min-microvolt = <1300000>;
			regulator-max-microvolt = <1400000>;
			regulator-name = "gpio_dvfs";
			regulator-type = "voltage";
			gpios = <&gpio5 3 GPIO_ACTIVE_HIGH>;
			states = <1300000 0x1 1400000 0x0>;
		};
*/
	};

	leds {
		compatible = "gpio-leds";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_led>;

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


	/* External sound card */
	sound: sound {
				status = "disabled";
	};

	spi4: 74hc595 {
		compatible = "spi-gpio";
		pinctrl-names = "default"; 
		pinctrl-0 = <&pinctrl_spi4>;
		pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
		status = "disabled";
		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 = <100000>;
		};
	};


	rgb_led{
		#address-cells = <1>;
		#size-cells = <1>;
		pinctrl-names = "default";
		compatible = "fire,rgb-led";
		pinctrl-0 = <&pinctrl_rgb_led>;
		rgb_led_red = <&gpio1 4 GPIO_ACTIVE_LOW>;
		rgb_led_green = <&gpio4 20 GPIO_ACTIVE_LOW>;
		rgb_led_blue = <&gpio4 19 GPIO_ACTIVE_LOW>;
		status = "okay";
	};
};

&cpu0 {
	/*dc-supply = <&reg_gpio_dvfs>;*/
	clock-frequency = <800000000>;
};

&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>;
	status = "okay";
};

&fec2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet2>;
	phy-mode = "rmii";
	phy-handle = <&ethphy1>;
	status = "okay";

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

		ethphy0: ethernet-phy@2 {
			compatible = "ethernet-phy-ieee802.3-c22";
			reg = <2>;
			micrel,led-mode = <1>;
			clocks = <&clks IMX6UL_CLK_ENET_REF>;
			clock-names = "rmii-ref";
		};

		ethphy1: ethernet-phy@1 {
			compatible = "ethernet-phy-ieee802.3-c22";
			reg = <1>;
			micrel,led-mode = <1>;
			clocks = <&clks IMX6UL_CLK_ENET2_REF>;
			clock-names = "rmii-ref";
		};
	};
};


&gpc {
	fsl,cpu_pupscr_sw2iso = <0xf>;
	fsl,cpu_pupscr_sw = <0x0>;
	fsl,cpu_pdnscr_iso2sw = <0x1>;
	fsl,cpu_pdnscr_iso = <0x1>;
	fsl,ldo-bypass = <0>; /* DCDC, ldo-enable */
};


&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_hog_1>;

	pinctrl_rgb_led:rgb_led{
		fsl,pins=<
			MX6UL_PAD_GPIO1_IO04__GPIO1_IO04    0x000010B1
			MX6UL_PAD_CSI_HSYNC__GPIO4_IO20     0x000010B1
			MX6UL_PAD_CSI_VSYNC__GPIO4_IO19     0x000010B1
		>;
	};

	pinctrl_hog_1: hoggrp-1 {
		fsl,pins = <
			MX6UL_PAD_UART1_RTS_B__GPIO1_IO19	0x17059 /* SD1 CD */
			MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT	0x17059 /* SD1 VSELECT */
			MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x17059 /* SD1 RESET */
		>;
	};

	pinctrl_enet1: enet1grp {
		fsl,pins = <
			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_enet2: enet2grp {
		fsl,pins = <
			MX6UL_PAD_GPIO1_IO07__ENET2_MDC		0x1b0b0
			MX6UL_PAD_GPIO1_IO06__ENET2_MDIO	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
		>;
	};

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

/*
        pinctrl_dvfs: dvfsgrp {
                fsl,pins = <
                        MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03      0x79
                >;
        };
*/
	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     0x10059
			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_led: ledgrp {
			fsl,pins = <
				MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x1b0b0
			>;
		};
};

&iomuxc_snvs {
	pinctrl-names = "default_snvs";
	pinctrl-0 = <&pinctrl_hog_2>;
	pinctrl_hog_2: hoggrp-2 {
		fsl,pins = <
			MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00      0x80000000
		>;
	};
	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
					>;
	};
};

&snvs_pwrkey {
	status = "okay";
};

&pxp {
	status = "okay";
};


&uart1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart1>;
	status = "okay";
};


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

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

&usbphy1 {
	fsl,tx-d-cal = <106>;
};

&usbphy2 {
	fsl,tx-d-cal = <106>;
};

&usdhc1 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc1>;
	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
	no-1-8-v;
	/*cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;*/
	keep-power-in-suspend;
	/*non-removable;*/
	enable-sdio-wakeup;
	vmmc-supply = <&reg_sd1_vmmc>;
	status = "okay";
};

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

;