diff options
author | Wolfgang Denk <wd@denx.de> | 2012-07-31 22:07:42 +0200 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2012-07-31 22:07:42 +0200 |
commit | 948fa1713cce09dd958bda41eb5c97015a217f91 (patch) | |
tree | 26ccc8735233389f214af564a4bfc75a7e041668 /drivers | |
parent | d978780b2e676c005460cd561f4f15b5220bdf49 (diff) | |
parent | e69e482bbf16795539af112d6a21d4ddaee35105 (diff) | |
download | u-boot-948fa1713cce09dd958bda41eb5c97015a217f91.zip u-boot-948fa1713cce09dd958bda41eb5c97015a217f91.tar.gz u-boot-948fa1713cce09dd958bda41eb5c97015a217f91.tar.bz2 |
Merge branch 'master' of git://git.denx.de/u-boot-i2c
* 'master' of git://git.denx.de/u-boot-i2c:
km/common: remove printfs for i2c deblocking code
CONFIG: SMDK5250: I2C: Enable I2C
I2C: Add support for Multi channel
I2C: Modify the I2C driver for EXYNOS5
I2C: Move struct s3c24x0_i2c to a common place.
EXYNOS: PINMUX: Add pinmux support for I2C
EXYNOS5: define EXYNOS5_I2C_SPACING
EXYNOS: Add I2C base address.
EXYNOS: CLK: Add i2c clock
mx6qsabrelite: add i2c multi-bus support
imx-common: add i2c.c for bus recovery support
i.mx53: add definition for I2C3_BASE_ADDR
i.mx: iomux-v3.c: move to imx-common directory
i.mx: iomux-v3.h: move to imx-common include directory
iomux-v3: remove include of mx6x_pins.h
mxc_i2c: finish adding CONFIG_I2C_MULTI_BUS support
mxc_i2c: add bus recovery support
mxc_i2c: prep work for multiple busses support
mxc_i2c: add i2c_regs argument to i2c_imx_stop
mxc_i2c: add retries
mxc_i2c: check for arbitration lost
mxc_i2c: change slave addr if conflicts with destination.
mxc_i2c: don't disable controller after every transaction
mxc_i2c: place i2c_reset code inline
mxc_i2c: place imx_start code inline
mxc_i2c: remove redundant read
mxc_i2c: combine i2c_imx_bus_busy and i2c_imx_trx_complete into wait_for_sr_state
mxc_i2c.c: code i2c_probe as a 0 length i2c_write
mxc_i2c: call i2c_imx_stop on error in i2c_read/i2c_write
mxc_i2c: create i2c_init_transfer
mxc_i2c: clear i2sr before waiting for bit
mxc_i2c: create tx_byte function
mxc_i2c: remove ifdef of CONFIG_HARD_I2C
mxc_i2c: fix i2c_imx_stop
i2c: deblock i2c bus also if accessed before realocation
Signed-off-by: Wolfgang Denk <wd@denx.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/mxc_i2c.c | 477 | ||||
-rw-r--r-- | drivers/i2c/s3c24x0_i2c.c | 221 | ||||
-rw-r--r-- | drivers/i2c/s3c24x0_i2c.h | 33 | ||||
-rw-r--r-- | drivers/usb/host/ehci-mx6.c | 2 |
4 files changed, 442 insertions, 291 deletions
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index fc68062..73d8958 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -31,13 +31,12 @@ */ #include <common.h> -#include <asm/io.h> - -#if defined(CONFIG_HARD_I2C) - #include <asm/arch/clock.h> #include <asm/arch/imx-regs.h> +#include <asm/errno.h> +#include <asm/io.h> #include <i2c.h> +#include <watchdog.h> struct mxc_i2c_regs { uint32_t iadr; @@ -56,17 +55,14 @@ struct mxc_i2c_regs { #define I2SR_ICF (1 << 7) #define I2SR_IBB (1 << 5) +#define I2SR_IAL (1 << 4) #define I2SR_IIF (1 << 1) #define I2SR_RX_NO_AK (1 << 0) -#ifdef CONFIG_SYS_I2C_BASE -#define I2C_BASE CONFIG_SYS_I2C_BASE -#else +#if defined(CONFIG_HARD_I2C) && !defined(CONFIG_SYS_I2C_BASE) #error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver" #endif -#define I2C_MAX_TIMEOUT 10000 - static u16 i2c_clk_div[50][2] = { { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, @@ -117,46 +113,29 @@ static uint8_t i2c_imx_get_clk(unsigned int rate) } /* - * Reset I2C Controller + * Set I2C Bus speed */ -void i2c_reset(void) +int bus_i2c_set_bus_speed(void *base, int speed) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - - writeb(0, &i2c_regs->i2cr); /* Reset module */ - writeb(0, &i2c_regs->i2sr); -} - -/* - * Init I2C Bus - */ -void i2c_init(int speed, int unused) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; + struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; u8 clk_idx = i2c_imx_get_clk(speed); u8 idx = i2c_clk_div[clk_idx][1]; /* Store divider value */ writeb(idx, &i2c_regs->ifdr); - i2c_reset(); -} - -/* - * Set I2C Speed - */ -int i2c_set_bus_speed(unsigned int speed) -{ - i2c_init(speed, 0); + /* Reset module */ + writeb(0, &i2c_regs->i2cr); + writeb(0, &i2c_regs->i2sr); return 0; } /* * Get I2C Speed */ -unsigned int i2c_get_bus_speed(void) +unsigned int bus_i2c_get_bus_speed(void *base) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; + struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; u8 clk_idx = readb(&i2c_regs->ifdr); u8 clk_div; @@ -166,210 +145,163 @@ unsigned int i2c_get_bus_speed(void) return mxc_get_clock(MXC_IPG_PERCLK) / i2c_clk_div[clk_div][0]; } -/* - * Wait for bus to be busy (or free if for_busy = 0) - * - * for_busy = 1: Wait for IBB to be asserted - * for_busy = 0: Wait for IBB to be de-asserted - */ -int i2c_imx_bus_busy(int for_busy) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - unsigned int temp; +#define ST_BUS_IDLE (0 | (I2SR_IBB << 8)) +#define ST_BUS_BUSY (I2SR_IBB | (I2SR_IBB << 8)) +#define ST_IIF (I2SR_IIF | (I2SR_IIF << 8)) - int timeout = I2C_MAX_TIMEOUT; - - while (timeout--) { - temp = readb(&i2c_regs->i2sr); - - if (for_busy && (temp & I2SR_IBB)) - return 0; - if (!for_busy && !(temp & I2SR_IBB)) - return 0; - - udelay(1); +static int wait_for_sr_state(struct mxc_i2c_regs *i2c_regs, unsigned state) +{ + unsigned sr; + ulong elapsed; + ulong start_time = get_timer(0); + for (;;) { + sr = readb(&i2c_regs->i2sr); + if (sr & I2SR_IAL) { + writeb(sr & ~I2SR_IAL, &i2c_regs->i2sr); + printf("%s: Arbitration lost sr=%x cr=%x state=%x\n", + __func__, sr, readb(&i2c_regs->i2cr), state); + return -ERESTART; + } + if ((sr & (state >> 8)) == (unsigned char)state) + return sr; + WATCHDOG_RESET(); + elapsed = get_timer(start_time); + if (elapsed > (CONFIG_SYS_HZ / 10)) /* .1 seconds */ + break; } - - return 1; + printf("%s: failed sr=%x cr=%x state=%x\n", __func__, + sr, readb(&i2c_regs->i2cr), state); + return -ETIMEDOUT; } -/* - * Wait for transaction to complete - */ -int i2c_imx_trx_complete(void) +static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - int timeout = I2C_MAX_TIMEOUT; - - while (timeout--) { - if (readb(&i2c_regs->i2sr) & I2SR_IIF) { - writeb(0, &i2c_regs->i2sr); - return 0; - } - - udelay(1); - } + int ret; - return 1; + writeb(0, &i2c_regs->i2sr); + writeb(byte, &i2c_regs->i2dr); + ret = wait_for_sr_state(i2c_regs, ST_IIF); + if (ret < 0) + return ret; + if (ret & I2SR_RX_NO_AK) + return -ENODEV; + return 0; } /* - * Check if the transaction was ACKed + * Stop I2C transaction */ -int i2c_imx_acked(void) +static void i2c_imx_stop(struct mxc_i2c_regs *i2c_regs) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; + int ret; + unsigned int temp = readb(&i2c_regs->i2cr); - return readb(&i2c_regs->i2sr) & I2SR_RX_NO_AK; + temp &= ~(I2CR_MSTA | I2CR_MTX); + writeb(temp, &i2c_regs->i2cr); + ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE); + if (ret < 0) + printf("%s:trigger stop failed\n", __func__); } /* - * Start the controller + * Send start signal, chip address and + * write register address */ -int i2c_imx_start(void) +static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs, + uchar chip, uint addr, int alen) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - unsigned int temp = 0; - int result; + unsigned int temp; + int ret; /* Enable I2C controller */ + if (!(readb(&i2c_regs->i2cr) & I2CR_IEN)) { + writeb(I2CR_IEN, &i2c_regs->i2cr); + /* Wait for controller to be stable */ + udelay(50); + } + if (readb(&i2c_regs->iadr) == (chip << 1)) + writeb((chip << 1) ^ 2, &i2c_regs->iadr); writeb(0, &i2c_regs->i2sr); - writeb(I2CR_IEN, &i2c_regs->i2cr); - - /* Wait controller to be stable */ - udelay(50); + ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE); + if (ret < 0) + return ret; /* Start I2C transaction */ temp = readb(&i2c_regs->i2cr); temp |= I2CR_MSTA; writeb(temp, &i2c_regs->i2cr); - result = i2c_imx_bus_busy(1); - if (result) - return result; + ret = wait_for_sr_state(i2c_regs, ST_BUS_BUSY); + if (ret < 0) + return ret; temp |= I2CR_MTX | I2CR_TX_NO_AK; writeb(temp, &i2c_regs->i2cr); - return 0; -} - -/* - * Stop the controller - */ -void i2c_imx_stop(void) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - unsigned int temp = 0; - - /* Stop I2C transaction */ - temp = readb(&i2c_regs->i2cr); - temp |= ~(I2CR_MSTA | I2CR_MTX); - writeb(temp, &i2c_regs->i2cr); - - i2c_imx_bus_busy(0); - - /* Disable I2C controller */ - writeb(0, &i2c_regs->i2cr); -} - -/* - * Set chip address and access mode - * - * read = 1: READ access - * read = 0: WRITE access - */ -int i2c_imx_set_chip_addr(uchar chip, int read) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - int ret; - - writeb((chip << 1) | read, &i2c_regs->i2dr); - - ret = i2c_imx_trx_complete(); - if (ret) - return ret; - - ret = i2c_imx_acked(); - if (ret) + /* write slave address */ + ret = tx_byte(i2c_regs, chip << 1); + if (ret < 0) return ret; - return ret; -} - -/* - * Write register address - */ -int i2c_imx_set_reg_addr(uint addr, int alen) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - int ret = 0; - while (alen--) { - writeb((addr >> (alen * 8)) & 0xff, &i2c_regs->i2dr); - - ret = i2c_imx_trx_complete(); - if (ret) - break; - - ret = i2c_imx_acked(); - if (ret) - break; + ret = tx_byte(i2c_regs, (addr >> (alen * 8)) & 0xff); + if (ret < 0) + return ret; } - - return ret; + return 0; } -/* - * Try if a chip add given address responds (probe the chip) - */ -int i2c_probe(uchar chip) +static int i2c_idle_bus(void *base); + +static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, + uchar chip, uint addr, int alen) { + int retry; int ret; + for (retry = 0; retry < 3; retry++) { + ret = i2c_init_transfer_(i2c_regs, chip, addr, alen); + if (ret >= 0) + return 0; + i2c_imx_stop(i2c_regs); + if (ret == -ENODEV) + return ret; - ret = i2c_imx_start(); - if (ret) - return ret; - - ret = i2c_imx_set_chip_addr(chip, 0); - if (ret) - return ret; - - i2c_imx_stop(); - + printf("%s: failed for chip 0x%x retry=%d\n", __func__, chip, + retry); + if (ret != -ERESTART) + writeb(0, &i2c_regs->i2cr); /* Disable controller */ + udelay(100); + if (i2c_idle_bus(i2c_regs) < 0) + break; + } + printf("%s: give up i2c_regs=%p\n", __func__, i2c_regs); return ret; } /* * Read data from I2C device */ -int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) +int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf, + int len) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; int ret; unsigned int temp; int i; + struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; - ret = i2c_imx_start(); - if (ret) - return ret; - - /* write slave address */ - ret = i2c_imx_set_chip_addr(chip, 0); - if (ret) - return ret; - - ret = i2c_imx_set_reg_addr(addr, alen); - if (ret) + ret = i2c_init_transfer(i2c_regs, chip, addr, alen); + if (ret < 0) return ret; temp = readb(&i2c_regs->i2cr); temp |= I2CR_RSTA; writeb(temp, &i2c_regs->i2cr); - ret = i2c_imx_set_chip_addr(chip, 1); - if (ret) + ret = tx_byte(i2c_regs, (chip << 1) | 1); + if (ret < 0) { + i2c_imx_stop(i2c_regs); return ret; + } /* setup bus to read data */ temp = readb(&i2c_regs->i2cr); @@ -377,73 +309,192 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) if (len == 1) temp |= I2CR_TX_NO_AK; writeb(temp, &i2c_regs->i2cr); - readb(&i2c_regs->i2dr); + writeb(0, &i2c_regs->i2sr); + readb(&i2c_regs->i2dr); /* dummy read to clear ICF */ /* read data */ for (i = 0; i < len; i++) { - ret = i2c_imx_trx_complete(); - if (ret) + ret = wait_for_sr_state(i2c_regs, ST_IIF); + if (ret < 0) { + i2c_imx_stop(i2c_regs); return ret; + } /* * It must generate STOP before read I2DR to prevent * controller from generating another clock cycle */ if (i == (len - 1)) { - temp = readb(&i2c_regs->i2cr); - temp &= ~(I2CR_MSTA | I2CR_MTX); - writeb(temp, &i2c_regs->i2cr); - i2c_imx_bus_busy(0); + i2c_imx_stop(i2c_regs); } else if (i == (len - 2)) { temp = readb(&i2c_regs->i2cr); temp |= I2CR_TX_NO_AK; writeb(temp, &i2c_regs->i2cr); } - + writeb(0, &i2c_regs->i2sr); buf[i] = readb(&i2c_regs->i2dr); } - - i2c_imx_stop(); - - return ret; + i2c_imx_stop(i2c_regs); + return 0; } /* * Write data to I2C device */ -int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) +int bus_i2c_write(void *base, uchar chip, uint addr, int alen, + const uchar *buf, int len) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; int ret; int i; + struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; - ret = i2c_imx_start(); - if (ret) + ret = i2c_init_transfer(i2c_regs, chip, addr, alen); + if (ret < 0) return ret; - /* write slave address */ - ret = i2c_imx_set_chip_addr(chip, 0); - if (ret) - return ret; + for (i = 0; i < len; i++) { + ret = tx_byte(i2c_regs, buf[i]); + if (ret < 0) + break; + } + i2c_imx_stop(i2c_regs); + return ret; +} + +struct i2c_parms { + void *base; + void *idle_bus_data; + int (*idle_bus_fn)(void *p); +}; + +struct sram_data { + unsigned curr_i2c_bus; + struct i2c_parms i2c_data[3]; +}; - ret = i2c_imx_set_reg_addr(addr, alen); +/* + * For SPL boot some boards need i2c before SDRAM is initialized so force + * variables to live in SRAM + */ +static struct sram_data __attribute__((section(".data"))) srdata; + +void *get_base(void) +{ +#ifdef CONFIG_SYS_I2C_BASE +#ifdef CONFIG_I2C_MULTI_BUS + void *ret = srdata.i2c_data[srdata.curr_i2c_bus].base; if (ret) return ret; +#endif + return (void *)CONFIG_SYS_I2C_BASE; +#elif defined(CONFIG_I2C_MULTI_BUS) + return srdata.i2c_data[srdata.curr_i2c_bus].base; +#else + return srdata.i2c_data[0].base; +#endif +} - for (i = 0; i < len; i++) { - writeb(buf[i], &i2c_regs->i2dr); +static struct i2c_parms *i2c_get_parms(void *base) +{ + int i = 0; + struct i2c_parms *p = srdata.i2c_data; + while (i < ARRAY_SIZE(srdata.i2c_data)) { + if (p->base == base) + return p; + p++; + i++; + } + printf("Invalid I2C base: %p\n", base); + return NULL; +} - ret = i2c_imx_trx_complete(); - if (ret) - return ret; +static int i2c_idle_bus(void *base) +{ + struct i2c_parms *p = i2c_get_parms(base); + if (p && p->idle_bus_fn) + return p->idle_bus_fn(p->idle_bus_data); + return 0; +} - ret = i2c_imx_acked(); - if (ret) - return ret; +#ifdef CONFIG_I2C_MULTI_BUS +unsigned int i2c_get_bus_num(void) +{ + return srdata.curr_i2c_bus; +} + +int i2c_set_bus_num(unsigned bus_idx) +{ + if (bus_idx >= ARRAY_SIZE(srdata.i2c_data)) + return -1; + if (!srdata.i2c_data[bus_idx].base) + return -1; + srdata.curr_i2c_bus = bus_idx; + return 0; +} +#endif + +int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + return bus_i2c_read(get_base(), chip, addr, alen, buf, len); +} + +int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + return bus_i2c_write(get_base(), chip, addr, alen, buf, len); +} + +/* + * Test if a chip at a given address responds (probe the chip) + */ +int i2c_probe(uchar chip) +{ + return bus_i2c_write(get_base(), chip, 0, 0, NULL, 0); +} + +void bus_i2c_init(void *base, int speed, int unused, + int (*idle_bus_fn)(void *p), void *idle_bus_data) +{ + int i = 0; + struct i2c_parms *p = srdata.i2c_data; + if (!base) + return; + for (;;) { + if (!p->base || (p->base == base)) { + p->base = base; + if (idle_bus_fn) { + p->idle_bus_fn = idle_bus_fn; + p->idle_bus_data = idle_bus_data; + } + break; + } + p++; + i++; + if (i >= ARRAY_SIZE(srdata.i2c_data)) + return; } + bus_i2c_set_bus_speed(base, speed); +} + +/* + * Init I2C Bus + */ +void i2c_init(int speed, int unused) +{ + bus_i2c_init(get_base(), speed, unused, NULL, NULL); +} - i2c_imx_stop(); +/* + * Set I2C Speed + */ +int i2c_set_bus_speed(unsigned int speed) +{ + return bus_i2c_set_bus_speed(get_base(), speed); +} - return ret; +/* + * Get I2C Speed + */ +unsigned int i2c_get_bus_speed(void) +{ + return bus_i2c_get_bus_speed(get_base()); } -#endif /* CONFIG_HARD_I2C */ diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index ba6f39b..9bc4c7f 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -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,102 @@ 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); +} + +/* + * 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 = s3c24x0_get_base_i2c(); + struct s3c24x0_i2c *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; + i2c = get_base_i2c(); + /* wait for some time to give previous transfer a chance to finish */ i = I2C_TIMEOUT * 1000; - while ((readl(&i2c->iicstat) && I2CSTAT_BSY) && (i > 0)) { + 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); @@ -170,27 +248,8 @@ void i2c_init(int speed, int slaveadd) writel(old_gpecon, &gpio->pgcon); #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); - +#endif /* #ifndef CONFIG_EXYNOS5 */ + i2c_ch_init(i2c, speed, slaveadd); } /* @@ -200,19 +259,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 +285,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 +297,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 +316,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 +338,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 +352,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 +376,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 +398,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 +423,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 +460,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 +472,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 +502,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 */ diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h new file mode 100644 index 0000000..2dd4b06 --- /dev/null +++ b/drivers/i2c/s3c24x0_i2c.h @@ -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 */ diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index 42c77fe..0280242 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -22,7 +22,7 @@ #include <asm/arch/imx-regs.h> #include <asm/arch/clock.h> #include <asm/arch/mx6x_pins.h> -#include <asm/arch/iomux-v3.h> +#include <asm/imx-common/iomux-v3.h> #include "ehci.h" #include "ehci-core.h" |