
Hi Simon,
Thank you for comments.
On Fri, Jun 1, 2012 at 6:47 AM, Simon Glass sjg@chromium.org wrote:
Hi,
On Fri, May 18, 2012 at 5:12 AM, Rajeshwari Shinde <rajeshwari.s@samsung.com
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 alim.akhtar@samsung.com Signed-off-by: Doug Anderson dianders@chromium.org Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Just a nit and a question, but:
Acked-by: Simon Glass sjg@chromium.org
drivers/i2c/s3c24x0_i2c.c | 250 ++++++++++++++++++++++++++++++++------------- drivers/i2c/s3c24x0_i2c.h | 10 ++ 2 files changed, 188 insertions(+), 72 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index ba6f39b..61b54a9 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,10 +27,18 @@ */
#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 +53,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 +62,41 @@
#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();
blank line here
-- will correct this.
- return &i2c[bus_idx];
+}
+static inline struct exynos5_gpio_part1 *exynos_get_base_gpio1(void) +{
- return (struct exynos5_gpio_part1 *)(EXYNOS5_GPIO_PART1_BASE);
OK for now - I assume you will pick up the GPIO patches later and move this there.
-- yes
+}
+#else static int GetI2CSDA(void) { struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); @@ -77,16 +121,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);
unrelated change?
-- it is correction of a checkpatch error
#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 +143,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 +275,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 +286,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 +312,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 +324,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 +343,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 +365,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 +379,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 +403,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 +425,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 +454,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 +491,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 +507,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 +537,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..3c144c0 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -23,6 +23,16 @@ #ifndef _S3C24X0_I2C_H #define _S3C24X0_I2C_H
+/* I2C channels exynos5 has 8 i2c channel */ +#define I2C0 0 +#define I2C1 1 +#define I2C2 2 +#define I2C3 3 +#define I2C4 4 +#define I2C5 5 +#define I2C6 6 +#define I2C7 7
Do you actually need these? Perhaps just use '0' in the code for bus 0.
-- You are right will correct this.
struct s3c24x0_i2c { u32 iiccon; u32 iicstat; -- 1.7.4.4
Regards,
Simon
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Regards, Rajeshwari Shinde