
Hi Joonyoung Shim,
Thank you for comments.
On Fri, Jun 15, 2012 at 12:40 PM, Joonyoung Shim dofmind@gmail.com wrote:
Hi,
2012/6/7 Rajeshwari Shinde rajeshwari.s@samsung.com:
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 - I2C init for Exynos5 is made as different function. - Channel initialisation is moved to a commom funation as it is required by both the i2c_init. - Separate functions written to get I2C base address, peripheral id for pinmux support. - Hardcoding for I2CCON_ACKGEN removed. - Replaced printf with debug. - Checkpatch issues resolved.
Signed-off-by: Alim Akhtar alim.akhtar@samsung.com Signed-off-by: Doug Anderson dianders@chromium.org Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com Acked-by: Simon Glass sjg@chromium.org
Changes in V2: - Removed #define for I2C cahnnels from hearder file except for I2C0. - Incorporated review comments from Simon Glass. drivers/i2c/s3c24x0_i2c.c | 254 ++++++++++++++++++++++++++++++++------------- drivers/i2c/s3c24x0_i2c.h | 3 + 2 files changed, 184 insertions(+), 73 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index ba6f39b..a71f147 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,10 +27,17 @@ */
#include <common.h> +#ifdef CONFIG_EXYNOS5 +#include <asm/arch/clk.h> +#include <asm/arch/cpu.h> +#include <asm/arch/gpio.h> +#include <asm/arch/pinmux.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 +52,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 +61,44 @@
#define I2C_TIMEOUT 1 /* 1 second */
+#ifdef CONFIG_EXYNOS5 +static unsigned int g_current_bus; /* Stores Current I2C Bus */
+/* We should not rely on any particular ordering of these IDs */ +static enum periph_id periph_for_dev[] = {
- PERIPH_ID_I2C0,
- PERIPH_ID_I2C1,
- PERIPH_ID_I2C2,
- PERIPH_ID_I2C3,
- PERIPH_ID_I2C4,
- PERIPH_ID_I2C5,
- PERIPH_ID_I2C6,
- PERIPH_ID_I2C7,
+};
+static enum periph_id i2c_get_periph_id(unsigned dev_index) +{
- if (dev_index < ARRAY_SIZE(periph_for_dev))
- return periph_for_dev[dev_index];
- debug("%s: invalid bus %d", __func__, dev_index);
- return PERIPH_ID_NONE;
+}
+static struct s3c24x0_i2c *get_base_i2c(int bus_idx) +{
- struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)samsung_get_base_i2c();
- return &i2c[bus_idx];
+}
This function can use in the s3c24xx adding #ifdef in this fuction, then you can reduce #ifdef.
-- Will do this.
+static inline struct exynos5_gpio_part1 *exynos_get_base_gpio1(void) +{
- return (struct exynos5_gpio_part1 *)(EXYNOS5_GPIO_PART1_BASE);
+}
+#else static int GetI2CSDA(void) { struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); @@ -77,16 +123,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,25 +145,84 @@ 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 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);
+}
+static void i2c_bus_init(struct s3c24x0_i2c *i2c, unsigned int bus) +{
- int periph_id = i2c_get_periph_id(bus);
- exynos_pinmux_config(periph_id, 0);
- i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+}
This function is used only in EXYNOS5.
-- This will be used in Multi bus also which other boards can use.
+#ifdef CONFIG_EXYNOS5 +void i2c_init(int speed, int slaveadd) +{
- struct s3c24x0_i2c *i2c;
- struct exynos5_gpio_part1 *gpio;
- int i;
- /* By default i2c channel 0 is the current bus */
- g_current_bus = I2C0;
- i2c = get_base_i2c(g_current_bus);
- i2c_bus_init(i2c, g_current_bus);
- /* 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--;
- }
- gpio = exynos_get_base_gpio1();
- writel((readl(&gpio->b3.con) & ~0x00FF) | 0x0022, &gpio->b3.con);
This doesn't need to do because of i2c_bus_init().
-- Will correct this.
- i2c_ch_init(i2c, speed, slaveadd);
The i2c_bus_init() calls i2c_ch_init() already.
-- You are right. Will correct this.
+}
+#else void i2c_init(int speed, int slaveadd) { struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
- ulong freq, pres = 16, div;
int i;
/* wait for some time to give previous transfer a chance to finish */ @@ -171,27 +277,9 @@ 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
/* * cmd_type is 0 for write, 1 for read. @@ -200,19 +288,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 +314,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 +326,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 +345,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 +367,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 +381,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 +405,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 +427,28 @@ 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];
+#ifdef CONFIG_EXYNOS5
- i2c = get_base_i2c(g_current_bus);
+#else
- i2c = s3c24x0_get_base_i2c();
+#endif buf[0] = 0;
/* @@ -360,16 +456,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 +493,15 @@ 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);
+#ifdef CONFIG_EXYNOS5
- i2c = get_base_i2c(g_current_bus);
+#else
- i2c = s3c24x0_get_base_i2c();
+#endif
- 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 +509,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 +539,13 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); #endif +#ifdef CONFIG_EXYNOS5
- i2c = get_base_i2c(g_current_bus);
+#else
- i2c = s3c24x0_get_base_i2c();
+#endif 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 */ diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index d357a0a..57aafb1 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -23,6 +23,9 @@ #ifndef _S3C24X0_I2C_H #define _S3C24X0_I2C_H
+/* I2C channels exynos5 has 8 i2c channel */ +#define I2C0 0
struct s3c24x0_i2c { u32 iiccon; u32 iicstat; -- 1.7.4.4
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Thanks.
--
Regards Rajeshwari Shinde
- Joonyoung Shim
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot