summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2015-08-06 19:56:03 -0400
committerTom Rini <trini@konsulko.com>2015-08-06 19:56:03 -0400
commitae27120c31d58b8bb694d9155bcffdcfae8552a6 (patch)
tree8fcd4823406dc3adfb82174314198e9396c24feb
parentf05fa6781ae1122f348e66b5b26acbfe552f6602 (diff)
parentfac971b2b5efbdb6ed2d12ebdbf7e029c5ed30e8 (diff)
downloadu-boot-ae27120c31d58b8bb694d9155bcffdcfae8552a6.tar.gz
u-boot-ae27120c31d58b8bb694d9155bcffdcfae8552a6.tar.xz
u-boot-ae27120c31d58b8bb694d9155bcffdcfae8552a6.zip
Merge git://git.denx.de/u-boot-dm
-rw-r--r--arch/arm/cpu/armv7/exynos/Kconfig6
-rw-r--r--arch/arm/cpu/armv7/exynos/lowlevel_init.c5
-rw-r--r--arch/arm/cpu/armv7/exynos/pinmux.c10
-rw-r--r--arch/arm/cpu/armv7/s5p-common/cpu_info.c7
-rw-r--r--arch/arm/dts/Makefile1
-rw-r--r--arch/arm/dts/exynos4412-odroid.dts56
-rw-r--r--arch/arm/dts/exynos4412-trats2.dts70
-rw-r--r--arch/arm/dts/exynos5.dtsi34
-rw-r--r--arch/arm/dts/exynos5250-arndale.dts16
-rw-r--r--arch/arm/dts/exynos5250-smdk5250.dts171
-rw-r--r--arch/arm/dts/exynos5250-snow.dts371
-rw-r--r--arch/arm/dts/exynos5250-spring.dts588
-rw-r--r--arch/arm/dts/exynos5250.dtsi24
-rw-r--r--arch/arm/dts/exynos5420-peach-pit.dts260
-rw-r--r--arch/arm/dts/exynos5420-smdk5420.dts4
-rw-r--r--arch/arm/dts/exynos54xx.dtsi36
-rw-r--r--arch/arm/dts/exynos5800-peach-pi.dts131
-rw-r--r--arch/arm/include/asm/arch-exynos/dp_info.h2
-rw-r--r--arch/arm/include/asm/arch-exynos/periph.h1
-rw-r--r--arch/x86/cpu/start.S9
-rw-r--r--board/samsung/common/Makefile1
-rw-r--r--board/samsung/common/board.c17
-rw-r--r--board/samsung/common/exynos5-dt.c362
-rw-r--r--board/samsung/smdk5250/Kconfig13
-rw-r--r--board/samsung/smdk5250/MAINTAINERS6
-rw-r--r--board/samsung/smdk5250/Makefile4
-rw-r--r--board/samsung/smdk5250/exynos5-dt.c306
-rw-r--r--board/samsung/smdk5420/Makefile4
-rw-r--r--board/samsung/smdk5420/smdk5420.c143
-rw-r--r--common/cmd_regulator.c3
-rw-r--r--common/cmd_usb.c9
-rw-r--r--configs/arndale_defconfig2
-rw-r--r--configs/minnowmax_defconfig4
-rw-r--r--configs/odroid-xu3_defconfig6
-rw-r--r--configs/peach-pi_defconfig19
-rw-r--r--configs/peach-pit_defconfig19
-rw-r--r--configs/sandbox_defconfig2
-rw-r--r--configs/smdk5250_defconfig10
-rw-r--r--configs/smdk5420_defconfig6
-rw-r--r--configs/snow_defconfig23
-rw-r--r--configs/spring_defconfig42
-rw-r--r--doc/README.i2c60
-rw-r--r--doc/device-tree-bindings/i2c/i2c-mux.txt60
-rw-r--r--doc/device-tree-bindings/video/bridge/ps8622.txt33
-rw-r--r--drivers/core/Kconfig43
-rw-r--r--drivers/core/Makefile5
-rw-r--r--drivers/core/device-remove.c8
-rw-r--r--drivers/core/device.c34
-rw-r--r--drivers/core/devres.c259
-rw-r--r--drivers/core/simple-bus.c30
-rw-r--r--drivers/core/uclass.c42
-rw-r--r--drivers/gpio/gpio-uclass.c6
-rw-r--r--drivers/i2c/Kconfig26
-rw-r--r--drivers/i2c/Makefile4
-rw-r--r--drivers/i2c/cros_ec_ldo.c77
-rw-r--r--drivers/i2c/cros_ec_tunnel.c41
-rw-r--r--drivers/i2c/i2c-uclass.c27
-rw-r--r--drivers/i2c/muxes/Kconfig17
-rw-r--r--drivers/i2c/muxes/Makefile7
-rw-r--r--drivers/i2c/muxes/i2c-arb-gpio-challenge.c147
-rw-r--r--drivers/i2c/muxes/i2c-mux-uclass.c198
-rw-r--r--drivers/i2c/s3c24x0_i2c.c153
-rw-r--r--drivers/misc/cros_ec.c288
-rw-r--r--drivers/mmc/s5p_sdhci.c2
-rw-r--r--drivers/pci/pci_tegra.c10
-rw-r--r--drivers/power/pmic/Kconfig18
-rw-r--r--drivers/power/pmic/Makefile5
-rw-r--r--drivers/power/pmic/max77686.c6
-rw-r--r--drivers/power/pmic/pmic-uclass.c2
-rw-r--r--drivers/power/pmic/pmic_tps65090.c310
-rw-r--r--drivers/power/pmic/pmic_tps65090_ec.c218
-rw-r--r--drivers/power/pmic/s5m8767.c95
-rw-r--r--drivers/power/pmic/tps65090.c94
-rw-r--r--drivers/power/regulator/Kconfig19
-rw-r--r--drivers/power/regulator/Makefile2
-rw-r--r--drivers/power/regulator/max77686.c28
-rw-r--r--drivers/power/regulator/regulator-uclass.c4
-rw-r--r--drivers/power/regulator/s5m8767.c269
-rw-r--r--drivers/power/regulator/tps65090_regulator.c138
-rw-r--r--drivers/serial/Kconfig7
-rw-r--r--drivers/serial/serial_s5p.c63
-rw-r--r--drivers/spi/exynos_spi.c6
-rw-r--r--drivers/spi/fsl_dspi.c4
-rw-r--r--drivers/usb/eth/smsc95xx.c469
-rw-r--r--drivers/usb/eth/usb_ether.c1
-rw-r--r--drivers/usb/host/dwc2.c255
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/bridge/Kconfig27
-rw-r--r--drivers/video/bridge/Makefile9
-rw-r--r--drivers/video/bridge/ps862x.c134
-rw-r--r--drivers/video/bridge/ptn3460.c38
-rw-r--r--drivers/video/bridge/video-bridge-uclass.c119
-rw-r--r--drivers/video/exynos_dp.c24
-rw-r--r--drivers/video/exynos_dp_lowlevel.c2
-rw-r--r--drivers/video/parade.c231
-rw-r--r--drivers/video/tegra.c2
-rw-r--r--include/configs/arndale.h18
-rw-r--r--include/configs/exynos5-common.h13
-rw-r--r--include/configs/exynos5-dt-common.h21
-rw-r--r--include/configs/exynos5250-common.h16
-rw-r--r--include/configs/exynos5420-common.h9
-rw-r--r--include/configs/odroid_xu3.h2
-rw-r--r--include/configs/peach-pi.h14
-rw-r--r--include/configs/peach-pit.h24
-rw-r--r--include/configs/smdk5250.h16
-rw-r--r--include/configs/smdk5420.h10
-rw-r--r--include/configs/snow.h15
-rw-r--r--include/configs/spring.h20
-rw-r--r--include/cros_ec.h16
-rw-r--r--include/dm/device-internal.h44
-rw-r--r--include/dm/device.h284
-rw-r--r--include/dm/uclass-id.h2
-rw-r--r--include/dm/uclass.h19
-rw-r--r--include/dm/util.h9
-rw-r--r--include/fdtdec.h9
-rw-r--r--include/i2c.h150
-rw-r--r--include/parade.h18
-rw-r--r--include/power/s5m8767.h85
-rw-r--r--include/power/tps65090.h56
-rw-r--r--include/power/tps65090_pmic.h73
-rw-r--r--include/video_bridge.h92
-rw-r--r--lib/fdtdec.c3
-rw-r--r--test/dm/cmd_dm.c12
124 files changed, 5743 insertions, 2291 deletions
diff --git a/arch/arm/cpu/armv7/exynos/Kconfig b/arch/arm/cpu/armv7/exynos/Kconfig
index 4a7d82f74c..37b89b0013 100644
--- a/arch/arm/cpu/armv7/exynos/Kconfig
+++ b/arch/arm/cpu/armv7/exynos/Kconfig
@@ -51,6 +51,12 @@ config TARGET_SNOW
select OF_CONTROL
select SPL_DISABLE_OF_CONTROL
+config TARGET_SPRING
+ bool "Spring board"
+ select SUPPORT_SPL
+ select OF_CONTROL
+ select SPL_DISABLE_OF_CONTROL
+
config TARGET_SMDK5420
bool "SMDK5420 board"
select SUPPORT_SPL
diff --git a/arch/arm/cpu/armv7/exynos/lowlevel_init.c b/arch/arm/cpu/armv7/exynos/lowlevel_init.c
index 120aaf8b96..3774607848 100644
--- a/arch/arm/cpu/armv7/exynos/lowlevel_init.c
+++ b/arch/arm/cpu/armv7/exynos/lowlevel_init.c
@@ -25,6 +25,7 @@
#include <common.h>
#include <config.h>
+#include <debug_uart.h>
#include <asm/arch/cpu.h>
#include <asm/arch/dmc.h>
#include <asm/arch/power.h>
@@ -216,6 +217,10 @@ int do_lowlevel_init(void)
if (actions & DO_CLOCKS) {
system_clock_init();
+#ifdef CONFIG_DEBUG_UART
+ exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE);
+ debug_uart_init();
+#endif
mem_ctrl_init(actions & DO_MEM_RESET);
tzpc_init();
}
diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c
index be43e224fa..e97cb376ff 100644
--- a/arch/arm/cpu/armv7/exynos/pinmux.c
+++ b/arch/arm/cpu/armv7/exynos/pinmux.c
@@ -496,6 +496,16 @@ static int exynos5_pinmux_config(int peripheral, int flags)
case PERIPH_ID_SPI4:
exynos5_spi_config(peripheral);
break;
+ case PERIPH_ID_DPHPD:
+ /* Set Hotplug detect for DP */
+ gpio_cfg_pin(EXYNOS5_GPIO_X07, S5P_GPIO_FUNC(0x3));
+
+ /*
+ * Hotplug detect should have an external pullup; disable the
+ * internal pulldown so they don't fight.
+ */
+ gpio_set_pull(EXYNOS5_GPIO_X07, S5P_GPIO_PULL_NONE);
+ break;
default:
debug("%s: invalid peripheral %d", __func__, peripheral);
return -1;
diff --git a/arch/arm/cpu/armv7/s5p-common/cpu_info.c b/arch/arm/cpu/armv7/s5p-common/cpu_info.c
index a8d91e769f..154d67490d 100644
--- a/arch/arm/cpu/armv7/s5p-common/cpu_info.c
+++ b/arch/arm/cpu/armv7/s5p-common/cpu_info.c
@@ -30,11 +30,8 @@ u32 get_device_type(void)
#ifdef CONFIG_DISPLAY_CPUINFO
int print_cpuinfo(void)
{
- char buf[32];
-
- printf("CPU:\t%s%X@%sMHz\n",
- s5p_get_cpu_name(), s5p_cpu_id,
- strmhz(buf, get_arm_clk()));
+ printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
+ print_freq(get_arm_clk(), "\n");
return 0;
}
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index f61060fc92..3aaeb6a53c 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -9,6 +9,7 @@ dtb-$(CONFIG_EXYNOS4) += exynos4210-origen.dtb \
dtb-$(CONFIG_EXYNOS5) += exynos5250-arndale.dtb \
exynos5250-snow.dtb \
+ exynos5250-spring.dtb \
exynos5250-smdk5250.dtb \
exynos5420-smdk5420.dtb \
exynos5420-peach-pit.dtb \
diff --git a/arch/arm/dts/exynos4412-odroid.dts b/arch/arm/dts/exynos4412-odroid.dts
index d572f1e72b..a63e8abab4 100644
--- a/arch/arm/dts/exynos4412-odroid.dts
+++ b/arch/arm/dts/exynos4412-odroid.dts
@@ -42,103 +42,103 @@
#clock-cells = <1>;
voltage-regulators {
- ldo1_reg: ldo1 {
+ ldo1_reg: LDO1 {
regulator-name = "VDD_ALIVE_1.0V";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
- ldo2_reg: ldo2 {
+ ldo2_reg: LDO2 {
regulator-name = "VDDQ_VM1M2_1.2V";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
- ldo3_reg: ldo3 {
+ ldo3_reg: LDO3 {
regulator-name = "VCC_1.8V_AP";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo4_reg: ldo4 {
+ ldo4_reg: LDO4 {
regulator-name = "VDDQ_MMC2_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
};
- ldo5_reg: ldo5 {
+ ldo5_reg: LDO5 {
regulator-name = "VDDQ_MMC0/1/3_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo6_reg: ldo6 {
+ ldo6_reg: LDO6 {
regulator-name = "VMPLL_1.0V";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
};
- ldo7_reg: ldo7 {
+ ldo7_reg: LDO7 {
regulator-name = "VPLL_1.1V";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
};
- ldo8_reg: ldo8 {
+ ldo8_reg: LDO8 {
regulator-name = "VDD_MIPI/HDMI_1.0V";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
- ldo10_reg: ldo10 {
+ ldo10_reg: LDO10 {
regulator-name = "VDD_MIPI/HDMI_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo11_reg: ldo11 {
+ ldo11_reg: LDO11 {
regulator-name = "VDD_ABB1_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo12_reg: ldo12 {
+ ldo12_reg: LDO12 {
regulator-name = "VDD_UOTG_3.0V";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
};
- ldo13_reg: ldo13 {
+ ldo13_reg: LDO13 {
regulator-name = "VDD_C2C_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo14_reg: ldo14 {
+ ldo14_reg: LDO14 {
regulator-name = "VDD_ABB02_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo15_reg: ldo15 {
+ ldo15_reg: LDO15 {
regulator-name = "VDD_HSIC/OTG_1.0V";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
- ldo16_reg: ldo16 {
+ ldo16_reg: LDO16 {
regulator-name = "VDD_HSIC_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo17_reg: ldo17 {
+ ldo17_reg: LDO17 {
regulator-name = "VDDQ_CAM_1.2V";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
- ldo20_reg: ldo20 {
+ ldo20_reg: LDO20 {
regulator-name = "VDDQ_EMMC_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -146,7 +146,7 @@
regulator-boot-on;
};
- ldo21_reg: ldo21 {
+ ldo21_reg: LDO21 {
regulator-name = "TFLASH_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
@@ -154,7 +154,7 @@
regulator-boot-on;
};
- ldo22_reg: ldo22 {
+ ldo22_reg: LDO22 {
regulator-name = "VDDQ_EMMC_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
@@ -162,56 +162,56 @@
regulator-boot-on;
};
- ldo25_reg: ldo25 {
+ ldo25_reg: LDO25 {
regulator-compatible = "LDO25";
regulator-name = "VDDQ_LCD_3.0V";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
};
- buck1_reg: buck1 {
+ buck1_reg: BUCK1 {
regulator-name = "VDD_MIF_1.0V";
regulator-min-microvolt = <8500000>;
regulator-max-microvolt = <1100000>;
};
- buck2_reg: buck2 {
+ buck2_reg: BUCK2 {
regulator-name = "VDD_ARM_1.0V";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1500000>;
};
- buck3_reg: buck3 {
+ buck3_reg: BUCK3 {
regulator-name = "VDD_INT_1.1V";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1150000>;
};
- buck4_reg: buck4 {
+ buck4_reg: BUCK4 {
regulator-name = "VDD_G3D_1.0V";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1150000>;
};
- buck5_reg: buck5 {
+ buck5_reg: BUCK5 {
regulator-name = "VDDQ_AP_1.2V";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
- buck6_reg: buck6 {
+ buck6_reg: BUCK6 {
regulator-name = "VCC_INL1/7_1.35V";
regulator-min-microvolt = <1350000>;
regulator-max-microvolt = <1350000>;
};
- buck7_reg: buck7 {
+ buck7_reg: BUCK7 {
regulator-name = "VCC_INL2/3/5_2.0V";
regulator-min-microvolt = <2000000>;
regulator-max-microvolt = <2000000>;
};
- buck8_reg: buck8 {
+ buck8_reg: BUCK8 {
regulator-name = "VCC_P3V3_2.85V";
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <3300000>;
diff --git a/arch/arm/dts/exynos4412-trats2.dts b/arch/arm/dts/exynos4412-trats2.dts
index 5c0bb9108b..2d4e522ea2 100644
--- a/arch/arm/dts/exynos4412-trats2.dts
+++ b/arch/arm/dts/exynos4412-trats2.dts
@@ -47,7 +47,7 @@
#clock-cells = <1>;
voltage-regulators {
- ldo1_reg: ldo1 {
+ ldo1_reg: LDO1 {
regulator-compatible = "LDO1";
regulator-name = "VALIVE_1.0V_AP";
regulator-min-microvolt = <1000000>;
@@ -56,7 +56,7 @@
regulator-mem-on;
};
- ldo2_reg: ldo2 {
+ ldo2_reg: LDO2 {
regulator-compatible = "LDO2";
regulator-name = "VM1M2_1.2V_AP";
regulator-min-microvolt = <1200000>;
@@ -65,7 +65,7 @@
regulator-mem-on;
};
- ldo3_reg: ldo3 {
+ ldo3_reg: LDO3 {
regulator-compatible = "LDO3";
regulator-name = "VCC_1.8V_AP";
regulator-min-microvolt = <1800000>;
@@ -74,7 +74,7 @@
regulator-mem-on;
};
- ldo4_reg: ldo4 {
+ ldo4_reg: LDO4 {
regulator-compatible = "LDO4";
regulator-name = "VCC_2.8V_AP";
regulator-min-microvolt = <2800000>;
@@ -83,7 +83,7 @@
regulator-mem-on;
};
- ldo5_reg: ldo5 {
+ ldo5_reg: LDO5 {
regulator-compatible = "LDO5";
regulator-name = "VCC_1.8V_IO";
regulator-min-microvolt = <1800000>;
@@ -92,7 +92,7 @@
regulator-mem-on;
};
- ldo6_reg: ldo6 {
+ ldo6_reg: LDO6 {
regulator-compatible = "LDO6";
regulator-name = "VMPLL_1.0V_AP";
regulator-min-microvolt = <1000000>;
@@ -101,7 +101,7 @@
regulator-mem-on;
};
- ldo7_reg: ldo7 {
+ ldo7_reg: LDO7 {
regulator-compatible = "LDO7";
regulator-name = "VPLL_1.0V_AP";
regulator-min-microvolt = <1000000>;
@@ -110,7 +110,7 @@
regulator-mem-on;
};
- ldo8_reg: ldo8 {
+ ldo8_reg: LDO8 {
regulator-compatible = "LDO8";
regulator-name = "VMIPI_1.0V";
regulator-min-microvolt = <1000000>;
@@ -118,7 +118,7 @@
regulator-mem-off;
};
- ldo9_reg: ldo9 {
+ ldo9_reg: LDO9 {
regulator-compatible = "LDO9";
regulator-name = "CAM_ISP_MIPI_1.2V";
regulator-min-microvolt = <1200000>;
@@ -126,7 +126,7 @@
regulator-mem-idle;
};
- ldo10_reg: ldo10 {
+ ldo10_reg: LDO10 {
regulator-compatible = "LDO10";
regulator-name = "VMIPI_1.8V";
regulator-min-microvolt = <1800000>;
@@ -134,7 +134,7 @@
regulator-mem-off;
};
- ldo11_reg: ldo11 {
+ ldo11_reg: LDO11 {
regulator-compatible = "LDO11";
regulator-name = "VABB1_1.95V";
regulator-min-microvolt = <1950000>;
@@ -143,7 +143,7 @@
regulator-mem-off;
};
- ldo12_reg: ldo12 {
+ ldo12_reg: LDO12 {
regulator-compatible = "LDO12";
regulator-name = "VUOTG_3.0V";
regulator-min-microvolt = <3000000>;
@@ -151,7 +151,7 @@
regulator-mem-off;
};
- ldo13_reg: ldo13 {
+ ldo13_reg: LDO13 {
regulator-compatible = "LDO13";
regulator-name = "NFC_AVDD_1.8V";
regulator-min-microvolt = <1800000>;
@@ -159,7 +159,7 @@
regulator-mem-idle;
};
- ldo14_reg: ldo14 {
+ ldo14_reg: LDO14 {
regulator-compatible = "LDO14";
regulator-name = "VABB2_1.95V";
regulator-min-microvolt = <1950000>;
@@ -168,7 +168,7 @@
regulator-mem-off;
};
- ldo15_reg: ldo15 {
+ ldo15_reg: LDO15 {
regulator-compatible = "LDO15";
regulator-name = "VHSIC_1.0V";
regulator-min-microvolt = <1000000>;
@@ -176,7 +176,7 @@
regulator-mem-off;
};
- ldo16_reg: ldo16 {
+ ldo16_reg: LDO16 {
regulator-compatible = "LDO16";
regulator-name = "VHSIC_1.8V";
regulator-min-microvolt = <1800000>;
@@ -184,7 +184,7 @@
regulator-mem-off;
};
- ldo17_reg: ldo17 {
+ ldo17_reg: LDO17 {
regulator-compatible = "LDO17";
regulator-name = "CAM_SENSOR_CORE_1.2V";
regulator-min-microvolt = <1200000>;
@@ -192,7 +192,7 @@
regulator-mem-idle;
};
- ldo18_reg: ldo18 {
+ ldo18_reg: LDO18 {
regulator-compatible = "LDO18";
regulator-name = "CAM_ISP_SEN_IO_1.8V";
regulator-min-microvolt = <1800000>;
@@ -200,7 +200,7 @@
regulator-mem-idle;
};
- ldo19_reg: ldo19 {
+ ldo19_reg: LDO19 {
regulator-compatible = "LDO19";
regulator-name = "VT_CAM_1.8V";
regulator-min-microvolt = <1800000>;
@@ -208,7 +208,7 @@
regulator-mem-idle;
};
- ldo20_reg: ldo20 {
+ ldo20_reg: LDO20 {
regulator-compatible = "LDO20";
regulator-name = "VDDQ_PRE_1.8V";
regulator-min-microvolt = <1800000>;
@@ -216,7 +216,7 @@
regulator-mem-idle;
};
- ldo21_reg: ldo21 {
+ ldo21_reg: LDO21 {
regulator-compatible = "LDO21";
regulator-name = "VTF_2.8V";
regulator-min-microvolt = <2800000>;
@@ -224,7 +224,7 @@
regulator-mem-idle;
};
- ldo22_reg: ldo22 {
+ ldo22_reg: LDO22 {
regulator-compatible = "LDO22";
regulator-name = "VMEM_VDD_2.8V";
regulator-min-microvolt = <2800000>;
@@ -233,7 +233,7 @@
regulator-mem-off;
};
- ldo23_reg: ldo23 {
+ ldo23_reg: LDO23 {
regulator-compatible = "LDO23";
regulator-name = "TSP_AVDD_3.3V";
regulator-min-microvolt = <3300000>;
@@ -241,7 +241,7 @@
regulator-mem-idle;
};
- ldo24_reg: ldo24 {
+ ldo24_reg: LDO24 {
regulator-compatible = "LDO24";
regulator-name = "TSP_VDD_1.8V";
regulator-min-microvolt = <1800000>;
@@ -249,7 +249,7 @@
regulator-mem-idle;
};
- ldo25_reg: ldo25 {
+ ldo25_reg: LDO25 {
regulator-compatible = "LDO25";
regulator-name = "LCD_VCC_3.3V";
regulator-min-microvolt = <2800000>;
@@ -257,7 +257,7 @@
regulator-mem-idle;
};
- ldo26_reg: ldo26 {
+ ldo26_reg: LDO26 {
regulator-compatible = "LDO26";
regulator-name = "MOTOR_VCC_3.0V";
regulator-min-microvolt = <3000000>;
@@ -265,7 +265,7 @@
regulator-mem-idle;
};
- buck1_reg: buck1 {
+ buck1_reg: BUCK1 {
regulator-compatible = "BUCK1";
regulator-name = "vdd_mif";
regulator-min-microvolt = <850000>;
@@ -275,7 +275,7 @@
regulator-mem-off;
};
- buck2_reg: buck2 {
+ buck2_reg: BUCK2 {
regulator-compatible = "BUCK2";
regulator-name = "vdd_arm";
regulator-min-microvolt = <850000>;
@@ -285,7 +285,7 @@
regulator-mem-off;
};
- buck3_reg: buck3 {
+ buck3_reg: BUCK3 {
regulator-compatible = "BUCK3";
regulator-name = "vdd_int";
regulator-min-microvolt = <850000>;
@@ -295,7 +295,7 @@
regulator-mem-off;
};
- buck4_reg: buck4 {
+ buck4_reg: BUCK4 {
regulator-compatible = "BUCK4";
regulator-name = "vdd_g3d";
regulator-min-microvolt = <850000>;
@@ -304,7 +304,7 @@
regulator-mem-off;
};
- buck5_reg: buck5 {
+ buck5_reg: BUCK5 {
regulator-compatible = "BUCK5";
regulator-name = "VMEM_1.2V_AP";
regulator-min-microvolt = <1200000>;
@@ -312,7 +312,7 @@
regulator-always-on;
};
- buck6_reg: buck6 {
+ buck6_reg: BUCK6 {
regulator-compatible = "BUCK6";
regulator-name = "VCC_SUB_1.35V";
regulator-min-microvolt = <1350000>;
@@ -320,7 +320,7 @@
regulator-always-on;
};
- buck7_reg: buck7 {
+ buck7_reg: BUCK7 {
regulator-compatible = "BUCK7";
regulator-name = "VCC_SUB_2.0V";
regulator-min-microvolt = <2000000>;
@@ -328,7 +328,7 @@
regulator-always-on;
};
- buck8_reg: buck8 {
+ buck8_reg: BUCK8 {
regulator-compatible = "BUCK8";
regulator-name = "VMEM_VDDF_3.0V";
regulator-min-microvolt = <2850000>;
@@ -337,7 +337,7 @@
regulator-mem-off;
};
- buck9_reg: buck9 {
+ buck9_reg: BUCK9 {
regulator-compatible = "BUCK9";
regulator-name = "CAM_ISP_CORE_1.2V";
regulator-min-microvolt = <1000000>;
diff --git a/arch/arm/dts/exynos5.dtsi b/arch/arm/dts/exynos5.dtsi
index 238acb80a2..179584c748 100644
--- a/arch/arm/dts/exynos5.dtsi
+++ b/arch/arm/dts/exynos5.dtsi
@@ -72,39 +72,39 @@
interrupts = <1 9 0xf04>;
};
- i2c@12c60000 {
- #address-cells = <1>;
- #size-cells = <0>;
+ i2c_0: i2c@12C60000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12C60000 0x100>;
interrupts = <0 56 0>;
- };
-
- i2c@12c70000 {
#address-cells = <1>;
#size-cells = <0>;
+ };
+
+ i2c_1: i2c@12C70000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12C70000 0x100>;
interrupts = <0 57 0>;
- };
-
- i2c@12c80000 {
#address-cells = <1>;
#size-cells = <0>;
+ };
+
+ i2c_2: i2c@12C80000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12C80000 0x100>;
interrupts = <0 58 0>;
- };
-
- i2c@12c90000 {
#address-cells = <1>;
#size-cells = <0>;
+ };
+
+ i2c_3: i2c@12C90000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12C90000 0x100>;
interrupts = <0 59 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
};
- spi@12d20000 {
+ spi_0: spi@12d20000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos-spi";
@@ -112,7 +112,7 @@
interrupts = <0 68 0>;
};
- spi@12d30000 {
+ spi_1: spi@12d30000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos-spi";
@@ -120,7 +120,7 @@
interrupts = <0 69 0>;
};
- spi@12d40000 {
+ spi_2: spi@12d40000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos-spi";
@@ -129,7 +129,7 @@
interrupts = <0 70 0>;
};
- spi@131a0000 {
+ spi_3: spi@131a0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos-spi";
@@ -137,7 +137,7 @@
interrupts = <0 129 0>;
};
- spi@131b0000 {
+ spi_4: spi@131b0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos-spi";
diff --git a/arch/arm/dts/exynos5250-arndale.dts b/arch/arm/dts/exynos5250-arndale.dts
index 21c0a214ea..031c622e0b 100644
--- a/arch/arm/dts/exynos5250-arndale.dts
+++ b/arch/arm/dts/exynos5250-arndale.dts
@@ -15,14 +15,14 @@
compatible = "samsung,arndale", "samsung,exynos5250";
aliases {
- i2c0 = "/i2c@12c60000";
- i2c1 = "/i2c@12c70000";
- i2c2 = "/i2c@12c80000";
- i2c3 = "/i2c@12c90000";
- i2c4 = "/i2c@12ca0000";
- i2c5 = "/i2c@12cb0000";
- i2c6 = "/i2c@12cc0000";
- i2c7 = "/i2c@12cd0000";
+ i2c0 = "/i2c@12C60000";
+ i2c1 = "/i2c@12C70000";
+ i2c2 = "/i2c@12C80000";
+ i2c3 = "/i2c@12C90000";
+ i2c4 = "/i2c@12CA0000";
+ i2c5 = "/i2c@12CB0000";
+ i2c6 = "/i2c@12CC0000";
+ i2c7 = "/i2c@12CD0000";
serial0 = "/serial@12C20000";
console = "/serial@12C20000";
};
diff --git a/arch/arm/dts/exynos5250-smdk5250.dts b/arch/arm/dts/exynos5250-smdk5250.dts
index 3cebfc28a5..8b695442b1 100644
--- a/arch/arm/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/dts/exynos5250-smdk5250.dts
@@ -11,20 +11,21 @@
/dts-v1/;
#include "exynos5250.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
/ {
model = "SAMSUNG SMDK5250 board based on EXYNOS5250";
compatible = "samsung,smdk5250", "samsung,exynos5250";
aliases {
- i2c0 = "/i2c@12c60000";
- i2c1 = "/i2c@12c70000";
- i2c2 = "/i2c@12c80000";
- i2c3 = "/i2c@12c90000";
- i2c4 = "/i2c@12ca0000";
- i2c5 = "/i2c@12cb0000";
- i2c6 = "/i2c@12cc0000";
- i2c7 = "/i2c@12cd0000";
+ i2c0 = "/i2c@12C60000";
+ i2c1 = "/i2c@12C70000";
+ i2c2 = "/i2c@12C80000";
+ i2c3 = "/i2c@12C90000";
+ i2c4 = "/i2c@12CA0000";
+ i2c5 = "/i2c@12CB0000";
+ i2c6 = "/i2c@12CC0000";
+ i2c7 = "/i2c@12CD0000";
spi0 = "/spi@12d20000";
spi1 = "/spi@12d30000";
spi2 = "/spi@12d40000";
@@ -58,14 +59,14 @@
status = "disabled";
};
- i2c@12c70000 {
+ i2c@12C70000 {
soundcodec@1a {
reg = <0x1a>;
compatible = "wolfson,wm8994-codec";
};
};
- i2c@12c60000 {
+ i2c@12C60000 {
pmic@9 {
reg = <0x9>;
compatible = "maxim,max77686";
@@ -149,3 +150,153 @@
samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
};
};
+
+&i2c_0 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <20000>;
+
+ max77686@09 {
+ compatible = "maxim,max77686";
+ reg = <0x09>;
+ interrupt-parent = <&gpx3>;
+ interrupts = <2 IRQ_TYPE_NONE>;
+
+ voltage-regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "P1.0V_LDO_OUT1";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "P1.2V_LDO_OUT2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "P1.8V_LDO_OUT3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "P2.8V_LDO_OUT4";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "P1.8V_LDO_OUT5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "P1.1V_LDO_OUT6";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "P1.1V_LDO_OUT7";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "P1.0V_LDO_OUT8";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "P1.8V_LDO_OUT10";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "P1.8V_LDO_OUT11";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "P3.0V_LDO_OUT12";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "P1.8V_LDO_OUT13";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "P1.8V_LDO_OUT14";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "P1.0V_LDO_OUT15";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "P1.8V_LDO_OUT16";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "P1.8V_BUCK_OUT5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+ };
+};
diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts
index e4b3dc29e4..32c0098bd8 100644
--- a/arch/arm/dts/exynos5250-snow.dts
+++ b/arch/arm/dts/exynos5250-snow.dts
@@ -7,24 +7,28 @@
* 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/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/input/input.h>
#include "exynos5250.dtsi"
/ {
model = "Google Snow";
- compatible = "google,snow", "samsung,exynos5250";
+ compatible = "google,snow", "samsung,exynos5250", "samsung,exynos5";
aliases {
- i2c0 = "/i2c@12c60000";
- i2c1 = "/i2c@12c70000";
- i2c2 = "/i2c@12c80000";
- i2c3 = "/i2c@12c90000";
- i2c4 = "/i2c@12ca0000";
- i2c5 = "/i2c@12cb0000";
- i2c6 = "/i2c@12cc0000";
- i2c7 = "/i2c@12cd0000";
+ i2c0 = "/i2c@12C60000";
+ i2c1 = "/i2c@12C70000";
+ i2c2 = "/i2c@12C80000";
+ i2c3 = "/i2c@12C90000";
+ i2c4 = "/i2c@12CA0000";
+ i2c104 = &i2c_104;
+ i2c5 = "/i2c@12CB0000";
+ i2c6 = "/i2c@12CC0000";
+ i2c7 = "/i2c@12CD0000";
spi0 = "/spi@12d20000";
spi1 = "/spi@12d30000";
spi2 = "/spi@12d40000";
@@ -39,18 +43,166 @@
i2s = "/sound@3830000";
};
- i2c4: i2c@12ca0000 {
- cros_ec: cros-ec@1e {
- reg = <0x1e>;
- compatible = "google,cros-ec-i2c";
- i2c-max-frequency = <100000>;
- u-boot,i2c-offset-len = <0>;
- ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
+ memory {
+ reg = <0x40000000 0x80000000>;
+ };
+
+ chosen {
+ bootargs = "console=tty1";
+ stdout-path = "serial3:115200n8";
+ };
+
+ iram {
+ reg = <0x02020000 0x60000>;
+ };
+
+ config {
+ samsung,bl1-offset = <0x1400>;
+ samsung,bl2-offset = <0x3400>;
+ u-boot-memory = "/memory";
+ u-boot-offset = <0x3e00000 0x100000>;
+ };
+
+ flash {
+ reg = <0 0x100000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ pre-boot {
+ label = "bl1 pre-boot";
+ reg = <0 0x2000>;
+ read-only;
+ filename = "e5250.nbl1.bin";
+ type = "blob exynos-bl1";
+ required;
};
- power-regulator@48 {
- compatible = "ti,tps65090";
- reg = <0x48>;
+ spl {
+ label = "bl2 spl";
+ reg = <0x2000 0x4000>;
+ read-only;
+ filename = "bl2.bin";
+ type = "blob exynos-bl2 boot,dtb";
+ payload = "/flash/ro-boot";
+ required;
+ };
+
+ ro-boot {
+ label = "u-boot";
+ reg = <0x6000 0x9a000>;
+ read-only;
+ type = "blob boot,dtb";
+ required;
+ };
+ };
+
+ i2c-arbitrator {
+ compatible = "i2c-arb-gpio-challenge";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c-parent = <&{/i2c@12CA0000}>;
+
+ our-claim-gpio = <&gpf0 3 GPIO_ACTIVE_LOW>;
+ their-claim-gpios = <&gpe0 4 GPIO_ACTIVE_LOW>;
+ slew-delay-us = <10>;
+ wait-retry-us = <3000>;
+ wait-free-us = <50000>;
+
+ /* Use ID 104 as a hint that we're on physical bus 4 */
+ i2c_104: i2c@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ battery: sbs-battery@b {
+ compatible = "sbs,sbs-battery";
+ reg = <0xb>;
+ sbs,poll-retry-count = <1>;
+ };
+
+ cros_ec: embedded-controller {
+ compatible = "google,cros-ec-i2c";
+ reg = <0x1e>;
+ interrupts = <6 IRQ_TYPE_NONE>;
+ interrupt-parent = <&gpx1>;
+ wakeup-source;
+ i2c-max-frequency = <100000>;
+ u-boot,i2c-offset-len = <0>;
+ ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
+ };
+
+ power-regulator {
+ compatible = "ti,tps65090";
+ reg = <0x48>;
+
+ regulators {
+ dcdc1 {
+ ti,enable-ext-control;
+ };
+ dcdc2 {
+ ti,enable-ext-control;
+ };
+ dcdc3 {
+ ti,enable-ext-control;
+ };
+ fet1: fet1 {
+ regulator-name = "vcd_led";
+ ti,overcurrent-wait = <3>;
+ };
+ tps65090_fet2: fet2 {
+ regulator-name = "video_mid";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ fet3 {
+ regulator-name = "wwan_r";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ fet4 {
+ regulator-name = "sdcard";
+ ti,overcurrent-wait = <3>;
+ };
+ fet5 {
+ regulator-name = "camout";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ fet6: fet6 {
+ regulator-name = "lcd_vdd";
+ ti,overcurrent-wait = <3>;
+ };
+ tps65090_fet7: fet7 {
+ regulator-name = "video_mid_1a";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ ldo1 {
+ };
+ ldo2 {
+ };
+ };
+
+ charger {
+ compatible = "ti,tps65090-charger";
+ };
+ };
+ };
+ };
+
+ i2c@12CD0000 {
+ ptn3460: lvds-bridge@20 {
+ compatible = "nxp,ptn3460";
+ reg = <0x20>;
+ sleep-gpios = <&gpy2 5 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&gpx1 5 GPIO_ACTIVE_LOW>;
+ hotplug-gpios = <&gpx0 7 GPIO_ACTIVE_HIGH>;
+ edid-emulation = <5>;
+ };
+
+ soundcodec@22 {
+ reg = <0x22>;
+ compatible = "maxim,max98095-codec";
};
};
@@ -66,6 +218,7 @@
spi-max-frequency = <1000000>;
spi-deactivate-delay = <100>;
+ /* Snow did support SPI but the released version used I2C */
embedded-controller {
compatible = "google,cros-ec-i2c";
reg = <0x1e>;
@@ -85,28 +238,8 @@
status = "disabled";
};
- i2c@12cd0000 {
- soundcodec@22 {
- reg = <0x22>;
- compatible = "maxim,max98095-codec";
- };
-
- ptn3460-bridge@20 {
- compatible = "nxp,ptn3460";
- reg = <0x20>;
- /*
- * TODO(sjg@chromium.org): Use GPIOs here
- * powerdown-gpio = <&gpy2 5 0>;
- * reset-gpio = <&gpx1 5 0>;
- * edid-emulation = <5>;
- * pinctrl-names = "default";
- * pinctrl-0 = <&ptn3460_gpios>;
- */
- };
- };
-
- i2c@12c60000 {
- pmic@9 {
+ i2c@12C60000 {
+ max77686@09 {
reg = <0x9>;
compatible = "maxim,max77686";
};
@@ -199,4 +332,158 @@
};
+&i2c_0 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <378000>;
+
+ max77686: max77686@09 {
+ compatible = "maxim,max77686";
+ interrupt-parent = <&gpx3>;
+ interrupts = <2 IRQ_TYPE_NONE>;
+ wakeup-source;
+ reg = <0x09>;
+ #clock-cells = <1>;
+
+ voltage-regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "P1.0V_LDO_OUT1";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "P1.8V_LDO_OUT2";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "P1.8V_LDO_OUT3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "P1.1V_LDO_OUT7";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "P1.0V_LDO_OUT8";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "P1.8V_LDO_OUT10";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "P3.0V_LDO_OUT12";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "P1.8V_LDO_OUT14";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "P1.0V_LDO_OUT15";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "P1.8V_LDO_OUT16";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "vdd_mydp";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "P1.8V_BUCK_OUT5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck6_reg: BUCK6 {
+ regulator-name = "P1.35V_BUCK_OUT6";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ };
+
+ buck7_reg: BUCK7 {
+ regulator-name = "P2.0V_BUCK_OUT7";
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-always-on;
+ };
+
+ buck8_reg: BUCK8 {
+ regulator-name = "P2.85V_BUCK_OUT8";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
#include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/dts/exynos5250-spring.dts b/arch/arm/dts/exynos5250-spring.dts
new file mode 100644
index 0000000000..76d5323dc3
--- /dev/null
+++ b/arch/arm/dts/exynos5250-spring.dts
@@ -0,0 +1,588 @@
+/*
+ * Google Spring board device tree source
+ *
+ * Copyright (c) 2013 Google, Inc
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/input/input.h>
+#include "exynos5250.dtsi"
+
+/ {
+ model = "Google Spring";
+ compatible = "google,spring", "samsung,exynos5250", "samsung,exynos5";
+
+ aliases {
+ i2c0 = "/i2c@12C60000";
+ i2c1 = "/i2c@12C70000";
+ i2c2 = "/i2c@12C80000";
+ i2c3 = "/i2c@12C90000";
+ i2c4 = "/i2c@12CA0000";
+ i2c5 = "/i2c@12CB0000";
+ i2c6 = "/i2c@12CC0000";
+ i2c7 = "/i2c@12CD0000";
+ i2c104 = &cros_ec_ldo_tunnel;
+ spi0 = "/spi@12d20000";
+ spi1 = "/spi@12d30000";
+ spi2 = "/spi@12d40000";
+ spi3 = "/spi@131a0000";
+ spi4 = "/spi@131b0000";
+ mmc0 = "/mmc@12000000";
+ serial0 = "/serial@12C30000";
+ console = "/serial@12C30000";
+ i2s = "/sound@3830000";
+ };
+
+ memory {
+ reg = <0x40000000 0x80000000>;
+ };
+
+ flash@0 {
+ spl { /* spl size override */
+ size = <0x8000>;
+ };
+ };
+
+ chosen {
+ bootargs = "console=tty1";
+ stdout-path = "serial3:115200n8";
+ };
+
+ board-rev {
+ compatible = "google,board-revision";
+ google,board-rev-gpios = <&gpy4 0 0>, <&gpy4 1 0>,
+ <&gpy4 2 0>;
+ };
+
+ mmc@12200000 {
+ samsung,bus-width = <8>;
+ samsung,timing = <1 3 3>;
+ samsung,removable = <0>;
+ };
+
+ mmc@12210000 {
+ status = "disabled";
+ };
+
+ mmc@12220000 {
+ /* MMC2 pins are used as GPIO for eDP bridge */
+ status = "disabled";
+ };
+
+ mmc@12230000 {
+ status = "disabled";
+ };
+
+ ehci@12110000 {
+ samsung,vbus-gpio = <&gpx1 1 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+ };
+
+ xhci@12000000 {
+ samsung,vbus-gpio = <&gpx2 7 GPIO_ACTIVE_HIGH>;
+ };
+
+ spi@12d30000 {
+ spi-max-frequency = <50000000>;
+ firmware_storage_spi: flash@0 {
+ compatible = "spi-flash";
+ reg = <0>;
+ };
+ };
+
+ tmu@10060000 {
+ samsung,min-temp = <25>;
+ samsung,max-temp = <125>;
+ samsung,start-warning = <95>;
+ samsung,start-tripping = <105>;
+ samsung,hw-tripping = <110>;
+ samsung,efuse-min-value = <40>;
+ samsung,efuse-value = <55>;
+ samsung,efuse-max-value = <100>;
+ samsung,slope = <274761730>;
+ samsung,dc-value = <25>;
+ };
+
+ fimd@14400000 {
+ samsung,vl-freq = <60>;
+ samsung,vl-col = <1366>;
+ samsung,vl-row = <768>;
+ samsung,vl-width = <1366>;
+ samsung,vl-height = <768>;
+
+ samsung,vl-clkp;
+ samsung,vl-dp;
+ samsung,vl-hsp;
+ samsung,vl-vsp;
+
+ samsung,vl-bpix = <4>;
+
+ samsung,vl-hspw = <32>;
+ samsung,vl-hbpd = <80>;
+ samsung,vl-hfpd = <48>;
+ samsung,vl-vspw = <5>;
+ samsung,vl-vbpd = <14>;
+ samsung,vl-vfpd = <3>;
+ samsung,vl-cmd-allow-len = <0xf>;
+
+ samsung,winid = <0>;
+ samsung,interface-mode = <1>;
+ samsung,dp-enabled = <1>;
+ samsung,dual-lcd-enabled = <0>;
+ };
+
+ dp@145b0000 {
+ samsung,lt-status = <0>;
+
+ samsung,master-mode = <0>;
+ samsung,bist-mode = <0>;
+ samsung,bist-pattern = <0>;
+ samsung,h-sync-polarity = <0>;
+ samsung,v-sync-polarity = <0>;
+ samsung,interlaced = <0>;
+ samsung,color-space = <0>;
+ samsung,dynamic-range = <0>;
+ samsung,ycbcr-coeff = <0>;
+ samsung,color-depth = <1>;
+ };
+};
+
+&i2c_0 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <378000>;
+
+ s5m8767-pmic@66 {
+ compatible = "samsung,s5m8767-pmic";
+ reg = <0x66>;
+ interrupt-parent = <&gpx3>;
+ wakeup-source;
+
+ s5m8767,pmic-buck-dvs-gpios = <&gpd1 0 GPIO_ACTIVE_LOW>, /* DVS1 */
+ <&gpd1 1 GPIO_ACTIVE_LOW>, /* DVS2 */
+ <&gpd1 2 GPIO_ACTIVE_LOW>; /* DVS3 */
+
+ s5m8767,pmic-buck-ds-gpios = <&gpx2 3 GPIO_ACTIVE_LOW>, /* SET1 */
+ <&gpx2 4 GPIO_ACTIVE_LOW>, /* SET2 */
+ <&gpx2 5 GPIO_ACTIVE_LOW>; /* SET3 */
+
+ /*
+ * The following arrays of DVS voltages are not used, since we are
+ * not using GPIOs to control PMIC bucks, but they must be defined
+ * to please the driver.
+ */
+ s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>,
+ <1250000>, <1200000>,
+ <1150000>, <1100000>,
+ <1000000>, <950000>;
+
+ s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>,
+ <1100000>, <1100000>,
+ <1000000>, <1000000>,
+ <1000000>, <1000000>;
+
+ s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>;
+
+ clocks {
+ compatible = "samsung,s5m8767-clk";
+ #clock-cells = <1>;
+ clock-output-names = "en32khz_ap",
+ "en32khz_cp",
+ "en32khz_bt";
+ };
+
+ regulators {
+ ldo4_reg: LDO4 {
+ regulator-name = "P1.0V_LDO_OUT4";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <0>;
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "P1.8V_LDO_OUT5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <0>;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "vdd_mydp";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "P1.1V_LDO_OUT7";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "P1.0V_LDO_OUT8";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "P1.8V_LDO_OUT10";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "P1.8V_LDO_OUT11";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <0>;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "P3.0V_LDO_OUT12";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "P1.8V_LDO_OUT13";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <0>;
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "P1.8V_LDO_OUT14";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "P1.0V_LDO_OUT15";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "P1.8V_LDO_OUT16";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "P1.2V_LDO_OUT17";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ op_mode = <0>;
+ };
+
+ ldo25_reg: LDO25 {
+ regulator-name = "vdd_bridge";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ op_mode = <1>;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <3>;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <3>;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <3>;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-boot-on;
+ op_mode = <3>;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "P1.8V_BUCK_OUT5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ buck6_reg: BUCK6 {
+ regulator-name = "P1.2V_BUCK_OUT6";
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <0>;
+ };
+
+ buck9_reg: BUCK9 {
+ regulator-name = "vdd_ummc";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <3>;
+ };
+ };
+ };
+};
+
+&i2c_1 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <378000>;
+};
+
+&i2c_2 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+};
+
+&i2c_3 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+};
+
+&i2c_4 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+ clock-frequency = <66000>;
+
+ cros_ec: embedded-controller {
+ compatible = "google,cros-ec-i2c";
+ reg = <0x1e>;
+ interrupts = <6 IRQ_TYPE_NONE>;
+ interrupt-parent = <&gpx1>;
+ wakeup-source;
+ u-boot,i2c-offset-len = <0>;
+ ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
+ cros_ec_ldo_tunnel: cros-ec-ldo-tunnel {
+ compatible = "google,cros-ec-ldo-tunnel";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-regulator {
+ compatible = "ti,tps65090";
+ reg = <0x48>;
+
+ regulators {
+ dcdc1 {
+ ti,enable-ext-control;
+ };
+ dcdc2 {
+ ti,enable-ext-control;
+ };
+ dcdc3 {
+ ti,enable-ext-control;
+ };
+ fet1: fet1 {
+ regulator-name = "vcd_led";
+ ti,overcurrent-wait = <3>;
+ };
+ tps65090_fet2: fet2 {
+ regulator-name = "video_mid";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ fet3 {
+ regulator-name = "wwan_r";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ fet4 {
+ regulator-name = "sdcard";
+ ti,overcurrent-wait = <3>;
+ };
+ fet5 {
+ regulator-name = "camout";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ fet6: fet6 {
+ regulator-name = "lcd_vdd";
+ ti,overcurrent-wait = <3>;
+ };
+ tps65090_fet7: fet7 {
+ regulator-name = "video_mid_1a";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ ldo1 {
+ };
+ ldo2 {
+ };
+ };
+ };
+ };
+ };
+};
+
+&i2c_5 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+};
+
+&i2c_7 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+
+ ps8622-bridge@8 {
+ compatible = "parade,ps8622";
+ reg = <0x8>;
+ sleep-gpios = <&gpc3 6 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&gpc3 1 GPIO_ACTIVE_LOW>;
+ hotplug-gpios = <&gpc3 0 GPIO_ACTIVE_HIGH>;
+ power-supply = <&ldo6_reg>;
+ parade,regs = /bits/ 8 <
+ 0x02 0xa1 0x01 /* HPD low */
+ /*
+ * SW setting: [1:0] SW output 1.2V voltage is
+ * lower to 96%
+ */
+ 0x04 0x14 0x01
+ /* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */
+ 0x04 0xe3 0x20
+ 0x04 0xe2 0x80 /* [7] RCO SS enable */
+ /*
+ * RPHY Setting: [3:2] CDR tune wait cycle before
+ * measure for fine tune b00: 1us,
+ * 01: 0.5us, 10:2us, 11:4us
+ */
+ 0x04 0x8a 0x0c
+ 0x04 0x89 0x08 /* [3] RFD always on */
+ /*
+ * CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times
+ */
+ 0x04 0x71 0x2d
+ /* 2.7G CDR settings */
+ 0x04 0x7d 0x07 /* NOF=40LSB for HBR CDR setting */
+ 0x04 0x7b 0x00 /* [1:0] Fmin=+4bands */
+ 0x04 0x7a 0xfd /* [7:5] DCO_FTRNG=+-40% */
+ /*
+ * 1.62G CDR settings:
+ * [5:2]NOF=64LSB [1:0]DCO scale is 2/5
+ */
+ 0x04 0xc0 0x12
+ 0x04 0xc1 0x92 /* Gitune=-37% */
+ 0x04 0xc2 0x1c /* Fbstep=100% */
+ 0x04 0x32 0x80 /* [7] LOS signal disable */
+ /* RPIO Setting */
+ /* [7:4] LVDS driver bias current 75% (250mV swing) */
+ 0x04 0x00 0xb0
+ /* [7:6] Right-bar GPIO output strength is 8mA */
+ 0x04 0x15 0x40
+ /* EQ Training State Machine Setting */
+ 0x04 0x54 0x10 /* RCO calibration start */
+ /* [4:0] MAX_LANE_COUNT set to one lane */
+ 0x01 0x02 0x81
+ /* [4:0] LANE_COUNT_SET set to one lane */
+ 0x01 0x21 0x81
+ 0x00 0x52 0x20
+ 0x00 0xf1 0x03 /* HPD CP toggle enable */
+ 0x00 0x62 0x41
+ /* Counter number add 1ms counter delay */
+ 0x00 0xf6 0x01
+ /*
+ * [6]PWM function control by DPCD0040f[7], default
+ * is PWM block always works
+ */
+ 0x00 0x77 0x06
+ 0x00 0x4c 0x04
+ /*
+ * 04h Adjust VTotal tolerance to fix the 30Hz no-
+ * display issue
+ * DPCD00400='h00 Parade OUI = 'h001cf8
+ */
+ 0x01 0xc0 0x00
+ 0x01 0xc1 0x1c /* DPCD00401='h1c */
+ 0x01 0xc2 0xf8 /* DPCD00402='hf8 */
+ /* DPCD403~408 = ASCII code D2SLV5='h4432534c5635 */
+ 0x01 0xc3 0x44
+ 0x01 0xc4 0x32 /* DPCD404 */
+ 0x01 0xc5 0x53 /* DPCD405 */
+ 0x01 0xc6 0x4c /* DPCD406 */
+ 0x01 0xc7 0x56 /* DPCD407 */
+ 0x01 0xc8 0x35 /* DPCD408 */
+ /* DPCD40A Initial Code major revision '01' */
+ 0x01 0xca 0x01
+ /* DPCD40B Initial Code minor revision '05' */
+ 0x01 0xcb 0x05
+ 0x01 0xa5 0xa0 /* DPCD720, Select internal PWM */
+ /*
+ * 0xff for 100% PWM of brightness, 0h for 0% brightness
+ */
+ 0x01 0xa7 0x00
+ /*
+ * Set LVDS output as 6bit-VESA mapping, single LVDS
+ * channel
+ */
+ 0x01 0xcc 0x13
+ 0x02 0xb1 0x20 /* Enable SSC set by register */
+ /* Set SSC enabled and +/-1% central spreading */
+ 0x04 0x10 0x16
+ 0x04 0x59 0x60 /* MPU Clock source: LC => RCO */
+ 0x04 0x54 0x14 /* LC -> RCO */
+ 0x02 0xa1 0x91>; /* HPD high */
+ };
+
+ soundcodec@20 {
+ reg = <0x20>;
+ compatible = "maxim,max98088-codec";
+ };
+};
+
+#include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi
index ccbafe9b07..7eef3e3f4f 100644
--- a/arch/arm/dts/exynos5250.dtsi
+++ b/arch/arm/dts/exynos5250.dtsi
@@ -47,36 +47,36 @@
interrupts = <0 47 0>;
};
- i2c@12ca0000 {
- #address-cells = <1>;
- #size-cells = <0>;
+ i2c_4: i2c@12CA0000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12CA0000 0x100>;
interrupts = <0 60 0>;
- };
-
- i2c@12cb0000 {
#address-cells = <1>;
#size-cells = <0>;
+ };
+
+ i2c_5: i2c@12CB0000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12CB0000 0x100>;
interrupts = <0 61 0>;
- };
-
- i2c@12cc0000 {
#address-cells = <1>;
#size-cells = <0>;
+ };
+
+ i2c_6: i2c@12CC0000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12CC0000 0x100>;
interrupts = <0 62 0>;
- };
-
- i2c@12cd0000 {
#address-cells = <1>;
#size-cells = <0>;
+ };
+
+ i2c_7: i2c@12CD0000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12CD0000 0x100>;
interrupts = <0 63 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
};
sound@3830000 {
diff --git a/arch/arm/dts/exynos5420-peach-pit.dts b/arch/arm/dts/exynos5420-peach-pit.dts
index 6fe762deb3..2d2b7c9bde 100644
--- a/arch/arm/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/dts/exynos5420-peach-pit.dts
@@ -25,7 +25,8 @@
aliases {
serial0 = "/serial@12C30000";
console = "/serial@12C30000";
- pmic = "/i2c@12ca0000";
+ pmic = "/i2c@12CA0000";
+ i2c104 = &i2c_tunnel;
};
dmc {
@@ -49,7 +50,7 @@
};
/* MAX77802 is on i2c bus 4 */
- i2c@12ca0000 {
+ i2c@12CA0000 {
clock-frequency = <400000>;
power-regulator@9 {
compatible = "maxim,max77802-pmic";
@@ -57,18 +58,136 @@
};
};
- i2c@12cd0000 { /* i2c7 */
+ i2c@12CD0000 { /* i2c7 */
clock-frequency = <100000>;
soundcodec@20 {
reg = <0x20>;
compatible = "maxim,max98090-codec";
};
- edp-lvds-bridge@48 {
- compatible = "parade,ps8625";
- reg = <0x48>;
- sleep-gpio = <&gpx3 5 GPIO_ACTIVE_HIGH>;
- reset-gpio = <&gpy7 7 GPIO_ACTIVE_HIGH>;
+ edp-lvds-bridge@48 {
+ compatible = "parade,ps8625";
+ reg = <0x48>;
+ sleep-gpios = <&gpx3 5 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&gpy7 7 GPIO_ACTIVE_LOW>;
+ parade,regs = /bits/ 8 <
+ 0x02 0xa1 0x01 /* HPD low */
+ /*
+ * SW setting
+ * [1:0] SW output 1.2V voltage is lower to 96%
+ */
+ 0x04 0x14 0x01
+ /*
+ * RCO SS setting
+ * [5:4] = b01 0.5%, b10 1%, b11 1.5%
+ */
+ 0x04 0xe3 0x20
+ 0x04 0xe2 0x80 /* [7] RCO SS enable */
+ /*
+ * RPHY Setting
+ * [3:2] CDR tune wait cycle before
+ * measure for fine tune b00: 1us,
+ * 01: 0.5us, 10:2us, 11:4us.
+ */
+ 0x04 0x8a 0x0c
+ 0x04 0x89 0x08 /* [3] RFD always on */
+ /*
+ * CTN lock in/out:
+ * 20000ppm/80000ppm. Lock out 2
+ * times.
+ */
+ 0x04 0x71 0x2d
+ /*
+ * 2.7G CDR settings
+ * NOF=40LSB for HBR CDR setting
+ */
+ 0x04 0x7d 0x07
+ 0x04 0x7b 0x00 /* [1:0] Fmin=+4bands */
+ 0x04 0x7a 0xfd /* [7:5] DCO_FTRNG=+-40% */
+ /*
+ * 1.62G CDR settings
+ * [5:2]NOF=64LSB [1:0]DCO scale is 2/5
+ */
+ 0x04 0xc0 0x12
+ 0x04 0xc1 0x92 /* Gitune=-37% */
+ 0x04 0xc2 0x1c /* Fbstep=100% */
+ 0x04 0x32 0x80 /* [7]LOS signal disable */
+ /*
+ * RPIO Setting
+ * [7:4] LVDS driver bias current :
+ * 75% (250mV swing)
+ */
+ 0x04 0x00 0xb0
+ /*
+ * [7:6] Right-bar GPIO output strength is 8mA
+ */
+ 0x04 0x15 0x40
+ /* EQ Training State Machine Setting */
+ 0x04 0x54 0x10 /* RCO calibration start */
+ /* [4:0] MAX_LANE_COUNT set to one lane */
+ 0x01 0x02 0x81
+ /* [4:0] LANE_COUNT_SET set to one lane */
+ 0x01 0x21 0x81
+ 0x00 0x52 0x20
+ 0x00 0xf1 0x03 /* HPD CP toggle enable */
+ 0x00 0x62 0x41
+ /* Counter number add 1ms counter delay */
+ 0x00 0xf6 0x01
+ /*
+ * [6]PWM function control by
+ * DPCD0040f[7], default is PWM
+ * block always works.
+ */
+ 0x00 0x77 0x06
+ /*
+ * 04h Adjust VTotal tolerance to
+ * fix the 30Hz no display issue
+ */
+ 0x00 0x4c 0x04
+ /* DPCD00400='h00, Parade OUI = 'h001cf8 */
+ 0x01 0xc0 0x00
+ 0x01 0xc1 0x1c /* DPCD00401='h1c */
+ 0x01 0xc2 0xf8 /* DPCD00402='hf8 */
+ /*
+ * DPCD403~408 = ASCII code
+ * D2SLV5='h4432534c5635
+ */
+ 0x01 0xc3 0x44
+ 0x01 0xc4 0x32 /* DPCD404 */
+ 0x01 0xc5 0x53 /* DPCD405 */
+ 0x01 0xc6 0x4c /* DPCD406 */
+ 0x01 0xc7 0x56 /* DPCD407 */
+ 0x01 0xc8 0x35 /* DPCD408 */
+ /*
+ * DPCD40A, Initial Code major revision
+ * '01'
+ */
+ 0x01 0xca 0x01
+ /* DPCD40B Initial Code minor revision '05' */
+ 0x01 0xcb 0x05
+ /* DPCD720 Select internal PWM */
+ 0x01 0xa5 0xa0
+ /*
+ * FFh for 100% PWM of brightness, 0h for 0%
+ * brightness
+ */
+ 0x01 0xa7 0xff
+ /*
+ * Set LVDS output as 6bit-VESA mapping,
+ * single LVDS channel
+ */
+ 0x01 0xcc 0x13
+ /* Enable SSC set by register */
+ 0x02 0xb1 0x20
+ /*
+ * Set SSC enabled and +/-1% central
+ * spreading
+ */
+ 0x04 0x10 0x16
+ /* MPU Clock source: LC => RCO */
+ 0x04 0x59 0x60
+ 0x04 0x54 0x14 /* LC -> RCO */
+ 0x02 0xa1 0x91>; /* HPD high */
};
};
@@ -76,7 +195,7 @@
samsung,codec-type = "max98090";
};
- i2c@12e10000 { /* i2c9 */
+ i2c@12E10000 { /* i2c9 */
clock-frequency = <400000>;
tpm@20 {
compatible = "infineon,slb9645tt";
@@ -101,30 +220,6 @@
};
};
- spi@12d40000 { /* spi2 */
- spi-max-frequency = <4000000>;
- spi-deactivate-delay = <200>;
-
- cros_ec: cros-ec@0 {
- compatible = "google,cros-ec-spi";
- reg = <0>;
- spi-half-duplex;
- spi-max-timeout-ms = <1100>;
- ec-interrupt = <&gpx1 5 GPIO_ACTIVE_LOW>;
-
- /*
- * This describes the flash memory within the EC. Note
- * that the STM32L flash erases to 0, not 0xff.
- */
- #address-cells = <1>;
- #size-cells = <1>;
- flash@8000000 {
- reg = <0x08000000 0x20000>;
- erase-value = <0>;
- };
- };
- };
-
xhci@12000000 {
samsung,vbus-gpio = <&gph0 0 GPIO_ACTIVE_HIGH>;
};
@@ -159,4 +254,103 @@
};
};
+&spi_2 {
+ spi-max-frequency = <3125000>;
+ spi-deactivate-delay = <200>;
+ status = "okay";
+ num-cs = <1>;
+ samsung,spi-src-clk = <0>;
+ cs-gpios = <&gpb1 2 0>;
+
+ cros_ec: cros-ec@0 {
+ compatible = "google,cros-ec-spi";
+ interrupt-parent = <&gpx1>;
+ interrupts = <5 0>;
+ reg = <0>;
+ spi-half-duplex;
+ spi-max-timeout-ms = <1100>;
+ ec-interrupt = <&gpx1 5 GPIO_ACTIVE_LOW>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /*
+ * This describes the flash memory within the EC. Note
+ * that the STM32L flash erases to 0, not 0xff.
+ */
+ flash@8000000 {
+ reg = <0x08000000 0x20000>;
+ erase-value = <0>;
+ };
+
+ controller-data {
+ samsung,spi-feedback-delay = <1>;
+ };
+
+ i2c_tunnel: i2c-tunnel {
+ compatible = "google,cros-ec-i2c-tunnel";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ google,remote-bus = <0>;
+
+ battery: sbs-battery@b {
+ compatible = "sbs,sbs-battery";
+ reg = <0xb>;
+ sbs,poll-retry-count = <1>;
+ sbs,i2c-retry-count = <2>;
+ };
+
+ power-regulator@48 {
+ compatible = "ti,tps65090";
+ reg = <0x48>;
+
+ regulators {
+ tps65090_dcdc1: dcdc1 {
+ ti,enable-ext-control;
+ };
+ tps65090_dcdc2: dcdc2 {
+ ti,enable-ext-control;
+ };
+ tps65090_dcdc3: dcdc3 {
+ ti,enable-ext-control;
+ };
+ tps65090_fet1: fet1 {
+ regulator-name = "vcd_led";
+ };
+ tps65090_fet2: fet2 {
+ regulator-name = "video_mid";
+ regulator-always-on;
+ };
+ tps65090_fet3: fet3 {
+ regulator-name = "wwan_r";
+ regulator-always-on;
+ };
+ tps65090_fet4: fet4 {
+ regulator-name = "sdcard";
+ regulator-always-on;
+ };
+ tps65090_fet5: fet5 {
+ regulator-name = "camout";
+ regulator-always-on;
+ };
+ tps65090_fet6: fet6 {
+ regulator-name = "lcd_vdd";
+ };
+ tps65090_fet7: fet7 {
+ regulator-name = "video_mid_1a";
+ regulator-always-on;
+ };
+ tps65090_ldo1: ldo1 {
+ };
+ tps65090_ldo2: ldo2 {
+ };
+ };
+
+ charger {
+ compatible = "ti,tps65090-charger";
+ };
+ };
+ };
+ };
+};
+
#include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/dts/exynos5420-smdk5420.dts b/arch/arm/dts/exynos5420-smdk5420.dts
index 6855027389..015ff151f2 100644
--- a/arch/arm/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/dts/exynos5420-smdk5420.dts
@@ -37,7 +37,7 @@
};
/* s2mps11 is on i2c bus 4 */
- i2c@12ca0000 {
+ i2c@12CA0000 {
#address-cells = <1>;
#size-cells = <0>;
pmic@66 {
@@ -82,7 +82,7 @@
samsung,codec-type = "wm8994";
};
- i2c@12c70000 {
+ i2c@12C70000 {
soundcodec@1a {
reg = <0x1a>;
compatible = "wolfson,wm8994-codec";
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi
index 31fabb190e..bd3619d751 100644
--- a/arch/arm/dts/exynos54xx.dtsi
+++ b/arch/arm/dts/exynos54xx.dtsi
@@ -14,17 +14,17 @@
};
aliases {
- i2c0 = "/i2c@12c60000";
- i2c1 = "/i2c@12c70000";
- i2c2 = "/i2c@12c80000";
- i2c3 = "/i2c@12c90000";
- i2c4 = "/i2c@12ca0000";
- i2c5 = "/i2c@12cb0000";
- i2c6 = "/i2c@12cc0000";
- i2c7 = "/i2c@12cd0000";
- i2c8 = "/i2c@12e00000";
- i2c9 = "/i2c@12e10000";
- i2c10 = "/i2c@12e20000";
+ i2c0 = "/i2c@12C60000";
+ i2c1 = "/i2c@12C70000";
+ i2c2 = "/i2c@12C80000";
+ i2c3 = "/i2c@12C90000";
+ i2c4 = "/i2c@12CA0000";
+ i2c5 = "/i2c@12CB0000";
+ i2c6 = "/i2c@12CC0000";
+ i2c7 = "/i2c@12CD0000";
+ i2c8 = "/i2c@12E00000";
+ i2c9 = "/i2c@12E10000";
+ i2c10 = "/i2c@12E20000";
pinctrl0 = &pinctrl_0;
pinctrl1 = &pinctrl_1;
pinctrl2 = &pinctrl_2;
@@ -42,7 +42,7 @@
xhci1 = "/xhci@12400000";
};
- i2c@12ca0000 {
+ i2c@12CA0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@@ -50,7 +50,7 @@
interrupts = <0 60 0>;
};
- i2c@12cb0000 {
+ i2c@12CB0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@@ -58,7 +58,7 @@
interrupts = <0 61 0>;
};
- i2c@12cc0000 {
+ i2c@12CC0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@@ -66,7 +66,7 @@
interrupts = <0 62 0>;
};
- i2c@12cd0000 {
+ i2c@12CD0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@@ -74,7 +74,7 @@
interrupts = <0 63 0>;
};
- i2c@12e00000 {
+ i2c@12E00000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@@ -82,7 +82,7 @@
interrupts = <0 87 0>;
};
- i2c@12e10000 {
+ i2c@12E10000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@@ -90,7 +90,7 @@
interrupts = <0 88 0>;
};
- i2c@12e20000 {
+ i2c@12E20000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts
index 176ce552ad..600c2948cf 100644
--- a/arch/arm/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/dts/exynos5800-peach-pi.dts
@@ -25,7 +25,8 @@
aliases {
serial0 = "/serial@12C30000";
console = "/serial@12C30000";
- pmic = "/i2c@12ca0000";
+ pmic = "/i2c@12CA0000";
+ i2c104 = &i2c_tunnel;
};
dmc {
@@ -49,7 +50,7 @@
};
/* MAX77802 is on i2c bus 4 */
- i2c@12ca0000 {
+ i2c@12CA0000 {
clock-frequency = <400000>;
power-regulator@9 {
compatible = "maxim,max77802-pmic";
@@ -57,7 +58,7 @@
};
};
- i2c@12cd0000 { /* i2c7 */
+ i2c@12CD0000 { /* i2c7 */
clock-frequency = <100000>;
soundcodec@20 {
reg = <0x20>;
@@ -69,7 +70,7 @@
samsung,codec-type = "max98090";
};
- i2c@12e10000 { /* i2c9 */
+ i2c@12E10000 { /* i2c9 */
clock-frequency = <400000>;
tpm@20 {
compatible = "infineon,slb9645tt";
@@ -93,29 +94,6 @@
};
};
- spi@12d40000 { /* spi2 */
- spi-max-frequency = <4000000>;
- spi-deactivate-delay = <200>;
- cros_ec: cros-ec@0 {
- compatible = "google,cros-ec-spi";
- reg = <0>;
- spi-half-duplex;
- spi-max-timeout-ms = <1100>;
- ec-interrupt = <&gpx1 5 GPIO_ACTIVE_LOW>;
-
- /*
- * This describes the flash memory within the EC. Note
- * that the STM32L flash erases to 0, not 0xff.
- */
- #address-cells = <1>;
- #size-cells = <1>;
- flash@8000000 {
- reg = <0x08000000 0x20000>;
- erase-value = <0>;
- };
- };
- };
-
xhci@12000000 {
samsung,vbus-gpio = <&gph0 0 GPIO_ACTIVE_HIGH>;
};
@@ -153,4 +131,103 @@
};
};
+&spi_2 {
+ spi-max-frequency = <3125000>;
+ spi-deactivate-delay = <200>;
+ status = "okay";
+ num-cs = <1>;
+ samsung,spi-src-clk = <0>;
+ cs-gpios = <&gpb1 2 0>;
+
+ cros_ec: cros-ec@0 {
+ compatible = "google,cros-ec-spi";
+ interrupt-parent = <&gpx1>;
+ interrupts = <5 0>;
+ reg = <0>;
+ spi-half-duplex;
+ spi-max-timeout-ms = <1100>;
+ ec-interrupt = <&gpx1 5 GPIO_ACTIVE_LOW>;
+
+ /*
+ * This describes the flash memory within the EC. Note
+ * that the STM32L flash erases to 0, not 0xff.
+ */
+ #address-cells = <1>;
+ #size-cells = <1>;
+ flash@8000000 {
+ reg = <0x08000000 0x20000>;
+ erase-value = <0>;
+ };
+
+ controller-data {
+ samsung,spi-feedback-delay = <1>;
+ };
+
+ i2c_tunnel: i2c-tunnel {
+ compatible = "google,cros-ec-i2c-tunnel";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ google,remote-bus = <0>;
+
+ battery: sbs-battery@b {
+ compatible = "sbs,sbs-battery";
+ reg = <0xb>;
+ sbs,poll-retry-count = <1>;
+ sbs,i2c-retry-count = <2>;
+ };
+
+ power-regulator@48 {
+ compatible = "ti,tps65090";
+ reg = <0x48>;
+
+ regulators {
+ tps65090_dcdc1: dcdc1 {
+ ti,enable-ext-control;
+ };
+ tps65090_dcdc2: dcdc2 {
+ ti,enable-ext-control;
+ };
+ tps65090_dcdc3: dcdc3 {
+ ti,enable-ext-control;
+ };
+ tps65090_fet1: fet1 {
+ regulator-name = "vcd_led";
+ };
+ tps65090_fet2: fet2 {
+ regulator-name = "video_mid";
+ regulator-always-on;
+ };
+ tps65090_fet3: fet3 {
+ regulator-name = "wwan_r";
+ regulator-always-on;
+ };
+ tps65090_fet4: fet4 {
+ regulator-name = "sdcard";
+ regulator-always-on;
+ };
+ tps65090_fet5: fet5 {
+ regulator-name = "camout";
+ regulator-always-on;
+ };
+ tps65090_fet6: fet6 {
+ regulator-name = "lcd_vdd";
+ };
+ tps65090_fet7: fet7 {
+ regulator-name = "video_mid_1a";
+ regulator-always-on;
+ };
+ tps65090_ldo1: ldo1 {
+ };
+ tps65090_ldo2: ldo2 {
+ };
+ };
+
+ charger {
+ compatible = "ti,tps65090-charger";
+ };
+ };
+ };
+ };
+};
+
#include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/include/asm/arch-exynos/dp_info.h b/arch/arm/include/asm/arch-exynos/dp_info.h
index 3f6750a6b2..17e8f56d90 100644
--- a/arch/arm/include/asm/arch-exynos/dp_info.h
+++ b/arch/arm/include/asm/arch-exynos/dp_info.h
@@ -197,6 +197,4 @@ unsigned int exynos_init_dp(void)
}
#endif
-void exynos_set_dp_platform_data(struct exynos_dp_platform_data *pd);
-
#endif /* _DP_INFO_H */
diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h
index 5c1c3d4a93..fdc9e87c69 100644
--- a/arch/arm/include/asm/arch-exynos/periph.h
+++ b/arch/arm/include/asm/arch-exynos/periph.h
@@ -53,6 +53,7 @@ enum periph_id {
PERIPH_ID_PWM2,
PERIPH_ID_PWM3,
PERIPH_ID_PWM4,
+ PERIPH_ID_DPHPD,
PERIPH_ID_I2C10 = 203,
PERIPH_ID_NONE = -1,
diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S
index e5c1733e59..313fa3ff96 100644
--- a/arch/x86/cpu/start.S
+++ b/arch/x86/cpu/start.S
@@ -128,6 +128,15 @@ car_init_ret:
andl $0xfffffff0, %esp
post_code(POST_START_STACK)
+ /*
+ * Debug UART is available here although it may not be plumbed out
+ * to pins depending on the board. To use it:
+ *
+ * call debug_uart_init
+ * mov $'a', %eax
+ * call printch
+ */
+
/* Zero the global data since it won't happen later */
xorl %eax, %eax
movl $GENERATED_GBL_DATA_SIZE, %ecx
diff --git a/board/samsung/common/Makefile b/board/samsung/common/Makefile
index 5fb01ce783..6cbd90661b 100644
--- a/board/samsung/common/Makefile
+++ b/board/samsung/common/Makefile
@@ -11,4 +11,5 @@ obj-$(CONFIG_MISC_COMMON) += misc.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_BOARD_COMMON) += board.o
+obj-$(CONFIG_EXYNOS5_DT) += exynos5-dt.o
endif
diff --git a/board/samsung/common/board.c b/board/samsung/common/board.c
index 1a4e8c9c99..d32c75de50 100644
--- a/board/samsung/common/board.c
+++ b/board/samsung/common/board.c
@@ -152,13 +152,14 @@ int board_early_init_f(void)
board_i2c_init(gd->fdt_blob);
#endif
-#if defined(CONFIG_OF_CONTROL) && defined(CONFIG_EXYNOS_FB)
-/*
- * board_init_f(arch/arm/lib/board.c) calls lcd_setmem() which needs
- * panel_info.vl_col, panel_info.vl_row and panel_info.vl_bpix, to reserve
- * FB memory at a very early stage. So, we need to fill panel_info.vl_col,
- * panel_info.vl_row and panel_info.vl_bpix before lcd_setmem() is called.
- */
+#if defined(CONFIG_EXYNOS_FB)
+ /*
+ * board_init_f(arch/arm/lib/board.c) calls lcd_setmem() which needs
+ * panel_info.vl_col, panel_info.vl_row and panel_info.vl_bpix,
+ * to reserve frame-buffer memory at a very early stage. So, we need
+ * to fill panel_info.vl_col, panel_info.vl_row and panel_info.vl_bpix
+ * before lcd_setmem() is called.
+ */
err = exynos_lcd_early_init(gd->fdt_blob);
if (err) {
debug("LCD early init failed\n");
@@ -179,7 +180,6 @@ int power_init_board(void)
}
#endif
-#ifdef CONFIG_OF_CONTROL
#ifdef CONFIG_SMC911X
static int decode_sromc(const void *blob, struct fdt_sromc *config)
{
@@ -310,7 +310,6 @@ int checkboard(void)
return 0;
}
#endif
-#endif /* CONFIG_OF_CONTROL */
#ifdef CONFIG_BOARD_LATE_INIT
int board_late_init(void)
diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c
new file mode 100644
index 0000000000..7d1b88a9b8
--- /dev/null
+++ b/board/samsung/common/exynos5-dt.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dwc3-uboot.h>
+#include <fdtdec.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <i2c.h>
+#include <mmc.h>
+#include <netdev.h>
+#include <samsung-usb-phy-uboot.h>
+#include <spi.h>
+#include <usb.h>
+#include <video_bridge.h>
+#include <asm/gpio.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/dwmmc.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/power.h>
+#include <asm/arch/sromc.h>
+#include <power/pmic.h>
+#include <power/max77686_pmic.h>
+#include <power/regulator.h>
+#include <power/s5m8767.h>
+#include <tmu.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void board_enable_audio_codec(void)
+{
+ int node, ret;
+ struct gpio_desc en_gpio;
+
+ node = fdtdec_next_compatible(gd->fdt_blob, 0,
+ COMPAT_SAMSUNG_EXYNOS5_SOUND);
+ if (node <= 0)
+ return;
+
+ ret = gpio_request_by_name_nodev(gd->fdt_blob, node,
+ "codec-enable-gpio", 0, &en_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret == -FDT_ERR_NOTFOUND)
+ return;
+
+ /* Turn on the GPIO which connects to the codec's "enable" line. */
+ gpio_set_pull(gpio_get_number(&en_gpio), S5P_GPIO_PULL_NONE);
+
+#ifdef CONFIG_SOUND_MAX98095
+ /* Enable MAX98095 Codec */
+ gpio_request(EXYNOS5_GPIO_X17, "max98095_enable");
+ gpio_direction_output(EXYNOS5_GPIO_X17, 1);
+ gpio_set_pull(EXYNOS5_GPIO_X17, S5P_GPIO_PULL_NONE);
+#endif
+}
+
+int exynos_init(void)
+{
+ board_enable_audio_codec();
+
+ return 0;
+}
+
+static int exynos_set_regulator(const char *name, uint uv)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = regulator_get_by_platname(name, &dev);
+ if (ret) {
+ debug("%s: Cannot find regulator %s\n", __func__, name);
+ return ret;
+ }
+ ret = regulator_set_value(dev, uv);
+ if (ret) {
+ debug("%s: Cannot set regulator %s\n", __func__, name);
+ return ret;
+ }
+
+ return 0;
+}
+
+int exynos_power_init(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = pmic_get("max77686", &dev);
+ if (!ret) {
+ /* TODO(sjg@chromium.org): Move into the clock/pmic API */
+ ret = pmic_clrsetbits(dev, MAX77686_REG_PMIC_32KHZ, 0,
+ MAX77686_32KHCP_EN);
+ if (ret)
+ return ret;
+ ret = pmic_clrsetbits(dev, MAX77686_REG_PMIC_BBAT, 0,
+ MAX77686_BBCHOSTEN | MAX77686_BBCVS_3_5V);
+ if (ret)
+ return ret;
+ } else {
+ ret = pmic_get("s5m8767-pmic", &dev);
+ /* TODO(sjg@chromium.org): Use driver model to access clock */
+#ifdef CONFIG_PMIC_S5M8767
+ if (!ret)
+ s5m8767_enable_32khz_cp(dev);
+#endif
+ }
+ if (ret == -ENODEV)
+ return 0;
+
+ ret = regulators_enable_boot_on(false);
+ if (ret)
+ return ret;
+
+ ret = exynos_set_regulator("vdd_mif", 1100000);
+ if (ret)
+ return ret;
+
+ /*
+ * This would normally be 1.3V, but since we are running slowly 1V
+ * is enough. For spring it helps reduce CPU temperature and avoid
+ * hangs with the case open.
+ */
+ ret = exynos_set_regulator("vdd_arm", 1000000);
+ if (ret)
+ return ret;
+ ret = exynos_set_regulator("vdd_int", 1012500);
+ if (ret)
+ return ret;
+ ret = exynos_set_regulator("vdd_g3d", 1200000);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int board_get_revision(void)
+{
+ return 0;
+}
+
+#ifdef CONFIG_LCD
+
+static int board_dp_bridge_init(struct udevice *dev)
+{
+ const int max_tries = 10;
+ int num_tries;
+ int ret;
+
+ debug("%s\n", __func__);
+ ret = video_bridge_attach(dev);
+ if (ret) {
+ debug("video bridge init failed: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * We need to wait for 90ms after bringing up the bridge since there
+ * is a phantom "high" on the HPD chip during its bootup. The phantom
+ * high comes within 7ms of de-asserting PD and persists for at least
+ * 15ms. The real high comes roughly 50ms after PD is de-asserted. The
+ * phantom high makes it hard for us to know when the NXP chip is up.
+ */
+ mdelay(90);
+
+ for (num_tries = 0; num_tries < max_tries; num_tries++) {
+ /* Check HPD. If it's high, or we don't have it, all is well */
+ ret = video_bridge_check_attached(dev);
+ if (!ret || ret == -ENOENT)
+ return 0;
+
+ debug("%s: eDP bridge failed to come up; try %d of %d\n",
+ __func__, num_tries, max_tries);
+ }
+
+ /* Immediately go into bridge reset if the hp line is not high */
+ return -EIO;
+}
+
+static int board_dp_bridge_setup(const void *blob)
+{
+ const int max_tries = 2;
+ int num_tries;
+ struct udevice *dev;
+ int ret;
+
+ /* Configure I2C registers for Parade bridge */
+ ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &dev);
+ if (ret) {
+ debug("video bridge init failed: %d\n", ret);
+ return ret;
+ }
+
+ if (strncmp(dev->driver->name, "parade", 6)) {
+ /* Mux HPHPD to the special hotplug detect mode */
+ exynos_pinmux_config(PERIPH_ID_DPHPD, 0);
+ }
+
+ for (num_tries = 0; num_tries < max_tries; num_tries++) {
+ ret = board_dp_bridge_init(dev);
+ if (!ret)
+ return 0;
+ if (num_tries == max_tries - 1)
+ break;
+
+ /*
+ * If we're here, the bridge chip failed to initialise.
+ * Power down the bridge in an attempt to reset.
+ */
+ video_bridge_set_active(dev, false);
+
+ /*
+ * Arbitrarily wait 300ms here with DP_N low. Don't know for
+ * sure how long we should wait, but we're being paranoid.
+ */
+ mdelay(300);
+ }
+
+ return ret;
+}
+
+void exynos_cfg_lcd_gpio(void)
+{
+ /* For Backlight */
+ gpio_request(EXYNOS5_GPIO_B20, "lcd_backlight");
+ gpio_cfg_pin(EXYNOS5_GPIO_B20, S5P_GPIO_OUTPUT);
+ gpio_set_value(EXYNOS5_GPIO_B20, 1);
+}
+
+void exynos_set_dp_phy(unsigned int onoff)
+{
+ set_dp_phy_ctrl(onoff);
+}
+
+static int board_dp_set_backlight(int percent)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &dev);
+ if (!ret)
+ ret = video_bridge_set_backlight(dev, percent);
+
+ return ret;
+}
+
+void exynos_backlight_on(unsigned int on)
+{
+ struct udevice *dev;
+ int ret;
+
+ debug("%s(%u)\n", __func__, on);
+ if (!on)
+ return;
+
+ ret = regulator_get_by_platname("vcd_led", &dev);
+ if (!ret)
+ ret = regulator_set_enable(dev, true);
+ if (ret)
+ debug("Failed to enable backlight: ret=%d\n", ret);
+
+ /* T5 in the LCD timing spec (defined as > 10ms) */
+ mdelay(10);
+
+ /* board_dp_backlight_pwm */
+ gpio_direction_output(EXYNOS5_GPIO_B20, 1);
+
+ /* T6 in the LCD timing spec (defined as > 10ms) */
+ mdelay(10);
+
+ /* try to set the backlight in the bridge registers */
+ ret = board_dp_set_backlight(80);
+
+ /* if we have no bridge or it does not support backlight, use a GPIO */
+ if (ret == -ENODEV || ret == -ENOSYS) {
+ gpio_request(EXYNOS5_GPIO_X30, "board_dp_backlight_en");
+ gpio_direction_output(EXYNOS5_GPIO_X30, 1);
+ }
+}
+
+void exynos_lcd_power_on(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ debug("%s\n", __func__);
+ ret = regulator_get_by_platname("lcd_vdd", &dev);
+ if (!ret)
+ ret = regulator_set_enable(dev, true);
+ if (ret)
+ debug("Failed to enable LCD panel: ret=%d\n", ret);
+
+ ret = board_dp_bridge_setup(gd->fdt_blob);
+ if (ret && ret != -ENODEV)
+ printf("LCD bridge failed to enable: %d\n", ret);
+}
+
+#endif
+
+#ifdef CONFIG_USB_DWC3
+static struct dwc3_device dwc3_device_data = {
+ .maximum_speed = USB_SPEED_SUPER,
+ .base = 0x12400000,
+ .dr_mode = USB_DR_MODE_PERIPHERAL,
+ .index = 0,
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+ dwc3_uboot_handle_interrupt(0);
+ return 0;
+}
+
+int board_usb_init(int index, enum usb_init_type init)
+{
+ struct exynos_usb3_phy *phy = (struct exynos_usb3_phy *)
+ samsung_get_base_usb3_phy();
+
+ if (!phy) {
+ error("usb3 phy not supported");
+ return -ENODEV;
+ }
+
+ set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
+ exynos5_usb3_phy_init(phy);
+
+ return dwc3_uboot_init(&dwc3_device_data);
+}
+#endif
+#ifdef CONFIG_SET_DFU_ALT_INFO
+char *get_dfu_alt_system(char *interface, char *devstr)
+{
+ return getenv("dfu_alt_system");
+}
+
+char *get_dfu_alt_boot(char *interface, char *devstr)
+{
+ struct mmc *mmc;
+ char *alt_boot;
+ int dev_num;
+
+ dev_num = simple_strtoul(devstr, NULL, 10);
+
+ mmc = find_mmc_device(dev_num);
+ if (!mmc)
+ return NULL;
+
+ if (mmc_init(mmc))
+ return NULL;
+
+ if (IS_SD(mmc))
+ alt_boot = CONFIG_DFU_ALT_BOOT_SD;
+ else
+ alt_boot = CONFIG_DFU_ALT_BOOT_EMMC;
+
+ return alt_boot;
+}
+#endif
diff --git a/board/samsung/smdk5250/Kconfig b/board/samsung/smdk5250/Kconfig
index 698ee9125c..11ffaee5ce 100644
--- a/board/samsung/smdk5250/Kconfig
+++ b/board/samsung/smdk5250/Kconfig
@@ -23,3 +23,16 @@ config SYS_CONFIG_NAME
default "snow"
endif
+
+if TARGET_SPRING
+
+config SYS_BOARD
+ default "smdk5250"
+
+config SYS_VENDOR
+ default "samsung"
+
+config SYS_CONFIG_NAME
+ default "spring"
+
+endif
diff --git a/board/samsung/smdk5250/MAINTAINERS b/board/samsung/smdk5250/MAINTAINERS
index 070593e266..cde966fdbf 100644
--- a/board/samsung/smdk5250/MAINTAINERS
+++ b/board/samsung/smdk5250/MAINTAINERS
@@ -10,3 +10,9 @@ M: Akshay Saraswat <akshay.s@samsung.com>
S: Maintained
F: include/configs/snow.h
F: configs/snow_defconfig
+
+SPRING BOARD
+M: Simon Glass <sjg@chromium.org>
+S: Maintained
+F: include/configs/spring.h
+F: configs/spring_defconfig
diff --git a/board/samsung/smdk5250/Makefile b/board/samsung/smdk5250/Makefile
index 3d96b077b4..501cab69e1 100644
--- a/board/samsung/smdk5250/Makefile
+++ b/board/samsung/smdk5250/Makefile
@@ -5,7 +5,3 @@
#
obj-y += smdk5250_spl.o
-
-ifndef CONFIG_SPL_BUILD
-obj-y += exynos5-dt.o
-endif
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c
deleted file mode 100644
index 53ff7061d7..0000000000
--- a/board/samsung/smdk5250/exynos5-dt.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2012 Samsung Electronics
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <fdtdec.h>
-#include <asm/io.h>
-#include <errno.h>
-#include <i2c.h>
-#include <netdev.h>
-#include <spi.h>
-#include <asm/gpio.h>
-#include <asm/arch/cpu.h>
-#include <asm/arch/dwmmc.h>
-#include <asm/arch/mmc.h>
-#include <asm/arch/pinmux.h>
-#include <asm/arch/power.h>
-#include <asm/arch/sromc.h>
-#include <power/pmic.h>
-#include <power/max77686_pmic.h>
-#include <power/tps65090_pmic.h>
-#include <tmu.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#ifdef CONFIG_SOUND_MAX98095
-static void board_enable_audio_codec(void)
-{
- /* Enable MAX98095 Codec */
- gpio_request(EXYNOS5_GPIO_X17, "max98095_enable");
- gpio_direction_output(EXYNOS5_GPIO_X17, 1);
- gpio_set_pull(EXYNOS5_GPIO_X17, S5P_GPIO_PULL_NONE);
-}
-#endif
-
-int exynos_init(void)
-{
-#ifdef CONFIG_SOUND_MAX98095
- board_enable_audio_codec();
-#endif
- return 0;
-}
-
-#if defined(CONFIG_POWER)
-#ifdef CONFIG_POWER_MAX77686
-static int pmic_reg_update(struct pmic *p, int reg, uint regval)
-{
- u32 val;
- int ret = 0;
-
- ret = pmic_reg_read(p, reg, &val);
- if (ret) {
- debug("%s: PMIC %d register read failed\n", __func__, reg);
- return -1;
- }
- val |= regval;
- ret = pmic_reg_write(p, reg, val);
- if (ret) {
- debug("%s: PMIC %d register write failed\n", __func__, reg);
- return -1;
- }
- return 0;
-}
-
-static int max77686_init(void)
-{
- struct pmic *p;
-
- if (pmic_init(I2C_PMIC))
- return -1;
-
- p = pmic_get("MAX77686_PMIC");
- if (!p)
- return -ENODEV;
-
- if (pmic_probe(p))
- return -1;
-
- if (pmic_reg_update(p, MAX77686_REG_PMIC_32KHZ, MAX77686_32KHCP_EN))
- return -1;
-
- if (pmic_reg_update(p, MAX77686_REG_PMIC_BBAT,
- MAX77686_BBCHOSTEN | MAX77686_BBCVS_3_5V))
- return -1;
-
- /* VDD_MIF */
- if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK1OUT,
- MAX77686_BUCK1OUT_1V)) {
- debug("%s: PMIC %d register write failed\n", __func__,
- MAX77686_REG_PMIC_BUCK1OUT);
- return -1;
- }
-
- if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK1CRTL,
- MAX77686_BUCK1CTRL_EN))
- return -1;
-
- /* VDD_ARM */
- if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK2DVS1,
- MAX77686_BUCK2DVS1_1_3V)) {
- debug("%s: PMIC %d register write failed\n", __func__,
- MAX77686_REG_PMIC_BUCK2DVS1);
- return -1;
- }
-
- if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK2CTRL1,
- MAX77686_BUCK2CTRL_ON))
- return -1;
-
- /* VDD_INT */
- if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK3DVS1,
- MAX77686_BUCK3DVS1_1_0125V)) {
- debug("%s: PMIC %d register write failed\n", __func__,
- MAX77686_REG_PMIC_BUCK3DVS1);
- return -1;
- }
-
- if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK3CTRL,
- MAX77686_BUCK3CTRL_ON))
- return -1;
-
- /* VDD_G3D */
- if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK4DVS1,
- MAX77686_BUCK4DVS1_1_2V)) {
- debug("%s: PMIC %d register write failed\n", __func__,
- MAX77686_REG_PMIC_BUCK4DVS1);
- return -1;
- }
-
- if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK4CTRL1,
- MAX77686_BUCK3CTRL_ON))
- return -1;
-
- /* VDD_LDO2 */
- if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO2CTRL1,
- MAX77686_LD02CTRL1_1_5V | EN_LDO))
- return -1;
-
- /* VDD_LDO3 */
- if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO3CTRL1,
- MAX77686_LD03CTRL1_1_8V | EN_LDO))
- return -1;
-
- /* VDD_LDO5 */
- if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO5CTRL1,
- MAX77686_LD05CTRL1_1_8V | EN_LDO))
- return -1;
-
- /* VDD_LDO10 */
- if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO10CTRL1,
- MAX77686_LD10CTRL1_1_8V | EN_LDO))
- return -1;
-
- return 0;
-}
-#endif /* CONFIG_POWER_MAX77686 */
-
-int exynos_power_init(void)
-{
- int ret = 0;
-
-#ifdef CONFIG_POWER_MAX77686
- ret = max77686_init();
- if (ret)
- return ret;
-#endif
-#ifdef CONFIG_POWER_TPS65090
- /*
- * The TPS65090 may not be in the device tree. If so, it is not
- * an error.
- */
- ret = tps65090_init();
- if (ret == 0 || ret == -ENODEV)
- return 0;
-#endif
-
- return ret;
-}
-#endif /* CONFIG_POWER */
-
-#ifdef CONFIG_LCD
-static int board_dp_bridge_setup(void)
-{
- const int max_tries = 10;
- int num_tries, node;
-
- /*
- * TODO(sjg): Use device tree for GPIOs when exynos GPIO
- * numbering patch is in mainline.
- */
- debug("%s\n", __func__);
- node = fdtdec_next_compatible(gd->fdt_blob, 0, COMPAT_NXP_PTN3460);
- if (node < 0) {
- debug("%s: No node for DP bridge in device tree\n", __func__);
- return -ENODEV;
- }
-
- /* Setup the GPIOs */
-
- /* PD is ACTIVE_LOW, and initially de-asserted */
- gpio_request(EXYNOS5_GPIO_Y25, "dp_bridge_pd");
- gpio_set_pull(EXYNOS5_GPIO_Y25, S5P_GPIO_PULL_NONE);
- gpio_direction_output(EXYNOS5_GPIO_Y25, 1);
-
- /* Reset is ACTIVE_LOW */
- gpio_request(EXYNOS5_GPIO_X15, "dp_bridge_reset");
- gpio_set_pull(EXYNOS5_GPIO_X15, S5P_GPIO_PULL_NONE);
- gpio_direction_output(EXYNOS5_GPIO_X15, 0);
-
- udelay(10);
- gpio_set_value(EXYNOS5_GPIO_X15, 1);
-
- gpio_request(EXYNOS5_GPIO_X07, "dp_bridge_hpd");
- gpio_direction_input(EXYNOS5_GPIO_X07);
-
- /*
- * We need to wait for 90ms after bringing up the bridge since there
- * is a phantom "high" on the HPD chip during its bootup. The phantom
- * high comes within 7ms of de-asserting PD and persists for at least
- * 15ms. The real high comes roughly 50ms after PD is de-asserted. The
- * phantom high makes it hard for us to know when the NXP chip is up.
- */
- mdelay(90);
-
- for (num_tries = 0; num_tries < max_tries; num_tries++) {
- /* Check HPD. If it's high, we're all good. */
- if (gpio_get_value(EXYNOS5_GPIO_X07))
- return 0;
-
- debug("%s: eDP bridge failed to come up; try %d of %d\n",
- __func__, num_tries, max_tries);
- }
-
- /* Immediately go into bridge reset if the hp line is not high */
- return -ENODEV;
-}
-
-void exynos_cfg_lcd_gpio(void)
-{
- /* For Backlight */
- gpio_request(EXYNOS5_GPIO_B20, "lcd_backlight");
- gpio_cfg_pin(EXYNOS5_GPIO_B20, S5P_GPIO_OUTPUT);
- gpio_set_value(EXYNOS5_GPIO_B20, 1);
-
- /* LCD power on */
- gpio_request(EXYNOS5_GPIO_X15, "lcd_power");
- gpio_cfg_pin(EXYNOS5_GPIO_X15, S5P_GPIO_OUTPUT);
- gpio_set_value(EXYNOS5_GPIO_X15, 1);
-
- /* Set Hotplug detect for DP */
- gpio_cfg_pin(EXYNOS5_GPIO_X07, S5P_GPIO_FUNC(0x3));
-}
-
-void exynos_set_dp_phy(unsigned int onoff)
-{
- set_dp_phy_ctrl(onoff);
-}
-
-void exynos_backlight_on(unsigned int on)
-{
- debug("%s(%u)\n", __func__, on);
-
- if (!on)
- return;
-
-#ifdef CONFIG_POWER_TPS65090
- int ret;
-
- ret = tps65090_fet_enable(1); /* Enable FET1, backlight */
- if (ret)
- return;
-
- /* T5 in the LCD timing spec (defined as > 10ms) */
- mdelay(10);
-
- /* board_dp_backlight_pwm */
- gpio_direction_output(EXYNOS5_GPIO_B20, 1);
-
- /* T6 in the LCD timing spec (defined as > 10ms) */
- mdelay(10);
-
- /* board_dp_backlight_en */
- gpio_request(EXYNOS5_GPIO_X30, "board_dp_backlight_en");
- gpio_direction_output(EXYNOS5_GPIO_X30, 1);
-#endif
-}
-
-void exynos_lcd_power_on(void)
-{
- int ret;
-
- debug("%s\n", __func__);
-
-#ifdef CONFIG_POWER_TPS65090
- /* board_dp_lcd_vdd */
- tps65090_fet_enable(6); /* Enable FET6, lcd panel */
-#endif
-
- ret = board_dp_bridge_setup();
- if (ret && ret != -ENODEV)
- printf("LCD bridge failed to enable: %d\n", ret);
-}
-
-#endif
diff --git a/board/samsung/smdk5420/Makefile b/board/samsung/smdk5420/Makefile
index c2f8886c99..96a400aacb 100644
--- a/board/samsung/smdk5420/Makefile
+++ b/board/samsung/smdk5420/Makefile
@@ -5,7 +5,3 @@
#
obj-y += smdk5420_spl.o
-
-ifndef CONFIG_SPL_BUILD
-obj-y += smdk5420.o
-endif
diff --git a/board/samsung/smdk5420/smdk5420.c b/board/samsung/smdk5420/smdk5420.c
deleted file mode 100644
index 88f4044d63..0000000000
--- a/board/samsung/smdk5420/smdk5420.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2013 Samsung Electronics
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <fdtdec.h>
-#include <errno.h>
-#include <asm/io.h>
-#include <asm/gpio.h>
-#include <asm/arch/cpu.h>
-#include <asm/arch/board.h>
-#include <asm/arch/power.h>
-#include <asm/arch/system.h>
-#include <asm/arch/pinmux.h>
-#include <asm/arch/dp_info.h>
-#include <asm/arch/xhci-exynos.h>
-#include <power/tps65090_pmic.h>
-#include <i2c.h>
-#include <lcd.h>
-#include <mmc.h>
-#include <parade.h>
-#include <spi.h>
-#include <usb.h>
-#include <dwc3-uboot.h>
-#include <samsung-usb-phy-uboot.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-int exynos_init(void)
-{
- return 0;
-}
-
-#ifdef CONFIG_LCD
-static int has_edp_bridge(void)
-{
- int node;
-
- node = fdtdec_next_compatible(gd->fdt_blob, 0, COMPAT_PARADE_PS8625);
-
- /* No node for bridge in device tree. */
- if (node <= 0)
- return 0;
-
- /* Default is with bridge ic */
- return 1;
-}
-
-void exynos_lcd_power_on(void)
-{
- int ret;
-
-#ifdef CONFIG_POWER_TPS65090
- ret = tps65090_init();
- if (ret < 0) {
- printf("%s: tps65090_init() failed\n", __func__);
- return;
- }
-
- tps65090_fet_enable(6);
-#endif
-
- mdelay(5);
-
- if (has_edp_bridge())
- if (parade_init(gd->fdt_blob))
- printf("%s: ps8625_init() failed\n", __func__);
-}
-
-void exynos_backlight_on(unsigned int onoff)
-{
-#ifdef CONFIG_POWER_TPS65090
- tps65090_fet_enable(1);
-#endif
-}
-#endif
-
-int board_get_revision(void)
-{
- return 0;
-}
-
-#ifdef CONFIG_USB_DWC3
-static struct dwc3_device dwc3_device_data = {
- .maximum_speed = USB_SPEED_SUPER,
- .base = 0x12400000,
- .dr_mode = USB_DR_MODE_PERIPHERAL,
- .index = 0,
-};
-
-int usb_gadget_handle_interrupts(void)
-{
- dwc3_uboot_handle_interrupt(0);
- return 0;
-}
-
-int board_usb_init(int index, enum usb_init_type init)
-{
- struct exynos_usb3_phy *phy = (struct exynos_usb3_phy *)
- samsung_get_base_usb3_phy();
-
- if (!phy) {
- error("usb3 phy not supported");
- return -ENODEV;
- }
-
- set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
- exynos5_usb3_phy_init(phy);
-
- return dwc3_uboot_init(&dwc3_device_data);
-}
-#endif
-#ifdef CONFIG_SET_DFU_ALT_INFO
-char *get_dfu_alt_system(char *interface, char *devstr)
-{
- return getenv("dfu_alt_system");
-}
-
-char *get_dfu_alt_boot(char *interface, char *devstr)
-{
- struct mmc *mmc;
- char *alt_boot;
- int dev_num;
-
- dev_num = simple_strtoul(devstr, NULL, 10);
-
- mmc = find_mmc_device(dev_num);
- if (!mmc)
- return NULL;
-
- if (mmc_init(mmc))
- return NULL;
-
- if (IS_SD(mmc))
- alt_boot = CONFIG_DFU_ALT_BOOT_SD;
- else
- alt_boot = CONFIG_DFU_ALT_BOOT_EMMC;
-
- return alt_boot;
-}
-#endif
diff --git a/common/cmd_regulator.c b/common/cmd_regulator.c
index 6149d1ee44..793f08e81a 100644
--- a/common/cmd_regulator.c
+++ b/common/cmd_regulator.c
@@ -241,7 +241,8 @@ static int do_value(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
value = simple_strtoul(argv[1], NULL, 0);
if ((value < uc_pdata->min_uV || value > uc_pdata->max_uV) && !force) {
- printf("Value exceeds regulator constraint limits\n");
+ printf("Value exceeds regulator constraint limits %d..%d uV\n",
+ uc_pdata->min_uV, uc_pdata->max_uV);
return CMD_RET_FAILURE;
}
diff --git a/common/cmd_usb.c b/common/cmd_usb.c
index 0ade7759f0..6874af7547 100644
--- a/common/cmd_usb.c
+++ b/common/cmd_usb.c
@@ -530,13 +530,16 @@ static void do_usb_start(void)
/* try to recognize storage devices immediately */
usb_stor_curr_dev = usb_stor_scan(1);
#endif
+#endif
#ifdef CONFIG_USB_HOST_ETHER
# ifdef CONFIG_DM_ETH
-# error "You must use CONFIG_DM_USB if you want to use CONFIG_USB_HOST_ETHER with CONFIG_DM_ETH"
-# endif
+# ifndef CONFIG_DM_USB
+# error "You must use CONFIG_DM_USB if you want to use CONFIG_USB_HOST_ETHER with CONFIG_DM_ETH"
+# endif
+# else
/* try to recognize ethernet devices immediately */
usb_ether_curr_dev = usb_host_eth_scan(1);
-#endif
+# endif
#endif
#ifdef CONFIG_USB_KEYBOARD
drv_usb_kbd_init();
diff --git a/configs/arndale_defconfig b/configs/arndale_defconfig
index aa489cfc2b..ebac9ad405 100644
--- a/configs/arndale_defconfig
+++ b/configs/arndale_defconfig
@@ -13,3 +13,5 @@ CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_DM_I2C=y
+CONFIG_DM_I2C_COMPAT=y
diff --git a/configs/minnowmax_defconfig b/configs/minnowmax_defconfig
index e98f5eb5ce..a67597d8d6 100644
--- a/configs/minnowmax_defconfig
+++ b/configs/minnowmax_defconfig
@@ -24,3 +24,7 @@ CONFIG_FRAMEBUFFER_VESA_MODE_11A=y
CONFIG_DM_RTC=y
CONFIG_USE_PRIVATE_LIBGCC=y
CONFIG_SYS_VSNPRINTF=y
+CONFIG_DEBUG_UART=y
+CONFIG_DEBUG_UART_NS16550=y
+CONFIG_DEBUG_UART_BASE=0x3f8
+CONFIG_DEBUG_UART_CLOCK=1843200
diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig
index 2b960d55a1..155ce39061 100644
--- a/configs/odroid-xu3_defconfig
+++ b/configs/odroid-xu3_defconfig
@@ -7,3 +7,9 @@ CONFIG_DEFAULT_DEVICE_TREE="exynos5422-odroidxu3"
# CONFIG_CMD_SETEXPR is not set
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_CMD_NET=y
+CONFIG_DM_I2C=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_REGULATOR=y
+CONFIG_VIDEO_BRIDGE=y
diff --git a/configs/peach-pi_defconfig b/configs/peach-pi_defconfig
index c17fc73253..86d5a0bc54 100644
--- a/configs/peach-pi_defconfig
+++ b/configs/peach-pi_defconfig
@@ -12,3 +12,22 @@ CONFIG_CROS_EC_SPI=y
CONFIG_CROS_EC_KEYB=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_CROS_EC_TUNNEL=y
+CONFIG_SOUND=y
+CONFIG_I2S=y
+CONFIG_I2S_SAMSUNG=y
+CONFIG_SOUND_MAX98095=y
+CONFIG_SOUND_WM8994=y
+CONFIG_DM_I2C=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_REGULATOR=y
+CONFIG_PMIC_TPS65090=y
+CONFIG_REGULATOR_TPS65090=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_I2C_ARB_GPIO_CHALLENGE=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_ERRNO_STR=y
+CONFIG_VIDEO_BRIDGE=y
+CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y
diff --git a/configs/peach-pit_defconfig b/configs/peach-pit_defconfig
index 8f217221a6..8fe423efb1 100644
--- a/configs/peach-pit_defconfig
+++ b/configs/peach-pit_defconfig
@@ -12,3 +12,22 @@ CONFIG_CROS_EC_SPI=y
CONFIG_CROS_EC_KEYB=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_CROS_EC_TUNNEL=y
+CONFIG_SOUND=y
+CONFIG_I2S=y
+CONFIG_I2S_SAMSUNG=y
+CONFIG_SOUND_MAX98095=y
+CONFIG_SOUND_WM8994=y
+CONFIG_DM_I2C=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_REGULATOR=y
+CONFIG_PMIC_TPS65090=y
+CONFIG_REGULATOR_TPS65090=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_I2C_ARB_GPIO_CHALLENGE=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_ERRNO_STR=y
+CONFIG_VIDEO_BRIDGE=y
+CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 553574682d..874a26b572 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -52,3 +52,5 @@ CONFIG_DM_MMC=y
CONFIG_LED=y
CONFIG_LED_GPIO=y
CONFIG_SYSCON=y
+CONFIG_REGMAP=y
+CONFIG_DEVRES=y
diff --git a/configs/smdk5250_defconfig b/configs/smdk5250_defconfig
index 8412d6fcf7..b061e4789d 100644
--- a/configs/smdk5250_defconfig
+++ b/configs/smdk5250_defconfig
@@ -14,3 +14,13 @@ CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_DM_I2C=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_REGULATOR=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_ERRNO_STR=y
+CONFIG_DM_PMIC_MAX77686=y
+CONFIG_DM_REGULATOR_MAX77686=y
+CONFIG_VIDEO_BRIDGE=y
diff --git a/configs/smdk5420_defconfig b/configs/smdk5420_defconfig
index a96b3683c6..1561f6a598 100644
--- a/configs/smdk5420_defconfig
+++ b/configs/smdk5420_defconfig
@@ -8,3 +8,9 @@ CONFIG_SPL=y
CONFIG_SPI_FLASH=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_CMD_NET=y
+CONFIG_DM_I2C=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_REGULATOR=y
+CONFIG_VIDEO_BRIDGE=y
diff --git a/configs/snow_defconfig b/configs/snow_defconfig
index 93fbcae5d9..a7d9e7a0db 100644
--- a/configs/snow_defconfig
+++ b/configs/snow_defconfig
@@ -18,3 +18,26 @@ CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_DM_I2C=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_REGULATOR=y
+CONFIG_PMIC_TPS65090=y
+CONFIG_REGULATOR_TPS65090=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_I2C_ARB_GPIO_CHALLENGE=y
+CONFIG_I2C_MUX=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_ERRNO_STR=y
+CONFIG_DM_PMIC_MAX77686=y
+CONFIG_DM_REGULATOR_MAX77686=y
+CONFIG_DEBUG_UART=y
+CONFIG_DEBUG_UART_S5P=y
+CONFIG_DEBUG_UART_CLOCK=100000000
+CONFIG_DEBUG_UART_BASE=0x12c30000
+CONFIG_I2C_CROS_EC_LDO=y
+CONFIG_PMIC_S5M8767=y
+CONFIG_REGULATOR_S5M8767=y
+CONFIG_VIDEO_BRIDGE=y
+CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y
+CONFIG_VIDEO_BRIDGE_NXP_PTN3460=y
diff --git a/configs/spring_defconfig b/configs/spring_defconfig
new file mode 100644
index 0000000000..a3abb35470
--- /dev/null
+++ b/configs/spring_defconfig
@@ -0,0 +1,42 @@
+CONFIG_ARM=y
+CONFIG_ARCH_EXYNOS=y
+CONFIG_TARGET_SPRING=y
+CONFIG_DEFAULT_DEVICE_TREE="exynos5250-spring"
+CONFIG_SPL=y
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_SOUND=y
+CONFIG_SPI_FLASH=y
+CONFIG_CMD_CROS_EC=y
+CONFIG_CROS_EC=y
+CONFIG_CROS_EC_I2C=y
+CONFIG_CROS_EC_KEYB=y
+CONFIG_SOUND=y
+CONFIG_I2S=y
+CONFIG_I2S_SAMSUNG=y
+CONFIG_SOUND_MAX98095=y
+CONFIG_SOUND_WM8994=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_DM_I2C=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_REGULATOR=y
+CONFIG_PMIC_TPS65090=y
+CONFIG_REGULATOR_TPS65090=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_I2C_ARB_GPIO_CHALLENGE=y
+CONFIG_I2C_MUX=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_ERRNO_STR=y
+CONFIG_DM_PMIC_MAX77686=y
+CONFIG_DM_REGULATOR_MAX77686=y
+CONFIG_DEBUG_UART=y
+CONFIG_DEBUG_UART_S5P=y
+CONFIG_DEBUG_UART_CLOCK=100000000
+CONFIG_DEBUG_UART_BASE=0x12c30000
+CONFIG_I2C_CROS_EC_LDO=y
+CONFIG_PMIC_S5M8767=y
+CONFIG_REGULATOR_S5M8767=y
+CONFIG_VIDEO_BRIDGE=y
+CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y
diff --git a/doc/README.i2c b/doc/README.i2c
new file mode 100644
index 0000000000..07cd8df85f
--- /dev/null
+++ b/doc/README.i2c
@@ -0,0 +1,60 @@
+I2C Bus Arbitration
+===================
+
+While I2C supports multi-master buses this is difficult to get right.
+The implementation on the master side in software is quite complex.
+Clock-stretching and the arbitrary time that an I2C transaction can take
+make it difficult to share the bus fairly in the face of high traffic.
+When one or more masters can be reset independently part-way through a
+transaction it is hard to know the state of the bus.
+
+U-Boot provides a scheme based on two 'claim' GPIOs, one driven by the
+AP (Application Processor, meaning the main CPU) and one driven by the EC
+(Embedded Controller, a small CPU aimed at handling system tasks). With
+these they can communicate and reliably share the bus. This scheme has
+minimal overhead and involves very little code. The scheme can survive
+reboots by either side without difficulty.
+
+Since U-Boot runs on the AP, the terminology used is 'our' claim GPIO,
+meaning the AP's, and 'their' claim GPIO, meaning the EC's. This terminology
+is used by the device tree bindings in Linux also.
+
+The driver is implemented as an I2C mux, as it is in Linux. See
+i2c-arb-gpio-challenge for the implementation.
+
+GPIO lines are shared between the AP and EC to manage the bus. The AP and EC
+each have a 'bus claim' line, which is an output that the other can see.
+
+- AP_CLAIM: output from AP, signalling to the EC that the AP wants the bus
+- EC_CLAIM: output from EC, signalling to the AP that the EC wants the bus
+
+The basic algorithm is to assert your line when you want the bus, then make
+sure that the other side doesn't want it also. A detailed explanation is best
+done with an example.
+
+Let's say the AP wants to claim the bus. It:
+
+1. Asserts AP_CLAIM
+2. Waits a little bit for the other side to notice (slew time)
+3. Checks EC_CLAIM. If this is not asserted, then the AP has the bus, and we
+ are done
+4. Otherwise, wait for a few milliseconds (retry time) and see if EC_CLAIM is
+ released
+5. If not, back off, release the claim and wait for a few more milliseconds
+ (retry time again)
+6. Go back to 1 if things don't look wedged (wait time has expired)
+7. Panic. The other side is hung with the CLAIM line set.
+
+The same algorithm applies on the EC.
+
+To release the bus, just de-assert the claim line.
+
+Typical delays are:
+- slew time 10 us
+- retry time 3 ms
+- wait time - 50ms
+
+In general the traffic is fairly light, and in particular the EC wants access
+to the bus quite rarely (maybe every 10s or 30s to check the battery). This
+scheme works very nicely with very low contention. There is only a 10 us
+wait for access to the bus assuming that the other side isn't using it.
diff --git a/doc/device-tree-bindings/i2c/i2c-mux.txt b/doc/device-tree-bindings/i2c/i2c-mux.txt
new file mode 100644
index 0000000000..af84cce5cd
--- /dev/null
+++ b/doc/device-tree-bindings/i2c/i2c-mux.txt
@@ -0,0 +1,60 @@
+Common i2c bus multiplexer/switch properties.
+
+An i2c bus multiplexer/switch will have several child busses that are
+numbered uniquely in a device dependent manner. The nodes for an i2c bus
+multiplexer/switch will have one child node for each child
+bus.
+
+Required properties:
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Required properties for child nodes:
+- #address-cells = <1>;
+- #size-cells = <0>;
+- reg : The sub-bus number.
+
+Optional properties for child nodes:
+- Other properties specific to the multiplexer/switch hardware.
+- Child nodes conforming to i2c bus binding
+
+
+Example :
+
+ /*
+ An NXP pca9548 8 channel I2C multiplexer at address 0x70
+ with two NXP pca8574 GPIO expanders attached, one each to
+ ports 3 and 4.
+ */
+
+ mux@70 {
+ compatible = "nxp,pca9548";
+ reg = <0x70>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ gpio1: gpio@38 {
+ compatible = "nxp,pca8574";
+ reg = <0x38>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+ i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+
+ gpio2: gpio@38 {
+ compatible = "nxp,pca8574";
+ reg = <0x38>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+ };
diff --git a/doc/device-tree-bindings/video/bridge/ps8622.txt b/doc/device-tree-bindings/video/bridge/ps8622.txt
new file mode 100644
index 0000000000..66d5d07ebb
--- /dev/null
+++ b/doc/device-tree-bindings/video/bridge/ps8622.txt
@@ -0,0 +1,33 @@
+ps8622-bridge bindings
+
+Required properties:
+ - compatible: "parade,ps8622" or "parade,ps8625"
+ - reg: first i2c address of the bridge
+ - sleep-gpios: OF device-tree gpio specification for PD_ pin.
+ - reset-gpios: OF device-tree gpio specification for RST_ pin.
+ - parade,regs: List of 3-byte registers tuples to write:
+ <I2C chip address offset> <register> <value>
+
+Optional properties:
+ - lane-count: number of DP lanes to use
+ - use-external-pwm: backlight will be controlled by an external PWM
+ - video interfaces: Device node can contain video interface port
+ nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+ lvds-bridge@48 {
+ compatible = "parade,ps8622";
+ reg = <0x48>;
+ sleep-gpios = <&gpc3 6 1 0 0>;
+ reset-gpios = <&gpc3 1 1 0 0>;
+ lane-count = <1>;
+ ports {
+ port@0 {
+ bridge_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+ };
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index e40372dd75..c82b5645cd 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -59,3 +59,46 @@ config DM_SEQ_ALIAS
Most boards will have a '/aliases' node containing the path to
numbered devices (e.g. serial0 = &serial0). This feature can be
disabled if it is not required, to save code space in SPL.
+
+config REGMAP
+ bool "Support register maps"
+ depends on DM
+ help
+ Hardware peripherals tend to have one or more sets of registers
+ which can be accessed to control the hardware. A register map
+ models this with a simple read/write interface. It can in principle
+ support any bus type (I2C, SPI) but so far this only supports
+ direct memory access.
+
+config SYSCON
+ bool "Support system controllers"
+ depends on REGMAP
+ help
+ Many SoCs have a number of system controllers which are dealt with
+ as a group by a single driver. Some common functionality is provided
+ by this uclass, including accessing registers via regmap and
+ assigning a unique number to each.
+
+config DEVRES
+ bool "Managed device resources"
+ depends on DM
+ help
+ This option enables the Managed device resources core support.
+ Device resources managed by the devres framework are automatically
+ released whether initialization fails half-way or the device gets
+ detached.
+
+ If this option is disabled, devres functions fall back to
+ non-managed variants. For example, devres_alloc() to kzalloc(),
+ devm_kmalloc() to kmalloc(), etc.
+
+config DEBUG_DEVRES
+ bool "Managed device resources debugging functions"
+ depends on DEVRES
+ help
+ If this option is enabled, devres debug messages are printed.
+ Also, a function is available to dump a list of device resources.
+ Select this if you are having a problem with devres or want to
+ debug resource management for a managed device.
+
+ If you are unsure about this, Say N here.
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index 5c2ead870b..ccc2fd4e21 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -5,10 +5,11 @@
#
obj-y += device.o lists.o root.o uclass.o util.o
+obj-$(CONFIG_DEVRES) += devres.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_OF_CONTROL) += simple-bus.o
endif
obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o
obj-$(CONFIG_DM) += dump.o
-obj-$(CONFIG_OF_CONTROL) += regmap.o
-obj-$(CONFIG_OF_CONTROL) += syscon-uclass.o
+obj-$(CONFIG_REGMAP) += regmap.o
+obj-$(CONFIG_SYSCON) += syscon-uclass.o
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 6b87f865e4..bd6d4062c9 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -61,6 +61,9 @@ int device_unbind(struct udevice *dev)
if (dev->flags & DM_FLAG_ACTIVATED)
return -EINVAL;
+ if (!(dev->flags & DM_FLAG_BOUND))
+ return -EINVAL;
+
drv = dev->driver;
assert(drv);
@@ -92,6 +95,9 @@ int device_unbind(struct udevice *dev)
if (dev->parent)
list_del(&dev->sibling_node);
+
+ devres_release_all(dev);
+
free(dev);
return 0;
@@ -125,6 +131,8 @@ void device_free(struct udevice *dev)
dev->parent_priv = NULL;
}
}
+
+ devres_release_probe(dev);
}
int device_remove(struct udevice *dev)
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 51b1b44e5b..bbe7a94f2a 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -47,6 +47,9 @@ int device_bind(struct udevice *parent, const struct driver *drv,
INIT_LIST_HEAD(&dev->sibling_node);
INIT_LIST_HEAD(&dev->child_head);
INIT_LIST_HEAD(&dev->uclass_node);
+#ifdef CONFIG_DEVRES
+ INIT_LIST_HEAD(&dev->devres_head);
+#endif
dev->platdata = platdata;
dev->name = name;
dev->of_offset = of_offset;
@@ -132,6 +135,8 @@ int device_bind(struct udevice *parent, const struct driver *drv,
dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
*devp = dev;
+ dev->flags |= DM_FLAG_BOUND;
+
return 0;
fail_child_post_bind:
@@ -168,6 +173,8 @@ fail_alloc2:
dev->platdata = NULL;
}
fail_alloc1:
+ devres_release_all(dev);
+
free(dev);
return ret;
@@ -552,17 +559,22 @@ const char *dev_get_uclass_name(struct udevice *dev)
return dev->uclass->uc_drv->name;
}
-#ifdef CONFIG_OF_CONTROL
fdt_addr_t dev_get_addr(struct udevice *dev)
{
- return fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
-}
+#ifdef CONFIG_OF_CONTROL
+ fdt_addr_t addr;
+
+ addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+ if (addr != FDT_ADDR_T_NONE) {
+ if (device_get_uclass_id(dev->parent) == UCLASS_SIMPLE_BUS)
+ addr = simple_bus_translate(dev->parent, addr);
+ }
+
+ return addr;
#else
-fdt_addr_t dev_get_addr(struct udevice *dev)
-{
return FDT_ADDR_T_NONE;
-}
#endif
+}
bool device_has_children(struct udevice *dev)
{
@@ -591,3 +603,13 @@ bool device_is_last_sibling(struct udevice *dev)
return false;
return list_is_last(&dev->sibling_node, &parent->child_head);
}
+
+int device_set_name(struct udevice *dev, const char *name)
+{
+ name = strdup(name);
+ if (!name)
+ return -ENOMEM;
+ dev->name = name;
+
+ return 0;
+}
diff --git a/drivers/core/devres.c b/drivers/core/devres.c
new file mode 100644
index 0000000000..605295bd14
--- /dev/null
+++ b/drivers/core/devres.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * Based on the original work in Linux by
+ * Copyright (c) 2006 SUSE Linux Products GmbH
+ * Copyright (c) 2006 Tejun Heo <teheo@suse.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/compat.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <dm/util.h>
+
+/**
+ * struct devres - Bookkeeping info for managed device resource
+ * @entry: List to associate this structure with a device
+ * @release: Callback invoked when this resource is released
+ * @probe: Flag to show when this resource was allocated
+ (true = probe, false = bind)
+ * @name: Name of release function
+ * @size: Size of resource data
+ * @data: Resource data
+ */
+struct devres {
+ struct list_head entry;
+ dr_release_t release;
+ bool probe;
+#ifdef CONFIG_DEBUG_DEVRES
+ const char *name;
+ size_t size;
+#endif
+ unsigned long long data[];
+};
+
+#ifdef CONFIG_DEBUG_DEVRES
+static void set_node_dbginfo(struct devres *dr, const char *name, size_t size)
+{
+ dr->name = name;
+ dr->size = size;
+}
+
+static void devres_log(struct udevice *dev, struct devres *dr,
+ const char *op)
+{
+ printf("%s: DEVRES %3s %p %s (%lu bytes)\n",
+ dev->name, op, dr, dr->name, (unsigned long)dr->size);
+}
+#else /* CONFIG_DEBUG_DEVRES */
+#define set_node_dbginfo(dr, n, s) do {} while (0)
+#define devres_log(dev, dr, op) do {} while (0)
+#endif
+
+#if CONFIG_DEBUG_DEVRES
+void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
+ const char *name)
+#else
+void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
+#endif
+{
+ size_t tot_size = sizeof(struct devres) + size;
+ struct devres *dr;
+
+ dr = kmalloc(tot_size, gfp);
+ if (unlikely(!dr))
+ return NULL;
+
+ INIT_LIST_HEAD(&dr->entry);
+ dr->release = release;
+ set_node_dbginfo(dr, name, size);
+
+ return dr->data;
+}
+
+void devres_free(void *res)
+{
+ if (res) {
+ struct devres *dr = container_of(res, struct devres, data);
+
+ BUG_ON(!list_empty(&dr->entry));
+ kfree(dr);
+ }
+}
+
+void devres_add(struct udevice *dev, void *res)
+{
+ struct devres *dr = container_of(res, struct devres, data);
+
+ devres_log(dev, dr, "ADD");
+ BUG_ON(!list_empty(&dr->entry));
+ dr->probe = dev->flags & DM_FLAG_BOUND ? true : false;
+ list_add_tail(&dr->entry, &dev->devres_head);
+}
+
+void *devres_find(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ struct devres *dr;
+
+ list_for_each_entry_reverse(dr, &dev->devres_head, entry) {
+ if (dr->release != release)
+ continue;
+ if (match && !match(dev, dr->data, match_data))
+ continue;
+ return dr->data;
+ }
+
+ return NULL;
+}
+
+void *devres_get(struct udevice *dev, void *new_res,
+ dr_match_t match, void *match_data)
+{
+ struct devres *new_dr = container_of(new_res, struct devres, data);
+ void *res;
+
+ res = devres_find(dev, new_dr->release, match, match_data);
+ if (!res) {
+ devres_add(dev, new_res);
+ res = new_res;
+ new_res = NULL;
+ }
+ devres_free(new_res);
+
+ return res;
+}
+
+void *devres_remove(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ void *res;
+
+ res = devres_find(dev, release, match, match_data);
+ if (res) {
+ struct devres *dr = container_of(res, struct devres, data);
+
+ list_del_init(&dr->entry);
+ devres_log(dev, dr, "REM");
+ }
+
+ return res;
+}
+
+int devres_destroy(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ void *res;
+
+ res = devres_remove(dev, release, match, match_data);
+ if (unlikely(!res))
+ return -ENOENT;
+
+ devres_free(res);
+ return 0;
+}
+
+int devres_release(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ void *res;
+
+ res = devres_remove(dev, release, match, match_data);
+ if (unlikely(!res))
+ return -ENOENT;
+
+ (*release)(dev, res);
+ devres_free(res);
+ return 0;
+}
+
+static void release_nodes(struct udevice *dev, struct list_head *head,
+ bool probe_only)
+{
+ struct devres *dr, *tmp;
+
+ list_for_each_entry_safe_reverse(dr, tmp, head, entry) {
+ if (probe_only && !dr->probe)
+ break;
+ devres_log(dev, dr, "REL");
+ dr->release(dev, dr->data);
+ list_del(&dr->entry);
+ kfree(dr);
+ }
+}
+
+void devres_release_probe(struct udevice *dev)
+{
+ release_nodes(dev, &dev->devres_head, true);
+}
+
+void devres_release_all(struct udevice *dev)
+{
+ release_nodes(dev, &dev->devres_head, false);
+}
+
+#ifdef CONFIG_DEBUG_DEVRES
+static void dump_resources(struct udevice *dev, int depth)
+{
+ struct devres *dr;
+ struct udevice *child;
+
+ printf("- %s\n", dev->name);
+
+ list_for_each_entry(dr, &dev->devres_head, entry)
+ printf(" %p (%lu byte) %s %s\n", dr,
+ (unsigned long)dr->size, dr->name,
+ dr->probe ? "PROBE" : "BIND");
+
+ list_for_each_entry(child, &dev->child_head, sibling_node)
+ dump_resources(child, depth + 1);
+}
+
+void dm_dump_devres(void)
+{
+ struct udevice *root;
+
+ root = dm_root();
+ if (root)
+ dump_resources(root, 0);
+}
+#endif
+
+/*
+ * Managed kmalloc/kfree
+ */
+static void devm_kmalloc_release(struct udevice *dev, void *res)
+{
+ /* noop */
+}
+
+static int devm_kmalloc_match(struct udevice *dev, void *res, void *data)
+{
+ return res == data;
+}
+
+void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp)
+{
+ void *data;
+
+ data = _devres_alloc(devm_kmalloc_release, size, gfp);
+ if (unlikely(!data))
+ return NULL;
+
+ devres_add(dev, data);
+
+ return data;
+}
+
+void devm_kfree(struct udevice *dev, void *p)
+{
+ int rc;
+
+ rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p);
+ WARN_ON(rc);
+}
diff --git a/drivers/core/simple-bus.c b/drivers/core/simple-bus.c
index 3ea4d8230b..913c3ccc70 100644
--- a/drivers/core/simple-bus.c
+++ b/drivers/core/simple-bus.c
@@ -10,8 +10,37 @@
DECLARE_GLOBAL_DATA_PTR;
+struct simple_bus_plat {
+ u32 base;
+ u32 size;
+ u32 target;
+};
+
+fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr)
+{
+ struct simple_bus_plat *plat = dev_get_uclass_platdata(dev);
+
+ if (addr >= plat->base && addr < plat->base + plat->size)
+ addr = (addr - plat->base) + plat->target;
+
+ return addr;
+}
+
static int simple_bus_post_bind(struct udevice *dev)
{
+ u32 cell[3];
+ int ret;
+
+ ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "ranges",
+ cell, ARRAY_SIZE(cell));
+ if (!ret) {
+ struct simple_bus_plat *plat = dev_get_uclass_platdata(dev);
+
+ plat->base = cell[0];
+ plat->target = cell[1];
+ plat->size = cell[2];
+ }
+
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
}
@@ -19,6 +48,7 @@ UCLASS_DRIVER(simple_bus) = {
.id = UCLASS_SIMPLE_BUS,
.name = "simple_bus",
.post_bind = simple_bus_post_bind,
+ .per_device_platdata_auto_alloc_size = sizeof(struct simple_bus_plat),
};
static const struct udevice_id generic_simple_bus_ids[] = {
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index ffe69956d5..5c4a66dd8c 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -273,6 +273,37 @@ static int uclass_find_device_by_of_offset(enum uclass_id id, int node,
return -ENODEV;
}
+static int uclass_find_device_by_phandle(enum uclass_id id,
+ struct udevice *parent,
+ const char *name,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int find_phandle;
+ int ret;
+
+ *devp = NULL;
+ find_phandle = fdtdec_get_int(gd->fdt_blob, parent->of_offset, name,
+ -1);
+ if (find_phandle <= 0)
+ return -ENOENT;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+ uint phandle = fdt_get_phandle(gd->fdt_blob, dev->of_offset);
+
+ if (phandle == find_phandle) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
int uclass_get_device_tail(struct udevice *dev, int ret,
struct udevice **devp)
{
@@ -338,6 +369,17 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node,
return uclass_get_device_tail(dev, ret, devp);
}
+int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
+ const char *name, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_device_by_phandle(id, parent, name, &dev);
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
int uclass_first_device(enum uclass_id id, struct udevice **devp)
{
struct udevice *dev;
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 4efda311a4..4cce11fe21 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -250,8 +250,12 @@ int gpio_free(unsigned gpio)
static int check_reserved(struct gpio_desc *desc, const char *func)
{
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(desc->dev);
+ struct gpio_dev_priv *uc_priv;
+
+ if (!dm_gpio_is_valid(desc))
+ return -ENOENT;
+ uc_priv = dev_get_uclass_priv(desc->dev);
if (!uc_priv->name[desc->offset]) {
printf("%s: %s: error: gpio %s%d not reserved\n",
desc->dev->name, func,
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 86fb36b5d4..9a62ddd9ca 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -19,6 +19,30 @@ config DM_I2C_COMPAT
to convert all code for a board in a single commit. It should not
be enabled for any board in an official release.
+config I2C_CROS_EC_TUNNEL
+ tristate "Chrome OS EC tunnel I2C bus"
+ depends on CROS_EC
+ help
+ This provides an I2C bus that will tunnel i2c commands through to
+ the other side of the Chrome OS EC to the I2C bus connected there.
+ This will work whatever the interface used to talk to the EC (SPI,
+ I2C or LPC). Some Chromebooks use this when the hardware design
+ does not allow direct access to the main PMIC from the AP.
+
+config I2C_CROS_EC_LDO
+ bool "Provide access to LDOs on the Chrome OS EC"
+ depends on CROS_EC
+ ---help---
+ On many Chromebooks the main PMIC is inaccessible to the AP. This is
+ often dealt with by using an I2C pass-through interface provided by
+ the EC. On some unfortunate models (e.g. Spring) the pass-through
+ is not available, and an LDO message is available instead. This
+ option enables a driver which provides very basic access to those
+ regulators, via the EC. We implement this as an I2C bus which
+ emulates just the TPS65090 messages we know about. This is done to
+ avoid duplicating the logic in the TPS65090 regulator driver for
+ enabling/disabling an LDO.
+
config DM_I2C_GPIO
bool "Enable Driver Model for software emulated I2C bus driver"
depends on DM_I2C && DM_GPIO
@@ -73,3 +97,5 @@ config SYS_I2C_UNIPHIER_F
help
Support for UniPhier FIFO-builtin I2C controller driver.
This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs.
+
+source "drivers/i2c/muxes/Kconfig"
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index d9e912f786..9b45248e2e 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -7,6 +7,8 @@
obj-$(CONFIG_DM_I2C) += i2c-uclass.o
obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
+obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
+obj-$(CONFIG_I2C_CROS_EC_LDO) += cros_ec_ldo.o
obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
obj-$(CONFIG_I2C_MV) += mv_i2c.o
@@ -37,3 +39,5 @@ obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o
+
+obj-y += muxes/
diff --git a/drivers/i2c/cros_ec_ldo.c b/drivers/i2c/cros_ec_ldo.c
new file mode 100644
index 0000000000..b817c61f1c
--- /dev/null
+++ b/drivers/i2c/cros_ec_ldo.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <cros_ec.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/tps65090.h>
+
+static int cros_ec_ldo_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ return 0;
+}
+
+static int cros_ec_ldo_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ bool is_read = nmsgs > 1;
+ int fet_id, ret;
+
+ /*
+ * Look for reads and writes of the LDO registers. In either case the
+ * first message is a write with the register number as the first byte.
+ */
+ if (!nmsgs || !msg->len || (msg->flags & I2C_M_RD)) {
+ debug("%s: Invalid message\n", __func__);
+ goto err;
+ }
+
+ fet_id = msg->buf[0] - REG_FET_BASE;
+ if (fet_id < 1 || fet_id > MAX_FET_NUM) {
+ debug("%s: Invalid FET %d\n", __func__, fet_id);
+ goto err;
+ }
+
+ if (is_read) {
+ uint8_t state;
+
+ ret = cros_ec_get_ldo(dev->parent, fet_id, &state);
+ if (!ret)
+ msg[1].buf[0] = state ?
+ FET_CTRL_ENFET | FET_CTRL_PGFET : 0;
+ } else {
+ bool on = msg->buf[1] & FET_CTRL_ENFET;
+
+ ret = cros_ec_set_ldo(dev->parent, fet_id, on);
+ }
+
+ return ret;
+
+err:
+ /* Indicate that the message is unimplemented */
+ return -ENOSYS;
+}
+
+static const struct dm_i2c_ops cros_ec_i2c_ops = {
+ .xfer = cros_ec_ldo_xfer,
+ .set_bus_speed = cros_ec_ldo_set_bus_speed,
+};
+
+static const struct udevice_id cros_ec_i2c_ids[] = {
+ { .compatible = "google,cros-ec-ldo-tunnel" },
+ { }
+};
+
+U_BOOT_DRIVER(cros_ec_ldo) = {
+ .name = "cros_ec_ldo_tunnel",
+ .id = UCLASS_I2C,
+ .of_match = cros_ec_i2c_ids,
+ .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
+ .ops = &cros_ec_i2c_ops,
+};
diff --git a/drivers/i2c/cros_ec_tunnel.c b/drivers/i2c/cros_ec_tunnel.c
new file mode 100644
index 0000000000..7ab1fd898a
--- /dev/null
+++ b/drivers/i2c/cros_ec_tunnel.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <cros_ec.h>
+#include <errno.h>
+#include <i2c.h>
+
+static int cros_ec_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ return 0;
+}
+
+static int cros_ec_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ return cros_ec_i2c_tunnel(dev->parent, msg, nmsgs);
+}
+
+static const struct dm_i2c_ops cros_ec_i2c_ops = {
+ .xfer = cros_ec_i2c_xfer,
+ .set_bus_speed = cros_ec_i2c_set_bus_speed,
+};
+
+static const struct udevice_id cros_ec_i2c_ids[] = {
+ { .compatible = "google,cros-ec-i2c-tunnel" },
+ { }
+};
+
+U_BOOT_DRIVER(cros_ec_tunnel) = {
+ .name = "cros_ec_tunnel",
+ .id = UCLASS_I2C,
+ .of_match = cros_ec_i2c_ids,
+ .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
+ .ops = &cros_ec_i2c_ops,
+};
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index eaba965fa3..50b99ead3d 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -18,6 +18,22 @@ DECLARE_GLOBAL_DATA_PTR;
#define I2C_MAX_OFFSET_LEN 4
+/* Useful debugging function */
+void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs)
+{
+ int i;
+
+ for (i = 0; i < nmsgs; i++) {
+ struct i2c_msg *m = &msg[i];
+
+ printf(" %s %x len=%x", m->flags & I2C_M_RD ? "R" : "W",
+ msg->addr, msg->len);
+ if (!(m->flags & I2C_M_RD))
+ printf(": %x", m->buf[0]);
+ printf("\n");
+ }
+}
+
/**
* i2c_setup_offset() - Set up a new message with a chip offset
*
@@ -186,6 +202,17 @@ int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
}
}
+int dm_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+
+ if (!ops->xfer)
+ return -ENOSYS;
+
+ return ops->xfer(bus, msg, nmsgs);
+}
+
int dm_i2c_reg_read(struct udevice *dev, uint offset)
{
uint8_t val;
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
new file mode 100644
index 0000000000..bd3e078d62
--- /dev/null
+++ b/drivers/i2c/muxes/Kconfig
@@ -0,0 +1,17 @@
+config I2C_MUX
+ bool "Suport I2C multiplexers"
+ depends on DM_I2C
+ help
+ This enables I2C buses to be multiplexed, so that you can select
+ one of several buses using some sort of control mechanism. The
+ bus select is handled automatically when that bus is accessed,
+ using a suitable I2C MUX driver.
+
+config I2C_ARB_GPIO_CHALLENGE
+ bool "GPIO-based I2C arbitration"
+ depends on I2C_MUX
+ help
+ If you say yes to this option, support will be included for an
+ I2C multimaster arbitration scheme using GPIOs and a challenge &
+ response mechanism where masters have to claim the bus by asserting
+ a GPIO.
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
new file mode 100644
index 0000000000..612cc2706b
--- /dev/null
+++ b/drivers/i2c/muxes/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2015 Google, Inc
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
+obj-$(CONFIG_I2C_MUX) += i2c-mux-uclass.o
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
new file mode 100644
index 0000000000..3f072c78b8
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <asm/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct i2c_arbitrator_priv {
+ struct gpio_desc ap_claim;
+ struct gpio_desc ec_claim;
+ uint slew_delay_us;
+ uint wait_retry_ms;
+ uint wait_free_ms;
+};
+
+int i2c_arbitrator_deselect(struct udevice *mux, struct udevice *bus,
+ uint channel)
+{
+ struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
+ int ret;
+
+ debug("%s: %s\n", __func__, mux->name);
+ ret = dm_gpio_set_value(&priv->ap_claim, 0);
+ udelay(priv->slew_delay_us);
+
+ return ret;
+}
+
+int i2c_arbitrator_select(struct udevice *mux, struct udevice *bus,
+ uint channel)
+{
+ struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
+ unsigned start;
+ int ret;
+
+ debug("%s: %s\n", __func__, mux->name);
+ /* Start a round of trying to claim the bus */
+ start = get_timer(0);
+ do {
+ unsigned start_retry;
+ int waiting = 0;
+
+ /* Indicate that we want to claim the bus */
+ ret = dm_gpio_set_value(&priv->ap_claim, 1);
+ if (ret)
+ goto err;
+ udelay(priv->slew_delay_us);
+
+ /* Wait for the EC to release it */
+ start_retry = get_timer(0);
+ while (get_timer(start_retry) < priv->wait_retry_ms) {
+ ret = dm_gpio_get_value(&priv->ec_claim);
+ if (ret < 0) {
+ goto err;
+ } else if (!ret) {
+ /* We got it, so return */
+ return 0;
+ }
+
+ if (!waiting)
+ waiting = 1;
+ }
+
+ /* It didn't release, so give up, wait, and try again */
+ ret = dm_gpio_set_value(&priv->ap_claim, 0);
+ if (ret)
+ goto err;
+
+ mdelay(priv->wait_retry_ms);
+ } while (get_timer(start) < priv->wait_free_ms);
+
+ /* Give up, release our claim */
+ printf("I2C: Could not claim bus, timeout %lu\n", get_timer(start));
+ ret = -ETIMEDOUT;
+ ret = 0;
+err:
+ return ret;
+}
+
+static int i2c_arbitrator_probe(struct udevice *dev)
+{
+ struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
+ const void *blob = gd->fdt_blob;
+ int node = dev->of_offset;
+ int ret;
+
+ debug("%s: %s\n", __func__, dev->name);
+ priv->slew_delay_us = fdtdec_get_int(blob, node, "slew-delay-us", 0);
+ priv->wait_retry_ms = fdtdec_get_int(blob, node, "wait-retry-us", 0) /
+ 1000;
+ priv->wait_free_ms = fdtdec_get_int(blob, node, "wait-free-us", 0) /
+ 1000;
+ ret = gpio_request_by_name(dev, "our-claim-gpio", 0, &priv->ap_claim,
+ GPIOD_IS_OUT);
+ if (ret)
+ goto err;
+ ret = gpio_request_by_name(dev, "their-claim-gpios", 0, &priv->ec_claim,
+ GPIOD_IS_IN);
+ if (ret)
+ goto err_ec_gpio;
+
+ return 0;
+
+err_ec_gpio:
+ dm_gpio_free(dev, &priv->ap_claim);
+err:
+ debug("%s: ret=%d\n", __func__, ret);
+ return ret;
+}
+
+static int i2c_arbitrator_remove(struct udevice *dev)
+{
+ struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
+
+ dm_gpio_free(dev, &priv->ap_claim);
+ dm_gpio_free(dev, &priv->ec_claim);
+
+ return 0;
+}
+
+static const struct i2c_mux_ops i2c_arbitrator_ops = {
+ .select = i2c_arbitrator_select,
+ .deselect = i2c_arbitrator_deselect,
+};
+
+static const struct udevice_id i2c_arbitrator_ids[] = {
+ { .compatible = "i2c-arb-gpio-challenge" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_arbitrator) = {
+ .name = "i2c_arbitrator",
+ .id = UCLASS_I2C_MUX,
+ .of_match = i2c_arbitrator_ids,
+ .probe = i2c_arbitrator_probe,
+ .remove = i2c_arbitrator_remove,
+ .ops = &i2c_arbitrator_ops,
+ .priv_auto_alloc_size = sizeof(struct i2c_arbitrator_priv),
+};
diff --git a/drivers/i2c/muxes/i2c-mux-uclass.c b/drivers/i2c/muxes/i2c-mux-uclass.c
new file mode 100644
index 0000000000..3f52bff2fb
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-mux-uclass.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct i2c_mux: Information the uclass stores about an I2C mux
+ *
+ * @selected: Currently selected mux, or -1 for none
+ * @i2c_bus: I2C bus to use for communcation
+ */
+struct i2c_mux {
+ int selected;
+ struct udevice *i2c_bus;
+};
+
+/**
+ * struct i2c_mux_bus: Information about each bus the mux controls
+ *
+ * @channel: Channel number used to select this bus
+ */
+struct i2c_mux_bus {
+ uint channel;
+};
+
+/* Find out the mux channel number */
+static int i2c_mux_child_post_bind(struct udevice *dev)
+{
+ struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
+ int channel;
+
+ channel = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1);
+ if (channel < 0)
+ return -EINVAL;
+ plat->channel = channel;
+
+ return 0;
+}
+
+/* Find the I2C buses selected by this mux */
+static int i2c_mux_post_bind(struct udevice *mux)
+{
+ const void *blob = gd->fdt_blob;
+ int ret;
+ int offset;
+
+ debug("%s: %s\n", __func__, mux->name);
+ /*
+ * There is no compatible string in the sub-nodes, so we must manually
+ * bind these
+ */
+ for (offset = fdt_first_subnode(blob, mux->of_offset);
+ offset > 0;
+ offset = fdt_next_subnode(blob, offset)) {
+ struct udevice *dev;
+ const char *name;
+
+ name = fdt_get_name(blob, offset, NULL);
+ ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv", name,
+ offset, &dev);
+ debug(" - bind ret=%d, %s\n", ret, dev ? dev->name : NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Set up the mux ready for use */
+static int i2c_mux_post_probe(struct udevice *mux)
+{
+ struct i2c_mux *priv = dev_get_uclass_priv(mux);
+ int ret;
+
+ debug("%s: %s\n", __func__, mux->name);
+ priv->selected = -1;
+
+ ret = uclass_get_device_by_phandle(UCLASS_I2C, mux, "i2c-parent",
+ &priv->i2c_bus);
+ if (ret)
+ return ret;
+ debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus, priv->i2c_bus->name);
+
+ return 0;
+}
+
+int i2c_mux_select(struct udevice *dev)
+{
+ struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
+ struct udevice *mux = dev->parent;
+ struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
+
+ if (!ops->select)
+ return -ENOSYS;
+
+ return ops->select(mux, dev, plat->channel);
+}
+
+int i2c_mux_deselect(struct udevice *dev)
+{
+ struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
+ struct udevice *mux = dev->parent;
+ struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
+
+ if (!ops->deselect)
+ return -ENOSYS;
+
+ return ops->deselect(mux, dev, plat->channel);
+}
+
+static int i2c_mux_bus_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ struct udevice *mux = dev->parent;
+ struct i2c_mux *priv = dev_get_uclass_priv(mux);
+ int ret, ret2;
+
+ ret = i2c_mux_select(dev);
+ if (ret)
+ return ret;
+ ret = dm_i2c_set_bus_speed(priv->i2c_bus, speed);
+ ret2 = i2c_mux_deselect(dev);
+
+ return ret ? ret : ret2;
+}
+
+static int i2c_mux_bus_probe(struct udevice *dev, uint chip_addr,
+ uint chip_flags)
+{
+ struct udevice *mux = dev->parent;
+ struct i2c_mux *priv = dev_get_uclass_priv(mux);
+ struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
+ int ret, ret2;
+
+ debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
+ if (!ops->probe_chip)
+ return -ENOSYS;
+ ret = i2c_mux_select(dev);
+ if (ret)
+ return ret;
+ ret = ops->probe_chip(priv->i2c_bus, chip_addr, chip_flags);
+ ret2 = i2c_mux_deselect(dev);
+
+ return ret ? ret : ret2;
+}
+
+static int i2c_mux_bus_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct udevice *mux = dev->parent;
+ struct i2c_mux *priv = dev_get_uclass_priv(mux);
+ struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
+ int ret, ret2;
+
+ debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
+ if (!ops->xfer)
+ return -ENOSYS;
+ ret = i2c_mux_select(dev);
+ if (ret)
+ return ret;
+ ret = ops->xfer(priv->i2c_bus, msg, nmsgs);
+ ret2 = i2c_mux_deselect(dev);
+
+ return ret ? ret : ret2;
+}
+
+static const struct dm_i2c_ops i2c_mux_bus_ops = {
+ .xfer = i2c_mux_bus_xfer,
+ .probe_chip = i2c_mux_bus_probe,
+ .set_bus_speed = i2c_mux_bus_set_bus_speed,
+};
+
+U_BOOT_DRIVER(i2c_mux_bus) = {
+ .name = "i2c_mux_bus_drv",
+ .id = UCLASS_I2C,
+ .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
+ .ops = &i2c_mux_bus_ops,
+};
+
+UCLASS_DRIVER(i2c_mux) = {
+ .id = UCLASS_I2C_MUX,
+ .name = "i2c_mux",
+ .post_bind = i2c_mux_post_bind,
+ .post_probe = i2c_mux_post_probe,
+ .per_device_auto_alloc_size = sizeof(struct i2c_mux),
+ .per_child_platdata_auto_alloc_size = sizeof(struct i2c_mux_bus),
+ .child_post_bind = i2c_mux_child_post_bind,
+};
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
index 9a04e48a0f..c11a6be7b7 100644
--- a/drivers/i2c/s3c24x0_i2c.c
+++ b/drivers/i2c/s3c24x0_i2c.c
@@ -258,9 +258,9 @@ static int hsi2c_wait_for_trx(struct exynos5_hsi2c *i2c)
return I2C_NOK_TOUT;
}
-static void ReadWriteByte(struct s3c24x0_i2c *i2c)
+static void read_write_byte(struct s3c24x0_i2c *i2c)
{
- writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
+ clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
}
#ifdef CONFIG_SYS_I2C
@@ -794,7 +794,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
if (addr && addr_len) {
while ((i < addr_len) && (result == I2C_OK)) {
writel(addr[i++], &i2c->iicds);
- ReadWriteByte(i2c);
+ read_write_byte(i2c);
result = WaitForXfer(i2c);
}
i = 0;
@@ -806,7 +806,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
case I2C_WRITE:
while ((i < data_len) && (result == I2C_OK)) {
writel(data[i++], &i2c->iicds);
- ReadWriteByte(i2c);
+ read_write_byte(i2c);
result = WaitForXfer(i2c);
}
break;
@@ -822,7 +822,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
/* Generate a re-START. */
writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP,
&i2c->iicstat);
- ReadWriteByte(i2c);
+ read_write_byte(i2c);
result = WaitForXfer(i2c);
if (result != I2C_OK)
@@ -835,7 +835,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
writel(readl(&i2c->iiccon)
& ~I2CCON_ACKGEN,
&i2c->iiccon);
- ReadWriteByte(i2c);
+ read_write_byte(i2c);
result = WaitForXfer(i2c);
data[i++] = readl(&i2c->iicds);
}
@@ -852,7 +852,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
bailout:
/* Send STOP. */
writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
- ReadWriteByte(i2c);
+ read_write_byte(i2c);
return result;
}
@@ -1284,62 +1284,106 @@ U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
#endif /* CONFIG_SYS_I2C */
#ifdef CONFIG_DM_I2C
-static int i2c_write_data(struct s3c24x0_i2c_bus *i2c_bus, uchar chip,
- uchar *buffer, int len, bool end_with_repeated_start)
+static int exynos_hs_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
{
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+ struct exynos5_hsi2c *hsregs = i2c_bus->hsregs;
int ret;
- if (i2c_bus->is_highspeed) {
- ret = hsi2c_write(i2c_bus->hsregs, chip, 0, 0,
- buffer, len, true);
- if (ret)
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ if (msg->flags & I2C_M_RD) {
+ ret = hsi2c_read(hsregs, msg->addr, 0, 0, msg->buf,
+ msg->len);
+ } else {
+ ret = hsi2c_write(hsregs, msg->addr, 0, 0, msg->buf,
+ msg->len, true);
+ }
+ if (ret) {
exynos5_i2c_reset(i2c_bus);
- } else {
- ret = i2c_transfer(i2c_bus->regs, I2C_WRITE,
- chip << 1, 0, 0, buffer, len);
+ return -EREMOTEIO;
+ }
}
- return ret != I2C_OK;
+ return 0;
}
-static int i2c_read_data(struct s3c24x0_i2c_bus *i2c_bus, uchar chip,
- uchar *buffer, int len)
+static int s3c24x0_do_msg(struct s3c24x0_i2c_bus *i2c_bus, struct i2c_msg *msg,
+ int seq)
{
- int ret;
+ struct s3c24x0_i2c *i2c = i2c_bus->regs;
+ bool is_read = msg->flags & I2C_M_RD;
+ uint status;
+ uint addr;
+ int ret, i;
- if (i2c_bus->is_highspeed) {
- ret = hsi2c_read(i2c_bus->hsregs, chip, 0, 0, buffer, len);
- if (ret)
- exynos5_i2c_reset(i2c_bus);
+ if (!seq)
+ setbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
+
+ /* Get the slave chip address going */
+ addr = msg->addr << 1;
+ writel(addr, &i2c->iicds);
+ status = I2C_TXRX_ENA | I2C_START_STOP;
+ if (is_read)
+ status |= I2C_MODE_MR;
+ else
+ status |= I2C_MODE_MT;
+ writel(status, &i2c->iicstat);
+ if (seq)
+ read_write_byte(i2c);
+
+ /* Wait for chip address to transmit */
+ ret = WaitForXfer(i2c);
+ if (ret)
+ goto err;
+
+ if (is_read) {
+ for (i = 0; !ret && i < msg->len; i++) {
+ /* disable ACK for final READ */
+ if (i == msg->len - 1)
+ clrbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
+ read_write_byte(i2c);
+ ret = WaitForXfer(i2c);
+ msg->buf[i] = readl(&i2c->iicds);
+ }
+ if (ret == I2C_NACK)
+ ret = I2C_OK; /* Normal terminated read */
} else {
- ret = i2c_transfer(i2c_bus->regs, I2C_READ,
- chip << 1, 0, 0, buffer, len);
+ for (i = 0; !ret && i < msg->len; i++) {
+ writel(msg->buf[i], &i2c->iicds);
+ read_write_byte(i2c);
+ ret = WaitForXfer(i2c);
+ }
}
- return ret != I2C_OK;
+err:
+ return ret;
}
static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
- int ret;
-
- for (; nmsgs > 0; nmsgs--, msg++) {
- bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
+ struct s3c24x0_i2c *i2c = i2c_bus->regs;
+ ulong start_time;
+ int ret, i;
- if (msg->flags & I2C_M_RD) {
- ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
- msg->len);
- } else {
- ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
- msg->len, next_is_read);
+ start_time = get_timer(0);
+ while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
+ if (get_timer(start_time) > I2C_TIMEOUT_MS) {
+ debug("Timeout\n");
+ return -ETIMEDOUT;
}
- if (ret)
- return -EREMOTEIO;
}
- return 0;
+ for (ret = 0, i = 0; !ret && i < nmsgs; i++)
+ ret = s3c24x0_do_msg(i2c_bus, &msg[i], i);
+
+ /* Send STOP */
+ writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
+ read_write_byte(i2c);
+
+ return ret ? -EREMOTEIO : 0;
}
static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
@@ -1364,8 +1408,7 @@ static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
i2c_bus->id = pinmux_decode_periph_id(blob, node);
i2c_bus->clock_frequency = fdtdec_get_int(blob, node,
- "clock-frequency",
- CONFIG_SYS_I2C_S3C24X0_SPEED);
+ "clock-frequency", 100000);
i2c_bus->node = node;
i2c_bus->bus_num = dev->seq;
@@ -1384,7 +1427,6 @@ static const struct dm_i2c_ops s3c_i2c_ops = {
static const struct udevice_id s3c_i2c_ids[] = {
{ .compatible = "samsung,s3c2440-i2c", .data = EXYNOS_I2C_STD },
- { .compatible = "samsung,exynos5-hsi2c", .data = EXYNOS_I2C_HS },
{ }
};
@@ -1397,4 +1439,29 @@ U_BOOT_DRIVER(i2c_s3c) = {
.priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
.ops = &s3c_i2c_ops,
};
+
+/*
+ * TODO(sjg@chromium.org): Move this to a separate file when everything uses
+ * driver model
+ */
+static const struct dm_i2c_ops exynos_hs_i2c_ops = {
+ .xfer = exynos_hs_i2c_xfer,
+ .probe_chip = s3c24x0_i2c_probe,
+ .set_bus_speed = s3c24x0_i2c_set_bus_speed,
+};
+
+static const struct udevice_id exynos_hs_i2c_ids[] = {
+ { .compatible = "samsung,exynos5-hsi2c", .data = EXYNOS_I2C_HS },
+ { }
+};
+
+U_BOOT_DRIVER(hs_i2c) = {
+ .name = "i2c_s3c_hs",
+ .id = UCLASS_I2C,
+ .of_match = exynos_hs_i2c_ids,
+ .ofdata_to_platdata = s3c_i2c_ofdata_to_platdata,
+ .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
+ .priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
+ .ops = &exynos_hs_i2c_ops,
+};
#endif /* CONFIG_DM_I2C */
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index 4b6ac6a6c0..ba36795c65 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -26,6 +26,7 @@
#include <asm/io.h>
#include <asm-generic/gpio.h>
#include <dm/device-internal.h>
+#include <dm/root.h>
#include <dm/uclass-internal.h>
#ifdef DEBUG_TRACE
@@ -930,31 +931,32 @@ int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block)
return 0;
}
-int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state)
+int cros_ec_set_ldo(struct udevice *dev, uint8_t index, uint8_t state)
{
+ struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
struct ec_params_ldo_set params;
params.index = index;
params.state = state;
- if (ec_command_inptr(dev, EC_CMD_LDO_SET, 0,
- &params, sizeof(params),
- NULL, 0))
+ if (ec_command_inptr(cdev, EC_CMD_LDO_SET, 0, &params, sizeof(params),
+ NULL, 0))
return -1;
return 0;
}
-int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
+int cros_ec_get_ldo(struct udevice *dev, uint8_t index, uint8_t *state)
{
+ struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
struct ec_params_ldo_get params;
struct ec_response_ldo_get *resp;
params.index = index;
- if (ec_command_inptr(dev, EC_CMD_LDO_GET, 0,
- &params, sizeof(params),
- (uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp))
+ if (ec_command_inptr(cdev, EC_CMD_LDO_GET, 0, &params, sizeof(params),
+ (uint8_t **)&resp, sizeof(*resp)) !=
+ sizeof(*resp))
return -1;
*state = resp->state;
@@ -1053,9 +1055,9 @@ int cros_ec_decode_ec_flash(const void *blob, int node,
return 0;
}
-int cros_ec_i2c_xfer(struct cros_ec_dev *dev, uchar chip, uint addr,
- int alen, uchar *buffer, int len, int is_read)
+int cros_ec_i2c_tunnel(struct udevice *dev, struct i2c_msg *in, int nmsgs)
{
+ struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
union {
struct ec_params_i2c_passthru p;
uint8_t outbuf[EC_PROTO2_MAX_PARAM_SIZE];
@@ -1066,53 +1068,46 @@ int cros_ec_i2c_xfer(struct cros_ec_dev *dev, uchar chip, uint addr,
} response;
struct ec_params_i2c_passthru *p = &params.p;
struct ec_response_i2c_passthru *r = &response.r;
- struct ec_params_i2c_passthru_msg *msg = p->msg;
- uint8_t *pdata;
- int read_len, write_len;
+ struct ec_params_i2c_passthru_msg *msg;
+ uint8_t *pdata, *read_ptr = NULL;
+ int read_len;
int size;
int rv;
+ int i;
p->port = 0;
- if (alen != 1) {
- printf("Unsupported address length %d\n", alen);
- return -1;
- }
- if (is_read) {
- read_len = len;
- write_len = alen;
- p->num_msgs = 2;
- } else {
- read_len = 0;
- write_len = alen + len;
- p->num_msgs = 1;
- }
-
+ p->num_msgs = nmsgs;
size = sizeof(*p) + p->num_msgs * sizeof(*msg);
- if (size + write_len > sizeof(params)) {
- puts("Params too large for buffer\n");
- return -1;
- }
- if (sizeof(*r) + read_len > sizeof(response)) {
- puts("Read length too big for buffer\n");
- return -1;
- }
/* Create a message to write the register address and optional data */
pdata = (uint8_t *)p + size;
- msg->addr_flags = chip;
- msg->len = write_len;
- pdata[0] = addr;
- if (!is_read)
- memcpy(pdata + 1, buffer, len);
- msg++;
-
- if (read_len) {
- msg->addr_flags = chip | EC_I2C_FLAG_READ;
- msg->len = read_len;
+
+ read_len = 0;
+ for (i = 0, msg = p->msg; i < nmsgs; i++, msg++, in++) {
+ bool is_read = in->flags & I2C_M_RD;
+
+ msg->addr_flags = in->addr;
+ msg->len = in->len;
+ if (is_read) {
+ msg->addr_flags |= EC_I2C_FLAG_READ;
+ read_len += in->len;
+ read_ptr = in->buf;
+ if (sizeof(*r) + read_len > sizeof(response)) {
+ puts("Read length too big for buffer\n");
+ return -1;
+ }
+ } else {
+ if (pdata - (uint8_t *)p + in->len > sizeof(params)) {
+ puts("Params too large for buffer\n");
+ return -1;
+ }
+ memcpy(pdata, in->buf, in->len);
+ pdata += in->len;
+ }
}
- rv = ec_command(dev, EC_CMD_I2C_PASSTHRU, 0, p, size + write_len,
+ rv = ec_command(cdev, EC_CMD_I2C_PASSTHRU, 0, p, pdata - (uint8_t *)p,
r, sizeof(*r) + read_len);
if (rv < 0)
return rv;
@@ -1128,8 +1123,9 @@ int cros_ec_i2c_xfer(struct cros_ec_dev *dev, uchar chip, uint addr,
return -1;
}
+ /* We only support a single read message for each transfer */
if (read_len)
- memcpy(buffer, r->data, read_len);
+ memcpy(read_ptr, r->data, read_len);
return 0;
}
@@ -1189,187 +1185,6 @@ static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc,
return 0;
}
-/**
- * get_alen() - Small parser helper function to get address length
- *
- * Returns the address length.
- */
-static uint get_alen(char *arg)
-{
- int j;
- int alen;
-
- alen = 1;
- for (j = 0; j < 8; j++) {
- if (arg[j] == '.') {
- alen = arg[j+1] - '0';
- break;
- } else if (arg[j] == '\0') {
- break;
- }
- }
- return alen;
-}
-
-#define DISP_LINE_LEN 16
-
-/*
- * TODO(sjg@chromium.org): This code copied almost verbatim from cmd_i2c.c
- * so we can remove it later.
- */
-static int cros_ec_i2c_md(struct cros_ec_dev *dev, int flag, int argc,
- char * const argv[])
-{
- u_char chip;
- uint addr, alen, length = 0x10;
- int j, nbytes, linebytes;
-
- if (argc < 2)
- return CMD_RET_USAGE;
-
- if (1 || (flag & CMD_FLAG_REPEAT) == 0) {
- /*
- * New command specified.
- */
-
- /*
- * I2C chip address
- */
- chip = simple_strtoul(argv[0], NULL, 16);
-
- /*
- * I2C data address within the chip. This can be 1 or
- * 2 bytes long. Some day it might be 3 bytes long :-).
- */
- addr = simple_strtoul(argv[1], NULL, 16);
- alen = get_alen(argv[1]);
- if (alen > 3)
- return CMD_RET_USAGE;
-
- /*
- * If another parameter, it is the length to display.
- * Length is the number of objects, not number of bytes.
- */
- if (argc > 2)
- length = simple_strtoul(argv[2], NULL, 16);
- }
-
- /*
- * Print the lines.
- *
- * We buffer all read data, so we can make sure data is read only
- * once.
- */
- nbytes = length;
- do {
- unsigned char linebuf[DISP_LINE_LEN];
- unsigned char *cp;
-
- linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
-
- if (cros_ec_i2c_xfer(dev, chip, addr, alen, linebuf, linebytes,
- 1))
- puts("Error reading the chip.\n");
- else {
- printf("%04x:", addr);
- cp = linebuf;
- for (j = 0; j < linebytes; j++) {
- printf(" %02x", *cp++);
- addr++;
- }
- puts(" ");
- cp = linebuf;
- for (j = 0; j < linebytes; j++) {
- if ((*cp < 0x20) || (*cp > 0x7e))
- puts(".");
- else
- printf("%c", *cp);
- cp++;
- }
- putc('\n');
- }
- nbytes -= linebytes;
- } while (nbytes > 0);
-
- return 0;
-}
-
-static int cros_ec_i2c_mw(struct cros_ec_dev *dev, int flag, int argc,
- char * const argv[])
-{
- uchar chip;
- ulong addr;
- uint alen;
- uchar byte;
- int count;
-
- if ((argc < 3) || (argc > 4))
- return CMD_RET_USAGE;
-
- /*
- * Chip is always specified.
- */
- chip = simple_strtoul(argv[0], NULL, 16);
-
- /*
- * Address is always specified.
- */
- addr = simple_strtoul(argv[1], NULL, 16);
- alen = get_alen(argv[1]);
- if (alen > 3)
- return CMD_RET_USAGE;
-
- /*
- * Value to write is always specified.
- */
- byte = simple_strtoul(argv[2], NULL, 16);
-
- /*
- * Optional count
- */
- if (argc == 4)
- count = simple_strtoul(argv[3], NULL, 16);
- else
- count = 1;
-
- while (count-- > 0) {
- if (cros_ec_i2c_xfer(dev, chip, addr++, alen, &byte, 1, 0))
- puts("Error writing the chip.\n");
- /*
- * Wait for the write to complete. The write can take
- * up to 10mSec (we allow a little more time).
- */
-/*
- * No write delay with FRAM devices.
- */
-#if !defined(CONFIG_SYS_I2C_FRAM)
- udelay(11000);
-#endif
- }
-
- return 0;
-}
-
-/* Temporary code until we have driver model and can use the i2c command */
-static int cros_ec_i2c_passthrough(struct cros_ec_dev *dev, int flag,
- int argc, char * const argv[])
-{
- const char *cmd;
-
- if (argc < 1)
- return CMD_RET_USAGE;
- cmd = *argv++;
- argc--;
- if (0 == strcmp("md", cmd))
- cros_ec_i2c_md(dev, flag, argc, argv);
- else if (0 == strcmp("mw", cmd))
- cros_ec_i2c_mw(dev, flag, argc, argv);
- else
- return CMD_RET_USAGE;
-
- return 0;
-}
-
static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct cros_ec_dev *dev;
@@ -1605,9 +1420,9 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
state = simple_strtoul(argv[3], &endp, 10);
if (*argv[3] == 0 || *endp != 0)
return CMD_RET_USAGE;
- ret = cros_ec_set_ldo(dev, index, state);
+ ret = cros_ec_set_ldo(udev, index, state);
} else {
- ret = cros_ec_get_ldo(dev, index, &state);
+ ret = cros_ec_get_ldo(udev, index, &state);
if (!ret) {
printf("LDO%d: %s\n", index,
state == EC_LDO_STATE_ON ?
@@ -1619,8 +1434,6 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
debug("%s: Could not access LDO%d\n", __func__, index);
return ret;
}
- } else if (0 == strcmp("i2c", cmd)) {
- ret = cros_ec_i2c_passthrough(dev, flag, argc - 2, argv + 2);
} else {
return CMD_RET_USAGE;
}
@@ -1633,6 +1446,12 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return ret;
}
+int cros_ec_post_bind(struct udevice *dev)
+{
+ /* Scan for available EC devices (e.g. I2C tunnel) */
+ return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
U_BOOT_CMD(
crosec, 6, 1, do_cros_ec,
"CROS-EC utility command",
@@ -1651,9 +1470,7 @@ U_BOOT_CMD(
"crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
"crosec ldo <idx> [<state>] Switch/Read LDO state\n"
"crosec test run tests on cros_ec\n"
- "crosec version Read CROS-EC version\n"
- "crosec i2c md chip address[.0, .1, .2] [# of objects] - read from I2C passthru\n"
- "crosec i2c mw chip address[.0, .1, .2] value [count] - write to I2C passthru (fill)"
+ "crosec version Read CROS-EC version"
);
#endif
@@ -1661,4 +1478,5 @@ UCLASS_DRIVER(cros_ec) = {
.id = UCLASS_CROS_EC,
.name = "cros_ec",
.per_device_auto_alloc_size = sizeof(struct cros_ec_dev),
+ .post_bind = cros_ec_post_bind,
};
diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index 8e1968a4ea..522eab9bbf 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -202,6 +202,6 @@ int exynos_mmc_init(const void *blob)
process_nodes(blob, node_list, count);
- return 1;
+ return 0;
}
#endif
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
index 67b5fdf07c..ebb959f1f3 100644
--- a/drivers/pci/pci_tegra.c
+++ b/drivers/pci/pci_tegra.c
@@ -445,11 +445,11 @@ static int tegra_pcie_parse_dt_ranges(const void *fdt, int node,
}
debug("PCI regions:\n");
- debug(" I/O: %#x-%#x\n", pcie->io.start, pcie->io.end);
- debug(" non-prefetchable memory: %#x-%#x\n", pcie->mem.start,
- pcie->mem.end);
- debug(" prefetchable memory: %#x-%#x\n", pcie->prefetch.start,
- pcie->prefetch.end);
+ debug(" I/O: %pa-%pa\n", &pcie->io.start, &pcie->io.end);
+ debug(" non-prefetchable memory: %pa-%pa\n", &pcie->mem.start,
+ &pcie->mem.end);
+ debug(" prefetchable memory: %pa-%pa\n", &pcie->prefetch.start,
+ &pcie->prefetch.end);
return 0;
}
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 164f42143f..7b98189ad8 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -41,3 +41,21 @@ config DM_PMIC_SANDBOX
- set by i2c emul driver's probe() (defaults in header)
Driver binding info: doc/device-tree-bindings/pmic/sandbox.txt
+
+config PMIC_S5M8767
+ bool "Enable Driver Model for the Samsung S5M8767 PMIC"
+ depends on DM_PMIC
+ ---help---
+ The S5M8767 PMIC provides a large array of LDOs and BUCKs for use
+ as a SoC power controller. It also provides 32KHz clock outputs. This
+ driver provides basic register access and sets up the attached
+ regulators if regulator support is enabled.
+
+config PMIC_TPS65090
+ bool "Enable driver for Texas Instruments TPS65090 PMIC"
+ depends on DM_PMIC
+ ---help---
+ The TPS65090 is a PMIC containing several LDOs, DC to DC convertors,
+ FETs and a battery charger. This driver provides register access
+ only, and you can enable the regulator/charger drivers separately if
+ required.
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 4ad6df36c2..6ef149aee7 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -8,6 +8,9 @@
obj-$(CONFIG_DM_PMIC) += pmic-uclass.o
obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o
obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
+obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
+obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
+
obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o
obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o
@@ -15,8 +18,6 @@ obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o
obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o
obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o
obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o
-obj-$(CONFIG_POWER_TPS65090_I2C) += pmic_tps65090.o
-obj-$(CONFIG_POWER_TPS65090_EC) += pmic_tps65090_ec.o
obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o
obj-$(CONFIG_POWER_TPS65218) += pmic_tps62362.o
obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o
diff --git a/drivers/power/pmic/max77686.c b/drivers/power/pmic/max77686.c
index 3523b4a2de..dc5a54a6a3 100644
--- a/drivers/power/pmic/max77686.c
+++ b/drivers/power/pmic/max77686.c
@@ -17,8 +17,8 @@
DECLARE_GLOBAL_DATA_PTR;
static const struct pmic_child_info pmic_children_info[] = {
- { .prefix = "ldo", .driver = MAX77686_LDO_DRIVER },
- { .prefix = "buck", .driver = MAX77686_BUCK_DRIVER },
+ { .prefix = "LDO", .driver = MAX77686_LDO_DRIVER },
+ { .prefix = "BUCK", .driver = MAX77686_BUCK_DRIVER },
{ },
};
@@ -84,7 +84,7 @@ static const struct udevice_id max77686_ids[] = {
};
U_BOOT_DRIVER(pmic_max77686) = {
- .name = "max77686 pmic",
+ .name = "max77686_pmic",
.id = UCLASS_PMIC,
.of_match = max77686_ids,
.bind = max77686_bind,
diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c
index d99cb9aada..49709f3084 100644
--- a/drivers/power/pmic/pmic-uclass.c
+++ b/drivers/power/pmic/pmic-uclass.c
@@ -142,7 +142,7 @@ int pmic_reg_write(struct udevice *dev, uint reg, uint value)
u8 byte = value;
debug("%s: reg=%x, value=%x\n", __func__, reg, value);
- return pmic_read(dev, reg, &byte, 1);
+ return pmic_write(dev, reg, &byte, 1);
}
int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set)
diff --git a/drivers/power/pmic/pmic_tps65090.c b/drivers/power/pmic/pmic_tps65090.c
deleted file mode 100644
index 337903acec..0000000000
--- a/drivers/power/pmic/pmic_tps65090.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright (c) 2012 The Chromium OS Authors.
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <errno.h>
-#include <fdtdec.h>
-#include <i2c.h>
-#include <power/pmic.h>
-#include <power/tps65090_pmic.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define TPS65090_NAME "TPS65090_PMIC"
-
-/* TPS65090 register addresses */
-enum {
- REG_IRQ1 = 0,
- REG_CG_CTRL0 = 4,
- REG_CG_STATUS1 = 0xa,
- REG_FET1_CTRL = 0x0f,
- REG_FET2_CTRL,
- REG_FET3_CTRL,
- REG_FET4_CTRL,
- REG_FET5_CTRL,
- REG_FET6_CTRL,
- REG_FET7_CTRL,
- TPS65090_NUM_REGS,
-};
-
-enum {
- IRQ1_VBATG = 1 << 3,
- CG_CTRL0_ENC_MASK = 0x01,
-
- MAX_FET_NUM = 7,
- MAX_CTRL_READ_TRIES = 5,
-
- /* TPS65090 FET_CTRL register values */
- FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */
- FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */
- FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */
- FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */
- FET_CTRL_ENFET = 1 << 0, /* Enable FET */
-};
-
-/**
- * Checks for a valid FET number
- *
- * @param fet_id FET number to check
- * @return 0 if ok, -EINVAL if FET value is out of range
- */
-static int tps65090_check_fet(unsigned int fet_id)
-{
- if (fet_id == 0 || fet_id > MAX_FET_NUM) {
- debug("parameter fet_id is out of range, %u not in 1 ~ %u\n",
- fet_id, MAX_FET_NUM);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * Set the power state for a FET
- *
- * @param pmic pmic structure for the tps65090
- * @param fet_id Fet number to set (1..MAX_FET_NUM)
- * @param set 1 to power on FET, 0 to power off
- * @return -EIO if we got a comms error, -EAGAIN if the FET failed to
- * change state. If all is ok, returns 0.
- */
-static int tps65090_fet_set(struct pmic *pmic, int fet_id, bool set)
-{
- int retry;
- u32 reg, value;
-
- value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
- if (set)
- value |= FET_CTRL_ENFET;
-
- if (pmic_reg_write(pmic, REG_FET1_CTRL + fet_id - 1, value))
- return -EIO;
-
- /* Try reading until we get a result */
- for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
- if (pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, &reg))
- return -EIO;
-
- /* Check that the fet went into the expected state */
- if (!!(reg & FET_CTRL_PGFET) == set)
- return 0;
-
- /* If we got a timeout, there is no point in waiting longer */
- if (reg & FET_CTRL_TOFET)
- break;
-
- mdelay(1);
- }
-
- debug("FET %d: Power good should have set to %d but reg=%#02x\n",
- fet_id, set, reg);
- return -EAGAIN;
-}
-
-int tps65090_fet_enable(unsigned int fet_id)
-{
- struct pmic *pmic;
- ulong start;
- int loops;
- int ret;
-
- ret = tps65090_check_fet(fet_id);
- if (ret)
- return ret;
-
- pmic = pmic_get(TPS65090_NAME);
- if (!pmic)
- return -EACCES;
-
- start = get_timer(0);
- for (loops = 0;; loops++) {
- ret = tps65090_fet_set(pmic, fet_id, true);
- if (!ret)
- break;
-
- if (get_timer(start) > 100)
- break;
-
- /* Turn it off and try again until we time out */
- tps65090_fet_set(pmic, fet_id, false);
- }
-
- if (ret)
- debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
- __func__, fet_id, get_timer(start), loops);
- else if (loops)
- debug("%s: FET%d powered on after %lums, loops=%d\n",
- __func__, fet_id, get_timer(start), loops);
-
- /*
- * Unfortunately, there are some conditions where the power
- * good bit will be 0, but the fet still comes up. One such
- * case occurs with the lcd backlight. We'll just return 0 here
- * and assume that the fet will eventually come up.
- */
- if (ret == -EAGAIN)
- ret = 0;
-
- return ret;
-}
-
-int tps65090_fet_disable(unsigned int fet_id)
-{
- struct pmic *pmic;
- int ret;
-
- ret = tps65090_check_fet(fet_id);
- if (ret)
- return ret;
-
- pmic = pmic_get(TPS65090_NAME);
- if (!pmic)
- return -EACCES;
- ret = tps65090_fet_set(pmic, fet_id, false);
-
- return ret;
-}
-
-int tps65090_fet_is_enabled(unsigned int fet_id)
-{
- struct pmic *pmic;
- u32 reg;
- int ret;
-
- ret = tps65090_check_fet(fet_id);
- if (ret)
- return ret;
-
- pmic = pmic_get(TPS65090_NAME);
- if (!pmic)
- return -ENODEV;
- ret = pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, &reg);
- if (ret) {
- debug("fail to read FET%u_CTRL register over I2C", fet_id);
- return -EIO;
- }
-
- return reg & FET_CTRL_ENFET;
-}
-
-int tps65090_get_charging(void)
-{
- struct pmic *pmic;
- u32 val;
- int ret;
-
- pmic = pmic_get(TPS65090_NAME);
- if (!pmic)
- return -EACCES;
-
- ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val);
- if (ret)
- return ret;
-
- return !!(val & CG_CTRL0_ENC_MASK);
-}
-
-static int tps65090_charger_state(struct pmic *pmic, int state,
- int current)
-{
- u32 val;
- int ret;
-
- ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val);
- if (!ret) {
- if (state == PMIC_CHARGER_ENABLE)
- val |= CG_CTRL0_ENC_MASK;
- else
- val &= ~CG_CTRL0_ENC_MASK;
- ret = pmic_reg_write(pmic, REG_CG_CTRL0, val);
- }
- if (ret) {
- debug("%s: Failed to read/write register\n", __func__);
- return ret;
- }
-
- return 0;
-}
-
-int tps65090_get_status(void)
-{
- struct pmic *pmic;
- u32 val;
- int ret;
-
- pmic = pmic_get(TPS65090_NAME);
- if (!pmic)
- return -EACCES;
-
- ret = pmic_reg_read(pmic, REG_CG_STATUS1, &val);
- if (ret)
- return ret;
-
- return val;
-}
-
-static int tps65090_charger_bat_present(struct pmic *pmic)
-{
- u32 val;
- int ret;
-
- ret = pmic_reg_read(pmic, REG_IRQ1, &val);
- if (ret)
- return ret;
-
- return !!(val & IRQ1_VBATG);
-}
-
-static struct power_chrg power_chrg_pmic_ops = {
- .chrg_bat_present = tps65090_charger_bat_present,
- .chrg_state = tps65090_charger_state,
-};
-
-int tps65090_init(void)
-{
- struct pmic *p;
- int bus;
- int addr;
- const void *blob = gd->fdt_blob;
- int node, parent;
-
- node = fdtdec_next_compatible(blob, 0, COMPAT_TI_TPS65090);
- if (node < 0) {
- debug("PMIC: No node for PMIC Chip in device tree\n");
- debug("node = %d\n", node);
- return -ENODEV;
- }
-
- parent = fdt_parent_offset(blob, node);
- if (parent < 0) {
- debug("%s: Cannot find node parent\n", __func__);
- return -EINVAL;
- }
-
- bus = i2c_get_bus_num_fdt(parent);
- if (bus < 0) {
- debug("%s: Cannot find I2C bus\n", __func__);
- return -ENOENT;
- }
- addr = fdtdec_get_int(blob, node, "reg", TPS65090_I2C_ADDR);
- p = pmic_alloc();
- if (!p) {
- printf("%s: POWER allocation error!\n", __func__);
- return -ENOMEM;
- }
-
- p->name = TPS65090_NAME;
- p->bus = bus;
- p->interface = PMIC_I2C;
- p->number_of_regs = TPS65090_NUM_REGS;
- p->hw.i2c.addr = addr;
- p->hw.i2c.tx_num = 1;
- p->chrg = &power_chrg_pmic_ops;
-
- puts("TPS65090 PMIC init\n");
-
- return 0;
-}
diff --git a/drivers/power/pmic/pmic_tps65090_ec.c b/drivers/power/pmic/pmic_tps65090_ec.c
deleted file mode 100644
index ac0d44fec8..0000000000
--- a/drivers/power/pmic/pmic_tps65090_ec.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (c) 2013 The Chromium OS Authors.
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <cros_ec.h>
-#include <errno.h>
-#include <power/tps65090_pmic.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define TPS65090_ADDR 0x48
-
-static struct tps65090 {
- struct cros_ec_dev *dev; /* The CROS_EC device */
-} config;
-
-/* TPS65090 register addresses */
-enum {
- REG_IRQ1 = 0,
- REG_CG_CTRL0 = 4,
- REG_CG_STATUS1 = 0xa,
- REG_FET1_CTRL = 0x0f,
- REG_FET2_CTRL,
- REG_FET3_CTRL,
- REG_FET4_CTRL,
- REG_FET5_CTRL,
- REG_FET6_CTRL,
- REG_FET7_CTRL,
- TPS65090_NUM_REGS,
-};
-
-enum {
- IRQ1_VBATG = 1 << 3,
- CG_CTRL0_ENC_MASK = 0x01,
-
- MAX_FET_NUM = 7,
- MAX_CTRL_READ_TRIES = 5,
-
- /* TPS65090 FET_CTRL register values */
- FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */
- FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */
- FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */
- FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */
- FET_CTRL_ENFET = 1 << 0, /* Enable FET */
-};
-
-/**
- * tps65090_read - read a byte from tps6090
- *
- * @param reg The register address to read from.
- * @param val We'll return value value read here.
- * @return 0 if ok; error if EC returns failure.
- */
-static int tps65090_read(u32 reg, u8 *val)
-{
- return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1,
- val, 1, true);
-}
-
-/**
- * tps65090_write - write a byte to tps6090
- *
- * @param reg The register address to write to.
- * @param val The value to write.
- * @return 0 if ok; error if EC returns failure.
- */
-static int tps65090_write(u32 reg, u8 val)
-{
- return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1,
- &val, 1, false);
-}
-
-/**
- * Checks for a valid FET number
- *
- * @param fet_id FET number to check
- * @return 0 if ok, -EINVAL if FET value is out of range
- */
-static int tps65090_check_fet(unsigned int fet_id)
-{
- if (fet_id == 0 || fet_id > MAX_FET_NUM) {
- debug("parameter fet_id is out of range, %u not in 1 ~ %u\n",
- fet_id, MAX_FET_NUM);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * Set the power state for a FET
- *
- * @param fet_id Fet number to set (1..MAX_FET_NUM)
- * @param set 1 to power on FET, 0 to power off
- * @return -EIO if we got a comms error, -EAGAIN if the FET failed to
- * change state. If all is ok, returns 0.
- */
-static int tps65090_fet_set(int fet_id, bool set)
-{
- int retry;
- u8 reg, value;
-
- value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
- if (set)
- value |= FET_CTRL_ENFET;
-
- if (tps65090_write(REG_FET1_CTRL + fet_id - 1, value))
- return -EIO;
-
- /* Try reading until we get a result */
- for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
- if (tps65090_read(REG_FET1_CTRL + fet_id - 1, &reg))
- return -EIO;
-
- /* Check that the fet went into the expected state */
- if (!!(reg & FET_CTRL_PGFET) == set)
- return 0;
-
- /* If we got a timeout, there is no point in waiting longer */
- if (reg & FET_CTRL_TOFET)
- break;
-
- mdelay(1);
- }
-
- debug("FET %d: Power good should have set to %d but reg=%#02x\n",
- fet_id, set, reg);
- return -EAGAIN;
-}
-
-int tps65090_fet_enable(unsigned int fet_id)
-{
- ulong start;
- int loops;
- int ret;
-
- ret = tps65090_check_fet(fet_id);
- if (ret)
- return ret;
-
- start = get_timer(0);
- for (loops = 0;; loops++) {
- ret = tps65090_fet_set(fet_id, true);
- if (!ret)
- break;
-
- if (get_timer(start) > 100)
- break;
-
- /* Turn it off and try again until we time out */
- tps65090_fet_set(fet_id, false);
- }
-
- if (ret) {
- debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
- __func__, fet_id, get_timer(start), loops);
- } else if (loops) {
- debug("%s: FET%d powered on after %lums, loops=%d\n",
- __func__, fet_id, get_timer(start), loops);
- }
- /*
- * Unfortunately, there are some conditions where the power
- * good bit will be 0, but the fet still comes up. One such
- * case occurs with the lcd backlight. We'll just return 0 here
- * and assume that the fet will eventually come up.
- */
- if (ret == -EAGAIN)
- ret = 0;
-
- return ret;
-}
-
-int tps65090_fet_disable(unsigned int fet_id)
-{
- int ret;
-
- ret = tps65090_check_fet(fet_id);
- if (ret)
- return ret;
-
- ret = tps65090_fet_set(fet_id, false);
-
- return ret;
-}
-
-int tps65090_fet_is_enabled(unsigned int fet_id)
-{
- u8 reg = 0;
- int ret;
-
- ret = tps65090_check_fet(fet_id);
- if (ret)
- return ret;
- ret = tps65090_read(REG_FET1_CTRL + fet_id - 1, &reg);
- if (ret) {
- debug("fail to read FET%u_CTRL register over I2C", fet_id);
- return -EIO;
- }
-
- return reg & FET_CTRL_ENFET;
-}
-
-int tps65090_init(void)
-{
- puts("TPS65090 PMIC EC init\n");
-
- config.dev = board_get_cros_ec_dev();
- if (!config.dev) {
- debug("%s: no cros_ec device: cannot init tps65090\n",
- __func__);
- return -ENODEV;
- }
-
- return 0;
-}
diff --git a/drivers/power/pmic/s5m8767.c b/drivers/power/pmic/s5m8767.c
new file mode 100644
index 0000000000..075fe7e2f1
--- /dev/null
+++ b/drivers/power/pmic/s5m8767.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/s5m8767.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "LDO", .driver = S5M8767_LDO_DRIVER },
+ { .prefix = "BUCK", .driver = S5M8767_BUCK_DRIVER },
+ { },
+};
+
+static int s5m8767_reg_count(struct udevice *dev)
+{
+ return S5M8767_NUM_OF_REGS;
+}
+
+static int s5m8767_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ error("write error to device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int s5m8767_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ error("read error from device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int s5m8767_enable_32khz_cp(struct udevice *dev)
+{
+ return pmic_clrsetbits(dev, S5M8767_EN32KHZ_CP, 0, 1 << 1);
+}
+
+static int s5m8767_bind(struct udevice *dev)
+{
+ int node;
+ const void *blob = gd->fdt_blob;
+ int children;
+
+ node = fdt_subnode_offset(blob, dev->of_offset, "regulators");
+ if (node <= 0) {
+ debug("%s: %s regulators subnode not found!", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops s5m8767_ops = {
+ .reg_count = s5m8767_reg_count,
+ .read = s5m8767_read,
+ .write = s5m8767_write,
+};
+
+static const struct udevice_id s5m8767_ids[] = {
+ { .compatible = "samsung,s5m8767-pmic" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_s5m8767) = {
+ .name = "s5m8767_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = s5m8767_ids,
+ .bind = s5m8767_bind,
+ .ops = &s5m8767_ops,
+};
diff --git a/drivers/power/pmic/tps65090.c b/drivers/power/pmic/tps65090.c
new file mode 100644
index 0000000000..4797f327fa
--- /dev/null
+++ b/drivers/power/pmic/tps65090.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/tps65090.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "fet", .driver = TPS65090_FET_DRIVER },
+ { },
+};
+
+static int tps65090_reg_count(struct udevice *dev)
+{
+ return TPS65090_NUM_REGS;
+}
+
+static int tps65090_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ error("write error to device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int tps65090_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret) {
+ error("read error %d from device: %p register: %#x!", ret, dev,
+ reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int tps65090_bind(struct udevice *dev)
+{
+ int regulators_node;
+ const void *blob = gd->fdt_blob;
+ int children;
+
+ regulators_node = fdt_subnode_offset(blob, dev->of_offset,
+ "regulators");
+ if (regulators_node <= 0) {
+ debug("%s: %s regulators subnode not found!", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops tps65090_ops = {
+ .reg_count = tps65090_reg_count,
+ .read = tps65090_read,
+ .write = tps65090_write,
+};
+
+static const struct udevice_id tps65090_ids[] = {
+ { .compatible = "ti,tps65090" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_tps65090) = {
+ .name = "tps65090 pmic",
+ .id = UCLASS_PMIC,
+ .of_match = tps65090_ids,
+ .bind = tps65090_bind,
+ .ops = &tps65090_ops,
+};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 6289b83910..e85c69231e 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -32,6 +32,15 @@ config DM_REGULATOR_FIXED
features for fixed value regulators. The driver implements get/set api
for enable and get only for voltage value.
+config REGULATOR_S5M8767
+ bool "Enable support for S5M8767 regulator"
+ depends on DM_REGULATOR && PMIC_S5M8767
+ ---help---
+ This enables the regulator features of the S5M8767, allowing voltages
+ to be set, etc. The driver is not fully complete but supports most
+ common requirements, including all LDOs and BUCKs. This allows many
+ supplies to be set automatically using the device tree values.
+
config DM_REGULATOR_SANDBOX
bool "Enable Driver Model for Sandbox PMIC regulator"
depends on DM_REGULATOR && DM_PMIC_SANDBOX
@@ -61,3 +70,13 @@ config DM_REGULATOR_SANDBOX
A detailed information can be found in header: '<power/sandbox_pmic.h>'
Binding info: 'doc/device-tree-bindings/pmic/max77686.txt'
+
+config REGULATOR_TPS65090
+ bool "Enable driver for TPS65090 PMIC regulators"
+ depends on PMIC_TPS65090
+ ---help---
+ The TPS65090 provides several FETs (Field-effect Transistors,
+ effectively switches) which are supported by this driver as
+ regulators, one for each FET. The standard regulator interface is
+ supported, but it is only possible to turn the regulators on or off.
+ There is no voltage/current control.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index 96aa624961..08d7b0d26d 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -8,4 +8,6 @@
obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o
+obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
+obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o
diff --git a/drivers/power/regulator/max77686.c b/drivers/power/regulator/max77686.c
index 37ebe94521..946b87c60a 100644
--- a/drivers/power/regulator/max77686.c
+++ b/drivers/power/regulator/max77686.c
@@ -61,10 +61,14 @@ static struct dm_regulator_mode max77686_buck_mode_onoff[] = {
MODE(OPMODE_ON, MAX77686_BUCK_MODE_ON, "ON"),
};
-static const char max77686_buck_addr[] = {
+static const char max77686_buck_ctrl[] = {
0xff, 0x10, 0x12, 0x1c, 0x26, 0x30, 0x32, 0x34, 0x36, 0x38
};
+static const char max77686_buck_out[] = {
+ 0xff, 0x11, 0x14, 0x1e, 0x28, 0x31, 0x33, 0x35, 0x37, 0x39
+};
+
static int max77686_buck_volt2hex(int buck, int uV)
{
unsigned int hex = 0;
@@ -77,13 +81,15 @@ static int max77686_buck_volt2hex(int buck, int uV)
/* hex = (uV - 600000) / 12500; */
hex = (uV - MAX77686_BUCK_UV_LMIN) / MAX77686_BUCK_UV_LSTEP;
hex_max = MAX77686_BUCK234_VOLT_MAX_HEX;
- /**
- * Those use voltage scaller - temporary not implemented
- * so return just 0
- */
- return -ENOSYS;
+ break;
default:
- /* hex = (uV - 750000) / 50000; */
+ /*
+ * hex = (uV - 750000) / 50000. We assume that dynamic voltage
+ * scaling via GPIOs is not enabled and don't support that.
+ * If this is enabled then the driver will need to take that
+ * into account anrd check different registers depending on
+ * the current setting See the datasheet for details.
+ */
hex = (uV - MAX77686_BUCK_UV_HMIN) / MAX77686_BUCK_UV_HSTEP;
hex_max = MAX77686_BUCK_VOLT_MAX_HEX;
break;
@@ -368,18 +374,18 @@ static int max77686_buck_val(struct udevice *dev, int op, int *uV)
*uV = 0;
/* &buck_out = ctrl + 1 */
- adr = max77686_buck_addr[buck] + 1;
+ adr = max77686_buck_out[buck];
/* mask */
switch (buck) {
case 2:
case 3:
case 4:
- /* Those use voltage scallers - will support in the future */
mask = MAX77686_BUCK234_VOLT_MASK;
- return -ENOSYS;
+ break;
default:
mask = MAX77686_BUCK_VOLT_MASK;
+ break;
}
ret = pmic_read(dev->parent, adr, &val, 1);
@@ -549,7 +555,7 @@ static int max77686_buck_mode(struct udevice *dev, int op, int *opmode)
return -EINVAL;
}
- adr = max77686_buck_addr[buck];
+ adr = max77686_buck_ctrl[buck];
/* mask */
switch (buck) {
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c
index 12e141b4ad..f3fe7a55e1 100644
--- a/drivers/power/regulator/regulator-uclass.c
+++ b/drivers/power/regulator/regulator-uclass.c
@@ -319,8 +319,10 @@ int regulators_enable_boot_on(bool verbose)
dev && !ret;
uclass_next_device(&dev)) {
ret = regulator_autoset(dev);
- if (ret == -EMEDIUMTYPE)
+ if (ret == -EMEDIUMTYPE) {
+ ret = 0;
continue;
+ }
if (verbose)
regulator_show(dev, ret);
}
diff --git a/drivers/power/regulator/s5m8767.c b/drivers/power/regulator/s5m8767.c
new file mode 100644
index 0000000000..93a3c942d1
--- /dev/null
+++ b/drivers/power/regulator/s5m8767.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/s5m8767.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct sec_voltage_desc buck_v1 = {
+ .max = 2225000,
+ .min = 650000,
+ .step = 6250,
+};
+
+static const struct sec_voltage_desc buck_v2 = {
+ .max = 1600000,
+ .min = 600000,
+ .step = 6250,
+};
+
+static const struct sec_voltage_desc buck_v3 = {
+ .max = 3000000,
+ .min = 750000,
+ .step = 12500,
+};
+
+static const struct sec_voltage_desc ldo_v1 = {
+ .max = 3950000,
+ .min = 800000,
+ .step = 50000,
+};
+
+static const struct sec_voltage_desc ldo_v2 = {
+ .max = 2375000,
+ .min = 800000,
+ .step = 25000,
+};
+
+static const struct s5m8767_para buck_param[] = {
+ /*
+ * | voltage ----| | enable -| voltage
+ * regnum addr bpos mask addr on desc
+ */
+ {S5M8767_BUCK1, 0x33, 0x0, 0xff, 0x32, 0x3, &buck_v1},
+ {S5M8767_BUCK2, 0x35, 0x0, 0xff, 0x34, 0x1, &buck_v2},
+ {S5M8767_BUCK3, 0x3e, 0x0, 0xff, 0x3d, 0x1, &buck_v2},
+ {S5M8767_BUCK4, 0x47, 0x0, 0xff, 0x46, 0x1, &buck_v2},
+ {S5M8767_BUCK5, 0x50, 0x0, 0xff, 0x4f, 0x3, &buck_v1},
+ {S5M8767_BUCK6, 0x55, 0x0, 0xff, 0x54, 0x3, &buck_v1},
+ {S5M8767_BUCK7, 0x57, 0x0, 0xff, 0x56, 0x3, &buck_v3},
+ {S5M8767_BUCK8, 0x59, 0x0, 0xff, 0x58, 0x3, &buck_v3},
+ {S5M8767_BUCK9, 0x5b, 0x0, 0xff, 0x5a, 0x3, &buck_v3},
+};
+
+static const struct s5m8767_para ldo_param[] = {
+ {S5M8767_LDO1, 0x5c, 0x0, 0x3f, 0x5c, 0x3, &ldo_v2},
+ {S5M8767_LDO2, 0x5d, 0x0, 0x3f, 0x5d, 0x1, &ldo_v2},
+ {S5M8767_LDO3, 0x61, 0x0, 0x3f, 0x61, 0x3, &ldo_v1},
+ {S5M8767_LDO4, 0x62, 0x0, 0x3f, 0x62, 0x3, &ldo_v1},
+ {S5M8767_LDO5, 0x63, 0x0, 0x3f, 0x63, 0x3, &ldo_v1},
+ {S5M8767_LDO6, 0x64, 0x0, 0x3f, 0x64, 0x1, &ldo_v2},
+ {S5M8767_LDO7, 0x65, 0x0, 0x3f, 0x65, 0x1, &ldo_v2},
+ {S5M8767_LDO8, 0x66, 0x0, 0x3f, 0x66, 0x1, &ldo_v2},
+ {S5M8767_LDO9, 0x67, 0x0, 0x3f, 0x67, 0x3, &ldo_v1},
+ {S5M8767_LDO10, 0x68, 0x0, 0x3f, 0x68, 0x1, &ldo_v1},
+ {S5M8767_LDO11, 0x69, 0x0, 0x3f, 0x69, 0x1, &ldo_v1},
+ {S5M8767_LDO12, 0x6a, 0x0, 0x3f, 0x6a, 0x1, &ldo_v1},
+ {S5M8767_LDO13, 0x6b, 0x0, 0x3f, 0x6b, 0x3, &ldo_v1},
+ {S5M8767_LDO14, 0x6c, 0x0, 0x3f, 0x6c, 0x1, &ldo_v1},
+ {S5M8767_LDO15, 0x6d, 0x0, 0x3f, 0x6d, 0x1, &ldo_v2},
+ {S5M8767_LDO16, 0x6e, 0x0, 0x3f, 0x6e, 0x1, &ldo_v1},
+ {S5M8767_LDO17, 0x6f, 0x0, 0x3f, 0x6f, 0x3, &ldo_v1},
+ {S5M8767_LDO18, 0x70, 0x0, 0x3f, 0x70, 0x3, &ldo_v1},
+ {S5M8767_LDO19, 0x71, 0x0, 0x3f, 0x71, 0x3, &ldo_v1},
+ {S5M8767_LDO20, 0x72, 0x0, 0x3f, 0x72, 0x3, &ldo_v1},
+ {S5M8767_LDO21, 0x73, 0x0, 0x3f, 0x73, 0x3, &ldo_v1},
+ {S5M8767_LDO22, 0x74, 0x0, 0x3f, 0x74, 0x3, &ldo_v1},
+ {S5M8767_LDO23, 0x75, 0x0, 0x3f, 0x75, 0x3, &ldo_v1},
+ {S5M8767_LDO24, 0x76, 0x0, 0x3f, 0x76, 0x3, &ldo_v1},
+ {S5M8767_LDO25, 0x77, 0x0, 0x3f, 0x77, 0x3, &ldo_v1},
+ {S5M8767_LDO26, 0x78, 0x0, 0x3f, 0x78, 0x3, &ldo_v1},
+ {S5M8767_LDO27, 0x79, 0x0, 0x3f, 0x79, 0x3, &ldo_v1},
+ {S5M8767_LDO28, 0x7a, 0x0, 0x3f, 0x7a, 0x3, &ldo_v1},
+};
+
+enum {
+ ENABLE_SHIFT = 6,
+ ENABLE_MASK = 3,
+};
+
+static int reg_get_value(struct udevice *dev, const struct s5m8767_para *param)
+{
+ const struct sec_voltage_desc *desc;
+ int ret, uv, val;
+
+ ret = pmic_reg_read(dev->parent, param->vol_addr);
+ if (ret < 0)
+ return ret;
+
+ desc = param->vol;
+ val = (ret >> param->vol_bitpos) & param->vol_bitmask;
+ uv = desc->min + val * desc->step;
+
+ return uv;
+}
+
+static int reg_set_value(struct udevice *dev, const struct s5m8767_para *param,
+ int uv)
+{
+ const struct sec_voltage_desc *desc;
+ int ret, val;
+
+ desc = param->vol;
+ if (uv < desc->min || uv > desc->max)
+ return -EINVAL;
+ val = (uv - desc->min) / desc->step;
+ val = (val & param->vol_bitmask) << param->vol_bitpos;
+ ret = pmic_clrsetbits(dev->parent, param->vol_addr,
+ param->vol_bitmask << param->vol_bitpos,
+ val);
+
+ return ret;
+}
+
+static int s5m8767_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+static int ldo_get_value(struct udevice *dev)
+{
+ int ldo = dev->driver_data;
+
+ return reg_get_value(dev, &ldo_param[ldo]);
+}
+
+static int ldo_set_value(struct udevice *dev, int uv)
+{
+ int ldo = dev->driver_data;
+
+ return reg_set_value(dev, &ldo_param[ldo], uv);
+}
+
+static int reg_get_enable(struct udevice *dev, const struct s5m8767_para *param)
+{
+ bool enable;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, param->reg_enaddr);
+ if (ret < 0)
+ return ret;
+
+ enable = (ret >> ENABLE_SHIFT) & ENABLE_MASK;
+
+ return enable;
+}
+
+static int reg_set_enable(struct udevice *dev, const struct s5m8767_para *param,
+ bool enable)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, param->reg_enaddr);
+ if (ret < 0)
+ return ret;
+
+ ret = pmic_clrsetbits(dev->parent, param->reg_enaddr,
+ ENABLE_MASK << ENABLE_SHIFT,
+ enable ? param->reg_enbiton << ENABLE_SHIFT : 0);
+
+ return ret;
+}
+
+static bool ldo_get_enable(struct udevice *dev)
+{
+ int ldo = dev->driver_data;
+
+ return reg_get_enable(dev, &ldo_param[ldo]);
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ int ldo = dev->driver_data;
+
+ return reg_set_enable(dev, &ldo_param[ldo], enable);
+}
+
+static int s5m8767_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+ int buck = dev->driver_data;
+
+ return reg_get_value(dev, &buck_param[buck]);
+}
+
+static int buck_set_value(struct udevice *dev, int uv)
+{
+ int buck = dev->driver_data;
+
+ return reg_set_value(dev, &buck_param[buck], uv);
+}
+
+static bool buck_get_enable(struct udevice *dev)
+{
+ int buck = dev->driver_data;
+
+ return reg_get_enable(dev, &buck_param[buck]);
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ int buck = dev->driver_data;
+
+ return reg_set_enable(dev, &buck_param[buck], enable);
+}
+
+static const struct dm_regulator_ops s5m8767_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+};
+
+U_BOOT_DRIVER(s5m8767_ldo) = {
+ .name = S5M8767_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &s5m8767_ldo_ops,
+ .probe = s5m8767_ldo_probe,
+};
+
+static const struct dm_regulator_ops s5m8767_buck_ops = {
+ .get_value = buck_get_value,
+ .set_value = buck_set_value,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+};
+
+U_BOOT_DRIVER(s5m8767_buck) = {
+ .name = S5M8767_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &s5m8767_buck_ops,
+ .probe = s5m8767_buck_probe,
+};
diff --git a/drivers/power/regulator/tps65090_regulator.c b/drivers/power/regulator/tps65090_regulator.c
new file mode 100644
index 0000000000..affc504071
--- /dev/null
+++ b/drivers/power/regulator/tps65090_regulator.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65090.h>
+
+static int tps65090_fet_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_OTHER;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static bool tps65090_fet_get_enable(struct udevice *dev)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ int ret, fet_id;
+
+ fet_id = dev->driver_data;
+ debug("%s: fet_id=%d\n", __func__, fet_id);
+
+ ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id);
+ if (ret < 0)
+ return ret;
+
+ return ret & FET_CTRL_ENFET;
+}
+
+/**
+ * Set the power state for a FET
+ *
+ * @param pmic pmic structure for the tps65090
+ * @param fet_id FET number to set (1..MAX_FET_NUM)
+ * @param set 1 to power on FET, 0 to power off
+ * @return -EIO if we got a comms error, -EAGAIN if the FET failed to
+ * change state. If all is ok, returns 0.
+ */
+static int tps65090_fet_set(struct udevice *pmic, int fet_id, bool set)
+{
+ int retry;
+ u32 value;
+ int ret;
+
+ value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
+ if (set)
+ value |= FET_CTRL_ENFET;
+
+ if (pmic_reg_write(pmic, REG_FET_BASE + fet_id, value))
+ return -EIO;
+
+ /* Try reading until we get a result */
+ for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
+ ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id);
+ if (ret < 0)
+ return ret;
+
+ /* Check that the FET went into the expected state */
+ debug("%s: flags=%x\n", __func__, ret);
+ if (!!(ret & FET_CTRL_PGFET) == set)
+ return 0;
+
+ /* If we got a timeout, there is no point in waiting longer */
+ if (ret & FET_CTRL_TOFET)
+ break;
+
+ mdelay(1);
+ }
+
+ debug("FET %d: Power good should have set to %d but reg=%#02x\n",
+ fet_id, set, ret);
+ return -EAGAIN;
+}
+
+static int tps65090_fet_set_enable(struct udevice *dev, bool enable)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ int ret, fet_id;
+ ulong start;
+ int loops;
+
+ fet_id = dev->driver_data;
+ debug("%s: fet_id=%d, enable=%d\n", __func__, fet_id, enable);
+
+ start = get_timer(0);
+ for (loops = 0;; loops++) {
+ ret = tps65090_fet_set(pmic, fet_id, enable);
+ if (!ret)
+ break;
+
+ if (get_timer(start) > 100)
+ break;
+
+ /* Turn it off and try again until we time out */
+ tps65090_fet_set(pmic, fet_id, false);
+ }
+
+ if (ret)
+ debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
+ __func__, fet_id, get_timer(start), loops);
+ else if (loops)
+ debug("%s: FET%d powered on after %lums, loops=%d\n",
+ __func__, fet_id, get_timer(start), loops);
+
+ /*
+ * Unfortunately there are some conditions where the power-good bit
+ * will be 0, but the FET still comes up. One such case occurs with
+ * the LCD backlight on snow. We'll just return 0 here and assume
+ * that the FET will eventually come up.
+ */
+ if (ret == -EAGAIN)
+ ret = 0;
+
+ return ret;
+}
+
+static const struct dm_regulator_ops tps65090_fet_ops = {
+ .get_enable = tps65090_fet_get_enable,
+ .set_enable = tps65090_fet_set_enable,
+};
+
+U_BOOT_DRIVER(tps65090_fet) = {
+ .name = TPS65090_FET_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65090_fet_ops,
+ .probe = tps65090_fet_probe,
+};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index b5a91b707e..fd126a825f 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -53,6 +53,13 @@ config DEBUG_EFI_CONSOLE
U-Boot when running on top of EFI (Extensive Firmware Interface).
This is a type of BIOS used by PCs.
+config DEBUG_UART_S5P
+ bool "Samsung S5P"
+ help
+ Select this to enable a debug UART using the serial_s5p driver. You
+ will need to provide parameters to make this work. The driver will
+ be available until the real driver-model serial is running.
+
endchoice
config DEBUG_UART_BASE
diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c
index 8469afdaae..21cb566c29 100644
--- a/drivers/serial/serial_s5p.c
+++ b/drivers/serial/serial_s5p.c
@@ -14,8 +14,8 @@
#include <fdtdec.h>
#include <linux/compiler.h>
#include <asm/io.h>
-#include <asm/arch/uart.h>
#include <asm/arch/clk.h>
+#include <asm/arch/uart.h>
#include <serial.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -59,11 +59,20 @@ static const int udivslot[] = {
0xffdf,
};
-int s5p_serial_setbrg(struct udevice *dev, int baudrate)
+static void __maybe_unused s5p_serial_init(struct s5p_uart *uart)
+{
+ /* enable FIFOs, auto clear Rx FIFO */
+ writel(0x3, &uart->ufcon);
+ writel(0, &uart->umcon);
+ /* 8N1 */
+ writel(0x3, &uart->ulcon);
+ /* No interrupts, no DMA, pure polling */
+ writel(0x245, &uart->ucon);
+}
+
+static void __maybe_unused s5p_serial_baud(struct s5p_uart *uart, uint uclk,
+ int baudrate)
{
- struct s5p_serial_platdata *plat = dev->platdata;
- struct s5p_uart *const uart = plat->reg;
- u32 uclk = get_uart_clk(plat->port_id);
u32 val;
val = uclk / baudrate;
@@ -74,6 +83,16 @@ int s5p_serial_setbrg(struct udevice *dev, int baudrate)
writew(udivslot[val % 16], &uart->rest.slot);
else
writeb(val % 16, &uart->rest.value);
+}
+
+#ifndef CONFIG_SPL_BUILD
+int s5p_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct s5p_serial_platdata *plat = dev->platdata;
+ struct s5p_uart *const uart = plat->reg;
+ u32 uclk = get_uart_clk(plat->port_id);
+
+ s5p_serial_baud(uart, uclk, baudrate);
return 0;
}
@@ -83,13 +102,7 @@ static int s5p_serial_probe(struct udevice *dev)
struct s5p_serial_platdata *plat = dev->platdata;
struct s5p_uart *const uart = plat->reg;
- /* enable FIFOs, auto clear Rx FIFO */
- writel(0x3, &uart->ufcon);
- writel(0, &uart->umcon);
- /* 8N1 */
- writel(0x3, &uart->ulcon);
- /* No interrupts, no DMA, pure polling */
- writel(0x245, &uart->ucon);
+ s5p_serial_init(uart);
return 0;
}
@@ -188,3 +201,29 @@ U_BOOT_DRIVER(serial_s5p) = {
.ops = &s5p_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};
+#endif
+
+#ifdef CONFIG_DEBUG_UART_S5P
+
+#include <debug_uart.h>
+
+void debug_uart_init(void)
+{
+ struct s5p_uart *uart = (struct s5p_uart *)CONFIG_DEBUG_UART_BASE;
+
+ s5p_serial_init(uart);
+ s5p_serial_baud(uart, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+ struct s5p_uart *uart = (struct s5p_uart *)CONFIG_DEBUG_UART_BASE;
+
+ while (readl(&uart->ufstat) & TX_FIFO_FULL);
+
+ writeb(ch, &uart->utxh);
+}
+
+DEBUG_UART_FUNCS
+
+#endif
diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index 67f6b2d7cd..6d77c319e7 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -190,9 +190,9 @@ static int spi_rx_tx(struct exynos_spi_priv *priv, int todo,
spi_request_bytes(regs, toread, step);
}
if (priv->skip_preamble && get_timer(start) > 100) {
- printf("SPI timeout: in_bytes=%d, out_bytes=%d, ",
- in_bytes, out_bytes);
- return -1;
+ debug("SPI timeout: in_bytes=%d, out_bytes=%d, ",
+ in_bytes, out_bytes);
+ return -ETIMEDOUT;
}
}
diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c
index 792853192e..3881b2e8a5 100644
--- a/drivers/spi/fsl_dspi.c
+++ b/drivers/spi/fsl_dspi.c
@@ -664,8 +664,8 @@ static int fsl_dspi_ofdata_to_platdata(struct udevice *bus)
plat->speed_hz = fdtdec_get_int(blob,
node, "spi-max-frequency", FSL_DSPI_DEFAULT_SCK_FREQ);
- debug("DSPI: regs=0x%llx, max-frequency=%d, endianess=%s, num-cs=%d\n",
- (u64)plat->regs_addr, plat->speed_hz,
+ debug("DSPI: regs=%pa, max-frequency=%d, endianess=%s, num-cs=%d\n",
+ &plat->regs_addr, plat->speed_hz,
plat->flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le",
plat->num_chipselect);
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
index a7e50d6a6c..1dcd088b8d 100644
--- a/drivers/usb/eth/smsc95xx.c
+++ b/drivers/usb/eth/smsc95xx.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2015 Google, Inc
* Copyright (c) 2011 The Chromium OS Authors.
* Copyright (C) 2009 NVIDIA, Corporation
* Copyright (C) 2007-2008 SMSC (Steve Glendinning)
@@ -6,12 +7,14 @@
* SPDX-License-Identifier: GPL-2.0+
*/
-#include <asm/unaligned.h>
#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
#include <usb.h>
+#include <asm/unaligned.h>
#include <linux/mii.h>
#include "usb_ether.h"
-#include <malloc.h>
/* SMSC LAN95xx based USB 2.0 Ethernet Devices */
@@ -131,16 +134,21 @@
#define USB_BULK_SEND_TIMEOUT 5000
#define USB_BULK_RECV_TIMEOUT 5000
-#define AX_RX_URB_SIZE 2048
+#define RX_URB_SIZE 2048
#define PHY_CONNECT_TIMEOUT 5000
#define TURBO_MODE
+#ifndef CONFIG_DM_ETH
/* local vars */
static int curr_eth_dev; /* index for name of next device detected */
+#endif
/* driver private */
struct smsc95xx_private {
+#ifdef CONFIG_DM_ETH
+ struct ueth_data ueth;
+#endif
size_t rx_urb_size; /* maximum USB URB size */
u32 mac_cr; /* MAC control register value */
int have_hwaddr; /* 1 if we have a hardware MAC address */
@@ -149,7 +157,7 @@ struct smsc95xx_private {
/*
* Smsc95xx infrastructure commands
*/
-static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data)
+static int smsc95xx_write_reg(struct usb_device *udev, u32 index, u32 data)
{
int len;
ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
@@ -157,32 +165,34 @@ static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data)
cpu_to_le32s(&data);
tmpbuf[0] = data;
- len = usb_control_msg(dev->pusb_dev, usb_sndctrlpipe(dev->pusb_dev, 0),
- USB_VENDOR_REQUEST_WRITE_REGISTER,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 00, index, tmpbuf, sizeof(data), USB_CTRL_SET_TIMEOUT);
+ len = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_VENDOR_REQUEST_WRITE_REGISTER,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index, tmpbuf, sizeof(data),
+ USB_CTRL_SET_TIMEOUT);
if (len != sizeof(data)) {
debug("smsc95xx_write_reg failed: index=%d, data=%d, len=%d",
index, data, len);
- return -1;
+ return -EIO;
}
return 0;
}
-static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data)
+static int smsc95xx_read_reg(struct usb_device *udev, u32 index, u32 *data)
{
int len;
ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
- len = usb_control_msg(dev->pusb_dev, usb_rcvctrlpipe(dev->pusb_dev, 0),
- USB_VENDOR_REQUEST_READ_REGISTER,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 00, index, tmpbuf, sizeof(data), USB_CTRL_GET_TIMEOUT);
+ len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ USB_VENDOR_REQUEST_READ_REGISTER,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index, tmpbuf, sizeof(data),
+ USB_CTRL_GET_TIMEOUT);
*data = tmpbuf[0];
if (len != sizeof(data)) {
debug("smsc95xx_read_reg failed: index=%d, len=%d",
index, len);
- return -1;
+ return -EIO;
}
le32_to_cpus(data);
@@ -190,89 +200,89 @@ static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data)
}
/* Loop until the read is completed with timeout */
-static int smsc95xx_phy_wait_not_busy(struct ueth_data *dev)
+static int smsc95xx_phy_wait_not_busy(struct usb_device *udev)
{
unsigned long start_time = get_timer(0);
u32 val;
do {
- smsc95xx_read_reg(dev, MII_ADDR, &val);
+ smsc95xx_read_reg(udev, MII_ADDR, &val);
if (!(val & MII_BUSY_))
return 0;
- } while (get_timer(start_time) < 1 * 1000 * 1000);
+ } while (get_timer(start_time) < 1000);
- return -1;
+ return -ETIMEDOUT;
}
-static int smsc95xx_mdio_read(struct ueth_data *dev, int phy_id, int idx)
+static int smsc95xx_mdio_read(struct usb_device *udev, int phy_id, int idx)
{
u32 val, addr;
/* confirm MII not busy */
- if (smsc95xx_phy_wait_not_busy(dev)) {
+ if (smsc95xx_phy_wait_not_busy(udev)) {
debug("MII is busy in smsc95xx_mdio_read\n");
- return -1;
+ return -ETIMEDOUT;
}
/* set the address, index & direction (read from PHY) */
addr = (phy_id << 11) | (idx << 6) | MII_READ_;
- smsc95xx_write_reg(dev, MII_ADDR, addr);
+ smsc95xx_write_reg(udev, MII_ADDR, addr);
- if (smsc95xx_phy_wait_not_busy(dev)) {
+ if (smsc95xx_phy_wait_not_busy(udev)) {
debug("Timed out reading MII reg %02X\n", idx);
- return -1;
+ return -ETIMEDOUT;
}
- smsc95xx_read_reg(dev, MII_DATA, &val);
+ smsc95xx_read_reg(udev, MII_DATA, &val);
return (u16)(val & 0xFFFF);
}
-static void smsc95xx_mdio_write(struct ueth_data *dev, int phy_id, int idx,
+static void smsc95xx_mdio_write(struct usb_device *udev, int phy_id, int idx,
int regval)
{
u32 val, addr;
/* confirm MII not busy */
- if (smsc95xx_phy_wait_not_busy(dev)) {
+ if (smsc95xx_phy_wait_not_busy(udev)) {
debug("MII is busy in smsc95xx_mdio_write\n");
return;
}
val = regval;
- smsc95xx_write_reg(dev, MII_DATA, val);
+ smsc95xx_write_reg(udev, MII_DATA, val);
/* set the address, index & direction (write to PHY) */
addr = (phy_id << 11) | (idx << 6) | MII_WRITE_;
- smsc95xx_write_reg(dev, MII_ADDR, addr);
+ smsc95xx_write_reg(udev, MII_ADDR, addr);
- if (smsc95xx_phy_wait_not_busy(dev))
+ if (smsc95xx_phy_wait_not_busy(udev))
debug("Timed out writing MII reg %02X\n", idx);
}
-static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev)
+static int smsc95xx_eeprom_confirm_not_busy(struct usb_device *udev)
{
unsigned long start_time = get_timer(0);
u32 val;
do {
- smsc95xx_read_reg(dev, E2P_CMD, &val);
+ smsc95xx_read_reg(udev, E2P_CMD, &val);
if (!(val & E2P_CMD_BUSY_))
return 0;
udelay(40);
} while (get_timer(start_time) < 1 * 1000 * 1000);
debug("EEPROM is busy\n");
- return -1;
+ return -ETIMEDOUT;
}
-static int smsc95xx_wait_eeprom(struct ueth_data *dev)
+static int smsc95xx_wait_eeprom(struct usb_device *udev)
{
unsigned long start_time = get_timer(0);
u32 val;
do {
- smsc95xx_read_reg(dev, E2P_CMD, &val);
+ smsc95xx_read_reg(udev, E2P_CMD, &val);
if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_))
break;
udelay(40);
@@ -280,30 +290,30 @@ static int smsc95xx_wait_eeprom(struct ueth_data *dev)
if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) {
debug("EEPROM read operation timeout\n");
- return -1;
+ return -ETIMEDOUT;
}
return 0;
}
-static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length,
+static int smsc95xx_read_eeprom(struct usb_device *udev, u32 offset, u32 length,
u8 *data)
{
u32 val;
int i, ret;
- ret = smsc95xx_eeprom_confirm_not_busy(dev);
+ ret = smsc95xx_eeprom_confirm_not_busy(udev);
if (ret)
return ret;
for (i = 0; i < length; i++) {
val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_);
- smsc95xx_write_reg(dev, E2P_CMD, val);
+ smsc95xx_write_reg(udev, E2P_CMD, val);
- ret = smsc95xx_wait_eeprom(dev);
+ ret = smsc95xx_wait_eeprom(udev);
if (ret < 0)
return ret;
- smsc95xx_read_reg(dev, E2P_DATA, &val);
+ smsc95xx_read_reg(udev, E2P_DATA, &val);
data[i] = val & 0xFF;
offset++;
}
@@ -315,89 +325,96 @@ static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length,
*
* Returns 0 on success, negative on error.
*/
-static int mii_nway_restart(struct ueth_data *dev)
+static int mii_nway_restart(struct usb_device *udev, struct ueth_data *dev)
{
int bmcr;
int r = -1;
/* if autoneg is off, it's an error */
- bmcr = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMCR);
+ bmcr = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMCR);
if (bmcr & BMCR_ANENABLE) {
bmcr |= BMCR_ANRESTART;
- smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr);
+ smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, bmcr);
r = 0;
}
return r;
}
-static int smsc95xx_phy_initialize(struct ueth_data *dev)
+static int smsc95xx_phy_initialize(struct usb_device *udev,
+ struct ueth_data *dev)
{
- smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET);
- smsc95xx_mdio_write(dev, dev->phy_id, MII_ADVERTISE,
- ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
- ADVERTISE_PAUSE_ASYM);
+ smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, BMCR_RESET);
+ smsc95xx_mdio_write(udev, dev->phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA |
+ ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
/* read to clear */
- smsc95xx_mdio_read(dev, dev->phy_id, PHY_INT_SRC);
+ smsc95xx_mdio_read(udev, dev->phy_id, PHY_INT_SRC);
- smsc95xx_mdio_write(dev, dev->phy_id, PHY_INT_MASK,
- PHY_INT_MASK_DEFAULT_);
- mii_nway_restart(dev);
+ smsc95xx_mdio_write(udev, dev->phy_id, PHY_INT_MASK,
+ PHY_INT_MASK_DEFAULT_);
+ mii_nway_restart(udev, dev);
debug("phy initialised succesfully\n");
return 0;
}
-static int smsc95xx_init_mac_address(struct eth_device *eth,
- struct ueth_data *dev)
+static int smsc95xx_init_mac_address(unsigned char *enetaddr,
+ struct usb_device *udev)
{
+ int ret;
+
/* try reading mac address from EEPROM */
- if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
- eth->enetaddr) == 0) {
- if (is_valid_ethaddr(eth->enetaddr)) {
- /* eeprom values are valid so use them */
- debug("MAC address read from EEPROM\n");
- return 0;
- }
+ ret = smsc95xx_read_eeprom(udev, EEPROM_MAC_OFFSET, ETH_ALEN, enetaddr);
+ if (ret)
+ return ret;
+
+ if (is_valid_ethaddr(enetaddr)) {
+ /* eeprom values are valid so use them */
+ debug("MAC address read from EEPROM\n");
+ return 0;
}
/*
* No eeprom, or eeprom values are invalid. Generating a random MAC
* address is not safe. Just return an error.
*/
- return -1;
+ debug("Invalid MAC address read from EEPROM\n");
+
+ return -ENXIO;
}
-static int smsc95xx_write_hwaddr(struct eth_device *eth)
+static int smsc95xx_write_hwaddr_common(struct usb_device *udev,
+ struct smsc95xx_private *priv,
+ unsigned char *enetaddr)
{
- struct ueth_data *dev = (struct ueth_data *)eth->priv;
- struct smsc95xx_private *priv = dev->dev_priv;
- u32 addr_lo = __get_unaligned_le32(&eth->enetaddr[0]);
- u32 addr_hi = __get_unaligned_le16(&eth->enetaddr[4]);
+ u32 addr_lo = __get_unaligned_le32(&enetaddr[0]);
+ u32 addr_hi = __get_unaligned_le16(&enetaddr[4]);
int ret;
/* set hardware address */
debug("** %s()\n", __func__);
- ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
+ ret = smsc95xx_write_reg(udev, ADDRL, addr_lo);
if (ret < 0)
return ret;
- ret = smsc95xx_write_reg(dev, ADDRH, addr_hi);
+ ret = smsc95xx_write_reg(udev, ADDRH, addr_hi);
if (ret < 0)
return ret;
- debug("MAC %pM\n", eth->enetaddr);
+ debug("MAC %pM\n", enetaddr);
priv->have_hwaddr = 1;
+
return 0;
}
/* Enable or disable Tx & Rx checksum offload engines */
-static int smsc95xx_set_csums(struct ueth_data *dev,
- int use_tx_csum, int use_rx_csum)
+static int smsc95xx_set_csums(struct usb_device *udev, int use_tx_csum,
+ int use_rx_csum)
{
u32 read_buf;
- int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
+ int ret = smsc95xx_read_reg(udev, COE_CR, &read_buf);
if (ret < 0)
return ret;
@@ -411,7 +428,7 @@ static int smsc95xx_set_csums(struct ueth_data *dev,
else
read_buf &= ~Rx_COE_EN_;
- ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
+ ret = smsc95xx_write_reg(udev, COE_CR, read_buf);
if (ret < 0)
return ret;
@@ -419,52 +436,45 @@ static int smsc95xx_set_csums(struct ueth_data *dev,
return 0;
}
-static void smsc95xx_set_multicast(struct ueth_data *dev)
+static void smsc95xx_set_multicast(struct smsc95xx_private *priv)
{
- struct smsc95xx_private *priv = dev->dev_priv;
-
/* No multicast in u-boot */
priv->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
}
/* starts the TX path */
-static void smsc95xx_start_tx_path(struct ueth_data *dev)
+static void smsc95xx_start_tx_path(struct usb_device *udev,
+ struct smsc95xx_private *priv)
{
- struct smsc95xx_private *priv = dev->dev_priv;
u32 reg_val;
/* Enable Tx at MAC */
priv->mac_cr |= MAC_CR_TXEN_;
- smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr);
+ smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr);
/* Enable Tx at SCSRs */
reg_val = TX_CFG_ON_;
- smsc95xx_write_reg(dev, TX_CFG, reg_val);
+ smsc95xx_write_reg(udev, TX_CFG, reg_val);
}
/* Starts the Receive path */
-static void smsc95xx_start_rx_path(struct ueth_data *dev)
+static void smsc95xx_start_rx_path(struct usb_device *udev,
+ struct smsc95xx_private *priv)
{
- struct smsc95xx_private *priv = dev->dev_priv;
-
priv->mac_cr |= MAC_CR_RXEN_;
- smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr);
+ smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr);
}
-/*
- * Smsc95xx callbacks
- */
-static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
+static int smsc95xx_init_common(struct usb_device *udev, struct ueth_data *dev,
+ struct smsc95xx_private *priv,
+ unsigned char *enetaddr)
{
int ret;
u32 write_buf;
u32 read_buf;
u32 burst_cap;
int timeout;
- struct ueth_data *dev = (struct ueth_data *)eth->priv;
- struct smsc95xx_private *priv =
- (struct smsc95xx_private *)dev->dev_priv;
#define TIMEOUT_RESOLUTION 50 /* ms */
int link_detected;
@@ -472,13 +482,13 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
dev->phy_id = SMSC95XX_INTERNAL_PHY_ID; /* fixed phy id */
write_buf = HW_CFG_LRST_;
- ret = smsc95xx_write_reg(dev, HW_CFG, write_buf);
+ ret = smsc95xx_write_reg(udev, HW_CFG, write_buf);
if (ret < 0)
return ret;
timeout = 0;
do {
- ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
if (ret < 0)
return ret;
udelay(10 * 1000);
@@ -487,17 +497,17 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
if (timeout >= 100) {
debug("timeout waiting for completion of Lite Reset\n");
- return -1;
+ return -ETIMEDOUT;
}
write_buf = PM_CTL_PHY_RST_;
- ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf);
+ ret = smsc95xx_write_reg(udev, PM_CTRL, write_buf);
if (ret < 0)
return ret;
timeout = 0;
do {
- ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
+ ret = smsc95xx_read_reg(udev, PM_CTRL, &read_buf);
if (ret < 0)
return ret;
udelay(10 * 1000);
@@ -505,28 +515,30 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
} while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
if (timeout >= 100) {
debug("timeout waiting for PHY Reset\n");
- return -1;
+ return -ETIMEDOUT;
}
- if (!priv->have_hwaddr && smsc95xx_init_mac_address(eth, dev) == 0)
+ if (!priv->have_hwaddr && smsc95xx_init_mac_address(enetaddr, udev) ==
+ 0)
priv->have_hwaddr = 1;
if (!priv->have_hwaddr) {
puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n");
- return -1;
+ return -EADDRNOTAVAIL;
}
- if (smsc95xx_write_hwaddr(eth) < 0)
- return -1;
+ ret = smsc95xx_write_hwaddr_common(udev, priv, enetaddr);
+ if (ret < 0)
+ return ret;
- ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from HW_CFG : 0x%08x\n", read_buf);
read_buf |= HW_CFG_BIR_;
- ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
+ ret = smsc95xx_write_reg(udev, HW_CFG, read_buf);
if (ret < 0)
return ret;
- ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from HW_CFG after writing "
@@ -546,27 +558,27 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
#endif
debug("rx_urb_size=%ld\n", (ulong)priv->rx_urb_size);
- ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
+ ret = smsc95xx_write_reg(udev, BURST_CAP, burst_cap);
if (ret < 0)
return ret;
- ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
+ ret = smsc95xx_read_reg(udev, BURST_CAP, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from BURST_CAP after writing: 0x%08x\n", read_buf);
read_buf = DEFAULT_BULK_IN_DELAY;
- ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf);
+ ret = smsc95xx_write_reg(udev, BULK_IN_DLY, read_buf);
if (ret < 0)
return ret;
- ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
+ ret = smsc95xx_read_reg(udev, BULK_IN_DLY, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from BULK_IN_DLY after writing: "
"0x%08x\n", read_buf);
- ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from HW_CFG: 0x%08x\n", read_buf);
@@ -579,21 +591,21 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
#define NET_IP_ALIGN 0
read_buf |= NET_IP_ALIGN << 9;
- ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
+ ret = smsc95xx_write_reg(udev, HW_CFG, read_buf);
if (ret < 0)
return ret;
- ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
write_buf = 0xFFFFFFFF;
- ret = smsc95xx_write_reg(dev, INT_STS, write_buf);
+ ret = smsc95xx_write_reg(udev, INT_STS, write_buf);
if (ret < 0)
return ret;
- ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
+ ret = smsc95xx_read_reg(udev, ID_REV, &read_buf);
if (ret < 0)
return ret;
debug("ID_REV = 0x%08x\n", read_buf);
@@ -601,59 +613,60 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
/* Configure GPIO pins as LED outputs */
write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
LED_GPIO_CFG_FDX_LED;
- ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
+ ret = smsc95xx_write_reg(udev, LED_GPIO_CFG, write_buf);
if (ret < 0)
return ret;
debug("LED_GPIO_CFG set\n");
/* Init Tx */
write_buf = 0;
- ret = smsc95xx_write_reg(dev, FLOW, write_buf);
+ ret = smsc95xx_write_reg(udev, FLOW, write_buf);
if (ret < 0)
return ret;
read_buf = AFC_CFG_DEFAULT;
- ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf);
+ ret = smsc95xx_write_reg(udev, AFC_CFG, read_buf);
if (ret < 0)
return ret;
- ret = smsc95xx_read_reg(dev, MAC_CR, &priv->mac_cr);
+ ret = smsc95xx_read_reg(udev, MAC_CR, &priv->mac_cr);
if (ret < 0)
return ret;
/* Init Rx. Set Vlan */
write_buf = (u32)ETH_P_8021Q;
- ret = smsc95xx_write_reg(dev, VLAN1, write_buf);
+ ret = smsc95xx_write_reg(udev, VLAN1, write_buf);
if (ret < 0)
return ret;
/* Disable checksum offload engines */
- ret = smsc95xx_set_csums(dev, 0, 0);
+ ret = smsc95xx_set_csums(udev, 0, 0);
if (ret < 0) {
debug("Failed to set csum offload: %d\n", ret);
return ret;
}
- smsc95xx_set_multicast(dev);
+ smsc95xx_set_multicast(priv);
- if (smsc95xx_phy_initialize(dev) < 0)
- return -1;
- ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
+ ret = smsc95xx_phy_initialize(udev, dev);
+ if (ret < 0)
+ return ret;
+ ret = smsc95xx_read_reg(udev, INT_EP_CTL, &read_buf);
if (ret < 0)
return ret;
/* enable PHY interrupts */
read_buf |= INT_EP_CTL_PHY_INT_;
- ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
+ ret = smsc95xx_write_reg(udev, INT_EP_CTL, read_buf);
if (ret < 0)
return ret;
- smsc95xx_start_tx_path(dev);
- smsc95xx_start_rx_path(dev);
+ smsc95xx_start_tx_path(udev, priv);
+ smsc95xx_start_rx_path(udev, priv);
timeout = 0;
do {
- link_detected = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMSR)
+ link_detected = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMSR)
& BMSR_LSTATUS;
if (!link_detected) {
if (timeout == 0)
@@ -667,14 +680,13 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
printf("done.\n");
} else {
printf("unable to connect.\n");
- return -1;
+ return -EIO;
}
return 0;
}
-static int smsc95xx_send(struct eth_device *eth, void* packet, int length)
+static int smsc95xx_send_common(struct ueth_data *dev, void *packet, int length)
{
- struct ueth_data *dev = (struct ueth_data *)eth->priv;
int err;
int actual_len;
u32 tx_cmd_a;
@@ -684,7 +696,7 @@ static int smsc95xx_send(struct eth_device *eth, void* packet, int length)
debug("** %s(), len %d, buf %#x\n", __func__, length, (int)msg);
if (length > PKTSIZE)
- return -1;
+ return -ENOSPC;
tx_cmd_a = (u32)length | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
tx_cmd_b = (u32)length;
@@ -705,13 +717,35 @@ static int smsc95xx_send(struct eth_device *eth, void* packet, int length)
debug("Tx: len = %u, actual = %u, err = %d\n",
length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b),
actual_len, err);
+
return err;
}
+#ifndef CONFIG_DM_ETH
+/*
+ * Smsc95xx callbacks
+ */
+static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ struct usb_device *udev = dev->pusb_dev;
+ struct smsc95xx_private *priv =
+ (struct smsc95xx_private *)dev->dev_priv;
+
+ return smsc95xx_init_common(udev, dev, priv, eth->enetaddr);
+}
+
+static int smsc95xx_send(struct eth_device *eth, void *packet, int length)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+ return smsc95xx_send_common(dev, packet, length);
+}
+
static int smsc95xx_recv(struct eth_device *eth)
{
struct ueth_data *dev = (struct ueth_data *)eth->priv;
- DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, AX_RX_URB_SIZE);
+ DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, RX_URB_SIZE);
unsigned char *buf_ptr;
int err;
int actual_len;
@@ -720,20 +754,18 @@ static int smsc95xx_recv(struct eth_device *eth)
debug("** %s()\n", __func__);
err = usb_bulk_msg(dev->pusb_dev,
- usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
- (void *)recv_buf,
- AX_RX_URB_SIZE,
- &actual_len,
- USB_BULK_RECV_TIMEOUT);
- debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE,
+ usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
+ (void *)recv_buf, RX_URB_SIZE, &actual_len,
+ USB_BULK_RECV_TIMEOUT);
+ debug("Rx: len = %u, actual = %u, err = %d\n", RX_URB_SIZE,
actual_len, err);
if (err != 0) {
debug("Rx: failed to receive\n");
- return -1;
+ return -err;
}
- if (actual_len > AX_RX_URB_SIZE) {
+ if (actual_len > RX_URB_SIZE) {
debug("Rx: received too many bytes %d\n", actual_len);
- return -1;
+ return -ENOSPC;
}
buf_ptr = recv_buf;
@@ -744,19 +776,19 @@ static int smsc95xx_recv(struct eth_device *eth)
*/
if (actual_len < sizeof(packet_len)) {
debug("Rx: incomplete packet length\n");
- return -1;
+ return -EIO;
}
memcpy(&packet_len, buf_ptr, sizeof(packet_len));
le32_to_cpus(&packet_len);
if (packet_len & RX_STS_ES_) {
debug("Rx: Error header=%#x", packet_len);
- return -1;
+ return -EIO;
}
packet_len = ((packet_len & RX_STS_FL_) >> 16);
if (packet_len > actual_len - sizeof(packet_len)) {
debug("Rx: too large packet: %d\n", packet_len);
- return -1;
+ return -EIO;
}
/* Notify net stack */
@@ -783,6 +815,15 @@ static void smsc95xx_halt(struct eth_device *eth)
debug("** %s()\n", __func__);
}
+static int smsc95xx_write_hwaddr(struct eth_device *eth)
+{
+ struct ueth_data *dev = eth->priv;
+ struct usb_device *udev = dev->pusb_dev;
+ struct smsc95xx_private *priv = dev->dev_priv;
+
+ return smsc95xx_write_hwaddr_common(udev, priv, eth->enetaddr);
+}
+
/*
* SMSC probing functions
*/
@@ -898,3 +939,137 @@ int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
eth->priv = ss;
return 1;
}
+#endif /* !CONFIG_DM_ETH */
+
+#ifdef CONFIG_DM_ETH
+static int smsc95xx_eth_start(struct udevice *dev)
+{
+ struct usb_device *udev = dev_get_parentdata(dev);
+ struct smsc95xx_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ /* Driver-model Ethernet ensures we have this */
+ priv->have_hwaddr = 1;
+
+ return smsc95xx_init_common(udev, &priv->ueth, priv, pdata->enetaddr);
+}
+
+void smsc95xx_eth_stop(struct udevice *dev)
+{
+ debug("** %s()\n", __func__);
+}
+
+int smsc95xx_eth_send(struct udevice *dev, void *packet, int length)
+{
+ struct smsc95xx_private *priv = dev_get_priv(dev);
+
+ return smsc95xx_send_common(&priv->ueth, packet, length);
+}
+
+int smsc95xx_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct smsc95xx_private *priv = dev_get_priv(dev);
+ struct ueth_data *ueth = &priv->ueth;
+ uint8_t *ptr;
+ int ret, len;
+ u32 packet_len;
+
+ len = usb_ether_get_rx_bytes(ueth, &ptr);
+ debug("%s: first try, len=%d\n", __func__, len);
+ if (!len) {
+ if (!(flags & ETH_RECV_CHECK_DEVICE))
+ return -EAGAIN;
+ ret = usb_ether_receive(ueth, RX_URB_SIZE);
+ if (ret == -EAGAIN)
+ return ret;
+
+ len = usb_ether_get_rx_bytes(ueth, &ptr);
+ debug("%s: second try, len=%d\n", __func__, len);
+ }
+
+ /*
+ * 1st 4 bytes contain the length of the actual data plus error info.
+ * Extract data length.
+ */
+ if (len < sizeof(packet_len)) {
+ debug("Rx: incomplete packet length\n");
+ goto err;
+ }
+ memcpy(&packet_len, ptr, sizeof(packet_len));
+ le32_to_cpus(&packet_len);
+ if (packet_len & RX_STS_ES_) {
+ debug("Rx: Error header=%#x", packet_len);
+ goto err;
+ }
+ packet_len = ((packet_len & RX_STS_FL_) >> 16);
+
+ if (packet_len > len - sizeof(packet_len)) {
+ debug("Rx: too large packet: %d\n", packet_len);
+ goto err;
+ }
+
+ *packetp = ptr + sizeof(packet_len);
+ return packet_len;
+
+err:
+ usb_ether_advance_rxbuf(ueth, -1);
+ return -EINVAL;
+}
+
+static int smsc95xx_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+ struct smsc95xx_private *priv = dev_get_priv(dev);
+
+ packet_len = ALIGN(packet_len, 4);
+ usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
+
+ return 0;
+}
+
+int smsc95xx_write_hwaddr(struct udevice *dev)
+{
+ struct usb_device *udev = dev_get_parentdata(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct smsc95xx_private *priv = dev_get_priv(dev);
+
+ return smsc95xx_write_hwaddr_common(udev, priv, pdata->enetaddr);
+}
+
+static int smsc95xx_eth_probe(struct udevice *dev)
+{
+ struct smsc95xx_private *priv = dev_get_priv(dev);
+ struct ueth_data *ueth = &priv->ueth;
+
+ return usb_ether_register(dev, ueth, RX_URB_SIZE);
+}
+
+static const struct eth_ops smsc95xx_eth_ops = {
+ .start = smsc95xx_eth_start,
+ .send = smsc95xx_eth_send,
+ .recv = smsc95xx_eth_recv,
+ .free_pkt = smsc95xx_free_pkt,
+ .stop = smsc95xx_eth_stop,
+ .write_hwaddr = smsc95xx_write_hwaddr,
+};
+
+U_BOOT_DRIVER(smsc95xx_eth) = {
+ .name = "smsc95xx_eth",
+ .id = UCLASS_ETH,
+ .probe = smsc95xx_eth_probe,
+ .ops = &smsc95xx_eth_ops,
+ .priv_auto_alloc_size = sizeof(struct smsc95xx_private),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id smsc95xx_eth_id_table[] = {
+ { USB_DEVICE(0x05ac, 0x1402) },
+ { USB_DEVICE(0x0424, 0xec00) }, /* LAN9512/LAN9514 Ethernet */
+ { USB_DEVICE(0x0424, 0x9500) }, /* LAN9500 Ethernet */
+ { USB_DEVICE(0x0424, 0x9730) }, /* LAN9730 Ethernet (HSIC) */
+ { USB_DEVICE(0x0424, 0x9900) }, /* SMSC9500 USB Ethernet (SAL10) */
+ { USB_DEVICE(0x0424, 0x9e00) }, /* LAN9500A Ethernet */
+ { } /* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(smsc95xx_eth, smsc95xx_eth_id_table);
+#endif
diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c
index 63785a9c59..3c3e082b27 100644
--- a/drivers/usb/eth/usb_ether.c
+++ b/drivers/usb/eth/usb_ether.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <dm.h>
+#include <errno.h>
#include <malloc.h>
#include <usb.h>
#include <dm/device-internal.h>
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index ad35841769..702ef63f87 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -6,6 +6,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <errno.h>
#include <usb.h>
#include <malloc.h>
@@ -21,18 +22,29 @@
#define DWC2_STATUS_BUF_SIZE 64
#define DWC2_DATA_BUF_SIZE (64 * 1024)
-/* We need doubleword-aligned buffers for DMA transfers */
-DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer, DWC2_DATA_BUF_SIZE, 8);
-DEFINE_ALIGN_BUFFER(uint8_t, status_buffer, DWC2_STATUS_BUF_SIZE, 8);
-
#define MAX_DEVICE 16
#define MAX_ENDPOINT 16
-static int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
-static int root_hub_devnum;
+struct dwc2_priv {
+#ifdef CONFIG_DM_USB
+ uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(8);
+ uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(8);
+#else
+ uint8_t *aligned_buffer;
+ uint8_t *status_buffer;
+#endif
+ int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
+ struct dwc2_core_regs *regs;
+ int root_hub_devnum;
+};
+
+#ifndef CONFIG_DM_USB
+/* We need doubleword-aligned buffers for DMA transfers */
+DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer_addr, DWC2_DATA_BUF_SIZE, 8);
+DEFINE_ALIGN_BUFFER(uint8_t, status_buffer_addr, DWC2_STATUS_BUF_SIZE, 8);
-static struct dwc2_core_regs *regs =
- (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR;
+static struct dwc2_priv local;
+#endif
/*
* DWC2 IP interface
@@ -428,7 +440,8 @@ static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num,
* DWC2 to USB API interface
*/
/* Direction: In ; Request: Status */
-static int dwc_otg_submit_rh_msg_in_status(struct usb_device *dev, void *buffer,
+static int dwc_otg_submit_rh_msg_in_status(struct dwc2_core_regs *regs,
+ struct usb_device *dev, void *buffer,
int txlen, struct devrequest *cmd)
{
uint32_t hprt0 = 0;
@@ -602,13 +615,13 @@ static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev,
}
/* Direction: In */
-static int dwc_otg_submit_rh_msg_in(struct usb_device *dev,
- void *buffer, int txlen,
- struct devrequest *cmd)
+static int dwc_otg_submit_rh_msg_in(struct dwc2_priv *priv,
+ struct usb_device *dev, void *buffer,
+ int txlen, struct devrequest *cmd)
{
switch (cmd->request) {
case USB_REQ_GET_STATUS:
- return dwc_otg_submit_rh_msg_in_status(dev, buffer,
+ return dwc_otg_submit_rh_msg_in_status(priv->regs, dev, buffer,
txlen, cmd);
case USB_REQ_GET_DESCRIPTOR:
return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer,
@@ -623,10 +636,12 @@ static int dwc_otg_submit_rh_msg_in(struct usb_device *dev,
}
/* Direction: Out */
-static int dwc_otg_submit_rh_msg_out(struct usb_device *dev,
- void *buffer, int txlen,
- struct devrequest *cmd)
+static int dwc_otg_submit_rh_msg_out(struct dwc2_priv *priv,
+ struct usb_device *dev,
+ void *buffer, int txlen,
+ struct devrequest *cmd)
{
+ struct dwc2_core_regs *regs = priv->regs;
int len = 0;
int stat = 0;
uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8);
@@ -673,7 +688,7 @@ static int dwc_otg_submit_rh_msg_out(struct usb_device *dev,
}
break;
case (USB_REQ_SET_ADDRESS << 8):
- root_hub_devnum = wValue;
+ priv->root_hub_devnum = wValue;
break;
case (USB_REQ_SET_CONFIGURATION << 8):
break;
@@ -690,8 +705,8 @@ static int dwc_otg_submit_rh_msg_out(struct usb_device *dev,
return stat;
}
-static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
- void *buffer, int txlen,
+static int dwc_otg_submit_rh_msg(struct dwc2_priv *priv, struct usb_device *dev,
+ unsigned long pipe, void *buffer, int txlen,
struct devrequest *cmd)
{
int stat = 0;
@@ -702,16 +717,17 @@ static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
}
if (cmd->requesttype & USB_DIR_IN)
- stat = dwc_otg_submit_rh_msg_in(dev, buffer, txlen, cmd);
+ stat = dwc_otg_submit_rh_msg_in(priv, dev, buffer, txlen, cmd);
else
- stat = dwc_otg_submit_rh_msg_out(dev, buffer, txlen, cmd);
+ stat = dwc_otg_submit_rh_msg_out(priv, dev, buffer, txlen, cmd);
mdelay(1);
return stat;
}
-int wait_for_chhltd(uint32_t *sub, int *toggle, bool ignore_ack)
+int wait_for_chhltd(struct dwc2_core_regs *regs, uint32_t *sub, int *toggle,
+ bool ignore_ack)
{
uint32_t hcint_comp_hlt_ack = DWC2_HCINT_XFERCOMP | DWC2_HCINT_CHHLTD;
struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
@@ -751,9 +767,11 @@ static int dwc2_eptype[] = {
DWC2_HCCHAR_EPTYPE_BULK,
};
-int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
- void *buffer, int len, bool ignore_ack)
+int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev,
+ unsigned long pipe, int *pid, int in, void *buffer, int len,
+ bool ignore_ack)
{
+ struct dwc2_core_regs *regs = priv->regs;
struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
int devnum = usb_pipedevice(pipe);
int ep = usb_pipeendpoint(pipe);
@@ -802,10 +820,12 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
(*pid << DWC2_HCTSIZ_PID_OFFSET),
&hc_regs->hctsiz);
- if (!in)
- memcpy(aligned_buffer, (char *)buffer + done, len);
+ if (!in) {
+ memcpy(priv->aligned_buffer, (char *)buffer + done,
+ len);
+ }
- writel(phys_to_bus((unsigned long)aligned_buffer),
+ writel(phys_to_bus((unsigned long)priv->aligned_buffer),
&hc_regs->hcdma);
/* Set host channel enable after all other setup is complete. */
@@ -814,13 +834,13 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
(1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
DWC2_HCCHAR_CHEN);
- ret = wait_for_chhltd(&sub, pid, ignore_ack);
+ ret = wait_for_chhltd(regs, &sub, pid, ignore_ack);
if (ret)
break;
if (in) {
xfer_len -= sub;
- memcpy(buffer + done, aligned_buffer, xfer_len);
+ memcpy(buffer + done, priv->aligned_buffer, xfer_len);
if (sub)
stop_transfer = 1;
}
@@ -839,43 +859,45 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
}
/* U-Boot USB transmission interface */
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len)
+int _submit_bulk_msg(struct dwc2_priv *priv, struct usb_device *dev,
+ unsigned long pipe, void *buffer, int len)
{
int devnum = usb_pipedevice(pipe);
int ep = usb_pipeendpoint(pipe);
- if (devnum == root_hub_devnum) {
+ if (devnum == priv->root_hub_devnum) {
dev->status = 0;
return -EINVAL;
}
- return chunk_msg(dev, pipe, &bulk_data_toggle[devnum][ep],
+ return chunk_msg(priv, dev, pipe, &priv->bulk_data_toggle[devnum][ep],
usb_pipein(pipe), buffer, len, true);
}
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len, struct devrequest *setup)
+static int _submit_control_msg(struct dwc2_priv *priv, struct usb_device *dev,
+ unsigned long pipe, void *buffer, int len,
+ struct devrequest *setup)
{
int devnum = usb_pipedevice(pipe);
int pid, ret, act_len;
/* For CONTROL endpoint pid should start with DATA1 */
int status_direction;
- if (devnum == root_hub_devnum) {
+ if (devnum == priv->root_hub_devnum) {
dev->status = 0;
dev->speed = USB_SPEED_HIGH;
- return dwc_otg_submit_rh_msg(dev, pipe, buffer, len, setup);
+ return dwc_otg_submit_rh_msg(priv, dev, pipe, buffer, len,
+ setup);
}
pid = DWC2_HC_PID_SETUP;
- ret = chunk_msg(dev, pipe, &pid, 0, setup, 8, true);
+ ret = chunk_msg(priv, dev, pipe, &pid, 0, setup, 8, true);
if (ret)
return ret;
if (buffer) {
pid = DWC2_HC_PID_DATA1;
- ret = chunk_msg(dev, pipe, &pid, usb_pipein(pipe), buffer,
+ ret = chunk_msg(priv, dev, pipe, &pid, usb_pipein(pipe), buffer,
len, false);
if (ret)
return ret;
@@ -891,8 +913,8 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
status_direction = 0;
pid = DWC2_HC_PID_DATA1;
- ret = chunk_msg(dev, pipe, &pid, status_direction, status_buffer, 0,
- false);
+ ret = chunk_msg(priv, dev, pipe, &pid, status_direction,
+ priv->status_buffer, 0, false);
if (ret)
return ret;
@@ -901,8 +923,8 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
return 0;
}
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len, int interval)
+int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev,
+ unsigned long pipe, void *buffer, int len, int interval)
{
unsigned long timeout;
int ret;
@@ -915,24 +937,18 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
printf("Timeout poll on interrupt endpoint\n");
return -ETIMEDOUT;
}
- ret = submit_bulk_msg(dev, pipe, buffer, len);
+ ret = _submit_bulk_msg(priv, dev, pipe, buffer, len);
if (ret != -EAGAIN)
return ret;
}
}
-/* U-Boot USB control interface */
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+static int dwc2_init_common(struct dwc2_priv *priv)
{
+ struct dwc2_core_regs *regs = priv->regs;
uint32_t snpsid;
int i, j;
- root_hub_devnum = 0;
-
- /* board dependant init */
- if (board_usb_init(index, USB_INIT_HOST))
- return -1;
-
snpsid = readl(&regs->gsnpsid);
printf("Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff);
@@ -956,18 +972,149 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
for (i = 0; i < MAX_DEVICE; i++) {
for (j = 0; j < MAX_ENDPOINT; j++)
- bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0;
+ priv->bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0;
}
return 0;
}
-int usb_lowlevel_stop(int index)
+static void dwc2_uninit_common(struct dwc2_core_regs *regs)
{
/* Put everything in reset. */
clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
DWC2_HPRT0_PRTOVRCURRCHNG,
DWC2_HPRT0_PRTRST);
+}
+
+#ifndef CONFIG_DM_USB
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len, struct devrequest *setup)
+{
+ return _submit_control_msg(&local, dev, pipe, buffer, len, setup);
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len)
+{
+ return _submit_bulk_msg(&local, dev, pipe, buffer, len);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len, int interval)
+{
+ return _submit_int_msg(&local, dev, pipe, buffer, len, interval);
+}
+
+/* U-Boot USB control interface */
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+ struct dwc2_priv *priv = &local;
+
+ memset(priv, '\0', sizeof(*priv));
+ priv->root_hub_devnum = 0;
+ priv->regs = (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR;
+ priv->aligned_buffer = aligned_buffer_addr;
+ priv->status_buffer = status_buffer_addr;
+
+ /* board-dependant init */
+ if (board_usb_init(index, USB_INIT_HOST))
+ return -1;
+
+ return dwc2_init_common(priv);
+}
+
+int usb_lowlevel_stop(int index)
+{
+ dwc2_uninit_common(local.regs);
+
return 0;
}
+#endif
+
+#ifdef CONFIG_DM_USB
+static int dwc2_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length,
+ struct devrequest *setup)
+{
+ struct dwc2_priv *priv = dev_get_priv(dev);
+
+ debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
+ dev->name, udev, udev->dev->name, udev->portnr);
+
+ return _submit_control_msg(priv, udev, pipe, buffer, length, setup);
+}
+
+static int dwc2_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length)
+{
+ struct dwc2_priv *priv = dev_get_priv(dev);
+
+ debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+
+ return _submit_bulk_msg(priv, udev, pipe, buffer, length);
+}
+
+static int dwc2_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length,
+ int interval)
+{
+ struct dwc2_priv *priv = dev_get_priv(dev);
+
+ debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+
+ return _submit_int_msg(priv, udev, pipe, buffer, length, interval);
+}
+
+static int dwc2_usb_ofdata_to_platdata(struct udevice *dev)
+{
+ struct dwc2_priv *priv = dev_get_priv(dev);
+ fdt_addr_t addr;
+
+ addr = dev_get_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ priv->regs = (struct dwc2_core_regs *)addr;
+
+ return 0;
+}
+
+static int dwc2_usb_probe(struct udevice *dev)
+{
+ struct dwc2_priv *priv = dev_get_priv(dev);
+
+ return dwc2_init_common(priv);
+}
+
+static int dwc2_usb_remove(struct udevice *dev)
+{
+ struct dwc2_priv *priv = dev_get_priv(dev);
+
+ dwc2_uninit_common(priv->regs);
+
+ return 0;
+}
+
+struct dm_usb_ops dwc2_usb_ops = {
+ .control = dwc2_submit_control_msg,
+ .bulk = dwc2_submit_bulk_msg,
+ .interrupt = dwc2_submit_int_msg,
+};
+
+static const struct udevice_id dwc2_usb_ids[] = {
+ { .compatible = "brcm,bcm2835-usb" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_dwc2) = {
+ .name = "dwc2_exynos",
+ .id = UCLASS_USB,
+ .of_match = dwc2_usb_ids,
+ .ofdata_to_platdata = dwc2_usb_ofdata_to_platdata,
+ .probe = dwc2_usb_probe,
+ .remove = dwc2_usb_remove,
+ .ops = &dwc2_usb_ops,
+ .priv_auto_alloc_size = sizeof(struct dwc2_priv),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 9ae23e8dd0..3244cd7edd 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -240,3 +240,5 @@ config VIDEO_TEGRA124
HDMI. At present only eDP is supported by U-Boot. This option
enables this support which can be used on devices which
have an eDP display connected.
+
+source "drivers/video/bridge/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 2ead7f192c..c2c4dfc57e 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_VIDEO_VESA) += vesa_fb.o
obj-$(CONFIG_FORMIKE) += formike.o
obj-$(CONFIG_LG4573) += lg4573.o
obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
-obj-$(CONFIG_VIDEO_PARADE) += parade.o
obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
+
+obj-y += bridge/
diff --git a/drivers/video/bridge/Kconfig b/drivers/video/bridge/Kconfig
new file mode 100644
index 0000000000..2a3b6c4bee
--- /dev/null
+++ b/drivers/video/bridge/Kconfig
@@ -0,0 +1,27 @@
+config VIDEO_BRIDGE
+ bool "Support video bridges"
+ depends on DM
+ help
+ Some platforms use video bridges to convert from one output to
+ another. For example, where the SoC only supports eDP and the LCD
+ requires LVDS, an eDP->LVDS bridge chip can be used to provide the
+ necessary conversion. This option enables support for these devices.
+
+config VIDEO_BRIDGE_PARADE_PS862X
+ bool "Support Parade PS862X DP->LVDS bridge"
+ depends on VIDEO_BRIDGE
+ help
+ The Parade PS8622 and PS8625 are DisplayPort-to-LVDS (Low voltage
+ differential signalling) converters. They enable an LVDS LCD panel
+ to be connected to an eDP output device such as an SoC that lacks
+ LVDS capability, or where LVDS requires too many signals to route
+ on the PCB. Setup parameters are provided in the device tree.
+
+config VIDEO_BRIDGE_NXP_PTN3460
+ bool "Support NXP PTN3460 DP->LVDS bridge"
+ depends on VIDEO_BRIDGE
+ help
+ The NXP PTN3460 is a DisplayPort-to-LVDS (Low voltage differential
+ signalling) converter. It enables an LVDS LCD panel to be connected
+ to an eDP output device such as an SoC that lacks LVDS capability,
+ or where LVDS requires too many signals to route on the PCB.
diff --git a/drivers/video/bridge/Makefile b/drivers/video/bridge/Makefile
new file mode 100644
index 0000000000..ce731fa4ca
--- /dev/null
+++ b/drivers/video/bridge/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (C) 2015 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_VIDEO_BRIDGE) += video-bridge-uclass.o
+obj-$(CONFIG_VIDEO_BRIDGE_PARADE_PS862X) += ps862x.o
+obj-$(CONFIG_VIDEO_BRIDGE_NXP_PTN3460) += ptn3460.o
diff --git a/drivers/video/bridge/ps862x.c b/drivers/video/bridge/ps862x.c
new file mode 100644
index 0000000000..80f63e3eb5
--- /dev/null
+++ b/drivers/video/bridge/ps862x.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <video_bridge.h>
+#include <power/regulator.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Initialisation of the chip is a process of writing certain values into
+ * certain registers over i2c bus. The chip in fact responds to a range of
+ * addresses on the i2c bus, so for each written value three parameters are
+ * required: i2c address, register address and the actual value.
+ *
+ * The base address is derived from the device tree, but oddly the chip
+ * responds on several addresses with different register sets for each.
+ */
+
+/**
+ * ps8622_write() Write a PS8622 eDP bridge i2c register
+ *
+ * @param dev I2C device
+ * @param addr_off offset from the i2c base address for ps8622
+ * @param reg_addr register address to write
+ * @param value value to be written
+ * @return 0 on success, non-0 on failure
+ */
+static int ps8622_write(struct udevice *dev, unsigned addr_off,
+ unsigned char reg_addr, unsigned char value)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+ uint8_t buf[2];
+ struct i2c_msg msg;
+ int ret;
+
+ msg.addr = chip->chip_addr + addr_off;
+ msg.flags = 0;
+ buf[0] = reg_addr;
+ buf[1] = value;
+ msg.buf = buf;
+ msg.len = 2;
+ ret = dm_i2c_xfer(dev, &msg, 1);
+ if (ret) {
+ debug("%s: write failed, reg=%#x, value=%#x, ret=%d\n",
+ __func__, reg_addr, value, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ps8622_set_backlight(struct udevice *dev, int percent)
+{
+ int level = percent * 255 / 100;
+
+ debug("%s: level=%d\n", __func__, level);
+ return ps8622_write(dev, 0x01, 0xa7, level);
+}
+
+static int ps8622_attach(struct udevice *dev)
+{
+ const uint8_t *params;
+ struct udevice *reg;
+ int ret, i, len;
+
+ debug("%s: %s\n", __func__, dev->name);
+ /* set the LDO providing the 1.2V rail to the Parade bridge */
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "power-supply", &reg);
+ if (!ret) {
+ ret = regulator_autoset(reg);
+ } else if (ret != -ENOENT) {
+ debug("%s: Failed to enable power: ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = video_bridge_set_active(dev, true);
+ if (ret)
+ return ret;
+
+ params = fdt_getprop(gd->fdt_blob, dev->of_offset, "parade,regs", &len);
+ if (!params || len % 3) {
+ debug("%s: missing/invalid params=%p, len=%x\n", __func__,
+ params, len);
+ return -EINVAL;
+ }
+
+ /* need to wait 20ms after power on before doing I2C writes */
+ mdelay(20);
+ for (i = 0; i < len; i += 3) {
+ ret = ps8622_write(dev, params[i + 0], params[i + 1],
+ params[i + 2]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ps8622_probe(struct udevice *dev)
+{
+ debug("%s\n", __func__);
+ if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
+ return -EPROTONOSUPPORT;
+
+ return 0;
+}
+
+struct video_bridge_ops ps8622_ops = {
+ .attach = ps8622_attach,
+ .set_backlight = ps8622_set_backlight,
+};
+
+static const struct udevice_id ps8622_ids[] = {
+ { .compatible = "parade,ps8622", },
+ { .compatible = "parade,ps8625", },
+ { }
+};
+
+U_BOOT_DRIVER(parade_ps8622) = {
+ .name = "parade_ps8622",
+ .id = UCLASS_VIDEO_BRIDGE,
+ .of_match = ps8622_ids,
+ .probe = ps8622_probe,
+ .ops = &ps8622_ops,
+};
diff --git a/drivers/video/bridge/ptn3460.c b/drivers/video/bridge/ptn3460.c
new file mode 100644
index 0000000000..2e2ae7c5a6
--- /dev/null
+++ b/drivers/video/bridge/ptn3460.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <video_bridge.h>
+
+static int ptn3460_attach(struct udevice *dev)
+{
+ int ret;
+
+ debug("%s: %s\n", __func__, dev->name);
+ ret = video_bridge_set_active(dev, true);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct video_bridge_ops ptn3460_ops = {
+ .attach = ptn3460_attach,
+};
+
+static const struct udevice_id ptn3460_ids[] = {
+ { .compatible = "nxp,ptn3460", },
+ { }
+};
+
+U_BOOT_DRIVER(parade_ptn3460) = {
+ .name = "nmp_ptn3460",
+ .id = UCLASS_VIDEO_BRIDGE,
+ .of_match = ptn3460_ids,
+ .ops = &ptn3460_ops,
+};
diff --git a/drivers/video/bridge/video-bridge-uclass.c b/drivers/video/bridge/video-bridge-uclass.c
new file mode 100644
index 0000000000..6c5990f54c
--- /dev/null
+++ b/drivers/video/bridge/video-bridge-uclass.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <video_bridge.h>
+
+int video_bridge_set_backlight(struct udevice *dev, int percent)
+{
+ struct video_bridge_ops *ops = video_bridge_get_ops(dev);
+
+ if (!ops->set_backlight)
+ return -ENOSYS;
+
+ return ops->set_backlight(dev, percent);
+}
+
+int video_bridge_attach(struct udevice *dev)
+{
+ struct video_bridge_ops *ops = video_bridge_get_ops(dev);
+
+ if (!ops->attach)
+ return -ENOSYS;
+
+ return ops->attach(dev);
+}
+
+int video_bridge_check_attached(struct udevice *dev)
+{
+ struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct video_bridge_ops *ops = video_bridge_get_ops(dev);
+ int ret;
+
+ if (!ops->check_attached) {
+ ret = dm_gpio_get_value(&uc_priv->hotplug);
+
+ return ret > 0 ? 0 : ret == 0 ? -ENOTCONN : ret;
+ }
+
+ return ops->check_attached(dev);
+}
+
+static int video_bridge_pre_probe(struct udevice *dev)
+{
+ struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ debug("%s\n", __func__);
+ ret = gpio_request_by_name(dev, "sleep-gpios", 0,
+ &uc_priv->sleep, GPIOD_IS_OUT);
+ if (ret) {
+ debug("%s: Could not decode sleep-gpios (%d)\n", __func__, ret);
+ return ret;
+ }
+ /*
+ * Drop this for now as we do not have driver model pinctrl support
+ *
+ * ret = dm_gpio_set_pull(&uc_priv->sleep, GPIO_PULL_NONE);
+ * if (ret) {
+ * debug("%s: Could not set sleep pull value\n", __func__);
+ * return ret;
+ * }
+ */
+ ret = gpio_request_by_name(dev, "reset-gpios", 0, &uc_priv->reset,
+ GPIOD_IS_OUT);
+ if (ret) {
+ debug("%s: Could not decode reset-gpios (%d)\n", __func__, ret);
+ return ret;
+ }
+ /*
+ * Drop this for now as we do not have driver model pinctrl support
+ *
+ * ret = dm_gpio_set_pull(&uc_priv->reset, GPIO_PULL_NONE);
+ * if (ret) {
+ * debug("%s: Could not set reset pull value\n", __func__);
+ * return ret;
+ * }
+ */
+ ret = gpio_request_by_name(dev, "hotplug-gpios", 0, &uc_priv->hotplug,
+ GPIOD_IS_IN);
+ if (ret && ret != -ENOENT) {
+ debug("%s: Could not decode hotplug (%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int video_bridge_set_active(struct udevice *dev, bool active)
+{
+ struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ debug("%s: %d\n", __func__, active);
+ ret = dm_gpio_set_value(&uc_priv->sleep, !active);
+ if (ret)
+ return ret;
+ if (active) {
+ ret = dm_gpio_set_value(&uc_priv->reset, true);
+ if (ret)
+ return ret;
+ udelay(10);
+ ret = dm_gpio_set_value(&uc_priv->reset, false);
+ }
+
+ return ret;
+}
+
+UCLASS_DRIVER(video_bridge) = {
+ .id = UCLASS_VIDEO_BRIDGE,
+ .name = "video_bridge",
+ .per_device_auto_alloc_size = sizeof(struct video_bridge_priv),
+ .pre_probe = video_bridge_pre_probe,
+};
diff --git a/drivers/video/exynos_dp.c b/drivers/video/exynos_dp.c
index f60b060ec1..5b6fc140e0 100644
--- a/drivers/video/exynos_dp.c
+++ b/drivers/video/exynos_dp.c
@@ -22,8 +22,6 @@
DECLARE_GLOBAL_DATA_PTR;
-static struct exynos_dp_platform_data *dp_pd;
-
void __exynos_set_dp_phy(unsigned int onoff)
{
}
@@ -851,7 +849,6 @@ static unsigned int exynos_dp_config_video(struct edp_device_info *edp_info)
return ret;
}
-#ifdef CONFIG_OF_CONTROL
int exynos_dp_parse_dt(const void *blob, struct edp_device_info *edp_info)
{
unsigned int node = fdtdec_next_compatible(blob, 0,
@@ -905,7 +902,6 @@ int exynos_dp_parse_dt(const void *blob, struct edp_device_info *edp_info)
"samsung,color-depth", 0);
return 0;
}
-#endif
unsigned int exynos_init_dp(void)
{
@@ -918,16 +914,8 @@ unsigned int exynos_init_dp(void)
return -EFAULT;
}
-#ifdef CONFIG_OF_CONTROL
if (exynos_dp_parse_dt(gd->fdt_blob, edp_info))
debug("unable to parse DP DT node\n");
-#else
- edp_info = dp_pd->edp_dev_info;
- if (edp_info == NULL) {
- debug("failed to get edp_info data.\n");
- return -EFAULT;
- }
-#endif
exynos_dp_set_base_addr();
@@ -967,17 +955,7 @@ unsigned int exynos_init_dp(void)
return ret;
}
- printf("Exynos DP init done\n");
+ debug("Exynos DP init done\n");
return ret;
}
-
-void exynos_set_dp_platform_data(struct exynos_dp_platform_data *pd)
-{
- if (pd == NULL) {
- debug("pd is NULL\n");
- return;
- }
-
- dp_pd = pd;
-}
diff --git a/drivers/video/exynos_dp_lowlevel.c b/drivers/video/exynos_dp_lowlevel.c
index bf0ea108e8..05118f801b 100644
--- a/drivers/video/exynos_dp_lowlevel.c
+++ b/drivers/video/exynos_dp_lowlevel.c
@@ -823,7 +823,7 @@ int exynos_dp_read_bytes_from_i2c(unsigned int device_addr,
reg = readl(&dp_regs->aux_rx_comm);
if (reg == AUX_RX_COMM_AUX_DEFER ||
reg == AUX_RX_COMM_I2C_DEFER) {
- printf("DP Defer: %d\n\n", reg);
+ printf("DP Defer: %d\n", reg);
defer = 1;
}
}
diff --git a/drivers/video/parade.c b/drivers/video/parade.c
deleted file mode 100644
index ae5097160f..0000000000
--- a/drivers/video/parade.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-/*
- * This file is a driver for Parade dP<->LVDS bridges. The original submission
- * is for the ps8625 chip.
- */
-#include <config.h>
-#include <common.h>
-#include <i2c.h>
-#include <fdtdec.h>
-#include <asm/gpio.h>
-
-/*
- * Initialization of the chip is a process of writing certaing values into
- * certain registers over i2c bus. The chip in fact responds to a range of
- * addresses on the i2c bus, so for each written value three parameters are
- * required: i2c address, register address and the actual value.
- *
- * The base address is derived from the device tree, only address offset is
- * stored in the table below.
- */
-/**
- * struct reg_data() - data for a parade register write
- *
- * @addr_off offset from the i2c base address for parade
- * @reg_addr register address to write
- * @value value to be written
- */
-struct reg_data {
- uint8_t addr_off;
- uint8_t reg;
- uint8_t value;
-} _packed;
-
-#define END_OF_TABLE 0xff /* Ficticious offset */
-
-static const struct reg_data parade_values[] = {
- {0x02, 0xa1, 0x01}, /* HPD low */
- /*
- * SW setting
- * [1:0] SW output 1.2V voltage is lower to 96%
- */
- {0x04, 0x14, 0x01},
- /*
- * RCO SS setting
- * [5:4] = b01 0.5%, b10 1%, b11 1.5%
- */
- {0x04, 0xe3, 0x20},
- {0x04, 0xe2, 0x80}, /* [7] RCO SS enable */
- /*
- * RPHY Setting
- * [3:2] CDR tune wait cycle before
- * measure for fine tune b00: 1us,
- * 01: 0.5us, 10:2us, 11:4us.
- */
- {0x04, 0x8a, 0x0c},
- {0x04, 0x89, 0x08}, /* [3] RFD always on */
- /*
- * CTN lock in/out:
- * 20000ppm/80000ppm. Lock out 2
- * times.
- */
- {0x04, 0x71, 0x2d},
- /*
- * 2.7G CDR settings
- * NOF=40LSB for HBR CDR setting
- */
- {0x04, 0x7d, 0x07},
- {0x04, 0x7b, 0x00}, /* [1:0] Fmin=+4bands */
- {0x04, 0x7a, 0xfd}, /* [7:5] DCO_FTRNG=+-40% */
- /*
- * 1.62G CDR settings
- * [5:2]NOF=64LSB [1:0]DCO scale is 2/5
- */
- {0x04, 0xc0, 0x12},
- {0x04, 0xc1, 0x92}, /* Gitune=-37% */
- {0x04, 0xc2, 0x1c}, /* Fbstep=100% */
- {0x04, 0x32, 0x80}, /* [7] LOS signal disable */
- /*
- * RPIO Setting
- * [7:4] LVDS driver bias current :
- * 75% (250mV swing)
- */
- {0x04, 0x00, 0xb0},
- /*
- * [7:6] Right-bar GPIO output strength is 8mA
- */
- {0x04, 0x15, 0x40},
- /* EQ Training State Machine Setting */
- {0x04, 0x54, 0x10}, /* RCO calibration start */
- /* [4:0] MAX_LANE_COUNT set to one lane */
- {0x01, 0x02, 0x81},
- /* [4:0] LANE_COUNT_SET set to one lane */
- {0x01, 0x21, 0x81},
- {0x00, 0x52, 0x20},
- {0x00, 0xf1, 0x03}, /* HPD CP toggle enable */
- {0x00, 0x62, 0x41},
- /* Counter number, add 1ms counter delay */
- {0x00, 0xf6, 0x01},
- /*
- * [6]PWM function control by
- * DPCD0040f[7], default is PWM
- * block always works.
- */
- {0x00, 0x77, 0x06},
- /*
- * 04h Adjust VTotal tolerance to
- * fix the 30Hz no display issue
- */
- {0x00, 0x4c, 0x04},
- /* DPCD00400='h00, Parade OUI = 'h001cf8 */
- {0x01, 0xc0, 0x00},
- {0x01, 0xc1, 0x1c}, /* DPCD00401='h1c */
- {0x01, 0xc2, 0xf8}, /* DPCD00402='hf8 */
- /*
- * DPCD403~408 = ASCII code
- * D2SLV5='h4432534c5635
- */
- {0x01, 0xc3, 0x44},
- {0x01, 0xc4, 0x32}, /* DPCD404 */
- {0x01, 0xc5, 0x53}, /* DPCD405 */
- {0x01, 0xc6, 0x4c}, /* DPCD406 */
- {0x01, 0xc7, 0x56}, /* DPCD407 */
- {0x01, 0xc8, 0x35}, /* DPCD408 */
- /*
- * DPCD40A, Initial Code major revision
- * '01'
- */
- {0x01, 0xca, 0x01},
- /* DPCD40B, Initial Code minor revision '05' */
- {0x01, 0xcb, 0x05},
- /* DPCD720, Select internal PWM */
- {0x01, 0xa5, 0xa0},
- /*
- * FFh for 100% PWM of brightness, 0h for 0%
- * brightness
- */
- {0x01, 0xa7, 0xff},
- /*
- * Set LVDS output as 6bit-VESA mapping,
- * single LVDS channel
- */
- {0x01, 0xcc, 0x13},
- /* Enable SSC set by register */
- {0x02, 0xb1, 0x20},
- /*
- * Set SSC enabled and +/-1% central
- * spreading
- */
- {0x04, 0x10, 0x16},
- /* MPU Clock source: LC => RCO */
- {0x04, 0x59, 0x60},
- {0x04, 0x54, 0x14}, /* LC -> RCO */
- {0x02, 0xa1, 0x91}, /* HPD high */
- {END_OF_TABLE}
-};
-
-/**
- * Write values table into the Parade eDP bridge
- *
- * @return 0 on success, non-0 on failure
- */
-
-static int parade_write_regs(int base_addr, const struct reg_data *table)
-{
- int ret = 0;
-
- while (!ret && (table->addr_off != END_OF_TABLE)) {
- ret = i2c_write(base_addr + table->addr_off,
- table->reg, 1,
- (uint8_t *)&table->value,
- sizeof(table->value));
- table++;
- }
- return ret;
-}
-
-int parade_init(const void *blob)
-{
- struct gpio_desc rst_gpio;
- struct gpio_desc slp_gpio;
- int bus, old_bus;
- int parent;
- int node;
- int addr;
- int ret;
-
- node = fdtdec_next_compatible(blob, 0, COMPAT_PARADE_PS8625);
- if (node < 0)
- return 0;
-
- parent = fdt_parent_offset(blob, node);
- if (parent < 0) {
- debug("%s: Could not find parent i2c node\n", __func__);
- return -1;
- }
- addr = fdtdec_get_int(blob, node, "reg", -1);
- if (addr < 0) {
- debug("%s: Could not find i2c address\n", __func__);
- return -1;
- }
-
- gpio_request_by_name_nodev(blob, node, "sleep-gpio", 0, &slp_gpio,
- GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
-
- mdelay(10);
-
- gpio_request_by_name_nodev(blob, node, "reset-gpio", 0, &rst_gpio,
- GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
-
- bus = i2c_get_bus_num_fdt(parent);
- old_bus = i2c_get_bus_num();
-
- debug("%s: Using i2c bus %d\n", __func__, bus);
-
- /*
- * TODO(sjg@chromium.org): Hmmm we seem to need some sort of delay
- * here.
- */
- mdelay(40);
- i2c_set_bus_num(bus);
- ret = parade_write_regs(addr, parade_values);
-
- i2c_set_bus_num(old_bus);
-
- return ret;
-}
diff --git a/drivers/video/tegra.c b/drivers/video/tegra.c
index b8f3431f24..33c6103994 100644
--- a/drivers/video/tegra.c
+++ b/drivers/video/tegra.c
@@ -92,7 +92,7 @@ void lcd_ctrl_init(void *lcdbase)
/* Enable flushing after LCD writes if requested */
lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH);
- debug("LCD frame buffer at %08X\n", disp_config->frame_buffer);
+ debug("LCD frame buffer at %pa\n", &disp_config->frame_buffer);
}
ulong calc_fbsize(void)
diff --git a/include/configs/arndale.h b/include/configs/arndale.h
index 3ad4a9ba91..8784c4e38d 100644
--- a/include/configs/arndale.h
+++ b/include/configs/arndale.h
@@ -13,6 +13,7 @@
"fdtfile=exynos5250-arndale.dtb\0"
#include "exynos5250-common.h"
+#include <configs/exynos5-common.h>
/* SD/MMC configuration */
#define CONFIG_SUPPORT_EMMC_BOOT
@@ -20,15 +21,6 @@
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
-/* USB */
-#define CONFIG_USB_EHCI
-#define CONFIG_USB_EHCI_EXYNOS
-
-#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3
-#define CONFIG_USB_HOST_ETHER
-#define CONFIG_USB_ETHER_ASIX
-#define CONFIG_USB_ETHER_ASIX88179
-
/* MMC SPL */
#define CONFIG_EXYNOS_SPL
@@ -36,9 +28,6 @@
#define CONFIG_SYS_PROMPT "ARNDALE # "
#define CONFIG_DEFAULT_CONSOLE "console=ttySAC2,115200n8\0"
-#define CONFIG_NR_DRAM_BANKS 8
-#define SDRAM_BANK_SIZE (256UL << 20UL) /* 256 MB */
-
#define CONFIG_IDENT_STRING " for ARNDALE"
#define CONFIG_ENV_IS_IN_MMC
@@ -49,6 +38,7 @@
#define CONFIG_SYS_INIT_SP_ADDR CONFIG_IRAM_STACK
/* PMIC */
+#define CONFIG_POWER
#define CONFIG_PMIC
#define CONFIG_POWER_I2C
@@ -60,4 +50,8 @@
/* The PERIPHBASE in the CBAR register is wrong on the Arndale, so override it */
#define CONFIG_ARM_GIC_BASE_ADDRESS 0x10480000
+/* Power */
+#define CONFIG_POWER
+#define CONFIG_POWER_I2C
+
#endif /* __CONFIG_H */
diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h
index e04dec7411..e710f41f79 100644
--- a/include/configs/exynos5-common.h
+++ b/include/configs/exynos5-common.h
@@ -67,6 +67,8 @@
#define CONFIG_SPL_LIBCOMMON_SUPPORT
#define CONFIG_SPL_GPIO_SUPPORT
+#define CONFIG_SPL_SERIAL_SUPPORT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
/* specific .lds file */
#define CONFIG_SPL_LDSCRIPT "board/samsung/common/exynos-uboot-spl.lds"
@@ -126,10 +128,6 @@
#define SPI_FLASH_UBOOT_POS (CONFIG_SEC_FW_SIZE + CONFIG_BL1_SIZE)
/* I2C */
-
-/* TODO(sjg@chromium.org): Move these two options to Kconfig */
-#define CONFIG_DM_I2C
-#define CONFIG_DM_I2C_COMPAT
#define CONFIG_CMD_I2C
#define CONFIG_SYS_I2C_S3C24X0
#define CONFIG_SYS_I2C_S3C24X0_SPEED 100000 /* 100 Kbps */
@@ -145,14 +143,8 @@
#define CONFIG_SPI_FLASH_GIGADEVICE
#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0
#define CONFIG_SF_DEFAULT_SPEED 50000000
-#define EXYNOS5_SPI_NUM_CONTROLLERS 5
-#define CONFIG_OF_SPI
#endif
-/* Power */
-#define CONFIG_POWER
-#define CONFIG_POWER_I2C
-
#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
#define CONFIG_ENV_SPI_MODE SPI_MODE_0
#define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE
@@ -200,7 +192,6 @@
#define CONFIG_FIT
#define CONFIG_FIT_BEST_MATCH
-
#define BOOT_TARGET_DEVICES(func) \
func(MMC, mmc, 1) \
func(MMC, mmc, 0) \
diff --git a/include/configs/exynos5-dt-common.h b/include/configs/exynos5-dt-common.h
index b1b8e1ace7..8b61a52c5a 100644
--- a/include/configs/exynos5-dt-common.h
+++ b/include/configs/exynos5-dt-common.h
@@ -16,12 +16,23 @@
"stdout=serial,lcd\0" \
"stderr=serial,lcd\0"
-#include "exynos5-common.h"
+#define CONFIG_EXYNOS5_DT
-/* PMIC */
-#define CONFIG_POWER
-#define CONFIG_POWER_I2C
-#define CONFIG_POWER_TPS65090
+#define CONFIG_ENV_IS_IN_SPI_FLASH
+#define CONFIG_ENV_SPI_BASE 0x12D30000
+#define FLASH_SIZE (4 << 20)
+#define CONFIG_ENV_OFFSET (FLASH_SIZE - CONFIG_ENV_SECT_SIZE)
+#define CONFIG_SPI_BOOTING
+
+#define CONFIG_BOARD_COMMON
+
+/* Display */
+#define CONFIG_LCD
+#ifdef CONFIG_LCD
+#define CONFIG_EXYNOS_FB
+#define CONFIG_EXYNOS_DP
+#define LCD_BPP LCD_COLOR16
+#endif
/* Enable keyboard */
#define CONFIG_KEYBOARD
diff --git a/include/configs/exynos5250-common.h b/include/configs/exynos5250-common.h
index 95e96ecde4..7d8921f24e 100644
--- a/include/configs/exynos5250-common.h
+++ b/include/configs/exynos5250-common.h
@@ -10,7 +10,6 @@
#ifndef __CONFIG_5250_H
#define __CONFIG_5250_H
-#include <configs/exynos5-common.h>
#define CONFIG_EXYNOS5250
#define CONFIG_SYS_SDRAM_BASE 0x40000000
@@ -28,16 +27,13 @@
#define CONFIG_SYS_INIT_SP_ADDR CONFIG_IRAM_STACK
-/* I2C */
-#define CONFIG_MAX_I2C_NUM 8
+/* USB */
+#define CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_EXYNOS
-/* Display */
-#define CONFIG_LCD
-#ifdef CONFIG_LCD
-#define CONFIG_EXYNOS_FB
-#define CONFIG_EXYNOS_DP
-#define LCD_BPP LCD_COLOR16
-#endif
+#define CONFIG_USB_HOST_ETHER
+#define CONFIG_USB_ETHER_ASIX
+#define CONFIG_USB_ETHER_ASIX88179
/* DRAM Memory Banks */
#define CONFIG_NR_DRAM_BANKS 8
diff --git a/include/configs/exynos5420-common.h b/include/configs/exynos5420-common.h
index 3b1ac2cecd..cd86e06668 100644
--- a/include/configs/exynos5420-common.h
+++ b/include/configs/exynos5420-common.h
@@ -13,7 +13,7 @@
/* A variant of Exynos5420 (Exynos5 Family) */
#define CONFIG_EXYNOS5800
-#include <configs/exynos5-common.h>
+#define CONFIG_EXYNOS5_DT
#define MACH_TYPE_SMDK5420 8002
#define CONFIG_MACH_TYPE MACH_TYPE_SMDK5420
@@ -32,10 +32,6 @@
#define CONFIG_DEVICE_TREE_LIST "exynos5800-peach-pi" \
"exynos5420-peach-pit exynos5420-smdk5420"
-#define CONFIG_MAX_I2C_NUM 11
-
-#define CONFIG_BOARD_REV_GPIO_COUNT 2
-
#define CONFIG_PHY_IRAM_BASE 0x02020000
/* Address for relocating helper code (Last 4 KB of IRAM) */
@@ -52,4 +48,7 @@
*/
#define CONFIG_CORE_COUNT 0x8
+#define CONFIG_USB_XHCI
+#define CONFIG_USB_XHCI_EXYNOS
+
#endif /* __CONFIG_EXYNOS5420_H */
diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h
index 8d5c736cc7..0deff46026 100644
--- a/include/configs/odroid_xu3.h
+++ b/include/configs/odroid_xu3.h
@@ -9,7 +9,9 @@
#define __CONFIG_ODROID_XU3_H
#include "exynos5420-common.h"
+#include <configs/exynos5-common.h>
+#undef CONFIG_ENV_IS_IN_SPI_FLASH
#define CONFIG_SYS_PROMPT "ODROID-XU3 # "
#define CONFIG_IDENT_STRING " for ODROID-XU3"
diff --git a/include/configs/peach-pi.h b/include/configs/peach-pi.h
index 46699ff635..0f5e9feeac 100644
--- a/include/configs/peach-pi.h
+++ b/include/configs/peach-pi.h
@@ -9,12 +9,6 @@
#ifndef __CONFIG_PEACH_PI_H
#define __CONFIG_PEACH_PI_H
-#define CONFIG_ENV_IS_IN_SPI_FLASH
-#define CONFIG_ENV_SPI_BASE 0x12D30000
-#define FLASH_SIZE (0x4 << 20)
-#define CONFIG_ENV_OFFSET (FLASH_SIZE - CONFIG_BL2_SIZE)
-#define CONFIG_SPI_BOOTING
-
#define MEM_LAYOUT_ENV_SETTINGS \
"bootm_size=0x10000000\0" \
"kernel_addr_r=0x22000000\0" \
@@ -25,8 +19,7 @@
#include <configs/exynos5420-common.h>
#include <configs/exynos5-dt-common.h>
-
-#define CONFIG_BOARD_COMMON
+#include <configs/exynos5-common.h>
#define CONFIG_SYS_SDRAM_BASE 0x20000000
#define CONFIG_SYS_TEXT_BASE 0x23E00000
@@ -39,8 +32,6 @@
#define CONFIG_SYS_PROMPT "Peach-Pi # "
#define CONFIG_IDENT_STRING " for Peach-Pi"
-#define CONFIG_VIDEO_PARADE
-
/* Display */
#define CONFIG_LCD
#ifdef CONFIG_LCD
@@ -51,9 +42,6 @@
#define CONFIG_POWER_TPS65090_EC
-#define CONFIG_USB_XHCI
-#define CONFIG_USB_XHCI_EXYNOS
-
/* DRAM Memory Banks */
#define CONFIG_NR_DRAM_BANKS 7
#define SDRAM_BANK_SIZE (512UL << 20UL) /* 512 MB */
diff --git a/include/configs/peach-pit.h b/include/configs/peach-pit.h
index c5c9e3aa38..f2594345c3 100644
--- a/include/configs/peach-pit.h
+++ b/include/configs/peach-pit.h
@@ -9,12 +9,6 @@
#ifndef __CONFIG_PEACH_PIT_H
#define __CONFIG_PEACH_PIT_H
-#define CONFIG_ENV_IS_IN_SPI_FLASH
-#define CONFIG_ENV_SPI_BASE 0x12D30000
-#define FLASH_SIZE (0x4 << 20)
-#define CONFIG_ENV_OFFSET (FLASH_SIZE - CONFIG_BL2_SIZE)
-#define CONFIG_SPI_BOOTING
-
#define MEM_LAYOUT_ENV_SETTINGS \
"bootm_size=0x10000000\0" \
"kernel_addr_r=0x22000000\0" \
@@ -25,8 +19,7 @@
#include <configs/exynos5420-common.h>
#include <configs/exynos5-dt-common.h>
-
-#define CONFIG_BOARD_COMMON
+#include <configs/exynos5-common.h>
#define CONFIG_SYS_SDRAM_BASE 0x20000000
#define CONFIG_SYS_TEXT_BASE 0x23E00000
@@ -39,21 +32,6 @@
#define CONFIG_SYS_PROMPT "Peach-Pit # "
#define CONFIG_IDENT_STRING " for Peach-Pit"
-#define CONFIG_VIDEO_PARADE
-
-/* Display */
-#define CONFIG_LCD
-#ifdef CONFIG_LCD
-#define CONFIG_EXYNOS_FB
-#define CONFIG_EXYNOS_DP
-#define LCD_BPP LCD_COLOR16
-#endif
-
-#define CONFIG_POWER_TPS65090_EC
-
-#define CONFIG_USB_XHCI
-#define CONFIG_USB_XHCI_EXYNOS
-
/* DRAM Memory Banks */
#define CONFIG_NR_DRAM_BANKS 4
#define SDRAM_BANK_SIZE (512UL << 20UL) /* 512 MB */
diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h
index e5655fce19..82d41ccfbb 100644
--- a/include/configs/smdk5250.h
+++ b/include/configs/smdk5250.h
@@ -9,26 +9,16 @@
#ifndef __CONFIG_SMDK_H
#define __CONFIG_SMDK_H
-#define CONFIG_ENV_IS_IN_SPI_FLASH
-#define CONFIG_ENV_SPI_BASE 0x12D30000
-#define FLASH_SIZE (0x4 << 20)
-#define CONFIG_ENV_OFFSET (FLASH_SIZE - CONFIG_BL2_SIZE)
-#define CONFIG_SPI_BOOTING
-
#include <configs/exynos5250-common.h>
+#include <configs/exynos5-dt-common.h>
+#include <configs/exynos5-common.h>
-/* PMIC */
-#define CONFIG_POWER_MAX77686
+#undef CONFIG_KEYBOARD
#define CONFIG_BOARD_COMMON
-#define CONFIG_USB_XHCI
-#define CONFIG_USB_XHCI_EXYNOS
-
#define CONFIG_SYS_PROMPT "SMDK5250 # "
#define CONFIG_IDENT_STRING " for SMDK5250"
-
-/* Miscellaneous configurable options */
#define CONFIG_DEFAULT_CONSOLE "console=ttySAC1,115200n8\0"
#endif /* __CONFIG_SMDK_H */
diff --git a/include/configs/smdk5420.h b/include/configs/smdk5420.h
index 607877c95d..623efa8a62 100644
--- a/include/configs/smdk5420.h
+++ b/include/configs/smdk5420.h
@@ -9,13 +9,11 @@
#ifndef __CONFIG_SMDK5420_H
#define __CONFIG_SMDK5420_H
-#define CONFIG_ENV_IS_IN_SPI_FLASH
-#define CONFIG_ENV_SPI_BASE 0x12D30000
-#define FLASH_SIZE (0x4 << 20)
-#define CONFIG_ENV_OFFSET (FLASH_SIZE - CONFIG_BL2_SIZE)
-#define CONFIG_SPI_BOOTING
-
#include <configs/exynos5420-common.h>
+#include <configs/exynos5-dt-common.h>
+#include <configs/exynos5-common.h>
+
+#undef CONFIG_KEYBOARD
#define CONFIG_BOARD_COMMON
diff --git a/include/configs/snow.h b/include/configs/snow.h
index 557f86c07c..bf3377cb10 100644
--- a/include/configs/snow.h
+++ b/include/configs/snow.h
@@ -9,25 +9,12 @@
#ifndef __CONFIG_SNOW_H
#define __CONFIG_SNOW_H
-#define CONFIG_ENV_IS_IN_SPI_FLASH
-#define CONFIG_ENV_SPI_BASE 0x12D30000
-#define FLASH_SIZE (0x4 << 20)
-#define CONFIG_ENV_OFFSET (FLASH_SIZE - CONFIG_BL2_SIZE)
-#define CONFIG_SPI_BOOTING
-
#include <configs/exynos5250-common.h>
#include <configs/exynos5-dt-common.h>
-
-
-#define CONFIG_POWER_TPS65090_I2C
+#include <configs/exynos5-common.h>
#define CONFIG_BOARD_COMMON
-#define CONFIG_USB_XHCI
-#define CONFIG_USB_EHCI
-#define CONFIG_USB_XHCI_EXYNOS
-#define CONFIG_USB_EHCI_EXYNOS
-
#define CONFIG_SYS_PROMPT "snow # "
#define CONFIG_IDENT_STRING " for snow"
#define CONFIG_DEFAULT_CONSOLE "console=ttySAC1,115200n8\0"
diff --git a/include/configs/spring.h b/include/configs/spring.h
new file mode 100644
index 0000000000..a692dfd7ec
--- /dev/null
+++ b/include/configs/spring.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_SPRING_H
+#define __CONFIG_SPRING_H
+
+#include <configs/exynos5250-common.h>
+#include <configs/exynos5-dt-common.h>
+#include <configs/exynos5-common.h>
+
+#define CONFIG_BOARD_COMMON
+
+#define CONFIG_SYS_PROMPT "spring # "
+#define CONFIG_IDENT_STRING " for spring"
+#define CONFIG_DEFAULT_CONSOLE "console=ttySAC1,115200n8\0"
+
+#endif /* __CONFIG_SPRING_H */
diff --git a/include/cros_ec.h b/include/cros_ec.h
index 3b2be2c2fa..b9269341c3 100644
--- a/include/cros_ec.h
+++ b/include/cros_ec.h
@@ -350,7 +350,7 @@ int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp);
* @param state new state of the LDO/FET : EC_LDO_STATE_ON|OFF
* @return 0 if ok, -1 on error
*/
-int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state);
+int cros_ec_set_ldo(struct udevice *dev, uint8_t index, uint8_t state);
/**
* Read back a LDO / FET current state.
@@ -360,7 +360,7 @@ int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state);
* @param state current state of the LDO/FET : EC_LDO_STATE_ON|OFF
* @return 0 if ok, -1 on error
*/
-int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state);
+int cros_ec_get_ldo(struct udevice *dev, uint8_t index, uint8_t *state);
/**
* Get access to the error reported when cros_ec_board_init() was called
@@ -390,18 +390,14 @@ int cros_ec_decode_ec_flash(const void *blob, int node,
*/
void cros_ec_check_keyboard(struct cros_ec_dev *dev);
+struct i2c_msg;
/*
* Tunnel an I2C transfer to the EC
*
* @param dev CROS-EC device
- * @param chip Chip address (7-bit I2C address)
- * @param addr Register address to read/write
- * @param alen Length of register address in bytes
- * @param buffer Buffer containing data to read/write
- * @param len Length of buffer
- * @param is_read 1 if this is a read, 0 if this is a write
+ * @param msg List of messages to transfer
+ * @param nmsgs Number of messages to transfer
*/
-int cros_ec_i2c_xfer(struct cros_ec_dev *dev, uchar chip, uint addr,
- int alen, uchar *buffer, int len, int is_read);
+int cros_ec_i2c_tunnel(struct udevice *dev, struct i2c_msg *msg, int nmsgs);
#endif
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 402304f19e..2cd2fe91d8 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -139,8 +139,52 @@ void device_free(struct udevice *dev);
static inline void device_free(struct udevice *dev) {}
#endif
+/**
+ * simple_bus_translate() - translate a bus address to a system address
+ *
+ * This handles the 'ranges' property in a simple bus. It translates the
+ * device address @addr to a system address using this property.
+ *
+ * @dev: Simple bus device (parent of target device)
+ * @addr: Address to translate
+ * @return new address
+ */
+fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr);
+
/* Cast away any volatile pointer */
#define DM_ROOT_NON_CONST (((gd_t *)gd)->dm_root)
#define DM_UCLASS_ROOT_NON_CONST (((gd_t *)gd)->uclass_root)
+/* device resource management */
+#ifdef CONFIG_DEVRES
+
+/**
+ * devres_release_probe - Release managed resources allocated after probing
+ * @dev: Device to release resources for
+ *
+ * Release all resources allocated for @dev when it was probed or later.
+ * This function is called on driver removal.
+ */
+void devres_release_probe(struct udevice *dev);
+
+/**
+ * devres_release_all - Release all managed resources
+ * @dev: Device to release resources for
+ *
+ * Release all resources associated with @dev. This function is
+ * called on driver unbinding.
+ */
+void devres_release_all(struct udevice *dev);
+
+#else /* ! CONFIG_DEVRES */
+
+static inline void devres_release_probe(struct udevice *dev)
+{
+}
+
+static inline void devres_release_all(struct udevice *dev)
+{
+}
+
+#endif /* ! CONFIG_DEVRES */
#endif
diff --git a/include/dm/device.h b/include/dm/device.h
index 12fd02d09a..1f78963803 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -14,6 +14,8 @@
#include <dm/uclass-id.h>
#include <fdtdec.h>
#include <linker_lists.h>
+#include <linux/compat.h>
+#include <linux/kernel.h>
#include <linux/list.h>
struct driver_info;
@@ -36,6 +38,9 @@ struct driver_info;
/* Allocate driver private data on a DMA boundary */
#define DM_FLAG_ALLOC_PRIV_DMA (1 << 5)
+/* Device is bound */
+#define DM_FLAG_BOUND (1 << 6)
+
/**
* struct udevice - An instance of a driver
*
@@ -93,6 +98,9 @@ struct udevice {
uint32_t flags;
int req_seq;
int seq;
+#ifdef CONFIG_DEVRES
+ struct list_head devres_head;
+#endif
};
/* Maximum sequence number supported */
@@ -462,4 +470,280 @@ bool device_has_active_children(struct udevice *dev);
*/
bool device_is_last_sibling(struct udevice *dev);
+/**
+ * device_set_name() - set the name of a device
+ *
+ * This must be called in the device's bind() method and no later. Normally
+ * this is unnecessary but for probed devices which don't get a useful name
+ * this function can be helpful.
+ *
+ * @dev: Device to update
+ * @name: New name (this string is allocated new memory and attached to
+ * the device)
+ * @return 0 if OK, -ENOMEM if there is not enough memory to allocate the
+ * string
+ */
+int device_set_name(struct udevice *dev, const char *name);
+
+/* device resource management */
+typedef void (*dr_release_t)(struct udevice *dev, void *res);
+typedef int (*dr_match_t)(struct udevice *dev, void *res, void *match_data);
+
+#ifdef CONFIG_DEVRES
+
+#ifdef CONFIG_DEBUG_DEVRES
+void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
+ const char *name);
+#define _devres_alloc(release, size, gfp) \
+ __devres_alloc(release, size, gfp, #release)
+#else
+void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp);
+#endif
+
+/**
+ * devres_alloc - Allocate device resource data
+ * @release: Release function devres will be associated with
+ * @size: Allocation size
+ * @gfp: Allocation flags
+ *
+ * Allocate devres of @size bytes. The allocated area is associated
+ * with @release. The returned pointer can be passed to
+ * other devres_*() functions.
+ *
+ * RETURNS:
+ * Pointer to allocated devres on success, NULL on failure.
+ */
+#define devres_alloc(release, size, gfp) \
+ _devres_alloc(release, size, gfp | __GFP_ZERO)
+
+/**
+ * devres_free - Free device resource data
+ * @res: Pointer to devres data to free
+ *
+ * Free devres created with devres_alloc().
+ */
+void devres_free(void *res);
+
+/**
+ * devres_add - Register device resource
+ * @dev: Device to add resource to
+ * @res: Resource to register
+ *
+ * Register devres @res to @dev. @res should have been allocated
+ * using devres_alloc(). On driver detach, the associated release
+ * function will be invoked and devres will be freed automatically.
+ */
+void devres_add(struct udevice *dev, void *res);
+
+/**
+ * devres_find - Find device resource
+ * @dev: Device to lookup resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev which is associated with @release
+ * and for which @match returns 1. If @match is NULL, it's considered
+ * to match all.
+ *
+ * RETURNS:
+ * Pointer to found devres, NULL if not found.
+ */
+void *devres_find(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data);
+
+/**
+ * devres_get - Find devres, if non-existent, add one atomically
+ * @dev: Device to lookup or add devres for
+ * @new_res: Pointer to new initialized devres to add if not found
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev which has the same release function
+ * as @new_res and for which @match return 1. If found, @new_res is
+ * freed; otherwise, @new_res is added atomically.
+ *
+ * RETURNS:
+ * Pointer to found or added devres.
+ */
+void *devres_get(struct udevice *dev, void *new_res,
+ dr_match_t match, void *match_data);
+
+/**
+ * devres_remove - Find a device resource and remove it
+ * @dev: Device to find resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev associated with @release and for
+ * which @match returns 1. If @match is NULL, it's considered to
+ * match all. If found, the resource is removed atomically and
+ * returned.
+ *
+ * RETURNS:
+ * Pointer to removed devres on success, NULL if not found.
+ */
+void *devres_remove(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data);
+
+/**
+ * devres_destroy - Find a device resource and destroy it
+ * @dev: Device to find resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev associated with @release and for
+ * which @match returns 1. If @match is NULL, it's considered to
+ * match all. If found, the resource is removed atomically and freed.
+ *
+ * Note that the release function for the resource will not be called,
+ * only the devres-allocated data will be freed. The caller becomes
+ * responsible for freeing any other data.
+ *
+ * RETURNS:
+ * 0 if devres is found and freed, -ENOENT if not found.
+ */
+int devres_destroy(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data);
+
+/**
+ * devres_release - Find a device resource and destroy it, calling release
+ * @dev: Device to find resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev associated with @release and for
+ * which @match returns 1. If @match is NULL, it's considered to
+ * match all. If found, the resource is removed atomically, the
+ * release function called and the resource freed.
+ *
+ * RETURNS:
+ * 0 if devres is found and freed, -ENOENT if not found.
+ */
+int devres_release(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data);
+
+/* managed devm_k.alloc/kfree for device drivers */
+/**
+ * devm_kmalloc - Resource-managed kmalloc
+ * @dev: Device to allocate memory for
+ * @size: Allocation size
+ * @gfp: Allocation gfp flags
+ *
+ * Managed kmalloc. Memory allocated with this function is
+ * automatically freed on driver detach. Like all other devres
+ * resources, guaranteed alignment is unsigned long long.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp);
+static inline void *devm_kzalloc(struct udevice *dev, size_t size, gfp_t gfp)
+{
+ return devm_kmalloc(dev, size, gfp | __GFP_ZERO);
+}
+static inline void *devm_kmalloc_array(struct udevice *dev,
+ size_t n, size_t size, gfp_t flags)
+{
+ if (size != 0 && n > SIZE_MAX / size)
+ return NULL;
+ return devm_kmalloc(dev, n * size, flags);
+}
+static inline void *devm_kcalloc(struct udevice *dev,
+ size_t n, size_t size, gfp_t flags)
+{
+ return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
+}
+
+/**
+ * devm_kfree - Resource-managed kfree
+ * @dev: Device this memory belongs to
+ * @p: Memory to free
+ *
+ * Free memory allocated with devm_kmalloc().
+ */
+void devm_kfree(struct udevice *dev, void *p);
+
+#else /* ! CONFIG_DEVRES */
+
+static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
+{
+ return kzalloc(size, gfp);
+}
+
+static inline void devres_free(void *res)
+{
+ kfree(res);
+}
+
+static inline void devres_add(struct udevice *dev, void *res)
+{
+}
+
+static inline void *devres_find(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ return NULL;
+}
+
+static inline void *devres_get(struct udevice *dev, void *new_res,
+ dr_match_t match, void *match_data)
+{
+ return NULL;
+}
+
+static inline void *devres_remove(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ return NULL;
+}
+
+static inline int devres_destroy(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ return 0;
+}
+
+static inline int devres_release(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ return 0;
+}
+
+static inline void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp)
+{
+ return kmalloc(size, gfp);
+}
+
+static inline void *devm_kzalloc(struct udevice *dev, size_t size, gfp_t gfp)
+{
+ return kzalloc(size, gfp);
+}
+
+static inline void *devm_kmaloc_array(struct udevice *dev,
+ size_t n, size_t size, gfp_t flags)
+{
+ /* TODO: add kmalloc_array() to linux/compat.h */
+ if (size != 0 && n > SIZE_MAX / size)
+ return NULL;
+ return kmalloc(n * size, flags);
+}
+
+static inline void *devm_kcalloc(struct udevice *dev,
+ size_t n, size_t size, gfp_t flags)
+{
+ /* TODO: add kcalloc() to linux/compat.h */
+ return kmalloc(n * size, flags | __GFP_ZERO);
+}
+
+static inline void devm_kfree(struct udevice *dev, void *p)
+{
+ kfree(p);
+}
+
+#endif /* ! CONFIG_DEVRES */
+
#endif
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index bc057d7adf..c744044bb8 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -35,6 +35,7 @@ enum uclass_id {
UCLASS_I2C, /* I2C bus */
UCLASS_I2C_EEPROM, /* I2C EEPROM device */
UCLASS_I2C_GENERIC, /* Generic I2C device */
+ UCLASS_I2C_MUX, /* I2C multiplexer */
UCLASS_LED, /* Light-emitting diode (LED) */
UCLASS_LPC, /* x86 'low pin count' interface */
UCLASS_MASS_STORAGE, /* Mass storage device */
@@ -56,6 +57,7 @@ enum uclass_id {
UCLASS_USB, /* USB bus */
UCLASS_USB_DEV_GENERIC, /* USB generic device */
UCLASS_USB_HUB, /* USB hub */
+ UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */
UCLASS_COUNT,
UCLASS_INVALID = -1,
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 4cfc0df84c..d56877c898 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -130,7 +130,7 @@ int uclass_get(enum uclass_id key, struct uclass **ucp);
int uclass_get_device(enum uclass_id id, int index, struct udevice **devp);
/**
- * uclass_get_device_by_name() - Get a uclass device by it's name
+ * uclass_get_device_by_name() - Get a uclass device by its name
*
* This searches the devices in the uclass for one with the exactly given name.
*
@@ -177,6 +177,23 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node,
struct udevice **devp);
/**
+ * uclass_get_device_by_phandle() - Get a uclass device by phandle
+ *
+ * This searches the devices in the uclass for one with the given phandle.
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @id: uclass ID to look up
+ * @parent: Parent device containing the phandle pointer
+ * @name: Name of property in the parent device node
+ * @devp: Returns pointer to device (there is only one for each node)
+ * @return 0 if OK, -ENOENT if there is no @name present in the node, other
+ * -ve on error
+ */
+int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
+ const char *name, struct udevice **devp);
+
+/**
* uclass_first_device() - Get the first device in a uclass
*
* The device returned is probed if necessary, and ready for use
diff --git a/include/dm/util.h b/include/dm/util.h
index 7dbed6793f..15daa3d19f 100644
--- a/include/dm/util.h
+++ b/include/dm/util.h
@@ -39,4 +39,13 @@ void dm_dump_all(void);
/* Dump out a list of uclasses and their devices */
void dm_dump_uclass(void);
+#ifdef CONFIG_DEBUG_DEVRES
+/* Dump out a list of device resources */
+void dm_dump_devres(void);
+#else
+static inline void dm_dump_devres(void)
+{
+}
+#endif
+
#endif
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 4b3f8d13c3..c9a5c9a9f9 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -21,15 +21,13 @@
* A typedef for a physical address. Note that fdt data is always big
* endian even on a litle endian machine.
*/
+typedef phys_addr_t fdt_addr_t;
+typedef phys_size_t fdt_size_t;
#ifdef CONFIG_PHYS_64BIT
-typedef u64 fdt_addr_t;
-typedef u64 fdt_size_t;
#define FDT_ADDR_T_NONE (-1ULL)
#define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
#define fdt_size_to_cpu(reg) be64_to_cpu(reg)
#else
-typedef u32 fdt_addr_t;
-typedef u32 fdt_size_t;
#define FDT_ADDR_T_NONE (-1U)
#define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
#define fdt_size_to_cpu(reg) be32_to_cpu(reg)
@@ -170,10 +168,7 @@ enum fdt_compat_id {
COMPAT_INFINEON_SLB9645_TPM, /* Infineon SLB9645 TPM */
COMPAT_SAMSUNG_EXYNOS5_I2C, /* Exynos5 High Speed I2C Controller */
COMPAT_SANDBOX_LCD_SDL, /* Sandbox LCD emulation with SDL */
- COMPAT_TI_TPS65090, /* Texas Instrument TPS65090 */
- COMPAT_NXP_PTN3460, /* NXP PTN3460 DP/LVDS bridge */
COMPAT_SAMSUNG_EXYNOS_SYSMMU, /* Exynos sysmmu */
- COMPAT_PARADE_PS8625, /* Parade PS8622 EDP->LVDS bridge */
COMPAT_INTEL_MICROCODE, /* Intel microcode update */
COMPAT_MEMORY_SPD, /* Memory SPD information */
COMPAT_INTEL_PANTHERPOINT_AHCI, /* Intel Pantherpoint AHCI */
diff --git a/include/i2c.h b/include/i2c.h
index 9300d97e14..6493931c35 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -74,6 +74,49 @@ struct dm_i2c_bus {
int speed_hz;
};
+/*
+ * Not all of these flags are implemented in the U-Boot API
+ */
+enum dm_i2c_msg_flags {
+ I2C_M_TEN = 0x0010, /* ten-bit chip address */
+ I2C_M_RD = 0x0001, /* read data, from slave to master */
+ I2C_M_STOP = 0x8000, /* send stop after this message */
+ I2C_M_NOSTART = 0x4000, /* no start before this message */
+ I2C_M_REV_DIR_ADDR = 0x2000, /* invert polarity of R/W bit */
+ I2C_M_IGNORE_NAK = 0x1000, /* continue after NAK */
+ I2C_M_NO_RD_ACK = 0x0800, /* skip the Ack bit on reads */
+ I2C_M_RECV_LEN = 0x0400, /* length is first received byte */
+};
+
+/**
+ * struct i2c_msg - an I2C message
+ *
+ * @addr: Slave address
+ * @flags: Flags (see enum dm_i2c_msg_flags)
+ * @len: Length of buffer in bytes, may be 0 for a probe
+ * @buf: Buffer to send/receive, or NULL if no data
+ */
+struct i2c_msg {
+ uint addr;
+ uint flags;
+ uint len;
+ u8 *buf;
+};
+
+/**
+ * struct i2c_msg_list - a list of I2C messages
+ *
+ * This is called i2c_rdwr_ioctl_data in Linux but the name does not seem
+ * appropriate in U-Boot.
+ *
+ * @msg: Pointer to i2c_msg array
+ * @nmsgs: Number of elements in the array
+ */
+struct i2c_msg_list {
+ struct i2c_msg *msgs;
+ uint nmsgs;
+};
+
/**
* dm_i2c_read() - read bytes from an I2C chip
*
@@ -129,6 +172,7 @@ int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
*
* This reads a single value from the given address in an I2C chip
*
+ * @dev: Device to use for transfer
* @addr: Address to read from
* @return value read, or -ve on error
*/
@@ -139,6 +183,7 @@ int dm_i2c_reg_read(struct udevice *dev, uint offset);
*
* This writes a single value to the given address in an I2C chip
*
+ * @dev: Device to use for transfer
* @addr: Address to write to
* @val: Value to write (normally a byte)
* @return 0 on success, -ve on error
@@ -146,6 +191,19 @@ int dm_i2c_reg_read(struct udevice *dev, uint offset);
int dm_i2c_reg_write(struct udevice *dev, uint offset, unsigned int val);
/**
+ * dm_i2c_xfer() - Transfer messages over I2C
+ *
+ * This transfers a raw message. It is best to use dm_i2c_reg_read/write()
+ * instead.
+ *
+ * @dev: Device to use for transfer
+ * @msg: List of messages to transfer
+ * @nmsgs: Number of messages to transfer
+ * @return 0 on success, -ve on error
+ */
+int dm_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs);
+
+/**
* dm_i2c_set_bus_speed() - set the speed of a bus
*
* @bus: Bus to adjust
@@ -292,49 +350,6 @@ void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val);
#endif
-/*
- * Not all of these flags are implemented in the U-Boot API
- */
-enum dm_i2c_msg_flags {
- I2C_M_TEN = 0x0010, /* ten-bit chip address */
- I2C_M_RD = 0x0001, /* read data, from slave to master */
- I2C_M_STOP = 0x8000, /* send stop after this message */
- I2C_M_NOSTART = 0x4000, /* no start before this message */
- I2C_M_REV_DIR_ADDR = 0x2000, /* invert polarity of R/W bit */
- I2C_M_IGNORE_NAK = 0x1000, /* continue after NAK */
- I2C_M_NO_RD_ACK = 0x0800, /* skip the Ack bit on reads */
- I2C_M_RECV_LEN = 0x0400, /* length is first received byte */
-};
-
-/**
- * struct i2c_msg - an I2C message
- *
- * @addr: Slave address
- * @flags: Flags (see enum dm_i2c_msg_flags)
- * @len: Length of buffer in bytes, may be 0 for a probe
- * @buf: Buffer to send/receive, or NULL if no data
- */
-struct i2c_msg {
- uint addr;
- uint flags;
- uint len;
- u8 *buf;
-};
-
-/**
- * struct i2c_msg_list - a list of I2C messages
- *
- * This is called i2c_rdwr_ioctl_data in Linux but the name does not seem
- * appropriate in U-Boot.
- *
- * @msg: Pointer to i2c_msg array
- * @nmsgs: Number of elements in the array
- */
-struct i2c_msg_list {
- struct i2c_msg *msgs;
- uint nmsgs;
-};
-
/**
* struct dm_i2c_ops - driver operations for I2C uclass
*
@@ -430,6 +445,45 @@ struct dm_i2c_ops {
#define i2c_get_ops(dev) ((struct dm_i2c_ops *)(dev)->driver->ops)
/**
+ * struct i2c_mux_ops - operations for an I2C mux
+ *
+ * The current mux state is expected to be stored in the mux itself since
+ * it is the only thing that knows how to make things work. The mux can
+ * record the current state and then avoid switching unless it is necessary.
+ * So select() can be skipped if the mux is already in the correct state.
+ * Also deselect() can be made a nop if required.
+ */
+struct i2c_mux_ops {
+ /**
+ * select() - select one of of I2C buses attached to a mux
+ *
+ * This will be called when there is no bus currently selected by the
+ * mux. This method does not need to deselect the old bus since
+ * deselect() will be already have been called if necessary.
+ *
+ * @mux: Mux device
+ * @bus: I2C bus to select
+ * @channel: Channel number correponding to the bus to select
+ * @return 0 if OK, -ve on error
+ */
+ int (*select)(struct udevice *mux, struct udevice *bus, uint channel);
+
+ /**
+ * deselect() - select one of of I2C buses attached to a mux
+ *
+ * This is used to deselect the currently selected I2C bus.
+ *
+ * @mux: Mux device
+ * @bus: I2C bus to deselect
+ * @channel: Channel number correponding to the bus to deselect
+ * @return 0 if OK, -ve on error
+ */
+ int (*deselect)(struct udevice *mux, struct udevice *bus, uint channel);
+};
+
+#define i2c_mux_get_ops(dev) ((struct i2c_mux_ops *)(dev)->driver->ops)
+
+/**
* i2c_get_chip() - get a device to use to access a chip on a bus
*
* This returns the device for the given chip address. The device can then
@@ -473,6 +527,16 @@ int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len,
int i2c_chip_ofdata_to_platdata(const void *blob, int node,
struct dm_i2c_chip *chip);
+/**
+ * i2c_dump_msgs() - Dump a list of I2C messages
+ *
+ * This may be useful for debugging.
+ *
+ * @msg: Message list to dump
+ * @nmsgs: Number of messages
+ */
+void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs);
+
#ifndef CONFIG_DM_I2C
/*
diff --git a/include/parade.h b/include/parade.h
deleted file mode 100644
index 887f56dcf2..0000000000
--- a/include/parade.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * (C) Copyright 2012 Samsung Electronics
- * Donghwa Lee <dh09.lee@samsung.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#ifndef __PARADE_H__
-#define __PARADE_H__
-
-/* Initialize the Parade dP<->LVDS bridge if present */
-#ifdef CONFIG_VIDEO_PARADE
-int parade_init(const void *blob);
-#else
-static inline int parade_init(const void *blob) { return -1; }
-#endif
-
-#endif /* __PARADE_H__ */
diff --git a/include/power/s5m8767.h b/include/power/s5m8767.h
new file mode 100644
index 0000000000..ba88ff75b0
--- /dev/null
+++ b/include/power/s5m8767.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __S5M8767_H_
+#define __S5M8767_H_
+
+enum s5m8767_regnum {
+ S5M8767_BUCK1 = 0,
+ S5M8767_BUCK2,
+ S5M8767_BUCK3,
+ S5M8767_BUCK4,
+ S5M8767_BUCK5,
+ S5M8767_BUCK6,
+ S5M8767_BUCK7,
+ S5M8767_BUCK8,
+ S5M8767_BUCK9,
+ S5M8767_LDO1,
+ S5M8767_LDO2,
+ S5M8767_LDO3,
+ S5M8767_LDO4,
+ S5M8767_LDO5,
+ S5M8767_LDO6,
+ S5M8767_LDO7,
+ S5M8767_LDO8,
+ S5M8767_LDO9,
+ S5M8767_LDO10,
+ S5M8767_LDO11,
+ S5M8767_LDO12,
+ S5M8767_LDO13,
+ S5M8767_LDO14,
+ S5M8767_LDO15,
+ S5M8767_LDO16,
+ S5M8767_LDO17,
+ S5M8767_LDO18,
+ S5M8767_LDO19,
+ S5M8767_LDO20,
+ S5M8767_LDO21,
+ S5M8767_LDO22,
+ S5M8767_LDO23,
+ S5M8767_LDO24,
+ S5M8767_LDO25,
+ S5M8767_LDO26,
+ S5M8767_LDO27,
+ S5M8767_LDO28,
+ S5M8767_EN32KHZ_CP,
+
+ S5M8767_NUM_OF_REGS,
+};
+
+struct sec_voltage_desc {
+ int max;
+ int min;
+ int step;
+};
+
+/**
+ * struct s5m8767_para - s5m8767 register parameters
+ * @param vol_addr i2c address of the given buck/ldo register
+ * @param vol_bitpos bit position to be set or clear within register
+ * @param vol_bitmask bit mask value
+ * @param reg_enaddr control register address, which enable the given
+ * given buck/ldo.
+ * @param reg_enbiton value to be written to buck/ldo to make it ON
+ * @param vol Voltage information
+ */
+struct s5m8767_para {
+ enum s5m8767_regnum regnum;
+ u8 vol_addr;
+ u8 vol_bitpos;
+ u8 vol_bitmask;
+ u8 reg_enaddr;
+ u8 reg_enbiton;
+ const struct sec_voltage_desc *vol;
+};
+
+/* Drivers name */
+#define S5M8767_LDO_DRIVER "s5m8767_ldo"
+#define S5M8767_BUCK_DRIVER "s5m8767_buck"
+
+int s5m8767_enable_32khz_cp(struct udevice *dev);
+
+#endif /* __S5M8767_PMIC_H_ */
diff --git a/include/power/tps65090.h b/include/power/tps65090.h
new file mode 100644
index 0000000000..3a0690b475
--- /dev/null
+++ b/include/power/tps65090.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __TPS65090_PMIC_H_
+#define __TPS65090_PMIC_H_
+
+/* I2C device address for TPS65090 PMU */
+#define TPS65090_I2C_ADDR 0x48
+
+/* TPS65090 register addresses */
+enum {
+ REG_IRQ1 = 0,
+ REG_CG_CTRL0 = 4,
+ REG_CG_STATUS1 = 0xa,
+ REG_FET_BASE = 0xe, /* Not a real register, FETs count from here */
+ REG_FET1_CTRL,
+ REG_FET2_CTRL,
+ REG_FET3_CTRL,
+ REG_FET4_CTRL,
+ REG_FET5_CTRL,
+ REG_FET6_CTRL,
+ REG_FET7_CTRL,
+ TPS65090_NUM_REGS,
+};
+
+enum {
+ IRQ1_VBATG = 1 << 3,
+ CG_CTRL0_ENC_MASK = 0x01,
+
+ MAX_FET_NUM = 7,
+ MAX_CTRL_READ_TRIES = 5,
+
+ /* TPS65090 FET_CTRL register values */
+ FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */
+ FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */
+ FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */
+ FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */
+ FET_CTRL_ENFET = 1 << 0, /* Enable FET */
+};
+
+enum {
+ /* Status register fields */
+ TPS65090_ST1_OTC = 1 << 0,
+ TPS65090_ST1_OCC = 1 << 1,
+ TPS65090_ST1_STATE_SHIFT = 4,
+ TPS65090_ST1_STATE_MASK = 0xf << TPS65090_ST1_STATE_SHIFT,
+};
+
+/* Drivers name */
+#define TPS65090_FET_DRIVER "tps65090_fet"
+
+#endif /* __TPS65090_PMIC_H_ */
diff --git a/include/power/tps65090_pmic.h b/include/power/tps65090_pmic.h
deleted file mode 100644
index dcf99c956a..0000000000
--- a/include/power/tps65090_pmic.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2012 The Chromium OS Authors.
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#ifndef __TPS65090_PMIC_H_
-#define __TPS65090_PMIC_H_
-
-/* I2C device address for TPS65090 PMU */
-#define TPS65090_I2C_ADDR 0x48
-
-enum {
- /* Status register fields */
- TPS65090_ST1_OTC = 1 << 0,
- TPS65090_ST1_OCC = 1 << 1,
- TPS65090_ST1_STATE_SHIFT = 4,
- TPS65090_ST1_STATE_MASK = 0xf << TPS65090_ST1_STATE_SHIFT,
-};
-
-/**
- * Enable FET
- *
- * @param fet_id FET ID, value between 1 and 7
- * @return 0 on success, non-0 on failure
- */
-int tps65090_fet_enable(unsigned int fet_id);
-
-/**
- * Disable FET
- *
- * @param fet_id FET ID, value between 1 and 7
- * @return 0 on success, non-0 on failure
- */
-int tps65090_fet_disable(unsigned int fet_id);
-
-/**
- * Is FET enabled?
- *
- * @param fet_id FET ID, value between 1 and 7
- * @return 1 enabled, 0 disabled, negative value on failure
- */
-int tps65090_fet_is_enabled(unsigned int fet_id);
-
-/**
- * Enable / disable the battery charger
- *
- * @param enable 0 to disable charging, non-zero to enable
- */
-int tps65090_set_charge_enable(int enable);
-
-/**
- * Check whether we have enabled battery charging
- *
- * @return 1 if enabled, 0 if disabled
- */
-int tps65090_get_charging(void);
-
-/**
- * Return the value of the status register
- *
- * @return status register value, or -1 on error
- */
-int tps65090_get_status(void);
-
-/**
- * Initialize the TPS65090 PMU.
- *
- * @return 0 on success, non-0 on failure
- */
-int tps65090_init(void);
-
-#endif /* __TPS65090_PMIC_H_ */
diff --git a/include/video_bridge.h b/include/video_bridge.h
new file mode 100644
index 0000000000..c7b8681849
--- /dev/null
+++ b/include/video_bridge.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __VIDEO_BRIDGE
+#define __VIDEO_BRIDGE
+
+#include <asm/gpio.h>
+
+/**
+ * struct video_bridge_priv - uclass information for video bridges
+ *
+ * @sleep: GPIO to assert to power down the bridge
+ * @reset: GPIO to assert to reset the bridge
+ * @hotplug: Optional GPIO to check if bridge is connected
+ */
+struct video_bridge_priv {
+ struct gpio_desc sleep;
+ struct gpio_desc reset;
+ struct gpio_desc hotplug;
+};
+
+/**
+ * Operations for video bridges
+ */
+struct video_bridge_ops {
+ /**
+ * attach() - attach a video bridge
+ *
+ * @return 0 if OK, -ve on error
+ */
+ int (*attach)(struct udevice *dev);
+
+ /**
+ * check_attached() - check if a bridge is correctly attached
+ *
+ * This method is optional - if not provided then the hotplug GPIO
+ * will be checked instead.
+ *
+ * @dev: Device to check
+ * @return 0 if attached, -EENOTCONN if not, or other -ve error
+ */
+ int (*check_attached)(struct udevice *dev);
+
+ /**
+ * set_backlight() - Set the backlight brightness
+ *
+ * @dev: device to adjust
+ * @percent: brightness percentage (0=off, 100=full brightness)
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_backlight)(struct udevice *dev, int percent);
+};
+
+#define video_bridge_get_ops(dev) \
+ ((struct video_bridge_ops *)(dev)->driver->ops)
+
+/**
+ * video_bridge_attach() - attach a video bridge
+ *
+ * @return 0 if OK, -ve on error
+ */
+int video_bridge_attach(struct udevice *dev);
+
+/**
+ * video_bridge_set_backlight() - Set the backlight brightness
+ *
+ * @percent: brightness percentage (0=off, 100=full brightness)
+ * @return 0 if OK, -ve on error
+ */
+int video_bridge_set_backlight(struct udevice *dev, int percent);
+
+/**
+ * video_bridge_set_active() - take the bridge in/out of reset/powerdown
+ *
+ * @dev: Device to adjust
+ * @active: true to power up and reset, false to power down
+ */
+int video_bridge_set_active(struct udevice *dev, bool active);
+
+/**
+ * check_attached() - check if a bridge is correctly attached
+ *
+ * @dev: Device to check
+ * @return 0 if attached, -EENOTCONN if not, or other -ve error
+ */
+int video_bridge_check_attached(struct udevice *dev);
+
+#endif
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 48667efcb5..0153109103 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -62,10 +62,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645tt"),
COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"),
COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"),
- COMPAT(TI_TPS65090, "ti,tps65090"),
- COMPAT(COMPAT_NXP_PTN3460, "nxp,ptn3460"),
COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"),
- COMPAT(PARADE_PS8625, "parade,ps8625"),
COMPAT(INTEL_MICROCODE, "intel,microcode"),
COMPAT(MEMORY_SPD, "memory-spd"),
COMPAT(INTEL_PANTHERPOINT_AHCI, "intel,pantherpoint-ahci"),
diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c
index 5c501ec254..caff49aa4f 100644
--- a/test/dm/cmd_dm.c
+++ b/test/dm/cmd_dm.c
@@ -32,9 +32,18 @@ static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc,
return 0;
}
+static int do_dm_dump_devres(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ dm_dump_devres();
+
+ return 0;
+}
+
static cmd_tbl_t test_commands[] = {
U_BOOT_CMD_MKENT(tree, 0, 1, do_dm_dump_all, "", ""),
U_BOOT_CMD_MKENT(uclass, 1, 1, do_dm_dump_uclass, "", ""),
+ U_BOOT_CMD_MKENT(devres, 1, 1, do_dm_dump_devres, "", ""),
};
static int do_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
@@ -60,5 +69,6 @@ U_BOOT_CMD(
dm, 3, 1, do_dm,
"Driver model low level access",
"tree Dump driver model tree ('*' = activated)\n"
- "dm uclass Dump list of instances for each uclass"
+ "dm uclass Dump list of instances for each uclass\n"
+ "dm devres Dump list of device resources for each device"
);