Skip to contentSkip to conversation

EXYNOS5: Enable I2C support

PATCH Superseded Rajeshwari Shinde 3 participants 15 messages Jul 19, 2012 – Jul 23, 2012

Subsystems (3)

v6 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

v6 cover EXYNOS5: Enable I2C support

This patch set enables I2C support for EXYNOS5.
This patchset modifies the s3c24x0 I2C driver to use same for EXYNOS5. Multichannel support has been added to the s3c24x0 I2C driver. s3c24x0_i2c struct has been moved to a common place as it can used by different SOC's.

Changes in V2:
- Incorporated review comments from Simon Glass.
- Aligned the pinmux functionality as per latest comments
Changes in V3:
- Incorporated review comments from Joonyoung Shim for I2C driver.
Changes in V4:
- Resolved build error for S3C2410.
Changes in V5:
- Pinmux setting moved to board file.
- Multi Bus I2C offset calculation done based on EXYNOS_I2C_SPACE.
- Peripheral id calculation removed from i2c driver.
Changes in V6:
- Incorporated review comments from Simon Glass.

Rajeshwari Shinde (8):
EXYNOS: CLK: Add i2c clock
EXYNOS: Add I2C base address.
EXYNOS5: Define EXYNOS5_I2C_SPACING
EXYNOS: PINMUX: Add pinmux support for I2C
I2C: Move struct s3c24x0_i2c to a common place.
I2C: Modify the I2C driver for EXYNOS5
I2C: Add support for Multi channel
CONFIG: SMDK5250: I2C: Enable I2C

 arch/arm/cpu/armv7/exynos/clock.c           |   33 ++++
 arch/arm/cpu/armv7/exynos/pinmux.c          |   52 +++++++
 arch/arm/include/asm/arch-exynos/clk.h      |    1 +
 arch/arm/include/asm/arch-exynos/cpu.h      |    5 +
 arch/arm/include/asm/arch-exynos/periph.h   |    8 +
 arch/arm/include/asm/arch-s3c24x0/s3c24x0.h |   10 --
 board/samsung/smdk5250/smdk5250.c           |   23 +++-
 drivers/i2c/s3c24x0_i2c.c                   |  220 ++++++++++++++++++---------
 drivers/i2c/s3c24x0_i2c.h                   |   33 ++++
 include/configs/smdk5250.h                  |    8 +
 10 files changed, 307 insertions(+), 86 deletions(-)
 create mode 100644 drivers/i2c/s3c24x0_i2c.h
Signature · 1 line
1.7.4.4
#1 lore raw

PATCH v6 1/8 EXYNOS: CLK: Add i2c clock

This adds i2c clock information for EXYNOS5.

---
changes in V2:
- Incorporated comments from Simon Glass which are removed extra braces around (readl(&clk->div_top1)) >> 24 and gave a tab space for return statement.
Changes in V3:
- None
Changes in V4:
- None
Changes in V5:
- None.
Changes in V6:
- Incorporated review comments from Simon Glass.

 arch/arm/cpu/armv7/exynos/clock.c      |   33 ++++++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-exynos/clk.h |    1 +
 2 files changed, 34 insertions(+), 0 deletions(-)
arch/arm/cpu/armv7/exynos/clock.c +33 -0
index 672598f..de3db8e 100644
@@ -605,6 +605,29 @@ void exynos4_set_mipi_clk(void)
 	writel(cfg, &clk->div_lcd0);
 }
 
+/*
+ * I2C
+ *
+ * exynos5: obtaining the I2C clock
+ */
+static unsigned long exynos5_get_i2c_clk(void)
+{
+	struct exynos5_clock *clk =
+		(struct exynos5_clock *)samsung_get_base_clock();
+	unsigned long aclk_66, aclk_66_pre, sclk;
+	unsigned int ratio;
+
+	sclk = get_pll_clk(MPLL);
+
+	ratio = (readl(&clk->div_top1)) >> 24;
+	ratio &= 0x7;
+	aclk_66_pre = sclk / (ratio + 1);
+	ratio = readl(&clk->div_top0);
+	ratio &= 0x7;
+	aclk_66 = aclk_66_pre / (ratio + 1);
+	return aclk_66;
+}
+
 unsigned long get_pll_clk(int pllreg)
 {
 	if (cpu_is_exynos5())
@@ -621,6 +644,16 @@ unsigned long get_arm_clk(void)
 		return exynos4_get_arm_clk();
 }
 
+unsigned long get_i2c_clk(void)
+{
+	if (cpu_is_exynos5()) {
+		return exynos5_get_i2c_clk();
+	} else {
+		debug("I2C clock is not set for this CPU\n");
+		return 0;
+	}
+}
+
 unsigned long get_pwm_clk(void)
 {
 	if (cpu_is_exynos5())
arch/arm/include/asm/arch-exynos/clk.h +1 -0
index e99339a..5529025 100644
@@ -31,6 +31,7 @@
 
 unsigned long get_pll_clk(int pllreg);
 unsigned long get_arm_clk(void);
+unsigned long get_i2c_clk(void);
 unsigned long get_pwm_clk(void);
 unsigned long get_uart_clk(int dev_index);
 void set_mmc_clk(int dev_index, unsigned int div);
Signature · 1 line
1.7.4.4
#2 lore raw

PATCH v6 1/8 EXYNOS: CLK: Add i2c clock

Quoted 6 lines · Rajeshwari Shinde

This adds i2c clock information for EXYNOS5.

Quoted 83 lines

---
changes in V2:
- Incorporated comments from Simon Glass which are removed extra braces around (readl(&clk->div_top1)) >> 24 and gave a tab space for return statement.
Changes in V3:
- None
Changes in V4:
- None
Changes in V5:
- None.
Changes in V6:
- Incorporated review comments from Simon Glass.

 arch/arm/cpu/armv7/exynos/clock.c      |   33 ++++++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-exynos/clk.h |    1 +
 2 files changed, 34 insertions(+), 0 deletions(-)
arch/arm/cpu/armv7/exynos/clock.c +33 -0
index 672598f..de3db8e 100644
@@ -605,6 +605,29 @@ void exynos4_set_mipi_clk(void)
        writel(cfg, &clk->div_lcd0);
 }
 
+/*
+ * I2C
+ *
+ * exynos5: obtaining the I2C clock
+ */
+static unsigned long exynos5_get_i2c_clk(void)
+{
+       struct exynos5_clock *clk =
+               (struct exynos5_clock *)samsung_get_base_clock();
+       unsigned long aclk_66, aclk_66_pre, sclk;
+       unsigned int ratio;
+
+       sclk = get_pll_clk(MPLL);
+
+       ratio = (readl(&clk->div_top1)) >> 24;
+       ratio &= 0x7;
+       aclk_66_pre = sclk / (ratio + 1);
+       ratio = readl(&clk->div_top0);
+       ratio &= 0x7;
+       aclk_66 = aclk_66_pre / (ratio + 1);
+       return aclk_66;
+}
+
 unsigned long get_pll_clk(int pllreg)
 {
        if (cpu_is_exynos5())
@@ -621,6 +644,16 @@ unsigned long get_arm_clk(void)
                return exynos4_get_arm_clk();
 }
 
+unsigned long get_i2c_clk(void)
+{
+       if (cpu_is_exynos5()) {
+               return exynos5_get_i2c_clk();
+       } else {
+               debug("I2C clock is not set for this CPU\n");
+               return 0;
+       }
+}
+
 unsigned long get_pwm_clk(void)
 {
        if (cpu_is_exynos5())
arch/arm/include/asm/arch-exynos/clk.h +1 -1
index e99339a..5529025 100644
@@ -31,6 +31,7 @@
 
 unsigned long get_pll_clk(int pllreg);
 unsigned long get_arm_clk(void);
+unsigned long get_i2c_clk(void);
 unsigned long get_pwm_clk(void);
 unsigned long get_uart_clk(int dev_index);
 void set_mmc_clk(int dev_index, unsigned int div);
--

1.7.4.4

#3 lore raw

PATCH v6 2/8 EXYNOS: Add I2C base address.

In reply to Rajeshwari Shinde

This patch adds the base address for I2C.

---
Changes in V2:
- None
Changes in V3:
- None
Changes in V4:
- None
Changes in V5:
- None
Changes in V6:
- None

 arch/arm/include/asm/arch-exynos/cpu.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
arch/arm/include/asm/arch-exynos/cpu.h +3 -0
index 0c341d4..ab46b70 100644
@@ -49,6 +49,7 @@
 #define EXYNOS4_USB_HOST_EHCI_BASE	0x12580000
 #define EXYNOS4_USBPHY_BASE		0x125B0000
 #define EXYNOS4_UART_BASE		0x13800000
+#define EXYNOS4_I2C_BASE		0x13860000
 #define EXYNOS4_ADC_BASE		0x13910000
 #define EXYNOS4_PWMTIMER_BASE		0x139D0000
 #define EXYNOS4_MODEM_BASE		0x13A00000
@@ -76,6 +77,7 @@
 #define EXYNOS5_MMC_BASE		0x12200000
 #define EXYNOS5_SROMC_BASE		0x12250000
 #define EXYNOS5_UART_BASE		0x12C00000
+#define EXYNOS5_I2C_BASE		0x12C60000
 #define EXYNOS5_PWMTIMER_BASE		0x12DD0000
 #define EXYNOS5_GPIO_PART2_BASE		0x13400000
 #define EXYNOS5_FIMD_BASE		0x14400000
@@ -148,6 +150,7 @@ SAMSUNG_BASE(adc, ADC_BASE)
 SAMSUNG_BASE(clock, CLOCK_BASE)
 SAMSUNG_BASE(sysreg, SYSREG_BASE)
 SAMSUNG_BASE(fimd, FIMD_BASE)
+SAMSUNG_BASE(i2c, I2C_BASE)
 SAMSUNG_BASE(mipi_dsim, MIPI_DSIM_BASE)
 SAMSUNG_BASE(gpio_part1, GPIO_PART1_BASE)
 SAMSUNG_BASE(gpio_part2, GPIO_PART2_BASE)
Signature · 1 line
1.7.4.4
#4 lore raw

PATCH v6 3/8 EXYNOS5: define EXYNOS5_I2C_SPACING

In reply to Rajeshwari Shinde

This patch defined EXYNOS5_I2C_SPACING used to calculate I2C channel base address.

---
Changes in V6:
- New patch.

 arch/arm/include/asm/arch-exynos/cpu.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
arch/arm/include/asm/arch-exynos/cpu.h +2 -0
index ab46b70..0e6ea87 100644
@@ -58,6 +58,8 @@
 #define EXYNOS4_GPIO_PART4_BASE		DEVICE_NOT_AVAILABLE
 
 /* EXYNOS5 */
+#define EXYNOS5_I2C_SPACING		0x10000
+
 #define EXYNOS5_GPIO_PART4_BASE		0x03860000
 #define EXYNOS5_PRO_ID			0x10000000
 #define EXYNOS5_CLOCK_BASE		0x10010000
Signature · 1 line
1.7.4.4
#5 lore raw

PATCH v6 3/8 EXYNOS5: define EXYNOS5_I2C_SPACING

Quoted 4 lines · Rajeshwari Shinde

This patch defined EXYNOS5_I2C_SPACING used to calculate I2C channel base address.

Quoted 22 lines

---
Changes in V6:
- New patch.

 arch/arm/include/asm/arch-exynos/cpu.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
arch/arm/include/asm/arch-exynos/cpu.h +2 -1
index ab46b70..0e6ea87 100644
@@ -58,6 +58,8 @@
 #define EXYNOS4_GPIO_PART4_BASE                DEVICE_NOT_AVAILABLE
 
 /* EXYNOS5 */
+#define EXYNOS5_I2C_SPACING            0x10000
+
 #define EXYNOS5_GPIO_PART4_BASE                0x03860000
 #define EXYNOS5_PRO_ID                 0x10000000
 #define EXYNOS5_CLOCK_BASE             0x10010000
--

1.7.4.4

#6 lore raw

PATCH v6 4/8 EXYNOS: PINMUX: Add pinmux support for I2C

In reply to Rajeshwari Shinde

This patch adds pinmux code for I2C.

---
Changes in V2:
- Aligned the pinmux functionality as per the latest comments.
Changes in V3:
- None
Changes in V4:
- None
Changes in V5:
- None
Changes in V6:
- None

 arch/arm/cpu/armv7/exynos/pinmux.c        |   52 +++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-exynos/periph.h |    8 ++++
 2 files changed, 60 insertions(+), 0 deletions(-)
arch/arm/cpu/armv7/exynos/pinmux.c +52 -0
index 0e91a6c..7776add 100644
@@ -188,6 +188,48 @@ static void exynos5_sromc_config(int flags)
 	}
 }
 
+static void exynos5_i2c_config(int peripheral, int flags)
+{
+
+	struct exynos5_gpio_part1 *gpio1 =
+		(struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1();
+
+	switch (peripheral) {
+	case PERIPH_ID_I2C0:
+		s5p_gpio_cfg_pin(&gpio1->b3, 0, GPIO_FUNC(0x2));
+		s5p_gpio_cfg_pin(&gpio1->b3, 1, GPIO_FUNC(0x2));
+		break;
+	case PERIPH_ID_I2C1:
+		s5p_gpio_cfg_pin(&gpio1->b3, 2, GPIO_FUNC(0x2));
+		s5p_gpio_cfg_pin(&gpio1->b3, 3, GPIO_FUNC(0x2));
+		break;
+	case PERIPH_ID_I2C2:
+		s5p_gpio_cfg_pin(&gpio1->a0, 6, GPIO_FUNC(0x3));
+		s5p_gpio_cfg_pin(&gpio1->a0, 7, GPIO_FUNC(0x3));
+		break;
+	case PERIPH_ID_I2C3:
+		s5p_gpio_cfg_pin(&gpio1->a1, 2, GPIO_FUNC(0x3));
+		s5p_gpio_cfg_pin(&gpio1->a1, 3, GPIO_FUNC(0x3));
+		break;
+	case PERIPH_ID_I2C4:
+		s5p_gpio_cfg_pin(&gpio1->a2, 0, GPIO_FUNC(0x3));
+		s5p_gpio_cfg_pin(&gpio1->a2, 1, GPIO_FUNC(0x3));
+		break;
+	case PERIPH_ID_I2C5:
+		s5p_gpio_cfg_pin(&gpio1->a2, 2, GPIO_FUNC(0x3));
+		s5p_gpio_cfg_pin(&gpio1->a2, 3, GPIO_FUNC(0x3));
+		break;
+	case PERIPH_ID_I2C6:
+		s5p_gpio_cfg_pin(&gpio1->b1, 3, GPIO_FUNC(0x4));
+		s5p_gpio_cfg_pin(&gpio1->b1, 4, GPIO_FUNC(0x4));
+		break;
+	case PERIPH_ID_I2C7:
+		s5p_gpio_cfg_pin(&gpio1->b2, 2, GPIO_FUNC(0x3));
+		s5p_gpio_cfg_pin(&gpio1->b2, 3, GPIO_FUNC(0x3));
+		break;
+	}
+}
+
 static int exynos5_pinmux_config(int peripheral, int flags)
 {
 	switch (peripheral) {
@@ -205,6 +247,16 @@ static int exynos5_pinmux_config(int peripheral, int flags)
 	case PERIPH_ID_SROMC:
 		exynos5_sromc_config(flags);
 		break;
+	case PERIPH_ID_I2C0:
+	case PERIPH_ID_I2C1:
+	case PERIPH_ID_I2C2:
+	case PERIPH_ID_I2C3:
+	case PERIPH_ID_I2C4:
+	case PERIPH_ID_I2C5:
+	case PERIPH_ID_I2C6:
+	case PERIPH_ID_I2C7:
+		exynos5_i2c_config(peripheral, flags);
+		break;
 	default:
 		debug("%s: invalid peripheral %d", __func__, peripheral);
 		return -1;
arch/arm/include/asm/arch-exynos/periph.h +8 -0
index 5db25aa..b861d7d 100644
@@ -30,6 +30,14 @@
  *
  */
 enum periph_id {
+	PERIPH_ID_I2C0,
+	PERIPH_ID_I2C1,
+	PERIPH_ID_I2C2,
+	PERIPH_ID_I2C3,
+	PERIPH_ID_I2C4,
+	PERIPH_ID_I2C5,
+	PERIPH_ID_I2C6,
+	PERIPH_ID_I2C7,
 	PERIPH_ID_SDMMC0,
 	PERIPH_ID_SDMMC1,
 	PERIPH_ID_SDMMC2,
Signature · 1 line
1.7.4.4
#7 lore raw

PATCH v6 5/8 I2C: Move struct s3c24x0_i2c to a common place.

In reply to Rajeshwari Shinde

struct s3c24x0_i2c is being moved to common local header file so that the same can be used by s3c series and exynos series SoCs.

---
Changes in V2:
- None
Changes in V3:
- None
Changes in V4:
- None
Changes in V5:
- None
Changes in V6:
- None

 arch/arm/include/asm/arch-s3c24x0/s3c24x0.h |   10 --------
 drivers/i2c/s3c24x0_i2c.h                   |   33 +++++++++++++++++++++++++++
 2 files changed, 33 insertions(+), 10 deletions(-)
 create mode 100644 drivers/i2c/s3c24x0_i2c.h
arch/arm/include/asm/arch-s3c24x0/s3c24x0.h +0 -10
index ca978c9..0f75c31 100644
@@ -343,16 +343,6 @@ struct s3c24x0_watchdog {
 	u32	wtcnt;
 };
 
-
-/* IIC (see manual chapter 20) */
-struct s3c24x0_i2c {
-	u32	iiccon;
-	u32	iicstat;
-	u32	iicadd;
-	u32	iicds;
-};
-
-
 /* IIS (see manual chapter 21) */
 struct s3c24x0_i2s {
 #ifdef __BIG_ENDIAN
drivers/i2c/s3c24x0_i2c.h new file +33 -0
new file mode 100644
index 0000000..2dd4b06
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _S3C24X0_I2C_H
+#define _S3C24X0_I2C_H
+
+struct s3c24x0_i2c {
+	u32	iiccon;
+	u32	iicstat;
+	u32	iicadd;
+	u32	iicds;
+	u32	iiclc;
+};
+#endif /* _S3C24X0_I2C_H */
Signature · 1 line
1.7.4.4
#8 lore raw

PATCH v6 6/8 I2C: Modify the I2C driver for EXYNOS5

In reply to Rajeshwari Shinde

This patch modifies the S3C I2C driver to suppport EXYNOS5.
The cahnges made to driver are as follows:
- I2C base address is passed as a parameter to many functions to avoid multiple #ifdef
- Channel initialisation is moved to a commom funation
as it is required by i2c_init.
- Hardcoding for I2CCON_ACKGEN removed.
- Replaced printf with debug.
- Checkpatch issues resolved.
- Pinmux setting will be done in board/samsung/smdk5250/smdk5250.c to avoid repeated setting of gpio lines, as it have multi bus support.

---
Changes in V2:
- Removed #define for I2C cahnnels from hearder file except for I2C0.
- Incorporated review comments from Simon Glass.
Changes in V3:
- Incorporated review comments from Joonyoung Shim.
- Reduced the number of #ifdef by modifying get_i2c_base function.
- Removed duplicate code.
Changes in V4:
- Resolved build error for s3c2410.
Changes in V5:
- Pinmux setting will be done in board/samsung/smdk5250/smdk5250.c to avoid repeated setting of gpio lines, as it have multi bus support.
- I2C bus offset calulation done based on EXYNOS_I2C_SPACING
- Peripharal related code removed.
Changes in V6:
- g_current_bus made common to all platforms.

 drivers/i2c/s3c24x0_i2c.c |  193 +++++++++++++++++++++++++++-----------------
 1 files changed, 118 insertions(+), 75 deletions(-)
drivers/i2c/s3c24x0_i2c.c +118 -75
index ba6f39b..421c7dd 100644
@@ -27,10 +27,15 @@
  */
 
 #include <common.h>
+#ifdef CONFIG_EXYNOS5
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#else
 #include <asm/arch/s3c24x0_cpu.h>
-
+#endif
 #include <asm/io.h>
 #include <i2c.h>
+#include "s3c24x0_i2c.h"
 
 #ifdef CONFIG_HARD_I2C
 
@@ -45,6 +50,7 @@
 
 #define I2CSTAT_BSY	0x20	/* Busy bit */
 #define I2CSTAT_NACK	0x01	/* Nack bit */
+#define I2CCON_ACKGEN	0x80	/* Acknowledge generation */
 #define I2CCON_IRPND	0x10	/* Interrupt pending bit */
 #define I2C_MODE_MT	0xC0	/* Master Transmit Mode */
 #define I2C_MODE_MR	0x80	/* Master Receive Mode */
@@ -53,6 +59,10 @@
 
 #define I2C_TIMEOUT 1		/* 1 second */
 
+
+static unsigned int g_current_bus;	/* Stores Current I2C Bus */
+
+#ifndef CONFIG_EXYNOS5
 static int GetI2CSDA(void)
 {
 	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
@@ -77,16 +87,17 @@ static void SetI2CSCL(int x)
 	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
 
 #ifdef CONFIG_S3C2410
-	writel((readl(&gpio->gpedat) & ~0x4000) | (x & 1) << 14, &gpio->gpedat);
+	writel((readl(&gpio->gpedat) & ~0x4000) |
+					(x & 1) << 14, &gpio->gpedat);
 #endif
 #ifdef CONFIG_S3C2400
 	writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat);
 #endif
 }
+#endif
 
-static int WaitForXfer(void)
+static int WaitForXfer(struct s3c24x0_i2c *i2c)
 {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
 	int i;
 
 	i = I2C_TIMEOUT * 10000;
@@ -98,35 +109,77 @@ static int WaitForXfer(void)
 	return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
 }
 
-static int IsACK(void)
+static int IsACK(struct s3c24x0_i2c *i2c)
 {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-
 	return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
 }
 
-static void ReadWriteByte(void)
+static void ReadWriteByte(struct s3c24x0_i2c *i2c)
 {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-
 	writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
 }
 
+static struct s3c24x0_i2c *get_base_i2c(void)
+{
+#ifdef CONFIG_EXYNOS5
+	struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c()
+							+ (EXYNOS5_I2C_SPACING
+							* g_current_bus));
+	return i2c;
+#else
+	return s3c24x0_get_base_i2c();
+#endif
+}
+
+static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
+{
+	ulong freq, pres = 16, div;
+#ifdef CONFIG_EXYNOS5
+	freq = get_i2c_clk();
+#else
+	freq = get_PCLK();
+#endif
+	/* calculate prescaler and divisor values */
+	if ((freq / pres / (16 + 1)) > speed)
+		/* set prescaler to 512 */
+		pres = 512;
+
+	div = 0;
+	while ((freq / pres / (div + 1)) > speed)
+		div++;
+
+	/* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
+	writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
+
+	/* init to SLAVE REVEIVE and set slaveaddr */
+	writel(0, &i2c->iicstat);
+	writel(slaveadd, &i2c->iicadd);
+	/* program Master Transmit (and implicit STOP) */
+	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
+}
+
 void i2c_init(int speed, int slaveadd)
 {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
+	struct s3c24x0_i2c *i2c = get_base_i2c();
+#ifndef CONFIG_EXYNOS5
 	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
-	ulong freq, pres = 16, div;
+#endif
 	int i;
 
-	/* wait for some time to give previous transfer a chance to finish */
+	/* By default i2c channel 0 is the current bus */
+	g_current_bus = 0;
 
+#ifdef CONFIG_EXYNOS5
+	i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+	/* wait for some time to give previous transfer a chance to finish */
 	i = I2C_TIMEOUT * 1000;
 	while ((readl(&i2c->iicstat) && I2CSTAT_BSY) && (i > 0)) {
 		udelay(1000);
 		i--;
 	}
 
+#ifndef CONFIG_EXYNOS5
 	if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) {
 #ifdef CONFIG_S3C2410
 		ulong old_gpecon = readl(&gpio->gpecon);
@@ -171,26 +224,8 @@ void i2c_init(int speed, int slaveadd)
 #endif
 	}
 
-	/* calculate prescaler and divisor values */
-	freq = get_PCLK();
-	if ((freq / pres / (16 + 1)) > speed)
-		/* set prescaler to 512 */
-		pres = 512;
-
-	div = 0;
-	while ((freq / pres / (div + 1)) > speed)
-		div++;
-
-	/* set prescaler, divisor according to freq, also set
-	 * ACKGEN, IRQ */
-	writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
-
-	/* init to SLAVE REVEIVE and set slaveaddr */
-	writel(0, &i2c->iicstat);
-	writel(slaveadd, &i2c->iicadd);
-	/* program Master Transmit (and implicit STOP) */
-	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
-
+	i2c_ch_init(i2c, speed, slaveadd);
+#endif /* #ifndef CONFIG_EXYNOS5 */
 }
 
 /*
@@ -200,19 +235,19 @@ void i2c_init(int speed, int slaveadd)
  * by the char, we could make it larger if needed. If it is
  * 0 we skip the address write cycle.
  */
-static
-int i2c_transfer(unsigned char cmd_type,
-		 unsigned char chip,
-		 unsigned char addr[],
-		 unsigned char addr_len,
-		 unsigned char data[], unsigned short data_len)
+static int i2c_transfer(struct s3c24x0_i2c *i2c,
+			unsigned char cmd_type,
+			unsigned char chip,
+			unsigned char addr[],
+			unsigned char addr_len,
+			unsigned char data[],
+			unsigned short data_len)
 {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
 	int i, result;
 
 	if (data == 0 || data_len == 0) {
 		/*Don't support data transfer of no length or to address 0 */
-		printf("i2c_transfer: bad call\n");
+		debug("i2c_transfer: bad call\n");
 		return I2C_NOK;
 	}
 
@@ -226,7 +261,7 @@ int i2c_transfer(unsigned char cmd_type,
 	if (readl(&i2c->iicstat) & I2CSTAT_BSY)
 		return I2C_NOK_TOUT;
 
-	writel(readl(&i2c->iiccon) | 0x80, &i2c->iiccon);
+	writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
 	result = I2C_OK;
 
 	switch (cmd_type) {
@@ -238,16 +273,16 @@ int i2c_transfer(unsigned char cmd_type,
 			       &i2c->iicstat);
 			i = 0;
 			while ((i < addr_len) && (result == I2C_OK)) {
-				result = WaitForXfer();
+				result = WaitForXfer(i2c);
 				writel(addr[i], &i2c->iicds);
-				ReadWriteByte();
+				ReadWriteByte(i2c);
 				i++;
 			}
 			i = 0;
 			while ((i < data_len) && (result == I2C_OK)) {
-				result = WaitForXfer();
+				result = WaitForXfer(i2c);
 				writel(data[i], &i2c->iicds);
-				ReadWriteByte();
+				ReadWriteByte(i2c);
 				i++;
 			}
 		} else {
@@ -257,19 +292,19 @@ int i2c_transfer(unsigned char cmd_type,
 			       &i2c->iicstat);
 			i = 0;
 			while ((i < data_len) && (result = I2C_OK)) {
-				result = WaitForXfer();
+				result = WaitForXfer(i2c);
 				writel(data[i], &i2c->iicds);
-				ReadWriteByte();
+				ReadWriteByte(i2c);
 				i++;
 			}
 		}
 
 		if (result == I2C_OK)
-			result = WaitForXfer();
+			result = WaitForXfer(i2c);
 
 		/* send STOP */
 		writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
-		ReadWriteByte();
+		ReadWriteByte(i2c);
 		break;
 
 	case I2C_READ:
@@ -279,13 +314,13 @@ int i2c_transfer(unsigned char cmd_type,
 			/* send START */
 			writel(readl(&i2c->iicstat) | I2C_START_STOP,
 			       &i2c->iicstat);
-			result = WaitForXfer();
-			if (IsACK()) {
+			result = WaitForXfer(i2c);
+			if (IsACK(i2c)) {
 				i = 0;
 				while ((i < addr_len) && (result == I2C_OK)) {
 					writel(addr[i], &i2c->iicds);
-					ReadWriteByte();
-					result = WaitForXfer();
+					ReadWriteByte(i2c);
+					result = WaitForXfer(i2c);
 					i++;
 				}
 
@@ -293,16 +328,17 @@ int i2c_transfer(unsigned char cmd_type,
 				/* resend START */
 				writel(I2C_MODE_MR | I2C_TXRX_ENA |
 				       I2C_START_STOP, &i2c->iicstat);
-				ReadWriteByte();
-				result = WaitForXfer();
+			ReadWriteByte(i2c);
+			result = WaitForXfer(i2c);
 				i = 0;
 				while ((i < data_len) && (result == I2C_OK)) {
 					/* disable ACK for final READ */
 					if (i == data_len - 1)
 						writel(readl(&i2c->iiccon)
-						       & ~0x80, &i2c->iiccon);
-					ReadWriteByte();
-					result = WaitForXfer();
+							& ~I2CCON_ACKGEN,
+							&i2c->iiccon);
+				ReadWriteByte(i2c);
+				result = WaitForXfer(i2c);
 					data[i] = readl(&i2c->iicds);
 					i++;
 				}
@@ -316,17 +352,18 @@ int i2c_transfer(unsigned char cmd_type,
 			/* send START */
 			writel(readl(&i2c->iicstat) | I2C_START_STOP,
 			       &i2c->iicstat);
-			result = WaitForXfer();
+			result = WaitForXfer(i2c);
 
-			if (IsACK()) {
+			if (IsACK(i2c)) {
 				i = 0;
 				while ((i < data_len) && (result == I2C_OK)) {
 					/* disable ACK for final READ */
 					if (i == data_len - 1)
 						writel(readl(&i2c->iiccon) &
-						       ~0x80, &i2c->iiccon);
-					ReadWriteByte();
-					result = WaitForXfer();
+							~I2CCON_ACKGEN,
+							&i2c->iiccon);
+					ReadWriteByte(i2c);
+					result = WaitForXfer(i2c);
 					data[i] = readl(&i2c->iicds);
 					i++;
 				}
@@ -337,22 +374,24 @@ int i2c_transfer(unsigned char cmd_type,
 
 		/* send STOP */
 		writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
-		ReadWriteByte();
+		ReadWriteByte(i2c);
 		break;
 
 	default:
-		printf("i2c_transfer: bad call\n");
+		debug("i2c_transfer: bad call\n");
 		result = I2C_NOK;
 		break;
 	}
 
-	return (result);
+	return result;
 }
 
 int i2c_probe(uchar chip)
 {
+	struct s3c24x0_i2c *i2c;
 	uchar buf[1];
 
+	i2c = get_base_i2c();
 	buf[0] = 0;
 
 	/*
@@ -360,16 +399,17 @@ int i2c_probe(uchar chip)
 	 * address was <ACK>ed (i.e. there was a chip at that address which
 	 * drove the data line low).
 	 */
-	return i2c_transfer(I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
+	return i2c_transfer(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
 }
 
 int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 {
+	struct s3c24x0_i2c *i2c;
 	uchar xaddr[4];
 	int ret;
 
 	if (alen > 4) {
-		printf("I2C read: addr len %d not supported\n", alen);
+		debug("I2C read: addr len %d not supported\n", alen);
 		return 1;
 	}
 
@@ -396,10 +436,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 		chip |= ((addr >> (alen * 8)) &
 			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
 #endif
-	if ((ret =
-	     i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen,
-			  buffer, len)) != 0) {
-		printf("I2c read: failed %d\n", ret);
+	i2c = get_base_i2c();
+	ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen,
+			buffer, len);
+	if (ret != 0) {
+		debug("I2c read: failed %d\n", ret);
 		return 1;
 	}
 	return 0;
@@ -407,10 +448,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 
 int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
 {
+	struct s3c24x0_i2c *i2c;
 	uchar xaddr[4];
 
 	if (alen > 4) {
-		printf("I2C write: addr len %d not supported\n", alen);
+		debug("I2C write: addr len %d not supported\n", alen);
 		return 1;
 	}
 
@@ -436,8 +478,9 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
 		chip |= ((addr >> (alen * 8)) &
 			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
 #endif
+	i2c = get_base_i2c();
 	return (i2c_transfer
-		(I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
+		(i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
 		 len) != 0);
 }
 #endif /* CONFIG_HARD_I2C */
Signature · 1 line
1.7.4.4
#9 lore raw

PATCH v6 6/8 I2C: Modify the I2C driver for EXYNOS5

Quoted 12 lines · Rajeshwari Shinde

This patch modifies the S3C I2C driver to suppport EXYNOS5.
The cahnges made to driver are as follows:
- I2C base address is passed as a parameter to many functions to avoid multiple #ifdef
- Channel initialisation is moved to a commom funation
as it is required by i2c_init.
- Hardcoding for I2CCON_ACKGEN removed.
- Replaced printf with debug.
- Checkpatch issues resolved.
- Pinmux setting will be done in board/samsung/smdk5250/smdk5250.c to avoid repeated setting of gpio lines, as it have multi bus support.

Quoted 4 lines

I think this is reasonable thank you.

Quoted 435 lines

---
Changes in V2:
- Removed #define for I2C cahnnels from hearder file except for I2C0.
- Incorporated review comments from Simon Glass.
Changes in V3:
- Incorporated review comments from Joonyoung Shim.
- Reduced the number of #ifdef by modifying get_i2c_base function.
- Removed duplicate code.
Changes in V4:
- Resolved build error for s3c2410.
Changes in V5:
- Pinmux setting will be done in board/samsung/smdk5250/smdk5250.c to avoid repeated setting of gpio lines, as it have multi bus support.
- I2C bus offset calulation done based on EXYNOS_I2C_SPACING
- Peripharal related code removed.
Changes in V6:
- g_current_bus made common to all platforms.

 drivers/i2c/s3c24x0_i2c.c |  193 +++++++++++++++++++++++++++-----------------
 1 files changed, 118 insertions(+), 75 deletions(-)
drivers/i2c/s3c24x0_i2c.c +118 -76
index ba6f39b..421c7dd 100644
@@ -27,10 +27,15 @@
  */
 
 #include <common.h>
+#ifdef CONFIG_EXYNOS5
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#else
 #include <asm/arch/s3c24x0_cpu.h>
-
+#endif
 #include <asm/io.h>
 #include <i2c.h>
+#include "s3c24x0_i2c.h"
 
 #ifdef CONFIG_HARD_I2C
 
@@ -45,6 +50,7 @@
 
 #define I2CSTAT_BSY    0x20    /* Busy bit */
 #define I2CSTAT_NACK   0x01    /* Nack bit */
+#define I2CCON_ACKGEN  0x80    /* Acknowledge generation */
 #define I2CCON_IRPND   0x10    /* Interrupt pending bit */
 #define I2C_MODE_MT    0xC0    /* Master Transmit Mode */
 #define I2C_MODE_MR    0x80    /* Master Receive Mode */
@@ -53,6 +59,10 @@
 
 #define I2C_TIMEOUT 1          /* 1 second */
 
+
+static unsigned int g_current_bus;     /* Stores Current I2C Bus */
+
+#ifndef CONFIG_EXYNOS5
 static int GetI2CSDA(void)
 {
        struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
@@ -77,16 +87,17 @@ static void SetI2CSCL(int x)
        struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
 
 #ifdef CONFIG_S3C2410
-       writel((readl(&gpio->gpedat) & ~0x4000) | (x & 1) << 14, &gpio->gpedat);
+       writel((readl(&gpio->gpedat) & ~0x4000) |
+                                       (x & 1) << 14, &gpio->gpedat);
 #endif
 #ifdef CONFIG_S3C2400
        writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat);
 #endif
 }
+#endif
 
-static int WaitForXfer(void)
+static int WaitForXfer(struct s3c24x0_i2c *i2c)
 {
-       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
        int i;
 
        i = I2C_TIMEOUT * 10000;
@@ -98,35 +109,77 @@ static int WaitForXfer(void)
        return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
 }
 
-static int IsACK(void)
+static int IsACK(struct s3c24x0_i2c *i2c)
 {
-       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-
        return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
 }
 
-static void ReadWriteByte(void)
+static void ReadWriteByte(struct s3c24x0_i2c *i2c)
 {
-       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-
        writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
 }
 
+static struct s3c24x0_i2c *get_base_i2c(void)
+{
+#ifdef CONFIG_EXYNOS5
+       struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c()
+                                                       + (EXYNOS5_I2C_SPACING
+                                                       * g_current_bus));
+       return i2c;
+#else
+       return s3c24x0_get_base_i2c();
+#endif
+}
+
+static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
+{
+       ulong freq, pres = 16, div;
+#ifdef CONFIG_EXYNOS5
+       freq = get_i2c_clk();
+#else
+       freq = get_PCLK();
+#endif
+       /* calculate prescaler and divisor values */
+       if ((freq / pres / (16 + 1)) > speed)
+               /* set prescaler to 512 */
+               pres = 512;
+
+       div = 0;
+       while ((freq / pres / (div + 1)) > speed)
+               div++;
+
+       /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
+       writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
+
+       /* init to SLAVE REVEIVE and set slaveaddr */
+       writel(0, &i2c->iicstat);
+       writel(slaveadd, &i2c->iicadd);
+       /* program Master Transmit (and implicit STOP) */
+       writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
+}
+
 void i2c_init(int speed, int slaveadd)
 {
-       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
+       struct s3c24x0_i2c *i2c = get_base_i2c();
+#ifndef CONFIG_EXYNOS5
        struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
-       ulong freq, pres = 16, div;
+#endif
        int i;
 
-       /* wait for some time to give previous transfer a chance to finish */
+       /* By default i2c channel 0 is the current bus */
+       g_current_bus = 0;
 
+#ifdef CONFIG_EXYNOS5
+       i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+       /* wait for some time to give previous transfer a chance to finish */
        i = I2C_TIMEOUT * 1000;
        while ((readl(&i2c->iicstat) && I2CSTAT_BSY) && (i > 0)) {
                udelay(1000);
                i--;
        }
 
+#ifndef CONFIG_EXYNOS5
        if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) {
 #ifdef CONFIG_S3C2410
                ulong old_gpecon = readl(&gpio->gpecon);
@@ -171,26 +224,8 @@ void i2c_init(int speed, int slaveadd)
 #endif
        }
 
-       /* calculate prescaler and divisor values */
-       freq = get_PCLK();
-       if ((freq / pres / (16 + 1)) > speed)
-               /* set prescaler to 512 */
-               pres = 512;
-
-       div = 0;
-       while ((freq / pres / (div + 1)) > speed)
-               div++;
-
-       /* set prescaler, divisor according to freq, also set
-        * ACKGEN, IRQ */
-       writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
-
-       /* init to SLAVE REVEIVE and set slaveaddr */
-       writel(0, &i2c->iicstat);
-       writel(slaveadd, &i2c->iicadd);
-       /* program Master Transmit (and implicit STOP) */
-       writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
-
+       i2c_ch_init(i2c, speed, slaveadd);
+#endif /* #ifndef CONFIG_EXYNOS5 */
 }
 
 /*
@@ -200,19 +235,19 @@ void i2c_init(int speed, int slaveadd)
  * by the char, we could make it larger if needed. If it is
  * 0 we skip the address write cycle.
  */
-static
-int i2c_transfer(unsigned char cmd_type,
-                unsigned char chip,
-                unsigned char addr[],
-                unsigned char addr_len,
-                unsigned char data[], unsigned short data_len)
+static int i2c_transfer(struct s3c24x0_i2c *i2c,
+                       unsigned char cmd_type,
+                       unsigned char chip,
+                       unsigned char addr[],
+                       unsigned char addr_len,
+                       unsigned char data[],
+                       unsigned short data_len)
 {
-       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
        int i, result;
 
        if (data == 0 || data_len == 0) {
                /*Don't support data transfer of no length or to address 0 */
-               printf("i2c_transfer: bad call\n");
+               debug("i2c_transfer: bad call\n");
                return I2C_NOK;
        }
 
@@ -226,7 +261,7 @@ int i2c_transfer(unsigned char cmd_type,
        if (readl(&i2c->iicstat) & I2CSTAT_BSY)
                return I2C_NOK_TOUT;
 
-       writel(readl(&i2c->iiccon) | 0x80, &i2c->iiccon);
+       writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
        result = I2C_OK;
 
        switch (cmd_type) {
@@ -238,16 +273,16 @@ int i2c_transfer(unsigned char cmd_type,
                               &i2c->iicstat);
                        i = 0;
                        while ((i < addr_len) && (result == I2C_OK)) {
-                               result = WaitForXfer();
+                               result = WaitForXfer(i2c);
                                writel(addr[i], &i2c->iicds);
-                               ReadWriteByte();
+                               ReadWriteByte(i2c);
                                i++;
                        }
                        i = 0;
                        while ((i < data_len) && (result == I2C_OK)) {
-                               result = WaitForXfer();
+                               result = WaitForXfer(i2c);
                                writel(data[i], &i2c->iicds);
-                               ReadWriteByte();
+                               ReadWriteByte(i2c);
                                i++;
                        }
                } else {
@@ -257,19 +292,19 @@ int i2c_transfer(unsigned char cmd_type,
                               &i2c->iicstat);
                        i = 0;
                        while ((i < data_len) && (result = I2C_OK)) {
-                               result = WaitForXfer();
+                               result = WaitForXfer(i2c);
                                writel(data[i], &i2c->iicds);
-                               ReadWriteByte();
+                               ReadWriteByte(i2c);
                                i++;
                        }
                }
 
                if (result == I2C_OK)
-                       result = WaitForXfer();
+                       result = WaitForXfer(i2c);
 
                /* send STOP */
                writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
-               ReadWriteByte();
+               ReadWriteByte(i2c);
                break;
 
        case I2C_READ:
@@ -279,13 +314,13 @@ int i2c_transfer(unsigned char cmd_type,
                        /* send START */
                        writel(readl(&i2c->iicstat) | I2C_START_STOP,
                               &i2c->iicstat);
-                       result = WaitForXfer();
-                       if (IsACK()) {
+                       result = WaitForXfer(i2c);
+                       if (IsACK(i2c)) {
                                i = 0;
                                while ((i < addr_len) && (result == I2C_OK)) {
                                        writel(addr[i], &i2c->iicds);
-                                       ReadWriteByte();
-                                       result = WaitForXfer();
+                                       ReadWriteByte(i2c);
+                                       result = WaitForXfer(i2c);
                                        i++;
                                }
 
@@ -293,16 +328,17 @@ int i2c_transfer(unsigned char cmd_type,
                                /* resend START */
                                writel(I2C_MODE_MR | I2C_TXRX_ENA |
                                       I2C_START_STOP, &i2c->iicstat);
-                               ReadWriteByte();
-                               result = WaitForXfer();
+                       ReadWriteByte(i2c);
+                       result = WaitForXfer(i2c);
                                i = 0;
                                while ((i < data_len) && (result == I2C_OK)) {
                                        /* disable ACK for final READ */
                                        if (i == data_len - 1)
                                                writel(readl(&i2c->iiccon)
-                                                      & ~0x80, &i2c->iiccon);
-                                       ReadWriteByte();
-                                       result = WaitForXfer();
+                                                       & ~I2CCON_ACKGEN,
+                                                       &i2c->iiccon);
+                               ReadWriteByte(i2c);
+                               result = WaitForXfer(i2c);
                                        data[i] = readl(&i2c->iicds);
                                        i++;
                                }
@@ -316,17 +352,18 @@ int i2c_transfer(unsigned char cmd_type,
                        /* send START */
                        writel(readl(&i2c->iicstat) | I2C_START_STOP,
                               &i2c->iicstat);
-                       result = WaitForXfer();
+                       result = WaitForXfer(i2c);
 
-                       if (IsACK()) {
+                       if (IsACK(i2c)) {
                                i = 0;
                                while ((i < data_len) && (result == I2C_OK)) {
                                        /* disable ACK for final READ */
                                        if (i == data_len - 1)
                                                writel(readl(&i2c->iiccon) &
-                                                      ~0x80, &i2c->iiccon);
-                                       ReadWriteByte();
-                                       result = WaitForXfer();
+                                                       ~I2CCON_ACKGEN,
+                                                       &i2c->iiccon);
+                                       ReadWriteByte(i2c);
+                                       result = WaitForXfer(i2c);
                                        data[i] = readl(&i2c->iicds);
                                        i++;
                                }
@@ -337,22 +374,24 @@ int i2c_transfer(unsigned char cmd_type,
 
                /* send STOP */
                writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
-               ReadWriteByte();
+               ReadWriteByte(i2c);
                break;
 
        default:
-               printf("i2c_transfer: bad call\n");
+               debug("i2c_transfer: bad call\n");
                result = I2C_NOK;
                break;
        }
 
-       return (result);
+       return result;
 }
 
 int i2c_probe(uchar chip)
 {
+       struct s3c24x0_i2c *i2c;
        uchar buf[1];
 
+       i2c = get_base_i2c();
        buf[0] = 0;
 
        /*
@@ -360,16 +399,17 @@ int i2c_probe(uchar chip)
         * address was <ACK>ed (i.e. there was a chip at that address which
         * drove the data line low).
         */
-       return i2c_transfer(I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
+       return i2c_transfer(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
 }
 
 int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 {
+       struct s3c24x0_i2c *i2c;
        uchar xaddr[4];
        int ret;
 
        if (alen > 4) {
-               printf("I2C read: addr len %d not supported\n", alen);
+               debug("I2C read: addr len %d not supported\n", alen);
                return 1;
        }
 
@@ -396,10 +436,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
                chip |= ((addr >> (alen * 8)) &
                         CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
 #endif
-       if ((ret =
-            i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen,
-                         buffer, len)) != 0) {
-               printf("I2c read: failed %d\n", ret);
+       i2c = get_base_i2c();
+       ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen,
+                       buffer, len);
+       if (ret != 0) {
+               debug("I2c read: failed %d\n", ret);
                return 1;
        }
        return 0;
@@ -407,10 +448,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 
 int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
 {
+       struct s3c24x0_i2c *i2c;
        uchar xaddr[4];
 
        if (alen > 4) {
-               printf("I2C write: addr len %d not supported\n", alen);
+               debug("I2C write: addr len %d not supported\n", alen);
                return 1;
        }
 
@@ -436,8 +478,9 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
                chip |= ((addr >> (alen * 8)) &
                         CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
 #endif
+       i2c = get_base_i2c();
        return (i2c_transfer
-               (I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
+               (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
                 len) != 0);
 }
 #endif /* CONFIG_HARD_I2C */
--

1.7.4.4

#10 lore raw

PATCH v6 6/8 I2C: Modify the I2C driver for EXYNOS5

In reply to Rajeshwari Shinde

Hi, Rajeshwari.

Quoted 150 lines · Rajeshwari Shinde

This patch modifies the S3C I2C driver to suppport EXYNOS5.
The cahnges made to driver are as follows:
- I2C base address is passed as a parameter to many functions to avoid multiple #ifdef
- Channel initialisation is moved to a commom funation
as it is required by i2c_init.
- Hardcoding for I2CCON_ACKGEN removed.
- Replaced printf with debug.
- Checkpatch issues resolved.
- Pinmux setting will be done in board/samsung/smdk5250/smdk5250.c to avoid repeated setting of gpio lines, as it have multi bus support.

---
Changes in V2:
- Removed #define for I2C cahnnels from hearder file except for I2C0.
- Incorporated review comments from Simon Glass.
Changes in V3:
- Incorporated review comments from Joonyoung Shim.
- Reduced the number of #ifdef by modifying get_i2c_base function.
- Removed duplicate code.
Changes in V4:
- Resolved build error for s3c2410.
Changes in V5:
- Pinmux setting will be done in board/samsung/smdk5250/smdk5250.c to avoid repeated setting of gpio lines, as it have multi bus support.
- I2C bus offset calulation done based on EXYNOS_I2C_SPACING
- Peripharal related code removed.
Changes in V6:
- g_current_bus made common to all platforms.

  drivers/i2c/s3c24x0_i2c.c |  193 +++++++++++++++++++++++++++-----------------
  1 files changed, 118 insertions(+), 75 deletions(-)
drivers/i2c/s3c24x0_i2c.c +50 -10
index ba6f39b..421c7dd 100644
@@ -27,10 +27,15 @@
   */
 
  #include <common.h>
+#ifdef CONFIG_EXYNOS5
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#else
  #include <asm/arch/s3c24x0_cpu.h>
-
+#endif
  #include <asm/io.h>
  #include <i2c.h>
+#include "s3c24x0_i2c.h"
 
  #ifdef CONFIG_HARD_I2C
 
@@ -45,6 +50,7 @@
 
  #define I2CSTAT_BSY	0x20	/* Busy bit */
  #define I2CSTAT_NACK	0x01	/* Nack bit */
+#define I2CCON_ACKGEN	0x80	/* Acknowledge generation */
  #define I2CCON_IRPND	0x10	/* Interrupt pending bit */
  #define I2C_MODE_MT	0xC0	/* Master Transmit Mode */
  #define I2C_MODE_MR	0x80	/* Master Receive Mode */
@@ -53,6 +59,10 @@
 
  #define I2C_TIMEOUT 1		/* 1 second */
 
+
+static unsigned int g_current_bus;	/* Stores Current I2C Bus */
+
+#ifndef CONFIG_EXYNOS5
  static int GetI2CSDA(void)
  {
  	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
@@ -77,16 +87,17 @@ static void SetI2CSCL(int x)
  	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
 
  #ifdef CONFIG_S3C2410
-	writel((readl(&gpio->gpedat) & ~0x4000) | (x & 1) << 14, &gpio->gpedat);
+	writel((readl(&gpio->gpedat) & ~0x4000) |
+					(x & 1) << 14, &gpio->gpedat);
  #endif
  #ifdef CONFIG_S3C2400
  	writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat);
  #endif
  }
+#endif
 
-static int WaitForXfer(void)
+static int WaitForXfer(struct s3c24x0_i2c *i2c)
  {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
  	int i;
 
  	i = I2C_TIMEOUT * 10000;
@@ -98,35 +109,77 @@ static int WaitForXfer(void)
  	return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
  }
 
-static int IsACK(void)
+static int IsACK(struct s3c24x0_i2c *i2c)
  {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-
  	return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
  }
 
-static void ReadWriteByte(void)
+static void ReadWriteByte(struct s3c24x0_i2c *i2c)
  {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-
  	writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
  }
 
+static struct s3c24x0_i2c *get_base_i2c(void)
+{
+#ifdef CONFIG_EXYNOS5
+	struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c()
+							+ (EXYNOS5_I2C_SPACING
+							* g_current_bus));
+	return i2c;
+#else
+	return s3c24x0_get_base_i2c();
+#endif
+}
+
+static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
+{
+	ulong freq, pres = 16, div;
+#ifdef CONFIG_EXYNOS5
+	freq = get_i2c_clk();
+#else
+	freq = get_PCLK();
+#endif
+	/* calculate prescaler and divisor values */
+	if ((freq / pres / (16 + 1)) > speed)
+		/* set prescaler to 512 */
+		pres = 512;
+
+	div = 0;
+	while ((freq / pres / (div + 1)) > speed)
+		div++;
+
+	/* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
+	writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
+
+	/* init to SLAVE REVEIVE and set slaveaddr */

drivers/i2c/s3c24x0_i2c.c static int WaitForXfer(void) · line 163

Quoted 10 lines
drivers/i2c/s3c24x0_i2c.c +7 -1
+	writel(0, &i2c->iicstat);
+	writel(slaveadd, &i2c->iicadd);
+	/* program Master Transmit (and implicit STOP) */
+	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
+}
+
  void i2c_init(int speed, int slaveadd)
  {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
+	struct s3c24x0_i2c *i2c = get_base_i2c();

This will refer g_current_bus before g_current_bus is initialized to 0.

drivers/i2c/s3c24x0_i2c.c static int WaitForXfer(void) · line 170

Quoted 9 lines
drivers/i2c/s3c24x0_i2c.c +4 -2
+#ifndef CONFIG_EXYNOS5
  	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
-	ulong freq, pres = 16, div;
+#endif
  	int i;
 
-	/* wait for some time to give previous transfer a chance to finish */
+	/* By default i2c channel 0 is the current bus */
+	g_current_bus = 0;

Let's initialize i2c at here.

i2c = get_base_i2c();

drivers/i2c/s3c24x0_i2c.c static int WaitForXfer(void) · line 174

Quoted 4 lines
drivers/i2c/s3c24x0_i2c.c +3 -0
+#ifdef CONFIG_EXYNOS5
+	i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif

I think it doesn't need to do this at here.

drivers/i2c/s3c24x0_i2c.c static int WaitForXfer(void) · line 177

Quoted 3 lines
drivers/i2c/s3c24x0_i2c.c +1 -0
+	/* wait for some time to give previous transfer a chance to finish */
  	i = I2C_TIMEOUT * 1000;
  	while ((readl(&i2c->iicstat) && I2CSTAT_BSY) && (i > 0)) {

I think this is bug, should use & instead of &&.

while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) {

Quoted 23 lines
drivers/i2c/s3c24x0_i2c.c +1 -11
  		udelay(1000);
  		i--;
  	}
 
+#ifndef CONFIG_EXYNOS5
  	if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) {
  #ifdef CONFIG_S3C2410
  		ulong old_gpecon = readl(&gpio->gpecon);
@@ -171,26 +224,8 @@ void i2c_init(int speed, int slaveadd)
  #endif
  	}
 
-	/* calculate prescaler and divisor values */
-	freq = get_PCLK();
-	if ((freq / pres / (16 + 1)) > speed)
-		/* set prescaler to 512 */
-		pres = 512;
-
-	div = 0;
-	while ((freq / pres / (div + 1)) > speed)
-		div++;
-
-	/* set prescaler, divisor according to freq, also set

drivers/i2c/s3c24x0_i2c.c void i2c_init(int speed, int slaveadd) · line 227

Quoted 10 lines
drivers/i2c/s3c24x0_i2c.c +1 -9
-	 * ACKGEN, IRQ */
-	writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
-
-	/* init to SLAVE REVEIVE and set slaveaddr */
-	writel(0, &i2c->iicstat);
-	writel(slaveadd, &i2c->iicadd);
-	/* program Master Transmit (and implicit STOP) */
-	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
-
+	i2c_ch_init(i2c, speed, slaveadd);

Also EXYNOS5, let's do i2c_ch_init() using speed and slaveadd arguments at here.

Quoted 229 lines
drivers/i2c/s3c24x0_i2c.c +49 -41
+#endif /* #ifndef CONFIG_EXYNOS5 */
  }
 
  /*
@@ -200,19 +235,19 @@ void i2c_init(int speed, int slaveadd)
   * by the char, we could make it larger if needed. If it is
   * 0 we skip the address write cycle.
   */
-static
-int i2c_transfer(unsigned char cmd_type,
-		 unsigned char chip,
-		 unsigned char addr[],
-		 unsigned char addr_len,
-		 unsigned char data[], unsigned short data_len)
+static int i2c_transfer(struct s3c24x0_i2c *i2c,
+			unsigned char cmd_type,
+			unsigned char chip,
+			unsigned char addr[],
+			unsigned char addr_len,
+			unsigned char data[],
+			unsigned short data_len)
  {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
  	int i, result;
 
  	if (data == 0 || data_len == 0) {
  		/*Don't support data transfer of no length or to address 0 */
-		printf("i2c_transfer: bad call\n");
+		debug("i2c_transfer: bad call\n");
  		return I2C_NOK;
  	}
 
@@ -226,7 +261,7 @@ int i2c_transfer(unsigned char cmd_type,
  	if (readl(&i2c->iicstat) & I2CSTAT_BSY)
  		return I2C_NOK_TOUT;
 
-	writel(readl(&i2c->iiccon) | 0x80, &i2c->iiccon);
+	writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
  	result = I2C_OK;
 
  	switch (cmd_type) {
@@ -238,16 +273,16 @@ int i2c_transfer(unsigned char cmd_type,
  			       &i2c->iicstat);
  			i = 0;
  			while ((i < addr_len) && (result == I2C_OK)) {
-				result = WaitForXfer();
+				result = WaitForXfer(i2c);
  				writel(addr[i], &i2c->iicds);
-				ReadWriteByte();
+				ReadWriteByte(i2c);
  				i++;
  			}
  			i = 0;
  			while ((i < data_len) && (result == I2C_OK)) {
-				result = WaitForXfer();
+				result = WaitForXfer(i2c);
  				writel(data[i], &i2c->iicds);
-				ReadWriteByte();
+				ReadWriteByte(i2c);
  				i++;
  			}
  		} else {
@@ -257,19 +292,19 @@ int i2c_transfer(unsigned char cmd_type,
  			       &i2c->iicstat);
  			i = 0;
  			while ((i < data_len) && (result = I2C_OK)) {
-				result = WaitForXfer();
+				result = WaitForXfer(i2c);
  				writel(data[i], &i2c->iicds);
-				ReadWriteByte();
+				ReadWriteByte(i2c);
  				i++;
  			}
  		}
 
  		if (result == I2C_OK)
-			result = WaitForXfer();
+			result = WaitForXfer(i2c);
 
  		/* send STOP */
  		writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
-		ReadWriteByte();
+		ReadWriteByte(i2c);
  		break;
 
  	case I2C_READ:
@@ -279,13 +314,13 @@ int i2c_transfer(unsigned char cmd_type,
  			/* send START */
  			writel(readl(&i2c->iicstat) | I2C_START_STOP,
  			       &i2c->iicstat);
-			result = WaitForXfer();
-			if (IsACK()) {
+			result = WaitForXfer(i2c);
+			if (IsACK(i2c)) {
  				i = 0;
  				while ((i < addr_len) && (result == I2C_OK)) {
  					writel(addr[i], &i2c->iicds);
-					ReadWriteByte();
-					result = WaitForXfer();
+					ReadWriteByte(i2c);
+					result = WaitForXfer(i2c);
  					i++;
  				}
 
@@ -293,16 +328,17 @@ int i2c_transfer(unsigned char cmd_type,
  				/* resend START */
  				writel(I2C_MODE_MR | I2C_TXRX_ENA |
  				       I2C_START_STOP, &i2c->iicstat);
-				ReadWriteByte();
-				result = WaitForXfer();
+			ReadWriteByte(i2c);
+			result = WaitForXfer(i2c);
  				i = 0;
  				while ((i < data_len) && (result == I2C_OK)) {
  					/* disable ACK for final READ */
  					if (i == data_len - 1)
  						writel(readl(&i2c->iiccon)
-						       & ~0x80, &i2c->iiccon);
-					ReadWriteByte();
-					result = WaitForXfer();
+							& ~I2CCON_ACKGEN,
+							&i2c->iiccon);
+				ReadWriteByte(i2c);
+				result = WaitForXfer(i2c);
  					data[i] = readl(&i2c->iicds);
  					i++;
  				}
@@ -316,17 +352,18 @@ int i2c_transfer(unsigned char cmd_type,
  			/* send START */
  			writel(readl(&i2c->iicstat) | I2C_START_STOP,
  			       &i2c->iicstat);
-			result = WaitForXfer();
+			result = WaitForXfer(i2c);
 
-			if (IsACK()) {
+			if (IsACK(i2c)) {
  				i = 0;
  				while ((i < data_len) && (result == I2C_OK)) {
  					/* disable ACK for final READ */
  					if (i == data_len - 1)
  						writel(readl(&i2c->iiccon) &
-						       ~0x80, &i2c->iiccon);
-					ReadWriteByte();
-					result = WaitForXfer();
+							~I2CCON_ACKGEN,
+							&i2c->iiccon);
+					ReadWriteByte(i2c);
+					result = WaitForXfer(i2c);
  					data[i] = readl(&i2c->iicds);
  					i++;
  				}
@@ -337,22 +374,24 @@ int i2c_transfer(unsigned char cmd_type,
 
  		/* send STOP */
  		writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
-		ReadWriteByte();
+		ReadWriteByte(i2c);
  		break;
 
  	default:
-		printf("i2c_transfer: bad call\n");
+		debug("i2c_transfer: bad call\n");
  		result = I2C_NOK;
  		break;
  	}
 
-	return (result);
+	return result;
  }
 
  int i2c_probe(uchar chip)
  {
+	struct s3c24x0_i2c *i2c;
  	uchar buf[1];
 
+	i2c = get_base_i2c();
  	buf[0] = 0;
 
  	/*
@@ -360,16 +399,17 @@ int i2c_probe(uchar chip)
  	 * address was <ACK>ed (i.e. there was a chip at that address which
  	 * drove the data line low).
  	 */
-	return i2c_transfer(I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
+	return i2c_transfer(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
  }
 
  int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
  {
+	struct s3c24x0_i2c *i2c;
  	uchar xaddr[4];
  	int ret;
 
  	if (alen > 4) {
-		printf("I2C read: addr len %d not supported\n", alen);
+		debug("I2C read: addr len %d not supported\n", alen);
  		return 1;
  	}
 
@@ -396,10 +436,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
  		chip |= ((addr >> (alen * 8)) &
  			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
  #endif
-	if ((ret =
-	     i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen,
-			  buffer, len)) != 0) {
-		printf("I2c read: failed %d\n", ret);
+	i2c = get_base_i2c();
+	ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen,
+			buffer, len);
+	if (ret != 0) {
+		debug("I2c read: failed %d\n", ret);
  		return 1;
  	}
  	return 0;
@@ -407,10 +448,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 
  int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
  {
+	struct s3c24x0_i2c *i2c;
  	uchar xaddr[4];
 
  	if (alen > 4) {
-		printf("I2C write: addr len %d not supported\n", alen);
+		debug("I2C write: addr len %d not supported\n", alen);
  		return 1;
  	}
 

drivers/i2c/s3c24x0_i2c.c int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) · line 486

Quoted 10 lines
drivers/i2c/s3c24x0_i2c.c +2 -1
@@ -436,8 +478,9 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
  		chip |= ((addr >> (alen * 8)) &
  			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
  #endif
+	i2c = get_base_i2c();
  	return (i2c_transfer
-		(I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
+		(i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
  		 len) != 0);
  }
  #endif /* CONFIG_HARD_I2C */

Thanks.

#11 lore raw

PATCH v6 7/8 I2C: Add support for Multi channel

In reply to Rajeshwari Shinde

This adds multiple i2c channel support for I2C.

---
Changes in V2:
- None
Changes in V3:
- None
Changes in V4:
- None
Changes in V5:
- Pinmux setting of all bus done during board init.
Changes in V6:
- None

 drivers/i2c/s3c24x0_i2c.c |   27 +++++++++++++++++++++++++++
 1 files changed, 27 insertions(+), 0 deletions(-)
drivers/i2c/s3c24x0_i2c.c +27 -0
index 421c7dd..39a0365 100644
@@ -158,6 +158,33 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
 	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
 }
 
+/*
+ * MULTI BUS I2C support
+ */
+
+#ifdef CONFIG_I2C_MULTI_BUS
+int i2c_set_bus_num(unsigned int bus)
+{
+	struct s3c24x0_i2c *i2c;
+
+	if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) {
+		debug("Bad bus: %d\n", bus);
+		return -1;
+	}
+
+	g_current_bus = bus;
+	i2c = get_base_i2c();
+	i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	return 0;
+}
+
+unsigned int i2c_get_bus_num(void)
+{
+	return g_current_bus;
+}
+#endif
+
 void i2c_init(int speed, int slaveadd)
 {
 	struct s3c24x0_i2c *i2c = get_base_i2c();
Signature · 1 line
1.7.4.4
#12 lore raw

PATCH v6 8/8 CONFIG: SMDK5250: I2C: Enable I2C

In reply to Rajeshwari Shinde

This enables I2C support on smdk5250.
Pinmux setting moved to board file to avoid repeated setting of gpio lines.

---
Changes in V2:
- None
Changes in V3:
- None
Changes in V4:
- None
Changes in V5:
- Pinmux setting of gpio lines moved to board_early_init_f.
Chnages in V6:
- EXYNOS_I2C_SPACING moved to cpu.h
- board_i2c_init compiled only when CONFIG_DRIVER_S3C24X0_I2C is defined.

 board/samsung/smdk5250/smdk5250.c |   28 +++++++++++++++++++++++++++-
 include/configs/smdk5250.h        |    8 ++++++++
 2 files changed, 35 insertions(+), 1 deletions(-)
board/samsung/smdk5250/smdk5250.c +27 -1
index b593325..12e6e66 100644
@@ -172,9 +172,35 @@ static int board_uart_init(void)
 	return 0;
 }
 
+#ifdef CONFIG_DRIVER_S3C24X0_I2C
+static int board_i2c_init(void)
+{
+	int i, err;
+
+	for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) {
+		err = exynos_pinmux_config((PERIPH_ID_I2C0 + i),
+						PINMUX_FLAG_NONE);
+		if (err) {
+			debug("I2C%d not configured\n", (PERIPH_ID_I2C0 + i));
+			return err;
+		}
+	}
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_BOARD_EARLY_INIT_F
 int board_early_init_f(void)
 {
-	return board_uart_init();
+	int err;
+	err = board_uart_init();
+	if (err) {
+		debug("UART init failed\n");
+		return err;
+	}
+#ifdef CONFIG_DRIVER_S3C24X0_I2C
+	err = board_i2c_init();
+#endif
+	return err;
 }
 #endif
include/configs/smdk5250.h +8 -0
index c0eaaf8..65dfe9f 100644
@@ -198,6 +198,14 @@
 
 #define CONFIG_SYS_INIT_SP_ADDR	(CONFIG_SYS_LOAD_ADDR - 0x1000000)
 
+/* I2C */
+#define CONFIG_HARD_I2C
+#define CONFIG_CMD_I2C
+#define CONFIG_SYS_I2C_SPEED	100000		/* 100 Kbps */
+#define CONFIG_DRIVER_S3C24X0_I2C
+#define CONFIG_I2C_MULTI_BUS
+#define CONFIG_MAX_I2C_NUM	8
+
 /* Ethernet Controllor Driver */
 #ifdef CONFIG_CMD_NET
 #define CONFIG_SMC911X
Signature · 1 line
1.7.4.4
#13 lore raw

PATCH v6 8/8 CONFIG: SMDK5250: I2C: Enable I2C

Quoted 8 lines · Rajeshwari Shinde

This enables I2C support on smdk5250.
Pinmux setting moved to board file to avoid repeated setting of gpio lines.

Quoted 79 lines

---
Changes in V2:
- None
Changes in V3:
- None
Changes in V4:
- None
Changes in V5:
- Pinmux setting of gpio lines moved to board_early_init_f.
Chnages in V6:
- EXYNOS_I2C_SPACING moved to cpu.h
- board_i2c_init compiled only when CONFIG_DRIVER_S3C24X0_I2C is defined.

 board/samsung/smdk5250/smdk5250.c |   28 +++++++++++++++++++++++++++-
 include/configs/smdk5250.h        |    8 ++++++++
 2 files changed, 35 insertions(+), 1 deletions(-)
board/samsung/smdk5250/smdk5250.c +27 -1
index b593325..12e6e66 100644
@@ -172,9 +172,35 @@ static int board_uart_init(void)
        return 0;
 }
 
+#ifdef CONFIG_DRIVER_S3C24X0_I2C
+static int board_i2c_init(void)
+{
+       int i, err;
+
+       for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) {
+               err = exynos_pinmux_config((PERIPH_ID_I2C0 + i),
+                                               PINMUX_FLAG_NONE);
+               if (err) {
+                       debug("I2C%d not configured\n", (PERIPH_ID_I2C0 + i));
+                       return err;
+               }
+       }
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_BOARD_EARLY_INIT_F
 int board_early_init_f(void)
 {
-       return board_uart_init();
+       int err;
+       err = board_uart_init();
+       if (err) {
+               debug("UART init failed\n");
+               return err;
+       }
+#ifdef CONFIG_DRIVER_S3C24X0_I2C
+       err = board_i2c_init();
+#endif
+       return err;
 }
 #endif
include/configs/smdk5250.h +8 -1
index c0eaaf8..65dfe9f 100644
@@ -198,6 +198,14 @@
 
 #define CONFIG_SYS_INIT_SP_ADDR        (CONFIG_SYS_LOAD_ADDR - 0x1000000)
 
+/* I2C */
+#define CONFIG_HARD_I2C
+#define CONFIG_CMD_I2C
+#define CONFIG_SYS_I2C_SPEED   100000          /* 100 Kbps */
+#define CONFIG_DRIVER_S3C24X0_I2C
+#define CONFIG_I2C_MULTI_BUS
+#define CONFIG_MAX_I2C_NUM     8
+
 /* Ethernet Controllor Driver */
 #ifdef CONFIG_CMD_NET
 #define CONFIG_SMC911X
--

1.7.4.4

#14 lore raw

PATCH v6 8/8 CONFIG: SMDK5250: I2C: Enable I2C

In reply to Rajeshwari Shinde
Quoted 38 lines · Rajeshwari Shinde

This enables I2C support on smdk5250.
Pinmux setting moved to board file to avoid repeated setting of gpio lines.

---
Changes in V2:
- None
Changes in V3:
- None
Changes in V4:
- None
Changes in V5:
- Pinmux setting of gpio lines moved to board_early_init_f.
Chnages in V6:
- EXYNOS_I2C_SPACING moved to cpu.h
- board_i2c_init compiled only when CONFIG_DRIVER_S3C24X0_I2C is defined.

  board/samsung/smdk5250/smdk5250.c |   28 +++++++++++++++++++++++++++-
  include/configs/smdk5250.h        |    8 ++++++++
  2 files changed, 35 insertions(+), 1 deletions(-)
board/samsung/smdk5250/smdk5250.c +6 -0
index b593325..12e6e66 100644
@@ -172,9 +172,35 @@ static int board_uart_init(void)
  	return 0;
  }
 
+#ifdef CONFIG_DRIVER_S3C24X0_I2C
+static int board_i2c_init(void)
+{
+	int i, err;
+
+	for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) {

board/samsung/smdk5250/smdk5250.c static int board_uart_init(void) · line 190

Quoted 10 lines
board/samsung/smdk5250/smdk5250.c +10 -0
+		err = exynos_pinmux_config((PERIPH_ID_I2C0 + i),
+						PINMUX_FLAG_NONE);
+		if (err) {
+			debug("I2C%d not configured\n", (PERIPH_ID_I2C0 + i));
+			return err;
+		}
+	}
+	return 0;
+}
+#endif

How about use CONFIG_SYS_I2C_INIT_BOARD and i2c_init_board()? Some i2c drivers are using them.

Quoted 36 lines
board/samsung/smdk5250/smdk5250.c +11 -1
+
  #ifdef CONFIG_BOARD_EARLY_INIT_F
  int board_early_init_f(void)
  {
-	return board_uart_init();
+	int err;
+	err = board_uart_init();
+	if (err) {
+		debug("UART init failed\n");
+		return err;
+	}
+#ifdef CONFIG_DRIVER_S3C24X0_I2C
+	err = board_i2c_init();
+#endif
+	return err;
  }
  #endif
include/configs/smdk5250.h +8 -0
index c0eaaf8..65dfe9f 100644
@@ -198,6 +198,14 @@
 
  #define CONFIG_SYS_INIT_SP_ADDR	(CONFIG_SYS_LOAD_ADDR - 0x1000000)
 
+/* I2C */
+#define CONFIG_HARD_I2C
+#define CONFIG_CMD_I2C
+#define CONFIG_SYS_I2C_SPEED	100000		/* 100 Kbps */
+#define CONFIG_DRIVER_S3C24X0_I2C
+#define CONFIG_I2C_MULTI_BUS
+#define CONFIG_MAX_I2C_NUM	8
+
  /* Ethernet Controllor Driver */
  #ifdef CONFIG_CMD_NET
  #define CONFIG_SMC911X