Skip to contentSkip to conversation

i2c: mvtwsi: Fix mvtwsi not working on sun6i and newer sunxi SoCs

PATCH New Hans de Goede 2 participants 4 messages Jan 14, 2016 – Jan 21, 2016

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/2 i2c: mvtwsi: Fix mvtwsi not working on sun6i and newer sunxi SoCs

On sun6i and newer IFLG is a write-clear bit which is cleared by writing 1, rather then a normal r/w bit which is cleared by writing 0.

---
 drivers/i2c/mvtwsi.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
drivers/i2c/mvtwsi.c +15 -4
index f20d1b2..698bfc1 100644
@@ -73,6 +73,17 @@ struct  mvtwsi_registers {
 #define	MVTWSI_CONTROL_INTEN	0x00000080
 
 /*
+ * On sun6i and newer IFLG is a write-clear bit which is cleared by writing 1,
+ * on other platforms it is a normal r/w bit which is cleared by writing 0.
+ */
+
+#ifdef CONFIG_SUNXI_GEN_SUN6I
+#define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000008
+#else
+#define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000000
+#endif
+
+/*
  * Status register values -- only those expected in normal master
  * operation on non-10-bit-address devices; whatever status we don't
  * expect in nominal conditions (bus errors, arbitration losses,
@@ -189,7 +200,7 @@ static int twsi_start(struct i2c_adapter *adap, int expected_status)
 	/* globally set TWSIEN in case it was not */
 	twsi_control_flags |= MVTWSI_CONTROL_TWSIEN;
 	/* assert START */
-	writel(twsi_control_flags | MVTWSI_CONTROL_START, &twsi->control);
+	writel(twsi_control_flags | MVTWSI_CONTROL_START | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
 	/* wait for controller to process START */
 	return twsi_wait(adap, expected_status);
 }
@@ -204,7 +215,7 @@ static int twsi_send(struct i2c_adapter *adap, u8 byte, int expected_status)
 	/* put byte in data register for sending */
 	writel(byte, &twsi->data);
 	/* clear any pending interrupt -- that'll cause sending */
-	writel(twsi_control_flags, &twsi->control);
+        writel(twsi_control_flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
 	/* wait for controller to receive byte and check ACK */
 	return twsi_wait(adap, expected_status);
 }
@@ -224,7 +235,7 @@ static int twsi_recv(struct i2c_adapter *adap, u8 *byte)
 	else
 		expected_status = MVTWSI_STATUS_DATA_R_NAK;
 	/* acknowledge *previous state* and launch receive */
-	writel(twsi_control_flags, &twsi->control);
+	writel(twsi_control_flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
 	/* wait for controller to receive byte and assert ACK or NAK */
 	status = twsi_wait(adap, expected_status);
 	/* if we did receive expected byte then store it */
@@ -246,7 +257,7 @@ static int twsi_stop(struct i2c_adapter *adap, int status)
 
 	/* assert STOP */
 	control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
-	writel(control, &twsi->control);
+	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
 	/* wait for IDLE; IFLG won't rise so twsi_wait() is no use. */
 	do {
 		stop_status = readl(&twsi->status);
Signature · 1 line
2.5.0
#1 lore raw

PATCH 2/2 sunxi: Add support for the I2C controller which is part of the PRCM

From: Jelle van der Waa <[email protected]>

[hdegoede at redhat.com: Minor cleanups]
---
 arch/arm/cpu/armv7/sunxi/clock_sun6i.c      | 10 ++++++++++
 arch/arm/cpu/armv7/sunxi/prcm.c             | 12 ++++++++++++
 arch/arm/include/asm/arch-sunxi/cpu_sun4i.h |  1 +
 arch/arm/include/asm/arch-sunxi/gpio.h      |  2 ++
 arch/arm/include/asm/arch-sunxi/i2c.h       |  3 +++
 arch/arm/include/asm/arch-sunxi/prcm.h      |  2 ++
 board/sunxi/Kconfig                         |  6 ++++++
 board/sunxi/board.c                         |  6 ++++++
 configs/orangepi_pc_defconfig               |  1 +
 drivers/i2c/mvtwsi.c                        | 11 +++++++++++
 include/configs/sunxi-common.h              |  2 +-
 11 files changed, 55 insertions(+), 1 deletion(-)
arch/arm/cpu/armv7/sunxi/clock_sun6i.c +10 -0
index 4501884..1da5455 100644
@@ -77,6 +77,16 @@ int clock_twi_onoff(int port, int state)
 	struct sunxi_ccm_reg *const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 
+	if (port == 5) {
+		if (state)
+			prcm_apb0_enable(
+				PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_I2C);
+		else
+			prcm_apb0_disable(
+				PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_I2C);
+		return 0;
+	}
+
 	/* set the apb clock gate for twi */
 	if (state)
 		setbits_le32(&ccm->apb2_gate,
arch/arm/cpu/armv7/sunxi/prcm.c +12 -0
index 19b4938..e1d091f 100644
@@ -33,3 +33,15 @@ void prcm_apb0_enable(u32 flags)
 	/* deassert reset for module */
 	setbits_le32(&prcm->apb0_reset, flags);
 }
+
+void prcm_apb0_disable(u32 flags)
+{
+	struct sunxi_prcm_reg *prcm =
+		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
+
+	/* assert reset for module */
+	clrbits_le32(&prcm->apb0_reset, flags);
+
+	/* close the clock for module */
+	clrbits_le32(&prcm->apb0_gate, flags);
+}
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h +1 -0
index 63b161a..0cdefdc 100644
@@ -134,6 +134,7 @@
 #define SUNXI_RTC_BASE			0x01f00000
 #define SUNXI_PRCM_BASE			0x01f01400
 #define SUN6I_CPUCFG_BASE		0x01f01c00
+#define SUNXI_R_TWI_BASE		0x01f02400
 #define SUNXI_R_UART_BASE		0x01f02800
 #define SUNXI_R_PIO_BASE		0x01f02c00
 #define SUN6I_P2WI_BASE			0x01f03400
arch/arm/include/asm/arch-sunxi/gpio.h +2 -0
index a2a9a38..0eca859 100644
@@ -199,6 +199,8 @@ enum sunxi_gpio_number {
 #define SUN6I_GPL1_R_P2WI_SDA	3
 
 #define SUN8I_GPL_R_RSB		2
+#define SUN8I_H3_GPL_R_TWI 	2
+#define SUN8I_A23_GPL_R_TWI 	3
 #define SUN8I_GPL_R_UART	2
 
 #define SUN9I_GPN_R_RSB		3
arch/arm/include/asm/arch-sunxi/i2c.h +3 -0
index 561cd2b..4dfd313 100644
@@ -23,6 +23,9 @@
 #ifdef CONFIG_I2C4_ENABLE
 #define CONFIG_I2C_MVTWSI_BASE4	SUNXI_TWI4_BASE
 #endif
+#ifdef CONFIG_R_I2C_ENABLE
+#define CONFIG_I2C_MVTWSI_BASE5 SUNXI_R_TWI_BASE
+#endif
 
 /* This is abp0-clk on sun4i/5i/7i / abp1-clk on sun6i/sun8i which is 24MHz */
 #define CONFIG_SYS_TCLK		24000000
arch/arm/include/asm/arch-sunxi/prcm.h +2 -0
index 82ed541..556c1af 100644
@@ -236,5 +236,7 @@ struct sunxi_prcm_reg {
 };
 
 void prcm_apb0_enable(u32 flags);
+void prcm_apb0_disable(u32 flags);
+
 #endif /* __ASSEMBLY__ */
 #endif /* _PRCM_H */
board/sunxi/Kconfig +6 -0
index 9d67847..7c69be9 100644
@@ -363,6 +363,12 @@ config I2C3_ENABLE
 	See I2C0_ENABLE help text.
 endif
 
+config R_I2C_ENABLE
+	bool "Enable the PRCM I2C/TWI controller"
+	default n
+	---help---
+	Set this to y to enable the I2C controller which is part of the PRCM.
+
 if MACH_SUN7I
 config I2C4_ENABLE
 	bool "Enable I2C/TWI controller 4"
board/sunxi/board.c +6 -0
index 386e2e0..1cc39e4 100644
@@ -422,6 +422,12 @@ void i2c_init_board(void)
 	clock_twi_onoff(4, 1);
 #endif
 #endif
+
+#ifdef CONFIG_R_I2C_ENABLE
+	clock_twi_onoff(5, 1);
+	sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_H3_GPL_R_TWI);
+	sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_H3_GPL_R_TWI);
+#endif
 }
 
 #ifdef CONFIG_SPL_BUILD
configs/orangepi_pc_defconfig +1 -0
index 358caa5..ea9ed87 100644
@@ -12,3 +12,4 @@ CONFIG_SPL=y
 # CONFIG_CMD_FLASH is not set
 # CONFIG_CMD_FPGA is not set
 CONFIG_CMD_GPIO=y
+CONFIG_R_I2C_ENABLE=y
drivers/i2c/mvtwsi.c +11 -0
index 698bfc1..b5304d8 100644
@@ -128,6 +128,10 @@ static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
 	case 4:
 		return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE4;
 #endif
+#ifdef CONFIG_I2C_MVTWSI_BASE5
+	case 5:
+		return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE5;
+#endif
 	default:
 		printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
 		break;
@@ -486,3 +490,10 @@ U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
 
 #endif
+#ifdef CONFIG_I2C_MVTWSI_BASE5
+U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
+			 twsi_i2c_read, twsi_i2c_write,
+			 twsi_i2c_set_bus_speed,
+			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
+
+#endif
include/configs/sunxi-common.h +1 -1
index 790e704..b4dfb3c 100644
@@ -212,7 +212,7 @@
 
 #if defined CONFIG_I2C0_ENABLE || defined CONFIG_I2C1_ENABLE || \
     defined CONFIG_I2C2_ENABLE || defined CONFIG_I2C3_ENABLE || \
-    defined CONFIG_I2C4_ENABLE
+    defined CONFIG_I2C4_ENABLE || defined CONFIG_R_I2C_ENABLE
 #define CONFIG_SYS_I2C
 #define CONFIG_SYS_I2C_MVTWSI
 #define CONFIG_SYS_I2C_SPEED		400000
Signature · 1 line
2.5.0
#2 lore raw

PATCH 2/2 sunxi: Add support for the I2C controller which is part of the PRCM

Hello Hans,

Am 14.01.2016 um 14:06 schrieb Hans de Goede:

Quoted 5 lines

From: Jelle van der Waa <[email protected]>

[hdegoede at redhat.com: Minor cleanups]
Quoted 13 lines
---
  arch/arm/cpu/armv7/sunxi/clock_sun6i.c      | 10 ++++++++++
  arch/arm/cpu/armv7/sunxi/prcm.c             | 12 ++++++++++++
  arch/arm/include/asm/arch-sunxi/cpu_sun4i.h |  1 +
  arch/arm/include/asm/arch-sunxi/gpio.h      |  2 ++
  arch/arm/include/asm/arch-sunxi/i2c.h       |  3 +++
  arch/arm/include/asm/arch-sunxi/prcm.h      |  2 ++
  board/sunxi/Kconfig                         |  6 ++++++
  board/sunxi/board.c                         |  6 ++++++
  configs/orangepi_pc_defconfig               |  1 +
  drivers/i2c/mvtwsi.c                        | 11 +++++++++++
  include/configs/sunxi-common.h              |  2 +-
  11 files changed, 55 insertions(+), 1 deletion(-)

Thanks!

Applied to u-boot-i2c.git with fixing 2 checkpatch warnigns.

bye,
Heiko

Quoted 176 lines
arch/arm/cpu/armv7/sunxi/clock_sun6i.c +10 -0
index 4501884..1da5455 100644
@@ -77,6 +77,16 @@ int clock_twi_onoff(int port, int state)
  	struct sunxi_ccm_reg *const ccm =
  		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 
+	if (port == 5) {
+		if (state)
+			prcm_apb0_enable(
+				PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_I2C);
+		else
+			prcm_apb0_disable(
+				PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_I2C);
+		return 0;
+	}
+
  	/* set the apb clock gate for twi */
  	if (state)
  		setbits_le32(&ccm->apb2_gate,
arch/arm/cpu/armv7/sunxi/prcm.c +12 -0
index 19b4938..e1d091f 100644
@@ -33,3 +33,15 @@ void prcm_apb0_enable(u32 flags)
  	/* deassert reset for module */
  	setbits_le32(&prcm->apb0_reset, flags);
  }
+
+void prcm_apb0_disable(u32 flags)
+{
+	struct sunxi_prcm_reg *prcm =
+		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
+
+	/* assert reset for module */
+	clrbits_le32(&prcm->apb0_reset, flags);
+
+	/* close the clock for module */
+	clrbits_le32(&prcm->apb0_gate, flags);
+}
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h +1 -0
index 63b161a..0cdefdc 100644
@@ -134,6 +134,7 @@
  #define SUNXI_RTC_BASE			0x01f00000
  #define SUNXI_PRCM_BASE			0x01f01400
  #define SUN6I_CPUCFG_BASE		0x01f01c00
+#define SUNXI_R_TWI_BASE		0x01f02400
  #define SUNXI_R_UART_BASE		0x01f02800
  #define SUNXI_R_PIO_BASE		0x01f02c00
  #define SUN6I_P2WI_BASE			0x01f03400
arch/arm/include/asm/arch-sunxi/gpio.h +2 -0
index a2a9a38..0eca859 100644
@@ -199,6 +199,8 @@ enum sunxi_gpio_number {
  #define SUN6I_GPL1_R_P2WI_SDA	3
 
  #define SUN8I_GPL_R_RSB		2
+#define SUN8I_H3_GPL_R_TWI 	2
+#define SUN8I_A23_GPL_R_TWI 	3
  #define SUN8I_GPL_R_UART	2
 
  #define SUN9I_GPN_R_RSB		3
arch/arm/include/asm/arch-sunxi/i2c.h +3 -0
index 561cd2b..4dfd313 100644
@@ -23,6 +23,9 @@
  #ifdef CONFIG_I2C4_ENABLE
  #define CONFIG_I2C_MVTWSI_BASE4	SUNXI_TWI4_BASE
  #endif
+#ifdef CONFIG_R_I2C_ENABLE
+#define CONFIG_I2C_MVTWSI_BASE5 SUNXI_R_TWI_BASE
+#endif
 
  /* This is abp0-clk on sun4i/5i/7i / abp1-clk on sun6i/sun8i which is 24MHz */
  #define CONFIG_SYS_TCLK		24000000
arch/arm/include/asm/arch-sunxi/prcm.h +2 -0
index 82ed541..556c1af 100644
@@ -236,5 +236,7 @@ struct sunxi_prcm_reg {
  };
 
  void prcm_apb0_enable(u32 flags);
+void prcm_apb0_disable(u32 flags);
+
  #endif /* __ASSEMBLY__ */
  #endif /* _PRCM_H */
board/sunxi/Kconfig +6 -0
index 9d67847..7c69be9 100644
@@ -363,6 +363,12 @@ config I2C3_ENABLE
  	See I2C0_ENABLE help text.
  endif
 
+config R_I2C_ENABLE
+	bool "Enable the PRCM I2C/TWI controller"
+	default n
+	---help---
+	Set this to y to enable the I2C controller which is part of the PRCM.
+
  if MACH_SUN7I
  config I2C4_ENABLE
  	bool "Enable I2C/TWI controller 4"
board/sunxi/board.c +6 -0
index 386e2e0..1cc39e4 100644
@@ -422,6 +422,12 @@ void i2c_init_board(void)
  	clock_twi_onoff(4, 1);
  #endif
  #endif
+
+#ifdef CONFIG_R_I2C_ENABLE
+	clock_twi_onoff(5, 1);
+	sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_H3_GPL_R_TWI);
+	sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_H3_GPL_R_TWI);
+#endif
  }
 
  #ifdef CONFIG_SPL_BUILD
configs/orangepi_pc_defconfig +1 -0
index 358caa5..ea9ed87 100644
@@ -12,3 +12,4 @@ CONFIG_SPL=y
  # CONFIG_CMD_FLASH is not set
  # CONFIG_CMD_FPGA is not set
  CONFIG_CMD_GPIO=y
+CONFIG_R_I2C_ENABLE=y
drivers/i2c/mvtwsi.c +11 -0
index 698bfc1..b5304d8 100644
@@ -128,6 +128,10 @@ static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
  	case 4:
  		return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE4;
  #endif
+#ifdef CONFIG_I2C_MVTWSI_BASE5
+	case 5:
+		return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE5;
+#endif
  	default:
  		printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
  		break;
@@ -486,3 +490,10 @@ U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
  			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
 
  #endif
+#ifdef CONFIG_I2C_MVTWSI_BASE5
+U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
+			 twsi_i2c_read, twsi_i2c_write,
+			 twsi_i2c_set_bus_speed,
+			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
+
+#endif
include/configs/sunxi-common.h +1 -1
index 790e704..b4dfb3c 100644
@@ -212,7 +212,7 @@
 
  #if defined CONFIG_I2C0_ENABLE || defined CONFIG_I2C1_ENABLE || \
      defined CONFIG_I2C2_ENABLE || defined CONFIG_I2C3_ENABLE || \
-    defined CONFIG_I2C4_ENABLE
+    defined CONFIG_I2C4_ENABLE || defined CONFIG_R_I2C_ENABLE
  #define CONFIG_SYS_I2C
  #define CONFIG_SYS_I2C_MVTWSI
  #define CONFIG_SYS_I2C_SPEED		400000
Signature · 2 lines
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
#3 lore raw

PATCH 1/2 i2c: mvtwsi: Fix mvtwsi not working on sun6i and newer sunxi SoCs

In reply to Hans de Goede

Hello Hans,

Am 14.01.2016 um 14:06 schrieb Hans de Goede:

Quoted 7 lines

On sun6i and newer IFLG is a write-clear bit which is cleared by writing 1, rather then a normal r/w bit which is cleared by writing 0.

---
  drivers/i2c/mvtwsi.c | 19 +++++++++++++++----
  1 file changed, 15 insertions(+), 4 deletions(-)

Thanks!

Applied to u-boot-i2c.git with fixing 3 checkpatch errors/warnings.

bye,
Heiko

Quoted 60 lines
drivers/i2c/mvtwsi.c +15 -4
index f20d1b2..698bfc1 100644
@@ -73,6 +73,17 @@ struct  mvtwsi_registers {
  #define	MVTWSI_CONTROL_INTEN	0x00000080
 
  /*
+ * On sun6i and newer IFLG is a write-clear bit which is cleared by writing 1,
+ * on other platforms it is a normal r/w bit which is cleared by writing 0.
+ */
+
+#ifdef CONFIG_SUNXI_GEN_SUN6I
+#define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000008
+#else
+#define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000000
+#endif
+
+/*
   * Status register values -- only those expected in normal master
   * operation on non-10-bit-address devices; whatever status we don't
   * expect in nominal conditions (bus errors, arbitration losses,
@@ -189,7 +200,7 @@ static int twsi_start(struct i2c_adapter *adap, int expected_status)
  	/* globally set TWSIEN in case it was not */
  	twsi_control_flags |= MVTWSI_CONTROL_TWSIEN;
  	/* assert START */
-	writel(twsi_control_flags | MVTWSI_CONTROL_START, &twsi->control);
+	writel(twsi_control_flags | MVTWSI_CONTROL_START | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
  	/* wait for controller to process START */
  	return twsi_wait(adap, expected_status);
  }
@@ -204,7 +215,7 @@ static int twsi_send(struct i2c_adapter *adap, u8 byte, int expected_status)
  	/* put byte in data register for sending */
  	writel(byte, &twsi->data);
  	/* clear any pending interrupt -- that'll cause sending */
-	writel(twsi_control_flags, &twsi->control);
+        writel(twsi_control_flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
  	/* wait for controller to receive byte and check ACK */
  	return twsi_wait(adap, expected_status);
  }
@@ -224,7 +235,7 @@ static int twsi_recv(struct i2c_adapter *adap, u8 *byte)
  	else
  		expected_status = MVTWSI_STATUS_DATA_R_NAK;
  	/* acknowledge *previous state* and launch receive */
-	writel(twsi_control_flags, &twsi->control);
+	writel(twsi_control_flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
  	/* wait for controller to receive byte and assert ACK or NAK */
  	status = twsi_wait(adap, expected_status);
  	/* if we did receive expected byte then store it */
@@ -246,7 +257,7 @@ static int twsi_stop(struct i2c_adapter *adap, int status)
 
  	/* assert STOP */
  	control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
-	writel(control, &twsi->control);
+	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
  	/* wait for IDLE; IFLG won't rise so twsi_wait() is no use. */
  	do {
  		stop_status = readl(&twsi->status);
Signature · 2 lines
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany