[U-Boot] [PATCH 0/3] Add I2C driver for Tegra30 Cardhu

Add/update clock tables and enable I2C driver support for the Tegra30 Cardhu board. This uses the standard Tegra I2C driver. 5 controllers are supported, although all may not have devices behind them on every board.
Tom Warren (3): Tegra30: clocks: Fix clock tables for I2C and other periphs Tegra30: fdt: Update DT files with I2C info for T30/Cardhu Tegra30: I2C: Enable I2C driver on Cardhu
arch/arm/cpu/tegra30-common/clock.c | 78 ++++++++++++---------- arch/arm/dts/tegra30.dtsi | 61 +++++++++++++++++ arch/arm/include/asm/arch-tegra30/clock-tables.h | 4 + board/nvidia/dts/tegra30-cardhu.dts | 41 +++++++++++ include/configs/cardhu.h | 9 +++ include/configs/tegra30-common.h | 3 + 6 files changed, 162 insertions(+), 34 deletions(-)

Add 16-bit divider support (I2C) to periph table, annotate and correct some entries, and fix clk_id lookup function.
Signed-off-by: Tom Warren twarren@nvidia.com --- arch/arm/cpu/tegra30-common/clock.c | 78 ++++++++++++---------- arch/arm/include/asm/arch-tegra30/clock-tables.h | 4 + 2 files changed, 48 insertions(+), 34 deletions(-)
diff --git a/arch/arm/cpu/tegra30-common/clock.c b/arch/arm/cpu/tegra30-common/clock.c index 5db9d20..c67a2e1 100644 --- a/arch/arm/cpu/tegra30-common/clock.c +++ b/arch/arm/cpu/tegra30-common/clock.c @@ -63,6 +63,7 @@ enum clock_type_id { CLOCK_TYPE_MCPT, CLOCK_TYPE_PCM, CLOCK_TYPE_PCMT, + CLOCK_TYPE_PCMT16, CLOCK_TYPE_PDCT, CLOCK_TYPE_ACPT, CLOCK_TYPE_ASPTE, @@ -114,6 +115,9 @@ static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = { { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY), CLK(OSC), CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), MASK_BITS_31_30}, + { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY), CLK(OSC), + CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_30}, { CLK(PERIPH), CLK(DISPLAY), CLK(CGENERAL), CLK(OSC), CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), MASK_BITS_31_30}, @@ -146,15 +150,15 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_I2S2, CLOCK_TYPE_AXPT), TYPE(PERIPHC_SPDIF_OUT, CLOCK_TYPE_AXPT), TYPE(PERIPHC_SPDIF_IN, CLOCK_TYPE_PCM), - TYPE(PERIPHC_PWM, CLOCK_TYPE_PCST), + TYPE(PERIPHC_PWM, CLOCK_TYPE_PCST), /* only PWM uses b29:28 */ TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_SBC2, CLOCK_TYPE_PCMT), TYPE(PERIPHC_SBC3, CLOCK_TYPE_PCMT),
/* 0x08 */ TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), - TYPE(PERIPHC_I2C1, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_DVC_I2C, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C1, CLOCK_TYPE_PCMT16), + TYPE(PERIPHC_DVC_I2C, CLOCK_TYPE_PCMT16), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_SBC1, CLOCK_TYPE_PCMT), @@ -177,7 +181,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_VFIR, CLOCK_TYPE_PCMT), TYPE(PERIPHC_EPP, CLOCK_TYPE_MCPA), TYPE(PERIPHC_MPE, CLOCK_TYPE_MCPA), - TYPE(PERIPHC_MIPI, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_MIPI, CLOCK_TYPE_PCMT), /* MIPI base-band HSI */ TYPE(PERIPHC_UART1, CLOCK_TYPE_PCMT), TYPE(PERIPHC_UART2, CLOCK_TYPE_PCMT),
@@ -188,7 +192,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_HDMI, CLOCK_TYPE_PMDACD2T), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_TVDAC, CLOCK_TYPE_PDCT), - TYPE(PERIPHC_I2C2, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C2, CLOCK_TYPE_PCMT16), TYPE(PERIPHC_EMC, CLOCK_TYPE_MCPT),
/* 0x28 */ @@ -198,7 +202,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_SBC4, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_I2C3, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C3, CLOCK_TYPE_PCMT16), TYPE(PERIPHC_SDMMC3, CLOCK_TYPE_PCMT),
/* 0x30 */ @@ -211,13 +215,13 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_I2S0, CLOCK_TYPE_AXPT), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE),
- /* 0x38h */ + /* 0x38h */ /* Jumps to reg offset 0x3B0h - new for T30 */ TYPE(PERIPHC_G3D2, CLOCK_TYPE_MCPA), TYPE(PERIPHC_MSELECT, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_TSENSOR, CLOCK_TYPE_PCM), + TYPE(PERIPHC_TSENSOR, CLOCK_TYPE_PCST), /* s/b PCTS */ TYPE(PERIPHC_I2S3, CLOCK_TYPE_AXPT), TYPE(PERIPHC_I2S4, CLOCK_TYPE_AXPT), - TYPE(PERIPHC_I2C4, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C4, CLOCK_TYPE_PCMT16), TYPE(PERIPHC_SBC5, CLOCK_TYPE_PCMT), TYPE(PERIPHC_SBC6, CLOCK_TYPE_PCMT),
@@ -228,21 +232,25 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_DAM1, CLOCK_TYPE_ACPT), TYPE(PERIPHC_DAM2, CLOCK_TYPE_ACPT), TYPE(PERIPHC_HDA2CODEC2X, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_ACTMON, CLOCK_TYPE_PCM), + TYPE(PERIPHC_ACTMON, CLOCK_TYPE_PCST), /* MASK 31:30 */ TYPE(PERIPHC_EXTPERIPH1, CLOCK_TYPE_ASPTE),
/* 0x48 */ TYPE(PERIPHC_EXTPERIPH2, CLOCK_TYPE_ASPTE), TYPE(PERIPHC_EXTPERIPH3, CLOCK_TYPE_ASPTE), TYPE(PERIPHC_NANDSPEED, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_I2CSLOW, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2CSLOW, CLOCK_TYPE_PCST), /* MASK 31:30 */ TYPE(PERIPHC_SYS, CLOCK_TYPE_NONE), TYPE(PERIPHC_SPEEDO, CLOCK_TYPE_PCMT), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE),
/* 0x50 */ - TYPE(PERIPHC_SATAOOB, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SATAOOB, CLOCK_TYPE_PCMT), /* offset 0x420h */ TYPE(PERIPHC_SATA, CLOCK_TYPE_PCMT), TYPE(PERIPHC_HDA, CLOCK_TYPE_PCMT), }; @@ -693,6 +701,11 @@ static int get_periph_clock_source(enum periph_id periph_id,
*mux_bits = clock_source[type][CLOCK_MAX_MUX];
+ if (type == CLOCK_TYPE_PCMT16) + *divider_bits = 16; + else + *divider_bits = 8; + for (mux = 0; mux < CLOCK_MAX_MUX; mux++) if (clock_source[type][mux] == parent) return mux; @@ -983,35 +996,32 @@ void clock_ll_start_uart(enum periph_id periph_id) * the same but we are very cautious so we check that a valid clock ID is * provided. * - * @param clk_id Clock ID according to tegra20 device tree binding + * @param clk_id Clock ID according to tegra30 device tree binding * @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid */ static enum periph_id clk_id_to_periph_id(int clk_id) { - if (clk_id > 95) + if (clk_id > PERIPH_ID_COUNT) return PERIPH_ID_NONE;
switch (clk_id) { - case 1: - case 2: - case 7: - case 10: - case 20: - case 30: - case 35: - case 49: - case 56: - case 74: - case 76: - case 77: - case 78: - case 79: - case 80: - case 81: - case 82: - case 83: - case 91: - case 95: + case PERIPH_ID_RESERVED3: + case PERIPH_ID_RESERVED4: + case PERIPH_ID_RESERVED16: + case PERIPH_ID_RESERVED24: + case PERIPH_ID_RESERVED35: + case PERIPH_ID_RESERVED43: + case PERIPH_ID_RESERVED45: + case PERIPH_ID_RESERVED56: + case PERIPH_ID_RESERVED76: + case PERIPH_ID_RESERVED77: + case PERIPH_ID_RESERVED78: + case PERIPH_ID_RESERVED83: + case PERIPH_ID_RESERVED89: + case PERIPH_ID_RESERVED91: + case PERIPH_ID_RESERVED93: + case PERIPH_ID_RESERVED94: + case PERIPH_ID_RESERVED95: return PERIPH_ID_NONE; default: return clk_id; diff --git a/arch/arm/include/asm/arch-tegra30/clock-tables.h b/arch/arm/include/asm/arch-tegra30/clock-tables.h index b55e09d..cb619f1 100644 --- a/arch/arm/include/asm/arch-tegra30/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra30/clock-tables.h @@ -351,6 +351,10 @@ enum periphc_internal_id { PERIPHC_4fh,
/* 0x50 */ + PERIPHC_50h, + PERIPHC_51h, + PERIPHC_52h, + PERIPHC_53h, PERIPHC_SATAOOB, PERIPHC_SATA, PERIPHC_HDA,

On 12/21/2012 05:16 PM, Tom Warren wrote:
Add 16-bit divider support (I2C) to periph table, annotate and correct some entries, and fix clk_id lookup function.
diff --git a/arch/arm/cpu/tegra30-common/clock.c b/arch/arm/cpu/tegra30-common/clock.c
- TYPE(PERIPHC_TSENSOR, CLOCK_TYPE_PCM),
- TYPE(PERIPHC_TSENSOR, CLOCK_TYPE_PCST), /* s/b PCTS */
It is now, so I assume that comment is stale?

No, it's now PCST, which is close as I can get to PCTS w/o adding a whole new clock_type entry for just this one piece of HW, which isn't used in U-Boot anyway.
PCST is PLLP, PLLC, CLK_S, and CLK_M. PCTS is PLLP, PLLC, CLK_M and CLK_S.
On Wed, Jan 2, 2013 at 1:35 PM, Stephen Warren swarren@wwwdotorg.org wrote:
On 12/21/2012 05:16 PM, Tom Warren wrote:
Add 16-bit divider support (I2C) to periph table, annotate and correct some entries, and fix clk_id lookup function.
diff --git a/arch/arm/cpu/tegra30-common/clock.c b/arch/arm/cpu/tegra30-common/clock.c
TYPE(PERIPHC_TSENSOR, CLOCK_TYPE_PCM),
TYPE(PERIPHC_TSENSOR, CLOCK_TYPE_PCST), /* s/b PCTS */
It is now, so I assume that comment is stale?

Note that T30 does not have a separate/different DVC (power I2C) controller like T20 - all 5 I2C controllers are identical, but DVC_I2C is still used to designate the controller intended for power control (PWR_I2C in the schematics). On Cardhu, it's used to access the PMU and EEPROM, as well as the audio codec, temp sensor, and fuel gauge devices from the OS.
Signed-off-by: Tom Warren twarren@nvidia.com --- arch/arm/dts/tegra30.dtsi | 61 +++++++++++++++++++++++++++++++++++ board/nvidia/dts/tegra30-cardhu.dts | 41 +++++++++++++++++++++++ 2 files changed, 102 insertions(+), 0 deletions(-)
diff --git a/arch/arm/dts/tegra30.dtsi b/arch/arm/dts/tegra30.dtsi index f568d44..664c397 100644 --- a/arch/arm/dts/tegra30.dtsi +++ b/arch/arm/dts/tegra30.dtsi @@ -2,4 +2,65 @@
/ { compatible = "nvidia,tegra30"; + + tegra_car: clock@60006000 { + compatible = "nvidia,tegra30-car", "nvidia,tegra20-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + osc: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + }; + + i2c@7000c000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000C000 0x100>; + /* PERIPH_ID_I2C1, CLK_M */ + clocks = <&tegra_car 12>; + }; + + i2c@7000c400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000C400 0x100>; + /* PERIPH_ID_I2C2, CLK_M */ + clocks = <&tegra_car 54>; + }; + + i2c@7000c500 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000C500 0x100>; + /* PERIPH_ID_I2C3, CLK_M */ + clocks = <&tegra_car 67>; + }; + + i2c@7000c700 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000C700 0x100>; + /* PERIPH_ID_I2C4, CLK_M */ + clocks = <&tegra_car 103>; + }; + + i2c@7000d000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000D000 0x100>; + /* PERIPH_ID_I2C_DVC, CLK_M */ + clocks = <&tegra_car 47>; + }; }; diff --git a/board/nvidia/dts/tegra30-cardhu.dts b/board/nvidia/dts/tegra30-cardhu.dts index 2345766..4eddde6 100644 --- a/board/nvidia/dts/tegra30-cardhu.dts +++ b/board/nvidia/dts/tegra30-cardhu.dts @@ -6,8 +6,49 @@ model = "NVIDIA Cardhu"; compatible = "nvidia,cardhu", "nvidia,tegra30";
+ aliases { + i2c0 = "/i2c@7000d000"; + i2c1 = "/i2c@7000c000"; + i2c2 = "/i2c@7000c400"; + i2c3 = "/i2c@7000c500"; + i2c4 = "/i2c@7000c700"; + }; + memory { device_type = "memory"; reg = <0x80000000 0x40000000>; }; + + clocks { + clk_32k: clk_32K { + clock-frequency = <32768>; + }; + osc { + clock-frequency = <12000000>; + }; + }; + + clock@60006000 { + clocks = <&clk_32k &osc>; + }; + + i2c@7000c000 { + clock-frequency = <100000>; + }; + + i2c@7000c400 { + clock-frequency = <100000>; + }; + + i2c@7000c500 { + clock-frequency = <100000>; + }; + + i2c@7000c700 { + clock-frequency = <100000>; + }; + + i2c@7000d000 { + clock-frequency = <100000>; + }; };

On 12/21/2012 05:16 PM, Tom Warren wrote:
Note that T30 does not have a separate/different DVC (power I2C) controller like T20 - all 5 I2C controllers are identical, but DVC_I2C is still used to designate the controller intended for power control (PWR_I2C in the schematics). On Cardhu, it's used to access the PMU and EEPROM, as well as the audio codec, temp sensor, and fuel gauge devices from the OS.
diff --git a/arch/arm/dts/tegra30.dtsi b/arch/arm/dts/tegra30.dtsi
- tegra_car: clock@60006000 {
compatible = "nvidia,tegra30-car", "nvidia,tegra20-car";
reg = <0x60006000 0x1000>;
#clock-cells = <1>;
- };
- clocks {
It'd be nice to keep the DT nodes sorted in the same order they are in the kernel. There, the rules are that nodes appears in order:
1) Any nodes from /include/d files, in the order they appeared in the underlying file.
2) Any nodes with a reg property, in order of the address in the reg property.
3) Any nodes without a reg property, in alphabetical order by node name.
This will allow the U-Boot and kernel DT files to be more easily compared/diff'd.
The clocks and osc node would usually be part of the board file, not the SoC file, I believe...
Actually, the clocks "osc" and (later) "clk_32k" don't appear to be used anywhere; can we just drop their nodes until if/when they are?
- i2c@7000c000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c";
reg = <0x7000C000 0x100>;
/* PERIPH_ID_I2C1, CLK_M */
clocks = <&tegra_car 12>;
- };
I think we should use lower-case for all hex constants in the DT. Also, can the properties appear in the same order as in the kernel DT files so they're easier to compare/diff.
Also, the SoC .dtsi file should have status="disabled" for all the optionally-used HW modules, and the board files set status="okay" for those that the board actually uses.

Alrightly. Can you send me a link to the latest-and-greatest T30/Cardhu kernel DT files so I can use 'em as a reference? Every time I do a Google search for kernel files I'm never sure if I've got the latest one or not.
Thanks
On Wed, Jan 2, 2013 at 1:41 PM, Stephen Warren swarren@wwwdotorg.org wrote:
On 12/21/2012 05:16 PM, Tom Warren wrote:
Note that T30 does not have a separate/different DVC (power I2C) controller like T20 - all 5 I2C controllers are identical, but DVC_I2C is still used to designate the controller intended for power control (PWR_I2C in the schematics). On Cardhu, it's used to access the PMU and EEPROM, as well as the audio codec, temp sensor, and fuel gauge devices from the OS.
diff --git a/arch/arm/dts/tegra30.dtsi b/arch/arm/dts/tegra30.dtsi
tegra_car: clock@60006000 {
compatible = "nvidia,tegra30-car", "nvidia,tegra20-car";
reg = <0x60006000 0x1000>;
#clock-cells = <1>;
};
clocks {
It'd be nice to keep the DT nodes sorted in the same order they are in the kernel. There, the rules are that nodes appears in order:
- Any nodes from /include/d files, in the order they appeared in the
underlying file.
- Any nodes with a reg property, in order of the address in the reg
property.
- Any nodes without a reg property, in alphabetical order by node name.
This will allow the U-Boot and kernel DT files to be more easily compared/diff'd.
The clocks and osc node would usually be part of the board file, not the SoC file, I believe...
Actually, the clocks "osc" and (later) "clk_32k" don't appear to be used anywhere; can we just drop their nodes until if/when they are?
i2c@7000c000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c";
reg = <0x7000C000 0x100>;
/* PERIPH_ID_I2C1, CLK_M */
clocks = <&tegra_car 12>;
};
I think we should use lower-case for all hex constants in the DT. Also, can the properties appear in the same order as in the kernel DT files so they're easier to compare/diff.
Also, the SoC .dtsi file should have status="disabled" for all the optionally-used HW modules, and the board files set status="okay" for those that the board actually uses.

On 01/02/2013 01:58 PM, Tom Warren wrote:
Alrightly. Can you send me a link to the latest-and-greatest T30/Cardhu kernel DT files so I can use 'em as a reference? Every time I do a Google search for kernel files I'm never sure if I've got the latest one or not.
The easiest way is probably:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
cd linux-2.6/arch/arm/boot/dts
ls *cardhu*

Tested all 5 'buses', i2c probe enumerates device addresses on all but dev 4 (I2C4) [no devices on that bus on my Cardhu].
Note that this uses the extant tegra_i2c.c driver w/o modification.
Signed-off-by: Tom Warren twarren@nvidia.com --- include/configs/cardhu.h | 9 +++++++++ include/configs/tegra30-common.h | 3 +++ 2 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/include/configs/cardhu.h b/include/configs/cardhu.h index 471df6e..aa725ba 100644 --- a/include/configs/cardhu.h +++ b/include/configs/cardhu.h @@ -38,6 +38,15 @@ #define CONFIG_MACH_TYPE MACH_TYPE_CARDHU
#define CONFIG_BOARD_EARLY_INIT_F + +/* I2C */ +#define CONFIG_TEGRA_I2C +#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_ENV_IS_NOWHERE
#include "tegra-common-post.h" diff --git a/include/configs/tegra30-common.h b/include/configs/tegra30-common.h index 282caec..04517e1 100644 --- a/include/configs/tegra30-common.h +++ b/include/configs/tegra30-common.h @@ -83,4 +83,7 @@
#define CONFIG_SPL_LDSCRIPT "$(CPUDIR)/tegra30/u-boot-spl.lds"
+/* Total I2C ports on Tegra30 */ +#define TEGRA_I2C_NUM_CONTROLLERS 5 + #endif /* _TEGRA30_COMMON_H_ */

On 12/21/2012 05:16 PM, Tom Warren wrote:
Tested all 5 'buses', i2c probe enumerates device addresses on all but dev 4 (I2C4) [no devices on that bus on my Cardhu].
Note that this uses the extant tegra_i2c.c driver w/o modification.
Aside from previous comments, Reviewed-by: Stephen Warren swarren@nvidia.com
participants (2)
-
Stephen Warren
-
Tom Warren