From: Tom Rini Date: Fri, 12 Dec 2014 20:02:00 +0000 (-0500) Subject: Merge branch 'master' of git://git.denx.de/u-boot-mmc X-Git-Tag: v2015.01-rc4~26 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6983951a612aeecd906521e31de83d7fae309950;hp=2b8a9692f9d8a744b6a93a9bed115ca46541ca1f;p=platform%2Fkernel%2Fu-boot.git Merge branch 'master' of git://git.denx.de/u-boot-mmc --- diff --git a/arch/arm/cpu/armv7/tegra124/Kconfig b/arch/arm/cpu/armv7/tegra124/Kconfig index 6a1c83a..88f627c 100644 --- a/arch/arm/cpu/armv7/tegra124/Kconfig +++ b/arch/arm/cpu/armv7/tegra124/Kconfig @@ -6,6 +6,15 @@ choice config TARGET_JETSON_TK1 bool "NVIDIA Tegra124 Jetson TK1 board" +config TARGET_NYAN_BIG + bool "Google/NVIDIA Nyan-big Chrombook" + help + Nyan Big is a Tegra124 clamshell board that is very similar + to venice2, but it has a different panel, the sdcard CD and WP + sense are flipped, and it has a different revision of the AS3722 + PMIC. The retail name is the Acer Chromebook 13 CB5-311-T7NN + (13.3-inch HD, NVIDIA Tegra K1, 2GB). + config TARGET_VENICE2 bool "NVIDIA Tegra124 Venice2" @@ -15,6 +24,7 @@ config SYS_SOC default "tegra124" source "board/nvidia/jetson-tk1/Kconfig" +source "board/nvidia/nyan-big/Kconfig" source "board/nvidia/venice2/Kconfig" endif diff --git a/arch/arm/cpu/tegra20-common/pmu.c b/arch/arm/cpu/tegra20-common/pmu.c index c595f70..36a76a2 100644 --- a/arch/arm/cpu/tegra20-common/pmu.c +++ b/arch/arm/cpu/tegra20-common/pmu.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -23,9 +24,13 @@ #define VDD_TRANSITION_STEP 0x06 /* 150mv */ #define VDD_TRANSITION_RATE 0x06 /* 3.52mv/us */ +#define PMI_I2C_ADDRESS 0x34 /* chip requires this address */ + int pmu_set_nominal(void) { - int core, cpu, bus; + struct udevice *bus, *dev; + int core, cpu; + int ret; /* by default, the table has been filled with T25 settings */ switch (tegra_get_chip_sku()) { @@ -42,12 +47,18 @@ int pmu_set_nominal(void) return -1; } - bus = tegra_i2c_get_dvc_bus_num(); - if (bus == -1) { + ret = tegra_i2c_get_dvc_bus(&bus); + if (ret) { debug("%s: Cannot find DVC I2C bus\n", __func__); - return -1; + return ret; } - tps6586x_init(bus); + ret = i2c_get_chip(bus, PMI_I2C_ADDRESS, &dev); + if (ret) { + debug("%s: Cannot find DVC I2C chip\n", __func__); + return ret; + } + + tps6586x_init(dev); tps6586x_set_pwm_mode(TPS6586X_PWM_SM1); return tps6586x_adjust_sm0_sm1(core, cpu, VDD_TRANSITION_STEP, VDD_TRANSITION_RATE, VDD_RELATION); diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 187d58c..e6a495c 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -31,6 +31,7 @@ dtb-$(CONFIG_TEGRA) += tegra20-harmony.dtb \ tegra30-tec-ng.dtb \ tegra114-dalmore.dtb \ tegra124-jetson-tk1.dtb \ + tegra124-nyan-big.dtb \ tegra124-venice2.dtb dtb-$(CONFIG_ARCH_UNIPHIER) += \ uniphier-ph1-sld3-ref.dtb \ diff --git a/arch/arm/dts/cros-ec-keyboard.dtsi b/arch/arm/dts/cros-ec-keyboard.dtsi new file mode 100644 index 0000000..9c7fb0a --- /dev/null +++ b/arch/arm/dts/cros-ec-keyboard.dtsi @@ -0,0 +1,105 @@ +/* + * Keyboard dts fragment for devices that use cros-ec-keyboard + * + * Copyright (c) 2014 Google, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include + +&cros_ec { + keyboard-controller { + compatible = "google,cros-ec-keyb"; + keypad,num-rows = <8>; + keypad,num-columns = <13>; + google,needs-ghost-filter; + + linux,keymap = < + MATRIX_KEY(0x00, 0x01, KEY_LEFTMETA) + MATRIX_KEY(0x00, 0x02, KEY_F1) + MATRIX_KEY(0x00, 0x03, KEY_B) + MATRIX_KEY(0x00, 0x04, KEY_F10) + MATRIX_KEY(0x00, 0x06, KEY_N) + MATRIX_KEY(0x00, 0x08, KEY_EQUAL) + MATRIX_KEY(0x00, 0x0a, KEY_RIGHTALT) + + MATRIX_KEY(0x01, 0x01, KEY_ESC) + MATRIX_KEY(0x01, 0x02, KEY_F4) + MATRIX_KEY(0x01, 0x03, KEY_G) + MATRIX_KEY(0x01, 0x04, KEY_F7) + MATRIX_KEY(0x01, 0x06, KEY_H) + MATRIX_KEY(0x01, 0x08, KEY_APOSTROPHE) + MATRIX_KEY(0x01, 0x09, KEY_F9) + MATRIX_KEY(0x01, 0x0b, KEY_BACKSPACE) + + MATRIX_KEY(0x02, 0x00, KEY_LEFTCTRL) + MATRIX_KEY(0x02, 0x01, KEY_TAB) + MATRIX_KEY(0x02, 0x02, KEY_F3) + MATRIX_KEY(0x02, 0x03, KEY_T) + MATRIX_KEY(0x02, 0x04, KEY_F6) + MATRIX_KEY(0x02, 0x05, KEY_RIGHTBRACE) + MATRIX_KEY(0x02, 0x06, KEY_Y) + MATRIX_KEY(0x02, 0x07, KEY_102ND) + MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE) + MATRIX_KEY(0x02, 0x09, KEY_F8) + + MATRIX_KEY(0x03, 0x01, KEY_GRAVE) + MATRIX_KEY(0x03, 0x02, KEY_F2) + MATRIX_KEY(0x03, 0x03, KEY_5) + MATRIX_KEY(0x03, 0x04, KEY_F5) + MATRIX_KEY(0x03, 0x06, KEY_6) + MATRIX_KEY(0x03, 0x08, KEY_MINUS) + MATRIX_KEY(0x03, 0x0b, KEY_BACKSLASH) + + MATRIX_KEY(0x04, 0x00, KEY_RIGHTCTRL) + MATRIX_KEY(0x04, 0x01, KEY_A) + MATRIX_KEY(0x04, 0x02, KEY_D) + MATRIX_KEY(0x04, 0x03, KEY_F) + MATRIX_KEY(0x04, 0x04, KEY_S) + MATRIX_KEY(0x04, 0x05, KEY_K) + MATRIX_KEY(0x04, 0x06, KEY_J) + MATRIX_KEY(0x04, 0x08, KEY_SEMICOLON) + MATRIX_KEY(0x04, 0x09, KEY_L) + MATRIX_KEY(0x04, 0x0a, KEY_BACKSLASH) + MATRIX_KEY(0x04, 0x0b, KEY_ENTER) + + MATRIX_KEY(0x05, 0x01, KEY_Z) + MATRIX_KEY(0x05, 0x02, KEY_C) + MATRIX_KEY(0x05, 0x03, KEY_V) + MATRIX_KEY(0x05, 0x04, KEY_X) + MATRIX_KEY(0x05, 0x05, KEY_COMMA) + MATRIX_KEY(0x05, 0x06, KEY_M) + MATRIX_KEY(0x05, 0x07, KEY_LEFTSHIFT) + MATRIX_KEY(0x05, 0x08, KEY_SLASH) + MATRIX_KEY(0x05, 0x09, KEY_DOT) + MATRIX_KEY(0x05, 0x0b, KEY_SPACE) + + MATRIX_KEY(0x06, 0x01, KEY_1) + MATRIX_KEY(0x06, 0x02, KEY_3) + MATRIX_KEY(0x06, 0x03, KEY_4) + MATRIX_KEY(0x06, 0x04, KEY_2) + MATRIX_KEY(0x06, 0x05, KEY_8) + MATRIX_KEY(0x06, 0x06, KEY_7) + MATRIX_KEY(0x06, 0x08, KEY_0) + MATRIX_KEY(0x06, 0x09, KEY_9) + MATRIX_KEY(0x06, 0x0a, KEY_LEFTALT) + MATRIX_KEY(0x06, 0x0b, KEY_DOWN) + MATRIX_KEY(0x06, 0x0c, KEY_RIGHT) + + MATRIX_KEY(0x07, 0x01, KEY_Q) + MATRIX_KEY(0x07, 0x02, KEY_E) + MATRIX_KEY(0x07, 0x03, KEY_R) + MATRIX_KEY(0x07, 0x04, KEY_W) + MATRIX_KEY(0x07, 0x05, KEY_I) + MATRIX_KEY(0x07, 0x06, KEY_U) + MATRIX_KEY(0x07, 0x07, KEY_RIGHTSHIFT) + MATRIX_KEY(0x07, 0x08, KEY_P) + MATRIX_KEY(0x07, 0x09, KEY_O) + MATRIX_KEY(0x07, 0x0b, KEY_UP) + MATRIX_KEY(0x07, 0x0c, KEY_LEFT) + >; + }; +}; diff --git a/arch/arm/dts/tegra124-jetson-tk1.dts b/arch/arm/dts/tegra124-jetson-tk1.dts index ffad116..f6fe9a0 100644 --- a/arch/arm/dts/tegra124-jetson-tk1.dts +++ b/arch/arm/dts/tegra124-jetson-tk1.dts @@ -16,7 +16,6 @@ i2c2 = "/i2c@7000c400"; i2c3 = "/i2c@7000c500"; i2c4 = "/i2c@7000c700"; - i2c5 = "/i2c@7000d100"; sdhci0 = "/sdhci@700b0600"; sdhci1 = "/sdhci@700b0400"; spi0 = "/spi@7000d400"; diff --git a/arch/arm/dts/tegra124-nyan-big.dts b/arch/arm/dts/tegra124-nyan-big.dts new file mode 100644 index 0000000..c1f35a0 --- /dev/null +++ b/arch/arm/dts/tegra124-nyan-big.dts @@ -0,0 +1,365 @@ +/dts-v1/; + +#include +#include "tegra124.dtsi" + +/ { + model = "Acer Chromebook 13 CB5-311"; + compatible = "google,nyan-big", "nvidia,tegra124"; + + aliases { + console = &uarta; + i2c0 = "/i2c@7000d000"; + i2c1 = "/i2c@7000c000"; + i2c2 = "/i2c@7000c400"; + i2c3 = "/i2c@7000c500"; + i2c4 = "/i2c@7000c700"; + i2c5 = "/i2c@7000d100"; + rtc0 = "/i2c@0,7000d000/pmic@40"; + rtc1 = "/rtc@0,7000e000"; + sdhci0 = "/sdhci@700b0600"; + sdhci1 = "/sdhci@700b0400"; + spi0 = "/spi@7000d400"; + spi1 = "/spi@7000da00"; + usb0 = "/usb@7d000000"; + usb1 = "/usb@7d008000"; + }; + + memory { + reg = <0x80000000 0x80000000>; + }; + + serial@70006000 { + /* Debug connector on the bottom of the board near SD card. */ + status = "okay"; + }; + + pwm@7000a000 { + status = "okay"; + }; + + i2c@7000c000 { + status = "okay"; + clock-frequency = <100000>; + + acodec: audio-codec@10 { + compatible = "maxim,max98090"; + reg = <0x10>; + interrupt-parent = <&gpio>; + interrupts = ; + }; + + temperature-sensor@4c { + compatible = "ti,tmp451"; + reg = <0x4c>; + interrupt-parent = <&gpio>; + interrupts = ; + + #thermal-sensor-cells = <1>; + }; + }; + + i2c@7000c400 { + status = "okay"; + clock-frequency = <100000>; + }; + + i2c@7000c500 { + status = "okay"; + clock-frequency = <400000>; + + tpm@20 { + compatible = "infineon,slb9645tt"; + reg = <0x20>; + }; + }; + + hdmi_ddc: i2c@7000c700 { + status = "okay"; + clock-frequency = <100000>; + }; + + i2c@7000d000 { + status = "okay"; + clock-frequency = <400000>; + + pmic: pmic@40 { + compatible = "ams,as3722"; + reg = <0x40>; + interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; + + ams,system-power-controller; + + #interrupt-cells = <2>; + interrupt-controller; + + gpio-controller; + #gpio-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&as3722_default>; + + as3722_default: pinmux { + gpio0 { + pins = "gpio0"; + function = "gpio"; + bias-pull-down; + }; + + gpio1 { + pins = "gpio1"; + function = "gpio"; + bias-pull-up; + }; + + gpio2_4_7 { + pins = "gpio2", "gpio4", "gpio7"; + function = "gpio"; + bias-pull-up; + }; + + gpio3_6 { + pins = "gpio3", "gpio6"; + bias-high-impedance; + }; + + gpio5 { + pins = "gpio5"; + function = "clk32k-out"; + bias-pull-down; + }; + }; + }; + }; + + spi@7000d400 { + status = "okay"; + + cros_ec: cros-ec@0 { + compatible = "google,cros-ec-spi"; + spi-max-frequency = <3000000>; + interrupt-parent = <&gpio>; + interrupts = ; + reg = <0>; + + google,cros-ec-spi-msg-delay = <2000>; + + i2c-tunnel { + compatible = "google,cros-ec-i2c-tunnel"; + #address-cells = <1>; + #size-cells = <0>; + + google,remote-bus = <0>; + + charger: bq24735@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + interrupt-parent = <&gpio>; + interrupts = ; + ti,ac-detect-gpios = <&gpio + TEGRA_GPIO(J, 0) + GPIO_ACTIVE_HIGH>; + }; + + battery: sbs-battery@b { + compatible = "sbs,sbs-battery"; + reg = <0xb>; + sbs,i2c-retry-count = <2>; + sbs,poll-retry-count = <10>; + power-supplies = <&charger>; + }; + }; + }; + }; + + spi@7000da00 { + status = "okay"; + spi-max-frequency = <25000000>; + + flash@0 { + compatible = "winbond,w25q32dw"; + reg = <0>; + }; + }; + + pmc@7000e400 { + nvidia,invert-interrupt; + nvidia,suspend-mode = <0>; + nvidia,cpu-pwr-good-time = <500>; + nvidia,cpu-pwr-off-time = <300>; + nvidia,core-pwr-good-time = <641 3845>; + nvidia,core-pwr-off-time = <61036>; + nvidia,core-power-req-active-high; + nvidia,sys-clock-req-active-high; + }; + + hda@70030000 { + status = "okay"; + }; + + sdhci@700b0000 { /* WiFi/BT on this bus */ + status = "okay"; + power-gpios = <&gpio TEGRA_GPIO(X, 7) GPIO_ACTIVE_HIGH>; + bus-width = <4>; + no-1-8-v; + non-removable; + }; + + sdhci@700b0400 { /* SD Card on this bus */ + status = "okay"; + cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>; + power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>; + wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_LOW>; + bus-width = <4>; + no-1-8-v; + }; + + sdhci@700b0600 { /* eMMC on this bus */ + status = "okay"; + bus-width = <8>; + no-1-8-v; + non-removable; + }; + + ahub@70300000 { + i2s@70301100 { + status = "okay"; + }; + }; + + usb@7d000000 { /* Rear external USB port. */ + status = "okay"; + }; + + usb-phy@7d000000 { + status = "okay"; + }; + + usb@7d004000 { /* Internal webcam. */ + status = "okay"; + }; + + usb-phy@7d004000 { + status = "okay"; + }; + + usb@7d008000 { /* Left external USB port. */ + status = "okay"; + }; + + usb-phy@7d008000 { + status = "okay"; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + + enable-gpios = <&gpio TEGRA_GPIO(H, 2) GPIO_ACTIVE_HIGH>; + pwms = <&pwm 1 1000000>; + + default-brightness-level = <224>; + brightness-levels = + < 0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30 31 + 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 + 48 49 50 51 52 53 54 55 + 56 57 58 59 60 61 62 63 + 64 65 66 67 68 69 70 71 + 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 + 88 89 90 91 92 93 94 95 + 96 97 98 99 100 101 102 103 + 104 105 106 107 108 109 110 111 + 112 113 114 115 116 117 118 119 + 120 121 122 123 124 125 126 127 + 128 129 130 131 132 133 134 135 + 136 137 138 139 140 141 142 143 + 144 145 146 147 148 149 150 151 + 152 153 154 155 156 157 158 159 + 160 161 162 163 164 165 166 167 + 168 169 170 171 172 173 174 175 + 176 177 178 179 180 181 182 183 + 184 185 186 187 188 189 190 191 + 192 193 194 195 196 197 198 199 + 200 201 202 203 204 205 206 207 + 208 209 210 211 212 213 214 215 + 216 217 218 219 220 221 222 223 + 224 225 226 227 228 229 230 231 + 232 233 234 235 236 237 238 239 + 240 241 242 243 244 245 246 247 + 248 249 250 251 252 253 254 255 + 256>; + }; + + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + lid { + label = "Lid"; + gpios = <&gpio TEGRA_GPIO(R, 4) GPIO_ACTIVE_LOW>; + linux,input-type = <5>; + linux,code = ; + debounce-interval = <1>; + gpio-key,wakeup; + }; + + power { + label = "Power"; + gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <30>; + gpio-key,wakeup; + }; + }; + + panel: panel { + compatible = "auo,b133xtn01"; + + backlight = <&backlight>; + }; + + sound { + compatible = "nvidia,tegra-audio-max98090-nyan-big", + "nvidia,tegra-audio-max98090"; + nvidia,model = "Acer Chromebook 13"; + + nvidia,audio-routing = + "Headphones", "HPR", + "Headphones", "HPL", + "Speakers", "SPKR", + "Speakers", "SPKL", + "Mic Jack", "MICBIAS", + "DMICL", "Int Mic", + "DMICR", "Int Mic", + "IN34", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&acodec>; + + clocks = <&tegra_car TEGRA124_CLK_PLL_A>, + <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA124_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(I, 7) GPIO_ACTIVE_HIGH>; + }; +}; + +#include "cros-ec-keyboard.dtsi" diff --git a/arch/arm/dts/tegra124.dtsi b/arch/arm/dts/tegra124.dtsi index 3288f28..6b5c2be 100644 --- a/arch/arm/dts/tegra124.dtsi +++ b/arch/arm/dts/tegra124.dtsi @@ -1,5 +1,6 @@ #include #include +#include #include #include "skeleton.dtsi" @@ -192,6 +193,16 @@ status = "disabled"; }; + pwm: pwm@7000a000 { + compatible = "nvidia,tegra124-pwm", "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + clocks = <&tegra_car TEGRA124_CLK_PWM>; + resets = <&tegra_car 17>; + reset-names = "pwm"; + status = "disabled"; + }; + spi@7000d400 { compatible = "nvidia,tegra124-spi", "nvidia,tegra114-spi"; reg = <0x7000d400 0x200>; @@ -290,6 +301,109 @@ status = "disabled"; }; + ahub@70300000 { + compatible = "nvidia,tegra124-ahub"; + reg = <0x70300000 0x200>, + <0x70300800 0x800>, + <0x70300200 0x600>; + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_D_AUDIO>, + <&tegra_car TEGRA124_CLK_APBIF>; + clock-names = "d_audio", "apbif"; + resets = <&tegra_car 106>, /* d_audio */ + <&tegra_car 107>, /* apbif */ + <&tegra_car 30>, /* i2s0 */ + <&tegra_car 11>, /* i2s1 */ + <&tegra_car 18>, /* i2s2 */ + <&tegra_car 101>, /* i2s3 */ + <&tegra_car 102>, /* i2s4 */ + <&tegra_car 108>, /* dam0 */ + <&tegra_car 109>, /* dam1 */ + <&tegra_car 110>, /* dam2 */ + <&tegra_car 10>, /* spdif */ + <&tegra_car 153>, /* amx */ + <&tegra_car 185>, /* amx1 */ + <&tegra_car 154>, /* adx */ + <&tegra_car 180>, /* adx1 */ + <&tegra_car 186>, /* afc0 */ + <&tegra_car 187>, /* afc1 */ + <&tegra_car 188>, /* afc2 */ + <&tegra_car 189>, /* afc3 */ + <&tegra_car 190>, /* afc4 */ + <&tegra_car 191>; /* afc5 */ + reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", + "i2s3", "i2s4", "dam0", "dam1", "dam2", + "spdif", "amx", "amx1", "adx", "adx1", + "afc0", "afc1", "afc2", "afc3", "afc4", "afc5"; + dmas = <&apbdma 1>, <&apbdma 1>, + <&apbdma 2>, <&apbdma 2>, + <&apbdma 3>, <&apbdma 3>, + <&apbdma 4>, <&apbdma 4>, + <&apbdma 6>, <&apbdma 6>, + <&apbdma 7>, <&apbdma 7>, + <&apbdma 12>, <&apbdma 12>, + <&apbdma 13>, <&apbdma 13>, + <&apbdma 14>, <&apbdma 14>, + <&apbdma 29>, <&apbdma 29>; + dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2", + "rx3", "tx3", "rx4", "tx4", "rx5", "tx5", + "rx6", "tx6", "rx7", "tx7", "rx8", "tx8", + "rx9", "tx9"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + + tegra_i2s0: i2s@70301000 { + compatible = "nvidia,tegra124-i2s"; + reg = <0x70301000 0x100>; + nvidia,ahub-cif-ids = <4 4>; + clocks = <&tegra_car TEGRA124_CLK_I2S0>; + resets = <&tegra_car 30>; + reset-names = "i2s"; + status = "disabled"; + }; + + tegra_i2s1: i2s@70301100 { + compatible = "nvidia,tegra124-i2s"; + reg = <0x70301100 0x100>; + nvidia,ahub-cif-ids = <5 5>; + clocks = <&tegra_car TEGRA124_CLK_I2S1>; + resets = <&tegra_car 11>; + reset-names = "i2s"; + status = "disabled"; + }; + + tegra_i2s2: i2s@70301200 { + compatible = "nvidia,tegra124-i2s"; + reg = <0x70301200 0x100>; + nvidia,ahub-cif-ids = <6 6>; + clocks = <&tegra_car TEGRA124_CLK_I2S2>; + resets = <&tegra_car 18>; + reset-names = "i2s"; + status = "disabled"; + }; + + tegra_i2s3: i2s@70301300 { + compatible = "nvidia,tegra124-i2s"; + reg = <0x70301300 0x100>; + nvidia,ahub-cif-ids = <7 7>; + clocks = <&tegra_car TEGRA124_CLK_I2S3>; + resets = <&tegra_car 101>; + reset-names = "i2s"; + status = "disabled"; + }; + + tegra_i2s4: i2s@70301400 { + compatible = "nvidia,tegra124-i2s"; + reg = <0x70301400 0x100>; + nvidia,ahub-cif-ids = <8 8>; + clocks = <&tegra_car TEGRA124_CLK_I2S4>; + resets = <&tegra_car 102>; + reset-names = "i2s"; + status = "disabled"; + }; + }; + usb@7d000000 { compatible = "nvidia,tegra124-ehci", "nvidia,tegra30-ehci"; reg = <0x7d000000 0x4000>; diff --git a/arch/arm/dts/tegra30-tec-ng.dts b/arch/arm/dts/tegra30-tec-ng.dts index 8a69e81..e924acc 100644 --- a/arch/arm/dts/tegra30-tec-ng.dts +++ b/arch/arm/dts/tegra30-tec-ng.dts @@ -6,6 +6,10 @@ model = "Avionic Design Tamonten™ NG Evaluation Carrier"; compatible = "ad,tec-ng", "nvidia,tegra30"; + aliases { + i2c0 = "/i2c@7000c400"; + }; + /* GEN2 */ i2c@7000c400 { status = "okay"; diff --git a/arch/arm/include/asm/arch-tegra/tegra_i2c.h b/arch/arm/include/asm/arch-tegra/tegra_i2c.h index 7ca6907..eeeb247 100644 --- a/arch/arm/include/asm/arch-tegra/tegra_i2c.h +++ b/arch/arm/include/asm/arch-tegra/tegra_i2c.h @@ -167,6 +167,6 @@ struct i2c_ctlr { * * @return number of bus, or -1 if there is no DVC active */ -int tegra_i2c_get_dvc_bus_num(void); +int tegra_i2c_get_dvc_bus(struct udevice **busp); #endif /* _TEGRA_I2C_H_ */ diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 7614715..11748ae 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -134,6 +134,23 @@ num-gpios = <20>; }; + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + compatible = "sandbox,i2c"; + clock-frequency = <400000>; + eeprom@2c { + reg = <0x2c>; + compatible = "i2c-eeprom"; + emul { + compatible = "sandbox,i2c-eeprom"; + sandbox,filename = "i2c.bin"; + sandbox,size = <128>; + }; + }; + }; + spi@0 { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h new file mode 100644 index 0000000..25a0c85 --- /dev/null +++ b/arch/sandbox/include/asm/test.h @@ -0,0 +1,26 @@ +/* + * Test-related constants for sandbox + * + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_TEST_H +#define __ASM_TEST_H + +/* The sandbox driver always permits an I2C device with this address */ +#define SANDBOX_I2C_TEST_ADDR 0x59 + +enum sandbox_i2c_eeprom_test_mode { + SIE_TEST_MODE_NONE, + /* Permits read/write of only one byte per I2C transaction */ + SIE_TEST_MODE_SINGLE_BYTE, +}; + +void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, + enum sandbox_i2c_eeprom_test_mode mode); + +void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len); + +#endif diff --git a/board/avionic-design/common/tamonten-ng.c b/board/avionic-design/common/tamonten-ng.c index 5870b95..86a0844 100644 --- a/board/avionic-design/common/tamonten-ng.c +++ b/board/avionic-design/common/tamonten-ng.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -51,8 +52,15 @@ void gpio_early_init(void) void pmu_write(uchar reg, uchar data) { - i2c_set_bus_num(4); /* PMU is on bus 4 */ - i2c_write(PMU_I2C_ADDRESS, reg, 1, &data, 1); + struct udevice *dev; + int ret; + + ret = i2c_get_chip_for_busnum(4, PMU_I2C_ADDRESS, &dev); + if (ret) { + debug("%s: Cannot find PMIC I2C chip\n", __func__); + return; + } + i2c_write(dev, reg, &data, 1); } /* diff --git a/board/nvidia/cardhu/cardhu.c b/board/nvidia/cardhu/cardhu.c index cc0e5e1..026f45c 100644 --- a/board/nvidia/cardhu/cardhu.c +++ b/board/nvidia/cardhu/cardhu.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include "pinmux-config-cardhu.h" @@ -37,17 +38,23 @@ void pinmux_init(void) */ void board_sdmmc_voltage_init(void) { + struct udevice *dev; uchar reg, data_buffer[1]; + int ret; int i; - i2c_set_bus_num(0); /* PMU is on bus 0 */ + ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev); + if (ret) { + debug("%s: Cannot find PMIC I2C chip\n", __func__); + return; + } /* TPS659110: LDO5_REG = 3.3v, ACTIVE to SDMMC1 */ data_buffer[0] = 0x65; reg = 0x32; for (i = 0; i < MAX_I2C_RETRY; ++i) { - if (i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1)) + if (i2c_write(dev, reg, data_buffer, 1)) udelay(100); } @@ -56,7 +63,7 @@ void board_sdmmc_voltage_init(void) reg = 0x67; for (i = 0; i < MAX_I2C_RETRY; ++i) { - if (i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1)) + if (i2c_write(dev, reg, data_buffer, 1)) udelay(100); } } diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index 0e4a65a..4bdbf01 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -113,10 +113,6 @@ int board_init(void) power_det_init(); #ifdef CONFIG_SYS_I2C_TEGRA -#ifndef CONFIG_SYS_I2C_INIT_BOARD -#error "You must define CONFIG_SYS_I2C_INIT_BOARD to use i2c on Nvidia boards" -#endif - i2c_init_board(); # ifdef CONFIG_TEGRA_PMU if (pmu_set_nominal()) debug("Failed to select nominal voltages\n"); diff --git a/board/nvidia/dalmore/dalmore.c b/board/nvidia/dalmore/dalmore.c index f2d05af..2a73746 100644 --- a/board/nvidia/dalmore/dalmore.c +++ b/board/nvidia/dalmore/dalmore.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include "pinmux-config-dalmore.h" @@ -50,18 +51,21 @@ void pinmux_init(void) */ void board_sdmmc_voltage_init(void) { + struct udevice *dev; uchar reg, data_buffer[1]; int ret; - ret = i2c_set_bus_num(0);/* PMU is on bus 0 */ - if (ret) - printf("%s: i2c_set_bus_num returned %d\n", __func__, ret); + ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev); + if (ret) { + debug("%s: Cannot find PMIC I2C chip\n", __func__); + return; + } /* TPS65913: LDO9_VOLTAGE = 3.3V */ data_buffer[0] = 0x31; reg = 0x61; - ret = i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1); + ret = i2c_write(dev, reg, data_buffer, 1); if (ret) printf("%s: PMU i2c_write %02X<-%02X returned %d\n", __func__, reg, data_buffer[0], ret); @@ -70,7 +74,7 @@ void board_sdmmc_voltage_init(void) data_buffer[0] = 0x01; reg = 0x60; - ret = i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1); + ret = i2c_write(dev, reg, data_buffer, 1); if (ret) printf("%s: PMU i2c_write %02X<-%02X returned %d\n", __func__, reg, data_buffer[0], ret); @@ -79,7 +83,12 @@ void board_sdmmc_voltage_init(void) data_buffer[0] = 0x03; reg = 0x14; - ret = i2c_write(BAT_I2C_ADDRESS, reg, 1, data_buffer, 1); + ret = i2c_get_chip_for_busnum(0, BAT_I2C_ADDRESS, &dev); + if (ret) { + debug("%s: Cannot find charger I2C chip\n", __func__); + return; + } + ret = i2c_write(dev, reg, data_buffer, 1); if (ret) printf("%s: BAT i2c_write %02X<-%02X returned %d\n", __func__, reg, data_buffer[0], ret); diff --git a/board/nvidia/nyan-big/Kconfig b/board/nvidia/nyan-big/Kconfig new file mode 100644 index 0000000..6c42bb9 --- /dev/null +++ b/board/nvidia/nyan-big/Kconfig @@ -0,0 +1,24 @@ +if TARGET_NYAN_BIG + +config SYS_CPU + string + default "arm720t" if SPL_BUILD + default "armv7" if !SPL_BUILD + +config SYS_BOARD + string + default "nyan-big" + +config SYS_VENDOR + string + default "nvidia" + +config SYS_SOC + string + default "tegra124" + +config SYS_CONFIG_NAME + string + default "nyan-big" + +endif diff --git a/board/nvidia/nyan-big/MAINTAINERS b/board/nvidia/nyan-big/MAINTAINERS new file mode 100644 index 0000000..ff74627 --- /dev/null +++ b/board/nvidia/nyan-big/MAINTAINERS @@ -0,0 +1,6 @@ +NORRIN BOARD +M: Allen Martin +S: Maintained +F: board/nvidia/nyan-big/ +F: include/configs/nyan-big.h +F: configs/nyan-big_defconfig diff --git a/board/nvidia/nyan-big/Makefile b/board/nvidia/nyan-big/Makefile new file mode 100644 index 0000000..cd2f61d --- /dev/null +++ b/board/nvidia/nyan-big/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2014 +# NVIDIA Corporation +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += ../venice2/as3722_init.o +obj-y += nyan-big.o diff --git a/board/nvidia/nyan-big/nyan-big.c b/board/nvidia/nyan-big/nyan-big.c new file mode 100644 index 0000000..d4d2496 --- /dev/null +++ b/board/nvidia/nyan-big/nyan-big.c @@ -0,0 +1,27 @@ +/* + * (C) Copyright 2014 + * NVIDIA Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include "pinmux-config-nyan-big.h" + +/* + * Routine: pinmux_init + * Description: Do individual peripheral pinmux configs + */ +void pinmux_init(void) +{ + gpio_config_table(nyan_big_gpio_inits, + ARRAY_SIZE(nyan_big_gpio_inits)); + + pinmux_config_pingrp_table(nyan_big_pingrps, + ARRAY_SIZE(nyan_big_pingrps)); + + pinmux_config_drvgrp_table(nyan_big_drvgrps, + ARRAY_SIZE(nyan_big_drvgrps)); +} diff --git a/board/nvidia/nyan-big/pinmux-config-nyan-big.h b/board/nvidia/nyan-big/pinmux-config-nyan-big.h new file mode 100644 index 0000000..9c5fbaa --- /dev/null +++ b/board/nvidia/nyan-big/pinmux-config-nyan-big.h @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _PINMUX_CONFIG_NYAN_BIG_H_ +#define _PINMUX_CONFIG_NYAN_BIG_H_ + +#define GPIO_INIT(_gpio, _init) \ + { \ + .gpio = GPIO_P##_gpio, \ + .init = TEGRA_GPIO_INIT_##_init, \ + } + +static const struct tegra_gpio_config nyan_big_gpio_inits[] = { + /* gpio, init_val */ + GPIO_INIT(A0, IN), + GPIO_INIT(C7, IN), + GPIO_INIT(G0, IN), + GPIO_INIT(G1, IN), + GPIO_INIT(G2, IN), + GPIO_INIT(G3, IN), + GPIO_INIT(H2, IN), + GPIO_INIT(H4, IN), + GPIO_INIT(H6, IN), + GPIO_INIT(H7, OUT1), + GPIO_INIT(I0, IN), + GPIO_INIT(I1, IN), + GPIO_INIT(I5, OUT1), + GPIO_INIT(I6, IN), + GPIO_INIT(I7, IN), + GPIO_INIT(J0, IN), + GPIO_INIT(J7, IN), + GPIO_INIT(K1, OUT0), + GPIO_INIT(K2, IN), + GPIO_INIT(K4, OUT0), + GPIO_INIT(K6, OUT0), + GPIO_INIT(K7, IN), + GPIO_INIT(N7, IN), + GPIO_INIT(P2, OUT0), + GPIO_INIT(Q0, IN), + GPIO_INIT(Q2, IN), + GPIO_INIT(Q3, IN), + GPIO_INIT(Q6, IN), + GPIO_INIT(Q7, IN), + GPIO_INIT(R0, OUT0), + GPIO_INIT(R1, IN), + GPIO_INIT(R4, IN), + GPIO_INIT(R7, IN), + GPIO_INIT(S3, OUT0), + GPIO_INIT(S4, OUT0), + GPIO_INIT(S7, IN), + GPIO_INIT(T1, IN), + GPIO_INIT(U4, IN), + GPIO_INIT(U5, IN), + GPIO_INIT(U6, IN), + GPIO_INIT(V0, IN), + GPIO_INIT(W3, IN), + GPIO_INIT(X1, IN), + GPIO_INIT(X4, IN), + GPIO_INIT(X7, OUT0), +}; + +#define PINCFG(_pingrp, _mux, _pull, _tri, _io, _od, _rcv_sel) \ + { \ + .pingrp = PMUX_PINGRP_##_pingrp, \ + .func = PMUX_FUNC_##_mux, \ + .pull = PMUX_PULL_##_pull, \ + .tristate = PMUX_TRI_##_tri, \ + .io = PMUX_PIN_##_io, \ + .od = PMUX_PIN_OD_##_od, \ + .rcv_sel = PMUX_PIN_RCV_SEL_##_rcv_sel, \ + .lock = PMUX_PIN_LOCK_DEFAULT, \ + .ioreset = PMUX_PIN_IO_RESET_DEFAULT, \ + } + +static const struct pmux_pingrp_config nyan_big_pingrps[] = { + /* pingrp, mux, pull, tri, e_input, od, rcv_sel */ + PINCFG(CLK_32K_OUT_PA0, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(UART3_CTS_N_PA1, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP2_FS_PA2, I2S1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DAP2_SCLK_PA3, I2S1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DAP2_DIN_PA4, I2S1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DAP2_DOUT_PA5, I2S1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_CLK_PA6, SDMMC3, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_CMD_PA7, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PB0, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PB1, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_DAT3_PB4, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_DAT2_PB5, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_DAT1_PB6, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_DAT0_PB7, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(UART3_RTS_N_PC0, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART2_TXD_PC2, IRDA, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART2_RXD_PC3, IRDA, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GEN1_I2C_SCL_PC4, I2C1, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(GEN1_I2C_SDA_PC5, I2C1, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(PC7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PG0, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PG1, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PG2, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PG3, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PG4, SPI4, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PG5, SPI4, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PG6, SPI4, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PG7, SPI4, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PH0, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PH1, PWM1, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PH2, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PH3, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PH4, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PH5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PH6, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PH7, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PI0, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PI1, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PI2, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PI3, SPI4, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PI4, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PI5, DEFAULT, UP, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PI6, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PI7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PJ0, DEFAULT, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PJ2, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART2_CTS_N_PJ5, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART2_RTS_N_PJ6, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PJ7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PK0, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PK1, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PK2, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PK3, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PK4, DEFAULT, UP, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SPDIF_OUT_PK5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SPDIF_IN_PK6, DEFAULT, DOWN, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PK7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DAP1_FS_PN0, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP1_DIN_PN1, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP1_DOUT_PN2, I2S0, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP1_SCLK_PN3, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(USB_VBUS_EN0_PN4, USB, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(USB_VBUS_EN1_PN5, USB, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(HDMI_INT_PN7, DEFAULT, DOWN, NORMAL, INPUT, DEFAULT, NORMAL), + PINCFG(ULPI_DATA7_PO0, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA0_PO1, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA1_PO2, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA2_PO3, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA3_PO4, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA4_PO5, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA5_PO6, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA6_PO7, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP3_FS_PP0, I2S2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP3_DIN_PP1, I2S2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP3_DOUT_PP2, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP3_SCLK_PP3, RSVD3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP4_FS_PP4, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP4_DIN_PP5, RSVD3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP4_DOUT_PP6, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP4_SCLK_PP7, RSVD3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL0_PQ0, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL1_PQ1, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL2_PQ2, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL3_PQ3, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL4_PQ4, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL5_PQ5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL6_PQ6, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL7_PQ7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW0_PR0, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW1_PR1, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW2_PR2, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW3_PR3, KBC, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW4_PR4, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW5_PR5, RSVD3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW6_PR6, KBC, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW7_PR7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW8_PS0, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW9_PS1, UARTA, DOWN, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW10_PS2, UARTA, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW11_PS3, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW12_PS4, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW13_PS5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW14_PS6, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW15_PS7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW16_PT0, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW17_PT1, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(GEN2_I2C_SCL_PT5, I2C2, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(GEN2_I2C_SDA_PT6, I2C2, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(SDMMC4_CMD_PT7, SDMMC4, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PU0, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PU1, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PU2, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PU3, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PU4, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PU5, DEFAULT, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PU6, DEFAULT, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PV0, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PV1, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_CD_N_PV2, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_WP_N_PV3, SDMMC1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DDC_SCL_PV4, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, NORMAL), + PINCFG(DDC_SDA_PV5, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, NORMAL), + PINCFG(GPIO_W2_AUD_PW2, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_W3_AUD_PW3, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DAP_MCLK1_PW4, EXTPERIPH1, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CLK2_OUT_PW5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART3_TXD_PW6, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART3_RXD_PW7, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DVFS_PWM_PX0, CLDVFS, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X1_AUD_PX1, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DVFS_CLK_PX2, CLDVFS, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X3_AUD_PX3, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X4_AUD_PX4, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X5_AUD_PX5, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X6_AUD_PX6, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X7_AUD_PX7, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_CLK_PY0, SPI1, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DIR_PY1, SPI1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_NXT_PY2, SPI1, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_STP_PY3, SPI1, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_DAT3_PY4, SDMMC1, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_DAT2_PY5, SDMMC1, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_DAT1_PY6, SDMMC1, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_DAT0_PY7, SDMMC1, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_CLK_PZ0, SDMMC1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_CMD_PZ1, SDMMC1, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PWR_I2C_SCL_PZ6, I2CPWR, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(PWR_I2C_SDA_PZ7, I2CPWR, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(SDMMC4_DAT0_PAA0, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT1_PAA1, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT2_PAA2, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT3_PAA3, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT4_PAA4, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT5_PAA5, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT6_PAA6, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT7_PAA7, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PBB0, VGP6, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CAM_I2C_SCL_PBB1, RSVD3, DOWN, TRISTATE, OUTPUT, DISABLE, DEFAULT), + PINCFG(CAM_I2C_SDA_PBB2, RSVD3, DOWN, TRISTATE, OUTPUT, DISABLE, DEFAULT), + PINCFG(PBB3, VGP3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PBB4, VGP4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PBB5, RSVD3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PBB6, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PBB7, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CAM_MCLK_PCC0, VI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PCC1, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PCC2, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_CLK_PCC4, SDMMC4, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(CLK2_REQ_PCC5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PEX_L0_RST_N_PDD1, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PEX_L0_CLKREQ_N_PDD2, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PEX_WAKE_N_PDD3, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PEX_L1_RST_N_PDD5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PEX_L1_CLKREQ_N_PDD6, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CLK3_OUT_PEE0, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CLK3_REQ_PEE1, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP_MCLK1_REQ_PEE2, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(HDMI_CEC_PEE3, CEC, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(SDMMC3_CLK_LB_OUT_PEE4, SDMMC3, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_CLK_LB_IN_PEE5, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DP_HPD_PFF0, DP, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(USB_VBUS_EN2_PFF1, RSVD2, DOWN, TRISTATE, OUTPUT, DISABLE, DEFAULT), + PINCFG(PFF2, RSVD2, DOWN, TRISTATE, OUTPUT, DISABLE, DEFAULT), + PINCFG(CORE_PWR_REQ, PWRON, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CPU_PWR_REQ, CPU, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PWR_INT_N, PMI, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(RESET_OUT_N, RESET_OUT_N, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(OWR, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, NORMAL), + PINCFG(CLK_32K_IN, CLK, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(JTAG_RTCK, RTCK, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), +}; + +#define DRVCFG(_drvgrp, _slwf, _slwr, _drvup, _drvdn, _lpmd, _schmt, _hsm) \ + { \ + .drvgrp = PMUX_DRVGRP_##_drvgrp, \ + .slwf = _slwf, \ + .slwr = _slwr, \ + .drvup = _drvup, \ + .drvdn = _drvdn, \ + .lpmd = PMUX_LPMD_##_lpmd, \ + .schmt = PMUX_SCHMT_##_schmt, \ + .hsm = PMUX_HSM_##_hsm, \ + } + +static const struct pmux_drvgrp_config nyan_big_drvgrps[] = { +}; + +#endif /* PINMUX_CONFIG_NYAN_BIG_H */ diff --git a/board/nvidia/venice2/as3722_init.h b/board/nvidia/venice2/as3722_init.h index 06c366e..992b11f 100644 --- a/board/nvidia/venice2/as3722_init.h +++ b/board/nvidia/venice2/as3722_init.h @@ -18,7 +18,7 @@ #define AS3722_LDO6VOLTAGE_REG 0x16 /* VDD_SDMMC */ #define AS3722_LDCONTROL_REG 0x4E -#ifdef CONFIG_TARGET_JETSON_TK1 +#if defined(CONFIG_TARGET_JETSON_TK1) || defined(CONFIG_TARGET_NYAN_BIG) #define AS3722_SD0VOLTAGE_DATA (0x3C00 | AS3722_SD0VOLTAGE_REG) #else #define AS3722_SD0VOLTAGE_DATA (0x2800 | AS3722_SD0VOLTAGE_REG) diff --git a/board/nvidia/whistler/whistler.c b/board/nvidia/whistler/whistler.c index 3e9d3d9..3114b20 100644 --- a/board/nvidia/whistler/whistler.c +++ b/board/nvidia/whistler/whistler.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -21,23 +22,26 @@ */ void pin_mux_mmc(void) { + struct udevice *dev; uchar val; int ret; /* Turn on MAX8907B LDO12 to 2.8V for J40 power */ - ret = i2c_set_bus_num(0); - if (ret) - printf("i2c_set_bus_num failed: %d\n", ret); + ret = i2c_get_chip_for_busnum(0, 0x3c, &dev); + if (ret) { + printf("%s: Cannot find MAX8907B I2C chip\n", __func__); + return; + } val = 0x29; - ret = i2c_write(0x3c, 0x46, 1, &val, 1); + ret = i2c_write(dev, 0x46, &val, 1); if (ret) printf("i2c_write 0 0x3c 0x46 failed: %d\n", ret); val = 0x00; - ret = i2c_write(0x3c, 0x45, 1, &val, 1); + ret = i2c_write(dev, 0x45, &val, 1); if (ret) printf("i2c_write 0 0x3c 0x45 failed: %d\n", ret); val = 0x1f; - ret = i2c_write(0x3c, 0x44, 1, &val, 1); + ret = i2c_write(dev, 0x44, &val, 1); if (ret) printf("i2c_write 0 0x3c 0x44 failed: %d\n", ret); @@ -49,6 +53,7 @@ void pin_mux_mmc(void) /* this is a weak define that we are overriding */ void pin_mux_usb(void) { + struct udevice *dev; uchar val; int ret; @@ -59,15 +64,17 @@ void pin_mux_usb(void) */ /* Turn on TAC6416's GPIO 0+1 for USB1/3's VBUS */ - ret = i2c_set_bus_num(0); - if (ret) - printf("i2c_set_bus_num failed: %d\n", ret); + ret = i2c_get_chip_for_busnum(0, 0x20, &dev); + if (ret) { + printf("%s: Cannot find TAC6416 I2C chip\n", __func__); + return; + } val = 0x03; - ret = i2c_write(0x20, 2, 1, &val, 1); + ret = i2c_write(dev, 2, &val, 1); if (ret) printf("i2c_write 0 0x20 2 failed: %d\n", ret); val = 0xfc; - ret = i2c_write(0x20, 6, 1, &val, 1); + ret = i2c_write(dev, 6, &val, 1); if (ret) printf("i2c_write 0 0x20 6 failed: %d\n", ret); } diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 51a4fa1..7dbd40e 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -24,6 +24,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -36,6 +37,17 @@ U_BOOT_DEVICE(bcm2835_gpios) = { .platdata = &gpio_platdata, }; +static const struct pl01x_serial_platdata serial_platdata = { + .base = 0x20201000, + .type = TYPE_PL011, + .clock = 3000000, +}; + +U_BOOT_DEVICE(bcm2835_serials) = { + .name = "serial_pl01x", + .platdata = &serial_platdata, +}; + struct msg_get_arm_mem { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; diff --git a/board/toradex/apalis_t30/apalis_t30.c b/board/toradex/apalis_t30/apalis_t30.c index b9d694a..5d2c024 100644 --- a/board/toradex/apalis_t30/apalis_t30.c +++ b/board/toradex/apalis_t30/apalis_t30.c @@ -6,7 +6,7 @@ */ #include - +#include #include #include #include @@ -38,23 +38,20 @@ void pinmux_init(void) #ifdef CONFIG_PCI_TEGRA int tegra_pcie_board_init(void) { - unsigned int old_bus; + struct udevice *dev; u8 addr, data[1]; int err; - old_bus = i2c_get_bus_num(); - - err = i2c_set_bus_num(0); + err = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev); if (err) { - debug("failed to set I2C bus\n"); + debug("%s: Cannot find PMIC I2C chip\n", __func__); return err; } - /* TPS659110: VDD2_OP_REG = 1.05V */ data[0] = 0x27; addr = 0x25; - err = i2c_write(PMU_I2C_ADDRESS, addr, 1, data, 1); + err = i2c_write(dev, addr, data, 1); if (err) { debug("failed to set VDD supply\n"); return err; @@ -64,7 +61,7 @@ int tegra_pcie_board_init(void) data[0] = 0x0D; addr = 0x24; - err = i2c_write(PMU_I2C_ADDRESS, addr, 1, data, 1); + err = i2c_write(dev, addr, data, 1); if (err) { debug("failed to enable VDD supply\n"); return err; @@ -74,14 +71,12 @@ int tegra_pcie_board_init(void) data[0] = 0x0D; addr = 0x35; - err = i2c_write(PMU_I2C_ADDRESS, addr, 1, data, 1); + err = i2c_write(dev, addr, data, 1); if (err) { debug("failed to set AVDD supply\n"); return err; } - i2c_set_bus_num(old_bus); - return 0; } diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c index c266b88..22db1bb 100644 --- a/common/cmd_i2c.c +++ b/common/cmd_i2c.c @@ -69,8 +69,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -117,6 +119,60 @@ static uchar i2c_no_probes[] = CONFIG_SYS_I2C_NOPROBES; #define DISP_LINE_LEN 16 +/* + * Default for driver model is to use the chip's existing address length. + * For legacy code, this is not stored, so we need to use a suitable + * default. + */ +#ifdef CONFIG_DM_I2C +#define DEFAULT_ADDR_LEN (-1) +#else +#define DEFAULT_ADDR_LEN 1 +#endif + +#ifdef CONFIG_DM_I2C +static struct udevice *i2c_cur_bus; + +static int i2c_set_bus_num(unsigned int busnum) +{ + struct udevice *bus; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus); + if (ret) { + debug("%s: No bus %d\n", __func__, busnum); + return ret; + } + i2c_cur_bus = bus; + + return 0; +} + +static int i2c_get_cur_bus(struct udevice **busp) +{ + if (!i2c_cur_bus) { + puts("No I2C bus selected\n"); + return -ENODEV; + } + *busp = i2c_cur_bus; + + return 0; +} + +static int i2c_get_cur_bus_chip(uint chip_addr, struct udevice **devp) +{ + struct udevice *bus; + int ret; + + ret = i2c_get_cur_bus(&bus); + if (ret) + return ret; + + return i2c_get_chip(bus, chip_addr, devp); +} + +#endif + /** * i2c_init_board() - Board-specific I2C bus init * @@ -143,7 +199,7 @@ void i2c_init_board(void) * * Returns I2C bus speed in Hz. */ -#if !defined(CONFIG_SYS_I2C) +#if !defined(CONFIG_SYS_I2C) && !defined(CONFIG_DM_I2C) /* * TODO: Implement architecture-specific get/set functions * Should go away, if we switched completely to new multibus support @@ -182,12 +238,12 @@ int i2c_set_bus_speed(unsigned int speed) * * Returns the address length. */ -static uint get_alen(char *arg) +static uint get_alen(char *arg, int default_len) { int j; int alen; - alen = 1; + alen = default_len; for (j = 0; j < 8; j++) { if (arg[j] == '.') { alen = arg[j+1] - '0'; @@ -227,8 +283,13 @@ static int i2c_report_err(int ret, enum i2c_err_op op) static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; - uint devaddr, alen, length; + uint devaddr, length; + int alen; u_char *memaddr; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc != 5) return CMD_RET_USAGE; @@ -243,7 +304,7 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv * 2 bytes long. Some day it might be 3 bytes long :-). */ devaddr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; @@ -257,18 +318,31 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv */ memaddr = (u_char *)simple_strtoul(argv[4], NULL, 16); - if (i2c_read(chip, devaddr, alen, memaddr, length) != 0) { - i2c_report_err(-1, I2C_ERR_READ); - return 1; - } +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (!ret) + ret = i2c_read(dev, devaddr, memaddr, length); +#else + ret = i2c_read(chip, devaddr, alen, memaddr, length); +#endif + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); + return 0; } static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; - uint devaddr, alen, length; + uint devaddr, length; + int alen; u_char *memaddr; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc != 5) return cmd_usage(cmdtp); @@ -288,7 +362,7 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ * 2 bytes long. Some day it might be 3 bytes long :-). */ devaddr = simple_strtoul(argv[3], NULL, 16); - alen = get_alen(argv[3]); + alen = get_alen(argv[3], DEFAULT_ADDR_LEN); if (alen > 3) return cmd_usage(cmdtp); @@ -297,10 +371,22 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ */ length = simple_strtoul(argv[4], NULL, 16); +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_WRITE); +#endif + while (length-- > 0) { - if (i2c_write(chip, devaddr++, alen, memaddr++, 1) != 0) { - return i2c_report_err(-1, I2C_ERR_WRITE); - } +#ifdef CONFIG_DM_I2C + ret = i2c_write(dev, devaddr++, memaddr++, 1); +#else + ret = i2c_write(chip, devaddr++, alen, memaddr++, 1); +#endif + if (ret) + return i2c_report_err(ret, I2C_ERR_WRITE); /* * No write delay with FRAM devices. */ @@ -311,6 +397,38 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ return 0; } +#ifdef CONFIG_DM_I2C +static int do_i2c_flags(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + uint flags; + int chip; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + chip = simple_strtoul(argv[1], NULL, 16); + ret = i2c_get_cur_bus_chip(chip, &dev); + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); + + if (argc > 2) { + flags = simple_strtoul(argv[2], NULL, 16); + ret = i2c_set_chip_flags(dev, flags); + } else { + ret = i2c_get_chip_flags(dev, &flags); + if (!ret) + printf("%x\n", flags); + } + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); + + return 0; +} +#endif + /** * do_i2c_md() - Handle the "i2c md" command-line command * @cmdtp: Command data struct pointer @@ -327,8 +445,13 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; - uint addr, alen, length; + uint addr, length; + int alen; int j, nbytes, linebytes; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif /* We use the last specified parameters, unless new ones are * entered. @@ -356,7 +479,7 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] * 2 bytes long. Some day it might be 3 bytes long :-). */ addr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; @@ -368,6 +491,14 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] length = simple_strtoul(argv[3], NULL, 16); } +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); +#endif + /* * Print the lines. * @@ -381,8 +512,13 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes; - if (i2c_read(chip, addr, alen, linebuf, linebytes) != 0) - i2c_report_err(-1, I2C_ERR_READ); +#ifdef CONFIG_DM_I2C + ret = i2c_read(dev, addr, linebuf, linebytes); +#else + ret = i2c_read(chip, addr, alen, linebuf, linebytes); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_READ); else { printf("%04x:", addr); cp = linebuf; @@ -429,9 +565,13 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] { uchar chip; ulong addr; - uint alen; + int alen; uchar byte; int count; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if ((argc < 4) || (argc > 5)) return CMD_RET_USAGE; @@ -445,10 +585,17 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] * Address is always specified. */ addr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_WRITE); +#endif /* * Value to write is always specified. */ @@ -463,8 +610,13 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] count = 1; while (count-- > 0) { - if (i2c_write(chip, addr++, alen, &byte, 1) != 0) - i2c_report_err(-1, I2C_ERR_WRITE); +#ifdef CONFIG_DM_I2C + ret = i2c_write(dev, addr++, &byte, 1); +#else + ret = i2c_write(chip, addr++, alen, &byte, 1); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_WRITE); /* * Wait for the write to complete. The write can take * up to 10mSec (we allow a little more time). @@ -499,11 +651,15 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] { uchar chip; ulong addr; - uint alen; + int alen; int count; uchar byte; ulong crc; ulong err; + int ret = 0; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc < 4) return CMD_RET_USAGE; @@ -517,10 +673,17 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] * Address is always specified. */ addr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); +#endif /* * Count is always specified */ @@ -534,13 +697,18 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] crc = 0; err = 0; while (count-- > 0) { - if (i2c_read(chip, addr, alen, &byte, 1) != 0) +#ifdef CONFIG_DM_I2C + ret = i2c_read(dev, addr, &byte, 1); +#else + ret = i2c_read(chip, addr, alen, &byte, 1); +#endif + if (ret) err++; crc = crc32 (crc, &byte, 1); addr++; } if (err > 0) - i2c_report_err(-1, I2C_ERR_READ); + i2c_report_err(ret, I2C_ERR_READ); else printf ("%08lx\n", crc); @@ -568,10 +736,14 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg { uchar chip; ulong addr; - uint alen; + int alen; ulong data; int size = 1; int nbytes; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc != 3) return CMD_RET_USAGE; @@ -601,19 +773,32 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg * Address is always specified. */ addr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; } +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_WRITE); +#endif + /* * Print the address, followed by value. Then accept input for * the next value. A non-converted value exits. */ do { printf("%08lx:", addr); - if (i2c_read(chip, addr, alen, (uchar *)&data, size) != 0) - i2c_report_err(-1, I2C_ERR_READ); +#ifdef CONFIG_DM_I2C + ret = i2c_read(dev, addr, (uchar *)&data, size); +#else + ret = i2c_read(chip, addr, alen, (uchar *)&data, size); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_READ); else { data = cpu_to_be32(data); if (size == 1) @@ -655,8 +840,15 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg * good enough to not time out */ bootretry_reset_cmd_timeout(); - if (i2c_write(chip, addr, alen, (uchar *)&data, size) != 0) - i2c_report_err(-1, I2C_ERR_WRITE); +#ifdef CONFIG_DM_I2C + ret = i2c_write(dev, addr, (uchar *)&data, + size); +#else + ret = i2c_write(chip, addr, alen, + (uchar *)&data, size); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_WRITE); #ifdef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000); #endif @@ -697,6 +889,13 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv int k, skip; unsigned int bus = GET_BUS_NUM; #endif /* NOPROBES */ + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *bus, *dev; + + if (i2c_get_cur_bus(&bus)) + return CMD_RET_FAILURE; +#endif if (argc == 2) addr = simple_strtol(argv[1], 0, 16); @@ -717,7 +916,12 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv if (skip) continue; #endif - if (i2c_probe(j) == 0) { +#ifdef CONFIG_DM_I2C + ret = i2c_probe(bus, j, 0, &dev); +#else + ret = i2c_probe(j); +#endif + if (ret == 0) { printf(" %02X", j); found++; } @@ -754,11 +958,15 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; - ulong alen; + int alen; uint addr; uint length; u_char bytes[16]; int delay; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc < 3) return CMD_RET_USAGE; @@ -772,9 +980,16 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] * Address is always specified. */ addr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_WRITE); +#endif /* * Length is the number of objects, not number of bytes. @@ -794,8 +1009,13 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] * Run the loop... */ while (1) { - if (i2c_read(chip, addr, alen, bytes, length) != 0) - i2c_report_err(-1, I2C_ERR_READ); +#ifdef CONFIG_DM_I2C + ret = i2c_read(dev, addr, bytes, length); +#else + ret = i2c_read(chip, addr, alen, bytes, length); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_READ); udelay(delay); } @@ -1345,6 +1565,10 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { u_char chip; struct edid1_info edid; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc < 2) { cmd_usage(cmdtp); @@ -1352,10 +1576,15 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) } chip = simple_strtoul(argv[1], NULL, 16); - if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) { - i2c_report_err(-1, I2C_ERR_READ); - return 1; - } +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret) + ret = i2c_read(dev, 0, (uchar *)&edid, sizeof(edid)); +#else + ret = i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)); +#endif + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); if (edid_check_info(&edid)) { puts("Content isn't valid EDID.\n"); @@ -1437,17 +1666,28 @@ static int do_i2c_show_bus(cmd_tbl_t *cmdtp, int flag, int argc, * Returns zero on success, CMD_RET_USAGE in case of misuse and negative * on error. */ -#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS) +#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS) || \ + defined(CONFIG_DM_I2C) static int do_i2c_bus_num(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int ret = 0; - unsigned int bus_no; + int bus_no; - if (argc == 1) + if (argc == 1) { /* querying current setting */ - printf("Current bus is %d\n", i2c_get_bus_num()); - else { +#ifdef CONFIG_DM_I2C + struct udevice *bus; + + if (!i2c_get_cur_bus(&bus)) + bus_no = bus->seq; + else + bus_no = -1; +#else + bus_no = i2c_get_bus_num(); +#endif + printf("Current bus is %d\n", bus_no); + } else { bus_no = simple_strtoul(argv[1], NULL, 10); #if defined(CONFIG_SYS_I2C) if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES) { @@ -1478,13 +1718,28 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const { int speed, ret=0; - if (argc == 1) +#ifdef CONFIG_DM_I2C + struct udevice *bus; + + if (i2c_get_cur_bus(&bus)) + return 1; +#endif + if (argc == 1) { +#ifdef CONFIG_DM_I2C + speed = i2c_get_bus_speed(bus); +#else + speed = i2c_get_bus_speed(); +#endif /* querying current speed */ - printf("Current bus speed=%d\n", i2c_get_bus_speed()); - else { + printf("Current bus speed=%d\n", speed); + } else { speed = simple_strtoul(argv[1], NULL, 10); printf("Setting bus speed to %d Hz\n", speed); +#ifdef CONFIG_DM_I2C + ret = i2c_set_bus_speed(bus, speed); +#else ret = i2c_set_bus_speed(speed); +#endif if (ret) printf("Failure changing bus speed (%d)\n", ret); } @@ -1532,7 +1787,16 @@ static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) */ static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { -#if defined(CONFIG_SYS_I2C) +#if defined(CONFIG_DM_I2C) + struct udevice *bus; + + if (i2c_get_cur_bus(&bus)) + return CMD_RET_FAILURE; + if (i2c_deblock(bus)) { + printf("Error: Not supported by the driver\n"); + return CMD_RET_FAILURE; + } +#elif defined(CONFIG_SYS_I2C) i2c_init(I2C_ADAP->speed, I2C_ADAP->slaveaddr); #else i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); @@ -1546,7 +1810,7 @@ static cmd_tbl_t cmd_i2c_sub[] = { #endif U_BOOT_CMD_MKENT(crc32, 3, 1, do_i2c_crc, "", ""), #if defined(CONFIG_SYS_I2C) || \ - defined(CONFIG_I2C_MULTI_BUS) + defined(CONFIG_I2C_MULTI_BUS) || defined(CONFIG_DM_I2C) U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""), #endif /* CONFIG_I2C_MULTI_BUS */ #if defined(CONFIG_I2C_EDID) @@ -1560,6 +1824,9 @@ static cmd_tbl_t cmd_i2c_sub[] = { U_BOOT_CMD_MKENT(probe, 0, 1, do_i2c_probe, "", ""), U_BOOT_CMD_MKENT(read, 5, 1, do_i2c_read, "", ""), U_BOOT_CMD_MKENT(write, 5, 0, do_i2c_write, "", ""), +#ifdef CONFIG_DM_I2C + U_BOOT_CMD_MKENT(flags, 2, 1, do_i2c_flags, "", ""), +#endif U_BOOT_CMD_MKENT(reset, 0, 1, do_i2c_reset, "", ""), #if defined(CONFIG_CMD_SDRAM) U_BOOT_CMD_MKENT(sdram, 1, 1, do_sdram, "", ""), @@ -1610,7 +1877,7 @@ static char i2c_help_text[] = #endif "crc32 chip address[.0, .1, .2] count - compute CRC32 checksum\n" #if defined(CONFIG_SYS_I2C) || \ - defined(CONFIG_I2C_MULTI_BUS) + defined(CONFIG_I2C_MULTI_BUS) || defined(CONFIG_DM_I2C) "i2c dev [dev] - show or set current I2C bus\n" #endif /* CONFIG_I2C_MULTI_BUS */ #if defined(CONFIG_I2C_EDID) @@ -1622,8 +1889,11 @@ static char i2c_help_text[] = "i2c mw chip address[.0, .1, .2] value [count] - write to I2C device (fill)\n" "i2c nm chip address[.0, .1, .2] - write to I2C device (constant address)\n" "i2c probe [address] - test for and show device(s) on the I2C bus\n" - "i2c read chip address[.0, .1, .2] length memaddress - read to memory \n" + "i2c read chip address[.0, .1, .2] length memaddress - read to memory\n" "i2c write memaddress chip address[.0, .1, .2] length - write memory to i2c\n" +#ifdef CONFIG_DM_I2C + "i2c flags chip [flags] - set or get chip flags\n" +#endif "i2c reset - re-init the I2C Controller\n" #if defined(CONFIG_CMD_SDRAM) "i2c sdram chip - print SDRAM configuration information\n" diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig new file mode 100644 index 0000000..ec79b5b --- /dev/null +++ b/configs/nyan-big_defconfig @@ -0,0 +1,5 @@ ++S:CONFIG_ARM=y ++S:CONFIG_TEGRA=y ++S:CONFIG_TEGRA124=y ++S:CONFIG_TARGET_NYAN_BIG=y +CONFIG_DEFAULT_DEVICE_TREE="tegra124-nyan-big" diff --git a/drivers/core/device.c b/drivers/core/device.c index 6793e1c..963b16f 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -234,7 +234,7 @@ int device_probe(struct udevice *dev) void *dev_get_platdata(struct udevice *dev) { if (!dev) { - dm_warn("%s: null device", __func__); + dm_warn("%s: null device\n", __func__); return NULL; } @@ -244,7 +244,7 @@ void *dev_get_platdata(struct udevice *dev) void *dev_get_priv(struct udevice *dev) { if (!dev) { - dm_warn("%s: null device", __func__); + dm_warn("%s: null device\n", __func__); return NULL; } @@ -254,7 +254,7 @@ void *dev_get_priv(struct udevice *dev) void *dev_get_parentdata(struct udevice *dev) { if (!dev) { - dm_warn("%s: null device", __func__); + dm_warn("%s: null device\n", __func__); return NULL; } diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index dae3d71..6f3c86c 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -4,6 +4,7 @@ # # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_DM_I2C) += i2c-uclass.o obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o obj-$(CONFIG_I2C_MV) += mv_i2c.o @@ -26,6 +27,7 @@ obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o +obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c new file mode 100644 index 0000000..aa89f95 --- /dev/null +++ b/drivers/i2c/i2c-emul-uclass.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +UCLASS_DRIVER(i2c_emul) = { + .id = UCLASS_I2C_EMUL, + .name = "i2c_emul", +}; diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c new file mode 100644 index 0000000..005bf86 --- /dev/null +++ b/drivers/i2c/i2c-uclass.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define I2C_MAX_OFFSET_LEN 4 + +/** + * i2c_setup_offset() - Set up a new message with a chip offset + * + * @chip: Chip to use + * @offset: Byte offset within chip + * @offset_buf: Place to put byte offset + * @msg: Message buffer + * @return 0 if OK, -EADDRNOTAVAIL if the offset length is 0. In that case the + * message is still set up but will not contain an offset. + */ +static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset, + uint8_t offset_buf[], struct i2c_msg *msg) +{ + int offset_len; + + msg->addr = chip->chip_addr; + msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; + msg->len = chip->offset_len; + msg->buf = offset_buf; + if (!chip->offset_len) + return -EADDRNOTAVAIL; + assert(chip->offset_len <= I2C_MAX_OFFSET_LEN); + offset_len = chip->offset_len; + while (offset_len--) + *offset_buf++ = offset >> (8 * offset_len); + + return 0; +} + +static int i2c_read_bytewise(struct udevice *dev, uint offset, + uint8_t *buffer, int len) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + struct udevice *bus = dev_get_parent(dev); + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct i2c_msg msg[2], *ptr; + uint8_t offset_buf[I2C_MAX_OFFSET_LEN]; + int ret; + int i; + + for (i = 0; i < len; i++) { + if (i2c_setup_offset(chip, offset + i, offset_buf, msg)) + return -EINVAL; + ptr = msg + 1; + ptr->addr = chip->chip_addr; + ptr->flags = msg->flags | I2C_M_RD; + ptr->len = 1; + ptr->buf = &buffer[i]; + ptr++; + + ret = ops->xfer(bus, msg, ptr - msg); + if (ret) + return ret; + } + + return 0; +} + +static int i2c_write_bytewise(struct udevice *dev, uint offset, + const uint8_t *buffer, int len) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + struct udevice *bus = dev_get_parent(dev); + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct i2c_msg msg[1]; + uint8_t buf[I2C_MAX_OFFSET_LEN + 1]; + int ret; + int i; + + for (i = 0; i < len; i++) { + if (i2c_setup_offset(chip, offset + i, buf, msg)) + return -EINVAL; + buf[msg->len++] = buffer[i]; + + ret = ops->xfer(bus, msg, 1); + if (ret) + return ret; + } + + return 0; +} + +int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + struct udevice *bus = dev_get_parent(dev); + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct i2c_msg msg[2], *ptr; + uint8_t offset_buf[I2C_MAX_OFFSET_LEN]; + int msg_count; + + if (!ops->xfer) + return -ENOSYS; + if (chip->flags & DM_I2C_CHIP_RD_ADDRESS) + return i2c_read_bytewise(dev, offset, buffer, len); + ptr = msg; + if (!i2c_setup_offset(chip, offset, offset_buf, ptr)) + ptr++; + + if (len) { + ptr->addr = chip->chip_addr; + ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; + ptr->flags |= I2C_M_RD; + ptr->len = len; + ptr->buf = buffer; + ptr++; + } + msg_count = ptr - msg; + + return ops->xfer(bus, msg, msg_count); +} + +int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, int len) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + struct udevice *bus = dev_get_parent(dev); + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct i2c_msg msg[1]; + + if (!ops->xfer) + return -ENOSYS; + + if (chip->flags & DM_I2C_CHIP_WR_ADDRESS) + return i2c_write_bytewise(dev, offset, buffer, len); + /* + * The simple approach would be to send two messages here: one to + * set the offset and one to write the bytes. However some drivers + * will not be expecting this, and some chips won't like how the + * driver presents this on the I2C bus. + * + * The API does not support separate offset and data. We could extend + * it with a flag indicating that there is data in the next message + * that needs to be processed in the same transaction. We could + * instead add an additional buffer to each message. For now, handle + * this in the uclass since it isn't clear what the impact on drivers + * would be with this extra complication. Unfortunately this means + * copying the message. + * + * Use the stack for small messages, malloc() for larger ones. We + * need to allow space for the offset (up to 4 bytes) and the message + * itself. + */ + if (len < 64) { + uint8_t buf[I2C_MAX_OFFSET_LEN + len]; + + i2c_setup_offset(chip, offset, buf, msg); + msg->len += len; + memcpy(buf + chip->offset_len, buffer, len); + + return ops->xfer(bus, msg, 1); + } else { + uint8_t *buf; + int ret; + + buf = malloc(I2C_MAX_OFFSET_LEN + len); + if (!buf) + return -ENOMEM; + i2c_setup_offset(chip, offset, buf, msg); + msg->len += len; + memcpy(buf + chip->offset_len, buffer, len); + + ret = ops->xfer(bus, msg, 1); + free(buf); + return ret; + } +} + +/** + * i2c_probe_chip() - probe for a chip on a bus + * + * @bus: Bus to probe + * @chip_addr: Chip address to probe + * @flags: Flags for the chip + * @return 0 if found, -ENOSYS if the driver is invalid, -EREMOTEIO if the chip + * does not respond to probe + */ +static int i2c_probe_chip(struct udevice *bus, uint chip_addr, + enum dm_i2c_chip_flags chip_flags) +{ + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct i2c_msg msg[1]; + int ret; + + if (ops->probe_chip) { + ret = ops->probe_chip(bus, chip_addr, chip_flags); + if (!ret || ret != -ENOSYS) + return ret; + } + + if (!ops->xfer) + return -ENOSYS; + + /* Probe with a zero-length message */ + msg->addr = chip_addr; + msg->flags = chip_flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; + msg->len = 0; + msg->buf = NULL; + + return ops->xfer(bus, msg, 1); +} + +static int i2c_bind_driver(struct udevice *bus, uint chip_addr, + struct udevice **devp) +{ + struct dm_i2c_chip chip; + char name[30], *str; + struct udevice *dev; + int ret; + + snprintf(name, sizeof(name), "generic_%x", chip_addr); + str = strdup(name); + ret = device_bind_driver(bus, "i2c_generic_chip_drv", str, &dev); + debug("%s: device_bind_driver: ret=%d\n", __func__, ret); + if (ret) + goto err_bind; + + /* Tell the device what we know about it */ + memset(&chip, '\0', sizeof(chip)); + chip.chip_addr = chip_addr; + chip.offset_len = 1; /* we assume */ + ret = device_probe_child(dev, &chip); + debug("%s: device_probe_child: ret=%d\n", __func__, ret); + if (ret) + goto err_probe; + + *devp = dev; + return 0; + +err_probe: + device_unbind(dev); +err_bind: + free(str); + return ret; +} + +int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp) +{ + struct udevice *dev; + + debug("%s: Searching bus '%s' for address %02x: ", __func__, + bus->name, chip_addr); + for (device_find_first_child(bus, &dev); dev; + device_find_next_child(&dev)) { + struct dm_i2c_chip store; + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + int ret; + + if (!chip) { + chip = &store; + i2c_chip_ofdata_to_platdata(gd->fdt_blob, + dev->of_offset, chip); + } + if (chip->chip_addr == chip_addr) { + ret = device_probe(dev); + debug("found, ret=%d\n", ret); + if (ret) + return ret; + *devp = dev; + return 0; + } + } + debug("not found\n"); + return i2c_bind_driver(bus, chip_addr, devp); +} + +int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp) +{ + struct udevice *bus; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus); + if (ret) { + debug("Cannot find I2C bus %d\n", busnum); + return ret; + } + ret = i2c_get_chip(bus, chip_addr, devp); + if (ret) { + debug("Cannot find I2C chip %02x on bus %d\n", chip_addr, + busnum); + return ret; + } + + return 0; +} + +int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags, + struct udevice **devp) +{ + int ret; + + *devp = NULL; + + /* First probe that chip */ + ret = i2c_probe_chip(bus, chip_addr, chip_flags); + debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name, + chip_addr, ret); + if (ret) + return ret; + + /* The chip was found, see if we have a driver, and probe it */ + ret = i2c_get_chip(bus, chip_addr, devp); + debug("%s: i2c_get_chip: ret=%d\n", __func__, ret); + + return ret; +} + +int i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +{ + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct dm_i2c_bus *i2c = bus->uclass_priv; + int ret; + + /* + * If we have a method, call it. If not then the driver probably wants + * to deal with speed changes on the next transfer. It can easily read + * the current speed from this uclass + */ + if (ops->set_bus_speed) { + ret = ops->set_bus_speed(bus, speed); + if (ret) + return ret; + } + i2c->speed_hz = speed; + + return 0; +} + +/* + * i2c_get_bus_speed: + * + * Returns speed of selected I2C bus in Hz + */ +int i2c_get_bus_speed(struct udevice *bus) +{ + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct dm_i2c_bus *i2c = bus->uclass_priv; + + if (!ops->get_bus_speed) + return i2c->speed_hz; + + return ops->get_bus_speed(bus); +} + +int i2c_set_chip_flags(struct udevice *dev, uint flags) +{ + struct udevice *bus = dev->parent; + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + struct dm_i2c_ops *ops = i2c_get_ops(bus); + int ret; + + if (ops->set_flags) { + ret = ops->set_flags(dev, flags); + if (ret) + return ret; + } + chip->flags = flags; + + return 0; +} + +int i2c_get_chip_flags(struct udevice *dev, uint *flagsp) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + + *flagsp = chip->flags; + + return 0; +} + +int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + + if (offset_len > I2C_MAX_OFFSET_LEN) + return -EINVAL; + chip->offset_len = offset_len; + + return 0; +} + +int i2c_deblock(struct udevice *bus) +{ + struct dm_i2c_ops *ops = i2c_get_ops(bus); + + /* + * We could implement a software deblocking here if we could get + * access to the GPIOs used by I2C, and switch them to GPIO mode + * and then back to I2C. This is somewhat beyond our powers in + * driver model at present, so for now just fail. + * + * See https://patchwork.ozlabs.org/patch/399040/ + */ + if (!ops->deblock) + return -ENOSYS; + + return ops->deblock(bus); +} + +int i2c_chip_ofdata_to_platdata(const void *blob, int node, + struct dm_i2c_chip *chip) +{ + chip->offset_len = 1; /* default */ + chip->flags = 0; + chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1); + if (chip->chip_addr == -1) { + debug("%s: I2C Node '%s' has no 'reg' property\n", __func__, + fdt_get_name(blob, node, NULL)); + return -EINVAL; + } + + return 0; +} + +static int i2c_post_probe(struct udevice *dev) +{ + struct dm_i2c_bus *i2c = dev->uclass_priv; + + i2c->speed_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "clock-frequency", 100000); + + return i2c_set_bus_speed(dev, i2c->speed_hz); +} + +int i2c_post_bind(struct udevice *dev) +{ + /* Scan the bus for devices */ + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); +} + +UCLASS_DRIVER(i2c) = { + .id = UCLASS_I2C, + .name = "i2c", + .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus), + .post_bind = i2c_post_bind, + .post_probe = i2c_post_probe, +}; + +UCLASS_DRIVER(i2c_generic) = { + .id = UCLASS_I2C_GENERIC, + .name = "i2c_generic", +}; + +U_BOOT_DRIVER(i2c_generic_chip_drv) = { + .name = "i2c_generic_chip_drv", + .id = UCLASS_I2C_GENERIC, +}; diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c new file mode 100644 index 0000000..f0e9f51 --- /dev/null +++ b/drivers/i2c/sandbox_i2c.c @@ -0,0 +1,111 @@ +/* + * Simulate an I2C port + * + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct dm_sandbox_i2c_emul_priv { + struct udevice *emul; +}; + +static int get_emul(struct udevice *dev, struct udevice **devp, + struct dm_i2c_ops **opsp) +{ + struct dm_i2c_chip *priv; + int ret; + + *devp = NULL; + *opsp = NULL; + priv = dev_get_parentdata(dev); + if (!priv->emul) { + ret = dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, + false); + if (ret) + return ret; + + ret = device_get_child(dev, 0, &priv->emul); + if (ret) + return ret; + } + *devp = priv->emul; + *opsp = i2c_get_ops(priv->emul); + + return 0; +} + +static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, + int nmsgs) +{ + struct dm_i2c_bus *i2c = bus->uclass_priv; + struct dm_i2c_ops *ops; + struct udevice *emul, *dev; + bool is_read; + int ret; + + /* Special test code to return success but with no emulation */ + if (msg->addr == SANDBOX_I2C_TEST_ADDR) + return 0; + + ret = i2c_get_chip(bus, msg->addr, &dev); + if (ret) + return ret; + + ret = get_emul(dev, &emul, &ops); + if (ret) + return ret; + + /* + * For testing, don't allow writing above 100KHz for writes and + * 400KHz for reads + */ + is_read = nmsgs > 1; + if (i2c->speed_hz > (is_read ? 400000 : 100000)) + return -EINVAL; + return ops->xfer(emul, msg, nmsgs); +} + +static const struct dm_i2c_ops sandbox_i2c_ops = { + .xfer = sandbox_i2c_xfer, +}; + +static int sandbox_i2c_child_pre_probe(struct udevice *dev) +{ + struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev); + + /* Ignore our test address */ + if (i2c_chip->chip_addr == SANDBOX_I2C_TEST_ADDR) + return 0; + if (dev->of_offset == -1) + return 0; + + return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, + i2c_chip); +} + +static const struct udevice_id sandbox_i2c_ids[] = { + { .compatible = "sandbox,i2c" }, + { } +}; + +U_BOOT_DRIVER(i2c_sandbox) = { + .name = "i2c_sandbox", + .id = UCLASS_I2C, + .of_match = sandbox_i2c_ids, + .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), + .child_pre_probe = sandbox_i2c_child_pre_probe, + .ops = &sandbox_i2c_ops, +}; diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index 562211e..87290c3 100644 --- a/drivers/i2c/tegra_i2c.c +++ b/drivers/i2c/tegra_i2c.c @@ -7,6 +7,8 @@ */ #include +#include +#include #include #include #include @@ -19,6 +21,12 @@ DECLARE_GLOBAL_DATA_PTR; +enum i2c_type { + TYPE_114, + TYPE_STD, + TYPE_DVC, +}; + /* Information about i2c controller */ struct i2c_bus { int id; @@ -27,20 +35,17 @@ struct i2c_bus { int pinmux_config; struct i2c_control *control; struct i2c_ctlr *regs; - int is_dvc; /* DVC type, rather than I2C */ - int is_scs; /* single clock source (T114+) */ + enum i2c_type type; int inited; /* bus is inited */ }; -static struct i2c_bus i2c_controllers[TEGRA_I2C_NUM_CONTROLLERS]; - static void set_packet_mode(struct i2c_bus *i2c_bus) { u32 config; config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK; - if (i2c_bus->is_dvc) { + if (i2c_bus->type == TYPE_DVC) { struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs; writel(config, &dvc->cnfg); @@ -65,6 +70,9 @@ static void i2c_reset_controller(struct i2c_bus *i2c_bus) static void i2c_init_controller(struct i2c_bus *i2c_bus) { + if (!i2c_bus->speed) + return; + debug("%s: speed=%d\n", __func__, i2c_bus->speed); /* * Use PLLP - DP-04508-001_v06 datasheet indicates a divisor of 8 * here, in section 23.3.1, but in fact we seem to need a factor of @@ -73,7 +81,7 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH, i2c_bus->speed * 2 * 8); - if (i2c_bus->is_scs) { + if (i2c_bus->type == TYPE_114) { /* * T114 I2C went to a single clock source for standard/fast and * HS clock speeds. The new clock rate setting calculation is: @@ -98,7 +106,7 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) i2c_reset_controller(i2c_bus); /* Configure I2C controller. */ - if (i2c_bus->is_dvc) { /* only for DVC I2C */ + if (i2c_bus->type == TYPE_DVC) { /* only for DVC I2C */ struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs; setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK); @@ -272,7 +280,7 @@ exit: return error; } -static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data, +static int tegra_i2c_write_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data, u32 len, bool end_with_repeated_start) { int error; @@ -286,14 +294,14 @@ static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data, trans_info.num_bytes = len; trans_info.is_10bit_address = 0; - error = send_recv_packets(bus, &trans_info); + error = send_recv_packets(i2c_bus, &trans_info); if (error) debug("tegra_i2c_write_data: Error (%d) !!!\n", error); return error; } -static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data, +static int tegra_i2c_read_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data, u32 len) { int error; @@ -305,52 +313,32 @@ static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data, trans_info.num_bytes = len; trans_info.is_10bit_address = 0; - error = send_recv_packets(bus, &trans_info); + error = send_recv_packets(i2c_bus, &trans_info); if (error) debug("tegra_i2c_read_data: Error (%d) !!!\n", error); return error; } -#ifndef CONFIG_OF_CONTROL -#error "Please enable device tree support to use this driver" -#endif - -/** - * Check that a bus number is valid and return a pointer to it - * - * @param bus_num Bus number to check / return - * @return pointer to bus, if valid, else NULL - */ -static struct i2c_bus *tegra_i2c_get_bus(struct i2c_adapter *adap) +static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) { - struct i2c_bus *bus; + struct i2c_bus *i2c_bus = dev_get_priv(dev); - bus = &i2c_controllers[adap->hwadapnr]; - if (!bus->inited) { - debug("%s: Bus %u not available\n", __func__, adap->hwadapnr); - return NULL; - } - - return bus; -} - -static unsigned int tegra_i2c_set_bus_speed(struct i2c_adapter *adap, - unsigned int speed) -{ - struct i2c_bus *bus; - - bus = tegra_i2c_get_bus(adap); - if (!bus) - return 0; - bus->speed = speed; - i2c_init_controller(bus); + i2c_bus->speed = speed; + i2c_init_controller(i2c_bus); return 0; } -static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus) +static int tegra_i2c_probe(struct udevice *dev) { + struct i2c_bus *i2c_bus = dev_get_priv(dev); + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + bool is_dvc; + + i2c_bus->id = dev->seq; + i2c_bus->type = dev_get_of_data(dev); i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg"); /* @@ -358,7 +346,6 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus) * far no one needs anything other than the default. */ i2c_bus->pinmux_config = FUNCMUX_DEFAULT; - i2c_bus->speed = fdtdec_get_int(blob, node, "clock-frequency", 0); i2c_bus->periph_id = clock_decode_periph_id(blob, node); /* @@ -371,107 +358,25 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus) * i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA; */ if (i2c_bus->periph_id == -1) - return -FDT_ERR_NOTFOUND; + return -EINVAL; - return 0; -} - -/* - * Process a list of nodes, adding them to our list of I2C ports. - * - * @param blob fdt blob - * @param node_list list of nodes to process (any <=0 are ignored) - * @param count number of nodes to process - * @param is_dvc 1 if these are DVC ports, 0 if standard I2C - * @param is_scs 1 if this HW uses a single clock source (T114+) - * @return 0 if ok, -1 on error - */ -static int process_nodes(const void *blob, int node_list[], int count, - int is_dvc, int is_scs) -{ - struct i2c_bus *i2c_bus; - int i; - - /* build the i2c_controllers[] for each controller */ - for (i = 0; i < count; i++) { - int node = node_list[i]; - - if (node <= 0) - continue; - - i2c_bus = &i2c_controllers[i]; - i2c_bus->id = i; - - if (i2c_get_config(blob, node, i2c_bus)) { - printf("i2c_init_board: failed to decode bus %d\n", i); - return -1; - } - - i2c_bus->is_scs = is_scs; - - i2c_bus->is_dvc = is_dvc; - if (is_dvc) { - i2c_bus->control = - &((struct dvc_ctlr *)i2c_bus->regs)->control; - } else { - i2c_bus->control = &i2c_bus->regs->control; - } - debug("%s: controller bus %d at %p, periph_id %d, speed %d: ", - is_dvc ? "dvc" : "i2c", i, i2c_bus->regs, - i2c_bus->periph_id, i2c_bus->speed); - i2c_init_controller(i2c_bus); - debug("ok\n"); - i2c_bus->inited = 1; - - /* Mark position as used */ - node_list[i] = -1; + is_dvc = dev_get_of_data(dev) == TYPE_DVC; + if (is_dvc) { + i2c_bus->control = + &((struct dvc_ctlr *)i2c_bus->regs)->control; + } else { + i2c_bus->control = &i2c_bus->regs->control; } + i2c_init_controller(i2c_bus); + debug("%s: controller bus %d at %p, periph_id %d, speed %d: ", + is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs, + i2c_bus->periph_id, i2c_bus->speed); return 0; } -/* Sadly there is no error return from this function */ -void i2c_init_board(void) -{ - int node_list[TEGRA_I2C_NUM_CONTROLLERS]; - const void *blob = gd->fdt_blob; - int count; - - /* First check for newer (T114+) I2C ports */ - count = fdtdec_find_aliases_for_id(blob, "i2c", - COMPAT_NVIDIA_TEGRA114_I2C, node_list, - TEGRA_I2C_NUM_CONTROLLERS); - if (process_nodes(blob, node_list, count, 0, 1)) - return; - - /* Now get the older (T20/T30) normal I2C ports */ - count = fdtdec_find_aliases_for_id(blob, "i2c", - COMPAT_NVIDIA_TEGRA20_I2C, node_list, - TEGRA_I2C_NUM_CONTROLLERS); - if (process_nodes(blob, node_list, count, 0, 0)) - return; - - /* Now look for dvc ports */ - count = fdtdec_add_aliases_for_id(blob, "i2c", - COMPAT_NVIDIA_TEGRA20_DVC, node_list, - TEGRA_I2C_NUM_CONTROLLERS); - if (process_nodes(blob, node_list, count, 1, 0)) - return; -} - -static void tegra_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) -{ - /* No i2c support prior to relocation */ - if (!(gd->flags & GD_FLG_RELOC)) - return; - - /* This will override the speed selected in the fdt for that port */ - debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr); - i2c_set_bus_speed(speed); -} - /* i2c write version without the register address */ -static int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, +static int i2c_write_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer, int len, bool end_with_repeated_start) { int rc; @@ -484,7 +389,7 @@ static int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, debug("\n"); /* Shift 7-bit address over for lower-level i2c functions */ - rc = tegra_i2c_write_data(bus, chip << 1, buffer, len, + rc = tegra_i2c_write_data(i2c_bus, chip << 1, buffer, len, end_with_repeated_start); if (rc) debug("i2c_write_data(): rc=%d\n", rc); @@ -493,14 +398,14 @@ static int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, } /* i2c read version without the register address */ -static int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer, - int len) +static int i2c_read_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer, + int len) { int rc; debug("inside i2c_read_data():\n"); /* Shift 7-bit address over for lower-level i2c functions */ - rc = tegra_i2c_read_data(bus, chip << 1, buffer, len); + rc = tegra_i2c_read_data(i2c_bus, chip << 1, buffer, len); if (rc) { debug("i2c_read_data(): rc=%d\n", rc); return rc; @@ -516,132 +421,99 @@ static int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer, } /* Probe to see if a chip is present. */ -static int tegra_i2c_probe(struct i2c_adapter *adap, uchar chip) +static int tegra_i2c_probe_chip(struct udevice *bus, uint chip_addr, + uint chip_flags) { - struct i2c_bus *bus; + struct i2c_bus *i2c_bus = dev_get_priv(bus); int rc; - uchar reg; - - debug("i2c_probe: addr=0x%x\n", chip); - bus = tegra_i2c_get_bus(adap); - if (!bus) - return 1; - reg = 0; - rc = i2c_write_data(bus, chip, ®, 1, false); - if (rc) { - debug("Error probing 0x%x.\n", chip); - return 1; - } - return 0; -} + u8 reg; -static int i2c_addr_ok(const uint addr, const int alen) -{ - /* We support 7 or 10 bit addresses, so one or two bytes each */ - return alen == 1 || alen == 2; + /* Shift 7-bit address over for lower-level i2c functions */ + rc = tegra_i2c_write_data(i2c_bus, chip_addr << 1, ®, sizeof(reg), + false); + + return rc; } -/* Read bytes */ -static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, - int alen, uchar *buffer, int len) +static int tegra_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, + int nmsgs) { - struct i2c_bus *bus; - uint offset; - int i; - - debug("i2c_read: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n", - chip, addr, alen, len); - bus = tegra_i2c_get_bus(adap); - if (!bus) - return 1; - if (!i2c_addr_ok(addr, alen)) { - debug("i2c_read: Bad address %x.%d.\n", addr, alen); - return 1; - } - for (offset = 0; offset < len; offset++) { - if (alen) { - uchar data[alen]; - for (i = 0; i < alen; i++) { - data[alen - i - 1] = - (addr + offset) >> (8 * i); - } - if (i2c_write_data(bus, chip, data, alen, true)) { - debug("i2c_read: error sending (0x%x)\n", - addr); - return 1; - } + struct i2c_bus *i2c_bus = dev_get_priv(bus); + int ret; + + debug("i2c_xfer: %d messages\n", nmsgs); + for (; nmsgs > 0; nmsgs--, msg++) { + bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD); + + debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); + 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); } - if (i2c_read_data(bus, chip, buffer + offset, 1)) { - debug("i2c_read: error reading (0x%x)\n", addr); - return 1; + if (ret) { + debug("i2c_write: error sending\n"); + return -EREMOTEIO; } } return 0; } -/* Write bytes */ -static int tegra_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, - int alen, uchar *buffer, int len) +int tegra_i2c_get_dvc_bus(struct udevice **busp) { - struct i2c_bus *bus; - uint offset; - int i; - - debug("i2c_write: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n", - chip, addr, alen, len); - bus = tegra_i2c_get_bus(adap); - if (!bus) - return 1; - if (!i2c_addr_ok(addr, alen)) { - debug("i2c_write: Bad address %x.%d.\n", addr, alen); - return 1; - } - for (offset = 0; offset < len; offset++) { - uchar data[alen + 1]; - for (i = 0; i < alen; i++) - data[alen - i - 1] = (addr + offset) >> (8 * i); - data[alen] = buffer[offset]; - if (i2c_write_data(bus, chip, data, alen + 1, false)) { - debug("i2c_write: error sending (0x%x)\n", addr); - return 1; + struct udevice *bus; + + for (uclass_first_device(UCLASS_I2C, &bus); + bus; + uclass_next_device(&bus)) { + if (dev_get_of_data(bus) == TYPE_DVC) { + *busp = bus; + return 0; } } - return 0; + return -ENODEV; } -int tegra_i2c_get_dvc_bus_num(void) -{ - int i; +static const struct dm_i2c_ops tegra_i2c_ops = { + .xfer = tegra_i2c_xfer, + .probe_chip = tegra_i2c_probe_chip, + .set_bus_speed = tegra_i2c_set_bus_speed, +}; - for (i = 0; i < TEGRA_I2C_NUM_CONTROLLERS; i++) { - struct i2c_bus *bus = &i2c_controllers[i]; +static int tegra_i2c_child_pre_probe(struct udevice *dev) +{ + struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev); - if (bus->inited && bus->is_dvc) - return i; - } + if (dev->of_offset == -1) + return 0; + return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, + i2c_chip); +} - return -1; +static int tegra_i2c_ofdata_to_platdata(struct udevice *dev) +{ + return 0; } -/* - * Register soft i2c adapters - */ -U_BOOT_I2C_ADAP_COMPLETE(tegra0, tegra_i2c_init, tegra_i2c_probe, - tegra_i2c_read, tegra_i2c_write, - tegra_i2c_set_bus_speed, 100000, 0, 0) -U_BOOT_I2C_ADAP_COMPLETE(tegra1, tegra_i2c_init, tegra_i2c_probe, - tegra_i2c_read, tegra_i2c_write, - tegra_i2c_set_bus_speed, 100000, 0, 1) -U_BOOT_I2C_ADAP_COMPLETE(tegra2, tegra_i2c_init, tegra_i2c_probe, - tegra_i2c_read, tegra_i2c_write, - tegra_i2c_set_bus_speed, 100000, 0, 2) -U_BOOT_I2C_ADAP_COMPLETE(tegra3, tegra_i2c_init, tegra_i2c_probe, - tegra_i2c_read, tegra_i2c_write, - tegra_i2c_set_bus_speed, 100000, 0, 3) -#if TEGRA_I2C_NUM_CONTROLLERS > 4 -U_BOOT_I2C_ADAP_COMPLETE(tegra4, tegra_i2c_init, tegra_i2c_probe, - tegra_i2c_read, tegra_i2c_write, - tegra_i2c_set_bus_speed, 100000, 0, 4) -#endif +static const struct udevice_id tegra_i2c_ids[] = { + { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 }, + { .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD }, + { .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC }, + { } +}; + +U_BOOT_DRIVER(i2c_tegra) = { + .name = "i2c_tegra", + .id = UCLASS_I2C, + .of_match = tegra_i2c_ids, + .ofdata_to_platdata = tegra_i2c_ofdata_to_platdata, + .probe = tegra_i2c_probe, + .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), + .child_pre_probe = tegra_i2c_child_pre_probe, + .priv_auto_alloc_size = sizeof(struct i2c_bus), + .ops = &tegra_i2c_ops, +}; diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 2f2e48f..6fa836f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -15,11 +15,15 @@ obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o obj-$(CONFIG_FSL_IIM) += fsl_iim.o obj-$(CONFIG_GPIO_LED) += gpio_led.o +obj-$(CONFIG_I2C_EEPROM) += i2c_eeprom.o obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o obj-$(CONFIG_NS87308) += ns87308.o obj-$(CONFIG_PDSP188x) += pdsp188x.o +ifdef CONFIG_DM_I2C +obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o +endif obj-$(CONFIG_STATUS_LED) += status_led.o obj-$(CONFIG_TWL4030_LED) += twl4030_led.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c new file mode 100644 index 0000000..d0548ec --- /dev/null +++ b/drivers/misc/i2c_eeprom.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +static int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, + int size) +{ + return -ENODEV; +} + +static int i2c_eeprom_write(struct udevice *dev, int offset, + const uint8_t *buf, int size) +{ + return -ENODEV; +} + +struct i2c_eeprom_ops i2c_eeprom_std_ops = { + .read = i2c_eeprom_read, + .write = i2c_eeprom_write, +}; + +int i2c_eeprom_std_probe(struct udevice *dev) +{ + return 0; +} + +static const struct udevice_id i2c_eeprom_std_ids[] = { + { .compatible = "i2c-eeprom" }, + { } +}; + +U_BOOT_DRIVER(i2c_eeprom_std) = { + .name = "i2c_eeprom", + .id = UCLASS_I2C_EEPROM, + .of_match = i2c_eeprom_std_ids, + .probe = i2c_eeprom_std_probe, + .priv_auto_alloc_size = sizeof(struct i2c_eeprom), + .ops = &i2c_eeprom_std_ops, +}; + +UCLASS_DRIVER(i2c_eeprom) = { + .id = UCLASS_I2C_EEPROM, + .name = "i2c_eeprom", +}; diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c new file mode 100644 index 0000000..7343445 --- /dev/null +++ b/drivers/misc/i2c_eeprom_emul.c @@ -0,0 +1,168 @@ +/* + * Simulate an I2C eeprom + * + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define debug_buffer print_buffer +#else +#define debug_buffer(x, ...) +#endif + +DECLARE_GLOBAL_DATA_PTR; + +struct sandbox_i2c_flash_plat_data { + enum sandbox_i2c_eeprom_test_mode test_mode; + const char *filename; + int offset_len; /* Length of an offset in bytes */ + int size; /* Size of data buffer */ +}; + +struct sandbox_i2c_flash { + uint8_t *data; +}; + +void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, + enum sandbox_i2c_eeprom_test_mode mode) +{ + struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); + + plat->test_mode = mode; +} + +void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len) +{ + struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); + + plat->offset_len = offset_len; +} + +static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, + int nmsgs) +{ + struct sandbox_i2c_flash *priv = dev_get_priv(emul); + uint offset = 0; + + debug("\n%s\n", __func__); + debug_buffer(0, priv->data, 1, 16, 0); + for (; nmsgs > 0; nmsgs--, msg++) { + struct sandbox_i2c_flash_plat_data *plat = + dev_get_platdata(emul); + int len; + u8 *ptr; + + if (!plat->size) + return -ENODEV; + if (msg->addr + msg->len > plat->size) { + debug("%s: Address %x, len %x is outside range 0..%x\n", + __func__, msg->addr, msg->len, plat->size); + return -EINVAL; + } + len = msg->len; + debug(" %s: msg->len=%d", + msg->flags & I2C_M_RD ? "read" : "write", + msg->len); + if (msg->flags & I2C_M_RD) { + if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) + len = 1; + debug(", offset %x, len %x: ", offset, len); + memcpy(msg->buf, priv->data + offset, len); + memset(msg->buf + len, '\xff', msg->len - len); + debug_buffer(0, msg->buf, 1, msg->len, 0); + } else if (len >= plat->offset_len) { + int i; + + ptr = msg->buf; + for (i = 0; i < plat->offset_len; i++, len--) + offset = (offset << 8) | *ptr++; + debug(", set offset %x: ", offset); + debug_buffer(0, msg->buf, 1, msg->len, 0); + if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) + len = min(len, 1); + + /* For testing, map offsets into our limited buffer */ + for (i = 24; i > 0; i -= 8) { + if (offset > (1 << i)) { + offset = (offset >> i) | + (offset & ((1 << i) - 1)); + offset += i; + } + } + memcpy(priv->data + offset, ptr, len); + } + } + debug_buffer(0, priv->data, 1, 16, 0); + + return 0; +} + +struct dm_i2c_ops sandbox_i2c_emul_ops = { + .xfer = sandbox_i2c_eeprom_xfer, +}; + +static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev) +{ + struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); + + plat->size = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "sandbox,size", 32); + plat->filename = fdt_getprop(gd->fdt_blob, dev->of_offset, + "sandbox,filename", NULL); + if (!plat->filename) { + debug("%s: No filename for device '%s'\n", __func__, + dev->name); + return -EINVAL; + } + plat->test_mode = SIE_TEST_MODE_NONE; + plat->offset_len = 1; + + return 0; +} + +static int sandbox_i2c_eeprom_probe(struct udevice *dev) +{ + struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); + struct sandbox_i2c_flash *priv = dev_get_priv(dev); + + priv->data = calloc(1, plat->size); + if (!priv->data) + return -ENOMEM; + + return 0; +} + +static int sandbox_i2c_eeprom_remove(struct udevice *dev) +{ + struct sandbox_i2c_flash *priv = dev_get_priv(dev); + + free(priv->data); + + return 0; +} + +static const struct udevice_id sandbox_i2c_ids[] = { + { .compatible = "sandbox,i2c-eeprom" }, + { } +}; + +U_BOOT_DRIVER(sandbox_i2c_emul) = { + .name = "sandbox_i2c_eeprom_emul", + .id = UCLASS_I2C_EMUL, + .of_match = sandbox_i2c_ids, + .ofdata_to_platdata = sandbox_i2c_eeprom_ofdata_to_platdata, + .probe = sandbox_i2c_eeprom_probe, + .remove = sandbox_i2c_eeprom_remove, + .priv_auto_alloc_size = sizeof(struct sandbox_i2c_flash), + .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_flash_plat_data), + .ops = &sandbox_i2c_emul_ops, +}; diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c index d29d969..29bab4c 100644 --- a/drivers/power/tps6586x.c +++ b/drivers/power/tps6586x.c @@ -10,9 +10,7 @@ #include #include -static int bus_num; /* I2C bus we are on */ -#define I2C_ADDRESS 0x34 /* chip requires this address */ -static char inited; /* 1 if we have been inited */ +static struct udevice *tps6586x_dev; enum { /* Registers that we access */ @@ -37,13 +35,9 @@ static int tps6586x_read(int reg) int i; uchar data; int retval = -1; - int old_bus_num; - - old_bus_num = i2c_get_bus_num(); - i2c_set_bus_num(bus_num); for (i = 0; i < MAX_I2C_RETRY; ++i) { - if (!i2c_read(I2C_ADDRESS, reg, 1, &data, 1)) { + if (!i2c_read(tps6586x_dev, reg, &data, 1)) { retval = (int)data; goto exit; } @@ -53,7 +47,6 @@ static int tps6586x_read(int reg) } exit: - i2c_set_bus_num(old_bus_num); debug("pmu_read %x=%x\n", reg, retval); if (retval < 0) debug("%s: failed to read register %#x: %d\n", __func__, reg, @@ -65,13 +58,9 @@ static int tps6586x_write(int reg, uchar *data, uint len) { int i; int retval = -1; - int old_bus_num; - - old_bus_num = i2c_get_bus_num(); - i2c_set_bus_num(bus_num); for (i = 0; i < MAX_I2C_RETRY; ++i) { - if (!i2c_write(I2C_ADDRESS, reg, 1, data, len)) { + if (!i2c_write(tps6586x_dev, reg, data, len)) { retval = 0; goto exit; } @@ -81,7 +70,6 @@ static int tps6586x_write(int reg, uchar *data, uint len) } exit: - i2c_set_bus_num(old_bus_num); debug("pmu_write %x=%x: ", reg, retval); for (i = 0; i < len; i++) debug("%x ", data[i]); @@ -163,7 +151,7 @@ int tps6586x_set_pwm_mode(int mask) uchar val; int ret; - assert(inited); + assert(tps6586x_dev); ret = tps6586x_read(PFM_MODE); if (ret != -1) { val = (uchar)ret; @@ -184,7 +172,7 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate, int sm0, sm1; int bad; - assert(inited); + assert(tps6586x_dev); /* get current voltage settings */ if (read_voltages(&sm0, &sm1)) { @@ -255,10 +243,9 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate, return bad ? -1 : 0; } -int tps6586x_init(int bus) +int tps6586x_init(struct udevice *dev) { - bus_num = bus; - inited = 1; + tps6586x_dev = dev; return 0; } diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index e1bf496..75eb6bd 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -348,6 +348,7 @@ U_BOOT_DRIVER(serial_pl01x) = { .probe = pl01x_serial_probe, .ops = &pl01x_serial_ops, .flags = DM_FLAG_PRE_RELOC, + .priv_auto_alloc_size = sizeof(struct pl01x_priv), }; #endif diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index d0dd29f..ba442d5 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -852,30 +852,6 @@ DEFINE_CACHE_ALIGN_BUFFER(u8, control_req, USB_BUFSIZ); DEFINE_CACHE_ALIGN_BUFFER(u8, status_req, STATUS_BYTECOUNT); #endif - -/** - * strlcpy - Copy a %NUL terminated string into a sized buffer - * @dest: Where to copy the string to - * @src: Where to copy the string from - * @size: size of destination buffer - * - * Compatible with *BSD: the result is always a valid - * NUL-terminated string that fits in the buffer (unless, - * of course, the buffer size is zero). It does not pad - * out the result like strncpy() does. - */ -size_t strlcpy(char *dest, const char *src, size_t size) -{ - size_t ret = strlen(src); - - if (size) { - size_t len = (ret >= size) ? size - 1 : ret; - memcpy(dest, src, len); - dest[len] = '\0'; - } - return ret; -} - /*============================================================================*/ /* diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h index 508db56..ddfe045 100644 --- a/include/config_fallbacks.h +++ b/include/config_fallbacks.h @@ -91,4 +91,10 @@ #undef CONFIG_IMAGE_FORMAT_LEGACY #endif +#ifdef CONFIG_DM_I2C +# ifdef CONFIG_SYS_I2C +# error "Cannot define CONFIG_SYS_I2C when CONFIG_DM_I2C is used" +# endif +#endif + #endif /* __CONFIG_FALLBACKS_H */ diff --git a/include/configs/apalis_t30.h b/include/configs/apalis_t30.h index 3cde923..61809fc 100644 --- a/include/configs/apalis_t30.h +++ b/include/configs/apalis_t30.h @@ -26,10 +26,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/beaver.h b/include/configs/beaver.h index 164b2dd..5d765f3 100644 --- a/include/configs/beaver.h +++ b/include/configs/beaver.h @@ -40,10 +40,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/cardhu.h b/include/configs/cardhu.h index 09129c7..758b7ad 100644 --- a/include/configs/cardhu.h +++ b/include/configs/cardhu.h @@ -43,12 +43,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/colibri_t30.h b/include/configs/colibri_t30.h index a582e25..ce6f23b 100644 --- a/include/configs/colibri_t30.h +++ b/include/configs/colibri_t30.h @@ -25,10 +25,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/dalmore.h b/include/configs/dalmore.h index ff7ec4a..0b04ee6 100644 --- a/include/configs/dalmore.h +++ b/include/configs/dalmore.h @@ -36,12 +36,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/jetson-tk1.h b/include/configs/jetson-tk1.h index d67c025..a7d7665 100644 --- a/include/configs/jetson-tk1.h +++ b/include/configs/jetson-tk1.h @@ -25,12 +25,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/nyan-big.h b/include/configs/nyan-big.h new file mode 100644 index 0000000..cf331ab --- /dev/null +++ b/include/configs/nyan-big.h @@ -0,0 +1,74 @@ +/* + * (C) Copyright 2014 + * NVIDIA Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include + +#include "tegra124-common.h" + +/* High-level configuration options */ +#define V_PROMPT "Tegra124 (Nyan-big) # " +#define CONFIG_TEGRA_BOARD_STRING "Google/NVIDIA Nyan-big" + +/* Board-specific serial config */ +#define CONFIG_SERIAL_MULTI +#define CONFIG_TEGRA_ENABLE_UARTA +#define CONFIG_SYS_NS16550_COM1 NV_PA_APB_UARTA_BASE + +#define CONFIG_BOARD_EARLY_INIT_F + +/* I2C */ +#define CONFIG_SYS_I2C_TEGRA +#define CONFIG_CMD_I2C + +/* SD/MMC */ +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_TEGRA_MMC +#define CONFIG_CMD_MMC + +/* Environment in eMMC, at the end of 2nd "boot sector" */ +#define CONFIG_ENV_IS_IN_MMC +#define CONFIG_SYS_MMC_ENV_DEV 0 +#define CONFIG_SYS_MMC_ENV_PART 2 +#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE) + +/* SPI */ +#define CONFIG_TEGRA114_SPI /* Compatible w/ Tegra114 SPI */ +#define CONFIG_TEGRA114_SPI_CTRLS 6 +#define CONFIG_SPI_FLASH +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0 +#define CONFIG_SF_DEFAULT_SPEED 24000000 +#define CONFIG_CMD_SPI +#define CONFIG_CMD_SF +#define CONFIG_SPI_FLASH_SIZE (4 << 20) + +/* USB Host support */ +#define CONFIG_USB_EHCI +#define CONFIG_USB_EHCI_TEGRA +#define CONFIG_USB_MAX_CONTROLLER_COUNT 2 +#define CONFIG_USB_STORAGE +#define CONFIG_CMD_USB + +/* USB networking support */ +#define CONFIG_USB_HOST_ETHER +#define CONFIG_USB_ETHER_ASIX + +/* General networking support */ +#define CONFIG_CMD_NET +#define CONFIG_CMD_DHCP + +#define CONFIG_FIT +#define CONFIG_OF_LIBFDT + +#include "tegra-common-usb-gadget.h" +#include "tegra-common-post.h" + +#endif /* __CONFIG_H */ diff --git a/include/configs/rpi.h b/include/configs/rpi.h index 4d5426e..c94f411 100644 --- a/include/configs/rpi.h +++ b/include/configs/rpi.h @@ -34,6 +34,7 @@ #define CONFIG_DM #define CONFIG_CMD_DM #define CONFIG_DM_GPIO +#define CONFIG_DM_SERIAL /* Memory layout */ #define CONFIG_NR_DRAM_BANKS 1 @@ -51,6 +52,7 @@ CONFIG_SYS_SDRAM_SIZE - \ GENERATED_GBL_DATA_SIZE) #define CONFIG_SYS_MALLOC_LEN SZ_4M +#define CONFIG_SYS_MALLOC_F_LEN (1 << 10) #define CONFIG_SYS_MEMTEST_START 0x00100000 #define CONFIG_SYS_MEMTEST_END 0x00200000 #define CONFIG_LOADADDR 0x00200000 @@ -92,9 +94,7 @@ #endif /* Console UART */ -#define CONFIG_PL011_SERIAL -#define CONFIG_PL011_CLOCK 3000000 -#define CONFIG_PL01x_PORTS { (void *)0x20201000 } +#define CONFIG_PL01X_SERIAL #define CONFIG_CONS_INDEX 0 #define CONFIG_BAUDRATE 115200 diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 2b03841..657f751 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -112,6 +112,12 @@ #define CONFIG_SPI_FLASH_STMICRO #define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_DM_I2C +#define CONFIG_CMD_I2C +#define CONFIG_SYS_I2C_SANDBOX +#define CONFIG_I2C_EDID +#define CONFIG_I2C_EEPROM + /* Memory things - we don't really want a memory test */ #define CONFIG_SYS_LOAD_ADDR 0x00000000 #define CONFIG_SYS_MEMTEST_START 0x00100000 diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h index 04e4f82..5f77051 100644 --- a/include/configs/seaboard.h +++ b/include/configs/seaboard.h @@ -37,10 +37,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/tec-ng.h b/include/configs/tec-ng.h index 51f87da..e37b233 100644 --- a/include/configs/tec-ng.h +++ b/include/configs/tec-ng.h @@ -23,12 +23,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h index d690045..0685328 100644 --- a/include/configs/tegra-common.h +++ b/include/configs/tegra-common.h @@ -26,6 +26,7 @@ #endif #define CONFIG_DM_SPI #define CONFIG_DM_SPI_FLASH +#define CONFIG_DM_I2C #define CONFIG_SYS_TIMER_RATE 1000000 #define CONFIG_SYS_TIMER_COUNTER NV_PA_TMRUS_BASE diff --git a/include/configs/tegra114-common.h b/include/configs/tegra114-common.h index 555c237..9eba5d5 100644 --- a/include/configs/tegra114-common.h +++ b/include/configs/tegra114-common.h @@ -76,9 +76,6 @@ #define CONFIG_SYS_SPL_MALLOC_START 0x80090000 #define CONFIG_SPL_STACK 0x800ffffc -/* Total I2C ports on Tegra114 */ -#define TEGRA_I2C_NUM_CONTROLLERS 5 - /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 diff --git a/include/configs/tegra124-common.h b/include/configs/tegra124-common.h index 61e5026..f2b3774 100644 --- a/include/configs/tegra124-common.h +++ b/include/configs/tegra124-common.h @@ -68,9 +68,6 @@ #define CONFIG_SYS_SPL_MALLOC_START 0x80090000 #define CONFIG_SPL_STACK 0x800ffffc -/* Total I2C ports on Tegra124 */ -#define TEGRA_I2C_NUM_CONTROLLERS 5 - /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 diff --git a/include/configs/tegra20-common.h b/include/configs/tegra20-common.h index 21bf977..6330281 100644 --- a/include/configs/tegra20-common.h +++ b/include/configs/tegra20-common.h @@ -97,9 +97,6 @@ #define CONFIG_EHCI_IS_TDI #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 -/* Total I2C ports on Tegra20 */ -#define TEGRA_I2C_NUM_CONTROLLERS 4 - #define CONFIG_SYS_NAND_SELF_INIT #define CONFIG_SYS_NAND_ONFI_DETECTION diff --git a/include/configs/tegra30-common.h b/include/configs/tegra30-common.h index 443c842..bfdbeb7 100644 --- a/include/configs/tegra30-common.h +++ b/include/configs/tegra30-common.h @@ -73,9 +73,6 @@ #define CONFIG_SYS_SPL_MALLOC_START 0x80090000 #define CONFIG_SPL_STACK 0x800ffffc -/* Total I2C ports on Tegra30 */ -#define TEGRA_I2C_NUM_CONTROLLERS 5 - /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 diff --git a/include/configs/trimslice.h b/include/configs/trimslice.h index 7c00642..a254f86 100644 --- a/include/configs/trimslice.h +++ b/include/configs/trimslice.h @@ -34,10 +34,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/venice2.h b/include/configs/venice2.h index 6897aa8..8880de8 100644 --- a/include/configs/venice2.h +++ b/include/configs/venice2.h @@ -25,12 +25,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/whistler.h b/include/configs/whistler.h index 10e70d2..e083cbd 100644 --- a/include/configs/whistler.h +++ b/include/configs/whistler.h @@ -26,10 +26,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 202f59b..f17c3c2 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -19,6 +19,7 @@ enum uclass_id { UCLASS_TEST_FDT, UCLASS_TEST_BUS, UCLASS_SPI_EMUL, /* sandbox SPI device emulator */ + UCLASS_I2C_EMUL, /* sandbox I2C device emulator */ UCLASS_SIMPLE_BUS, /* U-Boot uclasses start here */ @@ -29,6 +30,9 @@ enum uclass_id { UCLASS_SPI_FLASH, /* SPI flash */ UCLASS_CROS_EC, /* Chrome OS EC */ UCLASS_THERMAL, /* Thermal sensor */ + UCLASS_I2C, /* I2C bus */ + UCLASS_I2C_GENERIC, /* Generic I2C device */ + UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/dm/ut.h b/include/dm/ut.h index fa9eac0..ec61465 100644 --- a/include/dm/ut.h +++ b/include/dm/ut.h @@ -89,6 +89,18 @@ void ut_failf(struct dm_test_state *dms, const char *fname, int line, } \ } +/* Assert that a pointer is not NULL */ +#define ut_assertnonnull(expr) { \ + const void *val = (expr); \ + \ + if (val == NULL) { \ + ut_failf(dms, __FILE__, __LINE__, __func__, \ + #expr " = NULL", \ + "Expected non-null, got NULL"); \ + return -1; \ + } \ +} + /* Assert that an operation succeeds (returns 0) */ #define ut_assertok(cond) ut_asserteq(0, cond) diff --git a/include/dt-bindings/pinctrl/pinctrl-tegra.h b/include/dt-bindings/pinctrl/pinctrl-tegra.h new file mode 100644 index 0000000..ebafa49 --- /dev/null +++ b/include/dt-bindings/pinctrl/pinctrl-tegra.h @@ -0,0 +1,45 @@ +/* + * This header provides constants for Tegra pinctrl bindings. + * + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * + * Author: Laxman Dewangan + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef _DT_BINDINGS_PINCTRL_TEGRA_H +#define _DT_BINDINGS_PINCTRL_TEGRA_H + +/* + * Enable/disable for diffeent dt properties. This is applicable for + * properties nvidia,enable-input, nvidia,tristate, nvidia,open-drain, + * nvidia,lock, nvidia,rcv-sel, nvidia,high-speed-mode, nvidia,schmitt. + */ +#define TEGRA_PIN_DISABLE 0 +#define TEGRA_PIN_ENABLE 1 + +#define TEGRA_PIN_PULL_NONE 0 +#define TEGRA_PIN_PULL_DOWN 1 +#define TEGRA_PIN_PULL_UP 2 + +/* Low power mode driver */ +#define TEGRA_PIN_LP_DRIVE_DIV_8 0 +#define TEGRA_PIN_LP_DRIVE_DIV_4 1 +#define TEGRA_PIN_LP_DRIVE_DIV_2 2 +#define TEGRA_PIN_LP_DRIVE_DIV_1 3 + +/* Rising/Falling slew rate */ +#define TEGRA_PIN_SLEW_RATE_FASTEST 0 +#define TEGRA_PIN_SLEW_RATE_FAST 1 +#define TEGRA_PIN_SLEW_RATE_SLOW 2 +#define TEGRA_PIN_SLEW_RATE_SLOWEST 3 + +#endif diff --git a/include/errno.h b/include/errno.h index e24a33b..14ac3cb 100644 --- a/include/errno.h +++ b/include/errno.h @@ -6,4 +6,7 @@ extern int errno; #define __set_errno(val) do { errno = val; } while (0) +#ifdef CONFIG_ERRNO_STR +const char *errno_str(int errno); +#endif #endif /* _ERRNO_H */ diff --git a/include/i2c.h b/include/i2c.h index 1b4078e..9c6a60c 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -18,6 +18,355 @@ #define _I2C_H_ /* + * For now there are essentially two parts to this file - driver model + * here at the top, and the older code below (with CONFIG_SYS_I2C being + * most recent). The plan is to migrate everything to driver model. + * The driver model structures and API are separate as they are different + * enough as to be incompatible for compilation purposes. + */ + +#ifdef CONFIG_DM_I2C + +enum dm_i2c_chip_flags { + DM_I2C_CHIP_10BIT = 1 << 0, /* Use 10-bit addressing */ + DM_I2C_CHIP_RD_ADDRESS = 1 << 1, /* Send address for each read byte */ + DM_I2C_CHIP_WR_ADDRESS = 1 << 2, /* Send address for each write byte */ +}; + +/** + * struct dm_i2c_chip - information about an i2c chip + * + * An I2C chip is a device on the I2C bus. It sits at a particular address + * and normally supports 7-bit or 10-bit addressing. + * + * To obtain this structure, use dev_get_parentdata(dev) where dev is the + * chip to examine. + * + * @chip_addr: Chip address on bus + * @offset_len: Length of offset in bytes. A single byte offset can + * represent up to 256 bytes. A value larger than 1 may be + * needed for larger devices. + * @flags: Flags for this chip (dm_i2c_chip_flags) + * @emul: Emulator for this chip address (only used for emulation) + */ +struct dm_i2c_chip { + uint chip_addr; + uint offset_len; + uint flags; +#ifdef CONFIG_SANDBOX + struct udevice *emul; +#endif +}; + +/** + * struct dm_i2c_bus- information about an i2c bus + * + * An I2C bus contains 0 or more chips on it, each at its own address. The + * bus can operate at different speeds (measured in Hz, typically 100KHz + * or 400KHz). + * + * To obtain this structure, use bus->uclass_priv where bus is the I2C + * bus udevice. + * + * @speed_hz: Bus speed in hertz (typically 100000) + */ +struct dm_i2c_bus { + int speed_hz; +}; + +/** + * i2c_read() - read bytes from an I2C chip + * + * To obtain an I2C device (called a 'chip') given the I2C bus address you + * can use i2c_get_chip(). To obtain a bus by bus number use + * uclass_get_device_by_seq(UCLASS_I2C, ). + * + * To set the address length of a devce use i2c_set_addr_len(). It + * defaults to 1. + * + * @dev: Chip to read from + * @offset: Offset within chip to start reading + * @buffer: Place to put data + * @len: Number of bytes to read + * + * @return 0 on success, -ve on failure + */ +int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, + int len); + +/** + * i2c_write() - write bytes to an I2C chip + * + * See notes for i2c_read() above. + * + * @dev: Chip to write to + * @offset: Offset within chip to start writing + * @buffer: Buffer containing data to write + * @len: Number of bytes to write + * + * @return 0 on success, -ve on failure + */ +int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, + int len); + +/** + * i2c_probe() - probe a particular chip address + * + * This can be useful to check for the existence of a chip on the bus. + * It is typically implemented by writing the chip address to the bus + * and checking that the chip replies with an ACK. + * + * @bus: Bus to probe + * @chip_addr: 7-bit address to probe (10-bit and others are not supported) + * @chip_flags: Flags for the probe (see enum dm_i2c_chip_flags) + * @devp: Returns the device found, or NULL if none + * @return 0 if a chip was found at that address, -ve if not + */ +int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags, + struct udevice **devp); + +/** + * i2c_set_bus_speed() - set the speed of a bus + * + * @bus: Bus to adjust + * @speed: Requested speed in Hz + * @return 0 if OK, -EINVAL for invalid values + */ +int i2c_set_bus_speed(struct udevice *bus, unsigned int speed); + +/** + * i2c_get_bus_speed() - get the speed of a bus + * + * @bus: Bus to check + * @return speed of selected I2C bus in Hz, -ve on error + */ +int i2c_get_bus_speed(struct udevice *bus); + +/** + * i2c_set_chip_flags() - set flags for a chip + * + * Typically addresses are 7 bits, but for 10-bit addresses you should set + * flags to DM_I2C_CHIP_10BIT. All accesses will then use 10-bit addressing. + * + * @dev: Chip to adjust + * @flags: New flags + * @return 0 if OK, -EINVAL if value is unsupported, other -ve value on error + */ +int i2c_set_chip_flags(struct udevice *dev, uint flags); + +/** + * i2c_get_chip_flags() - get flags for a chip + * + * @dev: Chip to check + * @flagsp: Place to put flags + * @return 0 if OK, other -ve value on error + */ +int i2c_get_chip_flags(struct udevice *dev, uint *flagsp); + +/** + * i2c_set_offset_len() - set the offset length for a chip + * + * The offset used to access a chip may be up to 4 bytes long. Typically it + * is only 1 byte, which is enough for chips with 256 bytes of memory or + * registers. The default value is 1, but you can call this function to + * change it. + * + * @offset_len: New offset length value (typically 1 or 2) + */ + +int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len); +/** + * i2c_deblock() - recover a bus that is in an unknown state + * + * See the deblock() method in 'struct dm_i2c_ops' for full information + * + * @bus: Bus to recover + * @return 0 if OK, -ve on error + */ +int i2c_deblock(struct udevice *bus); + +/* + * 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 + * + * Drivers should support these operations unless otherwise noted. These + * operations are intended to be used by uclass code, not directly from + * other code. + */ +struct dm_i2c_ops { + /** + * xfer() - transfer a list of I2C messages + * + * @bus: Bus to read from + * @msg: List of messages to transfer + * @nmsgs: Number of messages in the list + * @return 0 if OK, -EREMOTEIO if the slave did not ACK a byte, + * -ECOMM if the speed cannot be supported, -EPROTO if the chip + * flags cannot be supported, other -ve value on some other error + */ + int (*xfer)(struct udevice *bus, struct i2c_msg *msg, int nmsgs); + + /** + * probe_chip() - probe for the presense of a chip address + * + * This function is optional. If omitted, the uclass will send a zero + * length message instead. + * + * @bus: Bus to probe + * @chip_addr: Chip address to probe + * @chip_flags: Probe flags (enum dm_i2c_chip_flags) + * @return 0 if chip was found, -EREMOTEIO if not, -ENOSYS to fall back + * to default probem other -ve value on error + */ + int (*probe_chip)(struct udevice *bus, uint chip_addr, uint chip_flags); + + /** + * set_bus_speed() - set the speed of a bus (optional) + * + * The bus speed value will be updated by the uclass if this function + * does not return an error. This method is optional - if it is not + * provided then the driver can read the speed from + * bus->uclass_priv->speed_hz + * + * @bus: Bus to adjust + * @speed: Requested speed in Hz + * @return 0 if OK, -EINVAL for invalid values + */ + int (*set_bus_speed)(struct udevice *bus, unsigned int speed); + + /** + * get_bus_speed() - get the speed of a bus (optional) + * + * Normally this can be provided by the uclass, but if you want your + * driver to check the bus speed by looking at the hardware, you can + * implement that here. This method is optional. This method would + * normally be expected to return bus->uclass_priv->speed_hz. + * + * @bus: Bus to check + * @return speed of selected I2C bus in Hz, -ve on error + */ + int (*get_bus_speed)(struct udevice *bus); + + /** + * set_flags() - set the flags for a chip (optional) + * + * This is generally implemented by the uclass, but drivers can + * check the value to ensure that unsupported options are not used. + * This method is optional. If provided, this method will always be + * called when the flags change. + * + * @dev: Chip to adjust + * @flags: New flags value + * @return 0 if OK, -EINVAL if value is unsupported + */ + int (*set_flags)(struct udevice *dev, uint flags); + + /** + * deblock() - recover a bus that is in an unknown state + * + * I2C is a synchronous protocol and resets of the processor in the + * middle of an access can block the I2C Bus until a powerdown of + * the full unit is done. This is because slaves can be stuck + * waiting for addition bus transitions for a transaction that will + * never complete. Resetting the I2C master does not help. The only + * way is to force the bus through a series of transitions to make + * sure that all slaves are done with the transaction. This method + * performs this 'deblocking' if support by the driver. + * + * This method is optional. + */ + int (*deblock)(struct udevice *bus); +}; + +#define i2c_get_ops(dev) ((struct dm_i2c_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 + * be used with calls to i2c_read(), i2c_write(), i2c_probe(), etc. + * + * @bus: Bus to examine + * @chip_addr: Chip address for the new device + * @devp: Returns pointer to new device if found or -ENODEV if not + * found + */ +int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp); + +/** + * i2c_get_chip() - get a device to use to access a chip on a bus number + * + * This returns the device for the given chip address on a particular bus + * number. + * + * @busnum: Bus number to examine + * @chip_addr: Chip address for the new device + * @devp: Returns pointer to new device if found or -ENODEV if not + * found + */ +int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp); + +/** + * i2c_chip_ofdata_to_platdata() - Decode standard I2C platform data + * + * This decodes the chip address from a device tree node and puts it into + * its dm_i2c_chip structure. This should be called in your driver's + * ofdata_to_platdata() method. + * + * @blob: Device tree blob + * @node: Node offset to read from + * @spi: Place to put the decoded information + */ +int i2c_chip_ofdata_to_platdata(const void *blob, int node, + struct dm_i2c_chip *chip); + +#endif + +#ifndef CONFIG_DM_I2C + +/* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * The implementation MUST NOT use static or global variables if the @@ -451,4 +800,7 @@ int i2c_get_bus_num_fdt(int node); * @return 0 if port was reset, -1 if not found */ int i2c_reset_port_fdt(const void *blob, int node); + +#endif /* !CONFIG_DM_I2C */ + #endif /* _I2C_H_ */ diff --git a/include/i2c_eeprom.h b/include/i2c_eeprom.h new file mode 100644 index 0000000..ea6c962 --- /dev/null +++ b/include/i2c_eeprom.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __I2C_EEPROM +#define __I2C_EEPROM + +struct i2c_eeprom_ops { + int (*read)(struct udevice *dev, int offset, uint8_t *buf, int size); + int (*write)(struct udevice *dev, int offset, const uint8_t *buf, + int size); +}; + +struct i2c_eeprom { +}; + +#endif diff --git a/include/linux/string.h b/include/linux/string.h index 96348d6..c7047ba 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -30,6 +30,9 @@ extern char * strcpy(char *,const char *); #ifndef __HAVE_ARCH_STRNCPY extern char * strncpy(char *,const char *, __kernel_size_t); #endif +#ifndef __HAVE_ARCH_STRLCPY +size_t strlcpy(char *, const char *, size_t); +#endif #ifndef __HAVE_ARCH_STRCAT extern char * strcat(char *, const char *); #endif diff --git a/include/tps6586x.h b/include/tps6586x.h index 78ce428..eefc95f 100644 --- a/include/tps6586x.h +++ b/include/tps6586x.h @@ -44,9 +44,9 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate, * Set up the TPS6586X I2C bus number. This will be used for all operations * on the device. This function must be called before using other functions. * - * @param bus I2C bus number containing the TPS6586X chip + * @param bus I2C bus containing the TPS6586X chip * @return 0 (always succeeds) */ -int tps6586x_init(int bus); +int tps6586x_init(struct udevice *bus); #endif /* _TPS6586X_H_ */ diff --git a/lib/Makefile b/lib/Makefile index 3ceb697..07d175f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -51,6 +51,7 @@ endif obj-$(CONFIG_ADDR_MAP) += addr_map.o obj-y += hashtable.o obj-y += errno.o +obj-$(CONFIG_ERRNO_STR) += errno_str.o obj-y += display_options.o obj-$(CONFIG_BCH) += bch.o obj-y += crc32.o diff --git a/lib/errno_str.c b/lib/errno_str.c new file mode 100644 index 0000000..0ba950e --- /dev/null +++ b/lib/errno_str.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2014 Samsung Electronics + * Przemyslaw Marczak + * + * SDPX-License-Identifier: GPL-2.0+ + */ +#include +#include + +#define ERRNO_MSG(errno, msg) msg +#define SAME_AS(x) (const char *)&errno_message[x] + +static const char * const errno_message[] = { + ERRNO_MSG(0, "Success"), + ERRNO_MSG(EPERM, "Operation not permitted"), + ERRNO_MSG(ENOEN, "No such file or directory"), + ERRNO_MSG(ESRCH, "No such process"), + ERRNO_MSG(EINTR, "Interrupted system call"), + ERRNO_MSG(EIO, "I/O error"), + ERRNO_MSG(ENXIO, "No such device or address"), + ERRNO_MSG(E2BIG, "Argument list too long"), + ERRNO_MSG(ENOEXEC, "Exec format error"), + ERRNO_MSG(EBADF, "Bad file number"), + ERRNO_MSG(ECHILD, "No child processes"), + ERRNO_MSG(EAGAIN, "Try again"), + ERRNO_MSG(ENOMEM, "Out of memory"), + ERRNO_MSG(EACCES, "Permission denied"), + ERRNO_MSG(EFAULT, "Bad address"), + ERRNO_MSG(ENOTBL, "Block device required"), + ERRNO_MSG(EBUSY, "Device or resource busy"), + ERRNO_MSG(EEXIST, "File exists"), + ERRNO_MSG(EXDEV, "Cross-device link"), + ERRNO_MSG(ENODEV, "No such device"), + ERRNO_MSG(ENOTDIR, "Not a directory"), + ERRNO_MSG(EISDIR, "Is a directory"), + ERRNO_MSG(EINVAL, "Invalid argument"), + ERRNO_MSG(ENFILE, "File table overflow"), + ERRNO_MSG(EMFILE, "Too many open files"), + ERRNO_MSG(ENOTTY, "Not a typewriter"), + ERRNO_MSG(ETXTBSY, "Text file busy"), + ERRNO_MSG(EFBIG, "File too large"), + ERRNO_MSG(ENOSPC, "No space left on device"), + ERRNO_MSG(ESPIPE, "Illegal seek"), + ERRNO_MSG(EROFS, "Read-only file system"), + ERRNO_MSG(EMLINK, "Too many links"), + ERRNO_MSG(EPIPE, "Broken pipe"), + ERRNO_MSG(EDOM, "Math argument out of domain of func"), + ERRNO_MSG(ERANGE, "Math result not representable"), + ERRNO_MSG(EDEADLK, "Resource deadlock would occur"), + ERRNO_MSG(ENAMETOOLONG, "File name too long"), + ERRNO_MSG(ENOLCK, "No record locks available"), + ERRNO_MSG(ENOSYS, "Function not implemented"), + ERRNO_MSG(ENOTEMPTY, "Directory not empty"), + ERRNO_MSG(ELOOP, "Too many symbolic links encountered"), + ERRNO_MSG(EWOULDBLOCK, SAME_AS(EAGAIN)), + ERRNO_MSG(ENOMSG, "No message of desired type"), + ERRNO_MSG(EIDRM, "Identifier removed"), + ERRNO_MSG(ECHRNG, "Channel number out of range"), + ERRNO_MSG(EL2NSYNC, "Level 2 not synchronized"), + ERRNO_MSG(EL3HLT, "Level 3 halted"), + ERRNO_MSG(EL3RST, "Level 3 reset"), + ERRNO_MSG(ELNRNG, "Link number out of range"), + ERRNO_MSG(EUNATCH, "Protocol driver not attached"), + ERRNO_MSG(ENOCSI, "No CSI structure available"), + ERRNO_MSG(EL2HLT, "Level 2 halted"), + ERRNO_MSG(EBADE, "Invalid exchange"), + ERRNO_MSG(EBADR, "Invalid request descriptor"), + ERRNO_MSG(EXFULL, "Exchange full"), + ERRNO_MSG(ENOANO, "No anode"), + ERRNO_MSG(EBADRQC, "Invalid request code"), + ERRNO_MSG(EBADSLT, "Invalid slot"), + ERRNO_MSG(EDEADLOCK, SAME_AS(EDEADLK)), + ERRNO_MSG(EBFONT, "Bad font file format"), + ERRNO_MSG(ENOSTR, "Device not a stream"), + ERRNO_MSG(ENODATA, "No data available"), + ERRNO_MSG(ETIME, "Timer expired"), + ERRNO_MSG(ENOSR, "Out of streams resources"), + ERRNO_MSG(ENONET, "Machine is not on the network"), + ERRNO_MSG(ENOPKG, "Package not installed"), + ERRNO_MSG(EREMOTE, "Object is remote"), + ERRNO_MSG(ENOLINK, "Link has been severed"), + ERRNO_MSG(EADV, "Advertise error"), + ERRNO_MSG(ESRMNT, "Srmount error"), + ERRNO_MSG(ECOMM, "Communication error on send"), + ERRNO_MSG(EPROTO, "Protocol error"), + ERRNO_MSG(EMULTIHOP, "Multihop attempted"), + ERRNO_MSG(EDOTDOT, "RFS specific error"), + ERRNO_MSG(EBADMSG, "Not a data message"), + ERRNO_MSG(EOVERFLOW, "Value too large for defined data type"), + ERRNO_MSG(ENOTUNIQ, "Name not unique on network"), + ERRNO_MSG(EBADFD, "File descriptor in bad state"), + ERRNO_MSG(EREMCHG, "Remote address changed"), + ERRNO_MSG(ELIBACC, "Can not access a needed shared library"), + ERRNO_MSG(ELIBBAD, "Accessing a corrupted shared library"), + ERRNO_MSG(ELIBSCN, ".lib section in a.out corrupted"), + ERRNO_MSG(ELIBMAX, "Attempting to link in too many shared libraries"), + ERRNO_MSG(ELIBEXEC, "Cannot exec a shared library directly"), + ERRNO_MSG(EILSEQ, "Illegal byte sequence"), + ERRNO_MSG(ERESTART, "Interrupted system call should be restarted"), + ERRNO_MSG(ESTRPIPE, "Streams pipe error"), + ERRNO_MSG(EUSERS, "Too many users"), + ERRNO_MSG(ENOTSOCK, "Socket operation on non-socket"), + ERRNO_MSG(EDESTADDRREQ, "Destination address required"), + ERRNO_MSG(EMSGSIZE, "Message too long"), + ERRNO_MSG(EPROTOTYPE, "Protocol wrong type for socket"), + ERRNO_MSG(ENOPROTOOPT, "Protocol not available"), + ERRNO_MSG(EPROTONOSUPPORT, "Protocol not supported"), + ERRNO_MSG(ESOCKTNOSUPPORT, "Socket type not supported"), + ERRNO_MSG(EOPNOTSUPP, "Operation not supported on transport endpoint"), + ERRNO_MSG(EPFNOSUPPORT, "Protocol family not supported"), + ERRNO_MSG(AFNOSUPPORT, "Address family not supported by protocol"), + ERRNO_MSG(EADDRINUSE, "Address already in use"), + ERRNO_MSG(EADDRNOTAVAIL, "Cannot assign requested address"), + ERRNO_MSG(ENETDOWN, "Network is down"), + ERRNO_MSG(ENETUNREACH, "Network is unreachable"), + ERRNO_MSG(ENETRESET, "Network dropped connection because of reset"), + ERRNO_MSG(ECONNABORTED, "Software caused connection abort"), + ERRNO_MSG(ECONNRESET, "Connection reset by peer"), + ERRNO_MSG(ENOBUFS, "No buffer space available"), + ERRNO_MSG(EISCONN, "Transport endpoint is already connected"), + ERRNO_MSG(ENOTCONN, "Transport endpoint is not connected"), + ERRNO_MSG(ESHUTDOWN, "Cannot send after transport endpoint shutdown"), + ERRNO_MSG(ETOOMANYREFS, "Too many references: cannot splice"), + ERRNO_MSG(ETIMEDOUT, "Connection timed out"), + ERRNO_MSG(ECONNREFUSED, "Connection refused"), + ERRNO_MSG(EHOSTDOWN, "Host is down"), + ERRNO_MSG(EHOSTUNREACH, "No route to host"), + ERRNO_MSG(EALREADY, "Operation already in progress"), + ERRNO_MSG(EINPROGRESS, "Operation now in progress"), + ERRNO_MSG(ESTALE, "Stale NFS file handle"), + ERRNO_MSG(EUCLEAN, "Structure needs cleaning"), + ERRNO_MSG(ENOTNAM, "Not a XENIX named type file"), + ERRNO_MSG(ENAVAIL, "No XENIX semaphores available"), + ERRNO_MSG(EISNAM, "Is a named type file"), + ERRNO_MSG(EREMOTEIO, "Remote I/O error"), + ERRNO_MSG(EDQUOT, "Quota exceeded"), + ERRNO_MSG(ENOMEDIUM, "No medium found"), + ERRNO_MSG(EMEDIUMTYPE, "Wrong medium type"), +}; + +const char *errno_str(int errno) +{ + if (errno >= 0) + return errno_message[0]; + + return errno_message[abs(errno)]; +} diff --git a/lib/string.c b/lib/string.c index 29c2ca7..87c9a40 100644 --- a/lib/string.c +++ b/lib/string.c @@ -102,6 +102,31 @@ char * strncpy(char * dest,const char *src,size_t count) } #endif +#ifndef __HAVE_ARCH_STRLCPY +/** + * strlcpy - Copy a C-string into a sized buffer + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @size: size of destination buffer + * + * Compatible with *BSD: the result is always a valid + * NUL-terminated string that fits in the buffer (unless, + * of course, the buffer size is zero). It does not pad + * out the result like strncpy() does. + */ +size_t strlcpy(char *dest, const char *src, size_t size) +{ + size_t ret = strlen(src); + + if (size) { + size_t len = (ret >= size) ? size - 1 : ret; + memcpy(dest, src, len); + dest[len] = '\0'; + } + return ret; +} +#endif + #ifndef __HAVE_ARCH_STRCAT /** * strcat - Append one %NUL-terminated string to another diff --git a/test/dm/Makefile b/test/dm/Makefile index 75d3d41..612aa95 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -20,4 +20,5 @@ ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_SPI) += spi.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o +obj-$(CONFIG_DM_I2C) += i2c.o endif diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c index 26980d2..79a674e 100644 --- a/test/dm/cmd_dm.c +++ b/test/dm/cmd_dm.c @@ -16,17 +16,65 @@ #include #include +static void show_devices(struct udevice *dev, int depth, int last_flag) +{ + int i, is_last; + struct udevice *child; + char class_name[12]; + + /* print the first 11 characters to not break the tree-format. */ + strlcpy(class_name, dev->uclass->uc_drv->name, sizeof(class_name)); + printf(" %-11s [ %c ] ", class_name, + dev->flags & DM_FLAG_ACTIVATED ? '+' : ' '); + + for (i = depth; i >= 0; i--) { + is_last = (last_flag >> i) & 1; + if (i) { + if (is_last) + printf(" "); + else + printf("| "); + } else { + if (is_last) + printf("`-- "); + else + printf("|-- "); + } + } + + printf("%s\n", dev->name); + + list_for_each_entry(child, &dev->child_head, sibling_node) { + is_last = list_is_last(&child->sibling_node, &dev->child_head); + show_devices(child, depth + 1, (last_flag << 1) | is_last); + } +} + +static int do_dm_dump_all(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + struct udevice *root; + + root = dm_root(); + if (root) { + printf(" Class Probed Name\n"); + printf("----------------------------------------\n"); + show_devices(root, -1, 0); + } + + return 0; +} + /** * dm_display_line() - Display information about a single device * * Displays a single line of information with an option prefix * * @dev: Device to display - * @buf: Prefix to display at the start of the line */ -static void dm_display_line(struct udevice *dev, char *buf) +static void dm_display_line(struct udevice *dev) { - printf("%s- %c %s @ %08lx", buf, + printf("- %c %s @ %08lx", dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ', dev->name, (ulong)map_to_sysmem(dev)); if (dev->req_seq != -1) @@ -34,53 +82,6 @@ static void dm_display_line(struct udevice *dev, char *buf) puts("\n"); } -static int display_succ(struct udevice *in, char *buf) -{ - int len; - int ip = 0; - char local[16]; - struct udevice *pos, *n, *prev = NULL; - - dm_display_line(in, buf); - - if (list_empty(&in->child_head)) - return 0; - - len = strlen(buf); - strncpy(local, buf, sizeof(local)); - snprintf(local + len, 2, "|"); - if (len && local[len - 1] == '`') - local[len - 1] = ' '; - - list_for_each_entry_safe(pos, n, &in->child_head, sibling_node) { - if (ip++) - display_succ(prev, local); - prev = pos; - } - - snprintf(local + len, 2, "`"); - display_succ(prev, local); - - return 0; -} - -static int dm_dump(struct udevice *dev) -{ - if (!dev) - return -EINVAL; - return display_succ(dev, ""); -} - -static int do_dm_dump_all(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - struct udevice *root; - - root = dm_root(); - printf("ROOT %08lx\n", (ulong)map_to_sysmem(root)); - return dm_dump(root); -} - static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -99,7 +100,7 @@ static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc, if (list_empty(&uc->dev_head)) continue; list_for_each_entry(dev, &uc->dev_head, uclass_node) { - dm_display_line(dev, ""); + dm_display_line(dev); } puts("\n"); } diff --git a/test/dm/i2c.c b/test/dm/i2c.c new file mode 100644 index 0000000..a53e28d --- /dev/null +++ b/test/dm/i2c.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2013 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Note: Test coverage does not include 10-bit addressing + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const int busnum; +static const int chip = 0x2c; + +/* Test that we can find buses and chips */ +static int dm_test_i2c_find(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + const int no_chip = 0x10; + + ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_I2C, busnum, + false, &bus)); + + /* + * i2c_post_bind() will bind devices to chip selects. Check this then + * remove the emulation and the slave device. + */ + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_probe(bus, chip, 0, &dev)); + ut_asserteq(-ENODEV, i2c_probe(bus, no_chip, 0, &dev)); + ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_I2C, 1, &bus)); + + return 0; +} +DM_TEST(dm_test_i2c_find, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_read_write(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + uint8_t buf[5]; + + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_get_chip(bus, chip, &dev)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf))); + ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0AB\0", sizeof(buf))); + + return 0; +} +DM_TEST(dm_test_i2c_read_write, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_speed(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + uint8_t buf[5]; + + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_get_chip(bus, chip, &dev)); + ut_assertok(i2c_set_bus_speed(bus, 100000)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(i2c_set_bus_speed(bus, 400000)); + ut_asserteq(400000, i2c_get_bus_speed(bus)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_asserteq(-EINVAL, i2c_write(dev, 0, buf, 5)); + + return 0; +} +DM_TEST(dm_test_i2c_speed, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_offset_len(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + uint8_t buf[5]; + + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_get_chip(bus, chip, &dev)); + ut_assertok(i2c_set_chip_offset_len(dev, 1)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + + /* This is not supported by the uclass */ + ut_asserteq(-EINVAL, i2c_set_chip_offset_len(dev, 5)); + + return 0; +} +DM_TEST(dm_test_i2c_offset_len, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_probe_empty(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_probe(bus, SANDBOX_I2C_TEST_ADDR, 0, &dev)); + + return 0; +} +DM_TEST(dm_test_i2c_probe_empty, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_bytewise(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + struct udevice *eeprom; + uint8_t buf[5]; + + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_get_chip(bus, chip, &dev)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf))); + + /* Tell the EEPROM to only read/write one register at a time */ + ut_assertok(uclass_first_device(UCLASS_I2C_EMUL, &eeprom)); + ut_assertnonnull(eeprom); + sandbox_i2c_eeprom_set_test_mode(eeprom, SIE_TEST_MODE_SINGLE_BYTE); + + /* Now we only get the first byte - the rest will be 0xff */ + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf))); + + /* If we do a separate transaction for each byte, it works */ + ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf))); + + /* This will only write A */ + ut_assertok(i2c_set_chip_flags(dev, 0)); + ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf))); + + /* Check that the B was ignored */ + ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0A\0\0\0", sizeof(buf))); + + /* Now write it again with the new flags, it should work */ + ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_WR_ADDRESS)); + ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf))); + + ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_WR_ADDRESS | + DM_I2C_CHIP_RD_ADDRESS)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0AB\0\0", sizeof(buf))); + + /* Restore defaults */ + sandbox_i2c_eeprom_set_test_mode(eeprom, SIE_TEST_MODE_NONE); + ut_assertok(i2c_set_chip_flags(dev, 0)); + + return 0; +} +DM_TEST(dm_test_i2c_bytewise, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_offset(struct dm_test_state *dms) +{ + struct udevice *eeprom; + struct udevice *dev; + uint8_t buf[5]; + + ut_assertok(i2c_get_chip_for_busnum(busnum, chip, &dev)); + + /* Do a transfer so we can find the emulator */ + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(uclass_first_device(UCLASS_I2C_EMUL, &eeprom)); + + /* Offset length 0 */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 0); + ut_assertok(i2c_set_chip_offset_len(dev, 0)); + ut_assertok(i2c_write(dev, 10 /* ignored */, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "AB\0\0\0\0", sizeof(buf))); + + /* Offset length 1 */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 1); + ut_assertok(i2c_set_chip_offset_len(dev, 1)); + ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "ABAB\0", sizeof(buf))); + + /* Offset length 2 */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 2); + ut_assertok(i2c_set_chip_offset_len(dev, 2)); + ut_assertok(i2c_write(dev, 0x210, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0x210, buf, 5)); + ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); + + /* Offset length 3 */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 2); + ut_assertok(i2c_set_chip_offset_len(dev, 2)); + ut_assertok(i2c_write(dev, 0x410, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0x410, buf, 5)); + ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); + + /* Offset length 4 */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 2); + ut_assertok(i2c_set_chip_offset_len(dev, 2)); + ut_assertok(i2c_write(dev, 0x420, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0x420, buf, 5)); + ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); + + /* Restore defaults */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 1); + + return 0; +} +DM_TEST(dm_test_i2c_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 1fba792..fb0272a 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -93,6 +93,23 @@ num-gpios = <10>; }; + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + compatible = "sandbox,i2c"; + clock-frequency = <100000>; + eeprom@2c { + reg = <0x2c>; + compatible = "i2c-eeprom"; + emul { + compatible = "sandbox,i2c-eeprom"; + sandbox,filename = "i2c.bin"; + sandbox,size = <256>; + }; + }; + }; + spi@0 { #address-cells = <1>; #size-cells = <0>;