From mboxrd@z Thu Jan 1 00:00:00 1970 From: Simon Glass Date: Mon, 11 Jun 2012 22:52:49 -0700 Subject: [U-Boot] [PATCH 6/8 V2] I2C: Modify the I2C driver for EXYNOS5 In-Reply-To: <1339049394-4816-7-git-send-email-rajeshwari.s@samsung.com> References: <1339049394-4816-1-git-send-email-rajeshwari.s@samsung.com> <1339049394-4816-7-git-send-email-rajeshwari.s@samsung.com> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On Wed, Jun 6, 2012 at 11:09 PM, Rajeshwari Shinde wrote: > 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 > Signed-off-by: Doug Anderson > Signed-off-by: Rajeshwari Shinde > Acked-by: Simon Glass > --- > Changes in V2: > - Removed #define for I2C cahnnels from hearder file except for > I2C0. > - Incorporated review comments from Simon Glass. > Acked-by: Simon Glass (Looking forward to getting the transfer loop simplified one day!) > 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 > +#ifdef CONFIG_EXYNOS5 > +#include > +#include > +#include > +#include > +#else > #include > - > +#endif > #include > #include > +#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]; > +} > + > +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); > +} > + > +#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); > + > + i2c_ch_init(i2c, speed, slaveadd); > +} > + > +#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 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 > >