[U-Boot] [RFC PATCH v2 6/6] fdt: example modification of i2c driver for fdt control

Simon Glass
2011-09-12T22:04:27Z

This is only an example for comment. It is not a real driver as yet. It
just shows how the config is read from the fdt.

You can see that the main difference (as you might expect) is whether
configuration comes from the fdt or the CONFIG options.

Some drivers will need changing to split their config out in such a clear
way, or to add a structure to hold the config rather than using CONFIG_...
options throughout their code.

This also provides an example fdt fragment to show what the device is
actually reading.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v2:
- Add example of i2c driver changes required to support fdt control
- Add example fdt fragments for Tegra2 I2C, just for illustration

board/nvidia/seaboard/tegra2-seaboard.dts | 20 ++++++
board/nvidia/seaboard/tegra250.dtsi | 42 +++++++++++++
drivers/i2c/tegra2_i2c.c | 91 +++++++++++++++++++++++++++++
3 files changed, 153 insertions(+), 0 deletions(-)
create mode 100644 board/nvidia/seaboard/tegra2-seaboard.dts
create mode 100644 board/nvidia/seaboard/tegra250.dtsi

diff --git a/board/nvidia/seaboard/tegra2-seaboard.dts b/board/nvidia/seaboard/tegra2-seaboard.dts
new file mode 100644
index 0000000..2c17139
--- /dev/null
+++ b/board/nvidia/seaboard/tegra2-seaboard.dts
@@ -0,0 +1,20 @@
+/dts-v1/;
+
+/memreserve/ 0x1c000000 0x04000000;
+/include/ "tegra250.dtsi"
+
+/ {
+ model = "NVIDIA Seaboard";
+ compatible = "nvidia,seaboard", "nvidia,tegra250";
+
+ /* Enable the ports we want to use, and update the speed if needed */
+ i2c at 0x7000c000 {
+ status = "ok";
+ };
+
+ i2c at 0x7000c400 {
+ speed = <400000>;
+ status = "ok";
+ };
+
+};
diff --git a/board/nvidia/seaboard/tegra250.dtsi b/board/nvidia/seaboard/tegra250.dtsi
new file mode 100644
index 0000000..d6dc19b
--- /dev/null
+++ b/board/nvidia/seaboard/tegra250.dtsi
@@ -0,0 +1,42 @@
+/* This is not a real fdt! It is just for illustration in this RFC */
+
+/ {
+ model = "NVIDIA Tegra 250";
+ compatible = "nvidia,tegra250";
+
+ i2c at 0x7000c000 {
+ compatible = "nvidia,tegra250-i2c";
+ reg = <0x7000c000 0x006c>;
+ pinmux = <1>;
+ speed = <100000>;
+ periph-id = <12>; // PERIPH_ID_I2C1
+ status = "disabled";
+ };
+
+ i2c at 0x7000c400 {
+ compatible = "nvidia,tegra250-i2c";
+ reg = <0x7000c400 0x006c>;
+ pinmux = <2>;
+ speed = <100000>;
+ periph-id = <54>; // PERIPH_ID_I2C2
+ status = "disabled";
+ };
+
+ i2c at 0x7000c500 {
+ compatible = "nvidia,tegra250-i2c";
+ reg = <0x7000c500 0x006c>;
+ pinmux = <1>;
+ speed = <100000>;
+ periph-id = <67>; // PERIPH_ID_I2C3
+ status = "disabled";
+ };
+
+ i2c at 0x7000d000 {
+ compatible = "nvidia,tegra250-i2c";
+ reg = <0x7000d000 0x007c>;
+ pinmux = <1>;
+ speed = <100000>;
+ periph-id = <47>; // PERIPH_ID_DVC_I2C
+ status = "disabled";
+ };
+};
diff --git a/drivers/i2c/tegra2_i2c.c b/drivers/i2c/tegra2_i2c.c
index d98519c..9485b56 100644
--- a/drivers/i2c/tegra2_i2c.c
+++ b/drivers/i2c/tegra2_i2c.c
@@ -388,6 +388,97 @@ static int tegra2_i2c_read_data(u32 addr, u8 *data, u32 len)
return error;
}

+#ifndef CONFIG_OF_CONTROL
+/* This is the original code, whic uses CONFIG_..., TEGRA2_...,etc. */
+static const enum periph_id i2c_periph_ids[CONFIG_SYS_MAX_I2C_BUS] = {
+ PERIPH_ID_DVC_I2C,
+ PERIPH_ID_I2C1,
+ PERIPH_ID_I2C2,
+ PERIPH_ID_I2C3
+};
+
+static const u32 *i2c_bus_base[CONFIG_SYS_MAX_I2C_BUS] = {
+ (u32 *)TEGRA2_DVC_BASE,
+ (u32 *)TEGRA2_I2C1_BASE,
+ (u32 *)TEGRA2_I2C2_BASE,
+ (u32 *)TEGRA2_I2C3_BASE
+};
+
+/* pinmux_configs based on the pinmux configuration */
+static const int pinmux_configs[CONFIG_SYS_MAX_I2C_BUS] = {
+ CONFIG_I2CP_PIN_MUX, /* for I2CP (DVC I2C) */
+ CONFIG_I2C1_PIN_MUX, /* for I2C1 */
+ CONFIG_I2C2_PIN_MUX, /* for I2C2 */
+ CONFIG_I2C3_PIN_MUX /* for I2C3 */
+};
+
+static int i2c_get_config(int *index, struct i2c_bus *i2c_bus)
+{
+ int i = *index;
+
+ if (i >= CONFIG_SYS_MAX_I2C_BUS)
+ return -1;
+
+ i2c_bus->periph_id = i2c_periph_ids[i];
+ i2c_bus->pinmux_config = pinmux_configs[i];
+ i2c_bus->regs = (struct i2c_ctlr *)i2c_bus_base[i];
+ i2c_bus->speed = I2CSPEED_KHZ * 1000;
+
+ *index = i + 1;
+
+ return 0;
+}
+#else
+/* This is the fdt code */
+static int i2c_get_config(int *index, struct i2c_bus *i2c_bus)
+{
+ const void *blob = gd->blob;
+ struct fdt_i2c config;
+ int node = fdt_decode_next_alias(blob,
+ "i2c",
+ COMPAT_NVIDIA_TEGRA250_I2C,
+ index);
+ if (node < 0)
+ return -1;
+
+ if (fdt_decode_i2c(blob, node, &config))
+ return -1;
+
+ i2c_bus->periph_id = config.periph_id;
+ i2c_bus->pinmux_config = config.pinmux;
+ i2c_bus->regs = config.reg;
+ i2c_bus->speed = config.speed;
+ i2c_bus->enabled = config.enable;
+
+ return 0;
+}
+#endif
+
+int i2c_init_board(void)
+{
+ struct i2c_bus *i2c_bus;
+ int index = 0;
+ int i;
+
+ /* build the i2c_controllers[] for each controller */
+ for (i = 0; i < CONFIG_SYS_MAX_I2C_BUS; ++i) {
+ i2c_bus = &i2c_controllers[i];
+ i2c_bus->id = i;
+
+ i2c_get_config(&index, i2c_bus);
+
+ if (i2c_bus->periph_id == PERIPH_ID_DVC_I2C)
+ i2c_bus->control =
+ &((struct dvc_ctlr *)i2c_bus->regs)->control;
+ else
+ i2c_bus->control = &i2c_bus->regs->control;
+
+ i2c_init_controller(i2c_bus);
+ }
+
+ return 0;
+}
+
void i2c_init(int speed, int slaveaddr)
{
debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
--
1.7.3.1