Message ID | 1303245762-18077-3-git-send-email-john.rigby@linaro.org |
---|---|
State | Accepted |
Commit | d3d6427a3f62bd6a652e1b90bd4ecec8f8b651ec |
Headers | show |
On Tue, Apr 19, 2011 at 2:42 PM, John Rigby <john.rigby@linaro.org> wrote: > From: Michael Brandt <michael.brandt@stericsson.com> > > Signed-off-by: John Rigby <john.rigby@linaro.org> > CC: Heiko Schocher <hs@denx.de> > --- > v2: Incorporate suggestions from Heiko Schocher > v3: Fix line length problem reported by Heiko Schocher > v4: No changes just rebased to latest and included for completeness > drivers/i2c/Makefile | 1 + > drivers/i2c/u8500_i2c.c | 613 +++++++++++++++++++++++++++++++++++++++++++++++ > drivers/i2c/u8500_i2c.h | 194 +++++++++++++++ > 3 files changed, 808 insertions(+), 0 deletions(-) > create mode 100644 drivers/i2c/u8500_i2c.c > create mode 100644 drivers/i2c/u8500_i2c.h > > diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile > index 052fe36..43507fc 100644 > --- a/drivers/i2c/Makefile > +++ b/drivers/i2c/Makefile > @@ -40,6 +40,7 @@ COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o > COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o > COBJS-$(CONFIG_SPEAR_I2C) += spr_i2c.o > COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o > +COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o > > COBJS := $(COBJS-y) > SRCS := $(COBJS:.o=.c) > diff --git a/drivers/i2c/u8500_i2c.c b/drivers/i2c/u8500_i2c.c > new file mode 100644 > index 0000000..ea8a71d > --- /dev/null > +++ b/drivers/i2c/u8500_i2c.c > @@ -0,0 +1,613 @@ > +/* > + * Copyright (C) ST-Ericsson SA 2010 > + * > + * Basic U-Boot I2C interface for STn8500/DB8500 > + * Author: Michael Brandt <Michael.Brandt@stericsson.com> for ST-Ericsson > + * > + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. > + */ > + > +/* > + * Only 7-bit I2C device addresses are supported. > + */ > + > +#include <common.h> > +#include <i2c.h> > + > +#include "u8500_i2c.h" > +#include <asm/io.h> > +#include <asm/arch/clock.h> > + > +#define U8500_I2C_ENDAD_COUNTER (CONFIG_SYS_HZ/100) /* I2C bus timeout */ > +#define U8500_I2C_FIFO_FLUSH_COUNTER 500000 /* flush "timeout" */ > +#define U8500_I2C_SCL_FREQ 100000 /* I2C bus clock freq */ > +#define U8500_I2C_INPUT_FREQ 48000000 /* Input clock freq */ > +#define TX_FIFO_THRESHOLD 0x4 > +#define RX_FIFO_THRESHOLD 0x4 > +#define SLAVE_SETUP_TIME 14 /* Slave data setup time, 250ns for 48MHz i2c_clk */ > + > +#define WRITE_FIELD(var, mask, shift, value) \ > + (var = ((var & ~(mask)) | ((value) << (shift)))) > + > +static unsigned int bus_initialized[CONFIG_SYS_U8500_I2C_BUS_MAX]; > +static unsigned int i2c_bus_num; > +static unsigned int i2c_bus_speed[] = { > + CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED, > + CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED > +}; > +static struct u8500_i2c_regs *i2c_dev[] = { > + (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C0_BASE, > + (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C1_BASE, > + (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C2_BASE, > + (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C3_BASE, > +}; > + > +static struct { > + int periph; > + int pcken; > + int kcken; > +} i2c_clock_bits[] = { > + {3, 3, 3}, /* I2C0 */ > + {1, 2, 2}, /* I2C1 */ > + {1, 6, 6}, /* I2C2 */ > + {2, 0, 0}, /* I2C3 */ > +}; > + > +static void i2c_set_bit(void *reg, u32 mask) > +{ > + writel(readl(reg) | mask, reg); > +} > + > +static void i2c_clr_bit(void *reg, u32 mask) > +{ > + writel(readl(reg) & ~mask, reg); > +} > + > +static void i2c_write_field(void *reg, u32 mask, uint shift, u32 value) > +{ > + writel((readl(reg) & ~mask) | (value << shift), reg); > +} > + > +static int __i2c_set_bus_speed(unsigned int speed) > +{ > + u32 value; > + struct u8500_i2c_regs *i2c_regs; > + > + i2c_regs = i2c_dev[i2c_bus_num]; > + > + /* Select standard (100 kbps) speed mode */ > + i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_SM, > + U8500_I2C_CR_SHIFT_SM, 0x0); > + > + /* > + * Set the Baud Rate Counter 2 value > + * Baud rate (standard) = fi2cclk / ( (BRCNT2 x 2) + Foncycle ) > + * Foncycle = 0 (no digital filtering) > + */ > + value = (u32) (U8500_I2C_INPUT_FREQ / (speed * 2)); > + i2c_write_field(&i2c_regs->brcr, U8500_I2C_BRCR_BRCNT2, > + U8500_I2C_BRCR_SHIFT_BRCNT2, value); > + > + /* ensure that BRCNT value is zero */ > + i2c_write_field(&i2c_regs->brcr, U8500_I2C_BRCR_BRCNT1, > + U8500_I2C_BRCR_SHIFT_BRCNT1, 0); > + > + return U8500_I2C_INPUT_FREQ/(value * 2); > +} > + > +/* > + * i2c_init - initialize the i2c bus > + * > + * speed: bus speed (in HZ) > + * slaveaddr: address of device in slave mode > + * > + * Slave mode is not implemented. > + */ > +void i2c_init(int speed, int slaveaddr) > +{ > + struct u8500_i2c_regs *i2c_regs; > + > + debug("i2c_init bus %d, speed %d\n", i2c_bus_num, speed); > + > + u8500_clock_enable(i2c_clock_bits[i2c_bus_num].periph, > + i2c_clock_bits[i2c_bus_num].pcken, > + i2c_clock_bits[i2c_bus_num].kcken); > + > + i2c_regs = i2c_dev[i2c_bus_num]; > + > + /* Disable the controller */ > + i2c_clr_bit(&i2c_regs->cr, U8500_I2C_CR_PE); > + > + /* Clear registers */ > + writel(0, &i2c_regs->cr); > + writel(0, &i2c_regs->scr); > + writel(0, &i2c_regs->hsmcr); > + writel(0, &i2c_regs->tftr); > + writel(0, &i2c_regs->rftr); > + writel(0, &i2c_regs->dmar); > + > + i2c_bus_speed[i2c_bus_num] = __i2c_set_bus_speed(speed); > + > + /* > + * Set our own address. > + * Set slave address mode to 7 bit addressing mode > + */ > + i2c_clr_bit(&i2c_regs->cr, U8500_I2C_CR_SAM); > + i2c_write_field(&i2c_regs->scr, U8500_I2C_SCR_ADDR, > + U8500_I2C_SCR_SHIFT_ADDR, slaveaddr); > + /* Slave Data Set up Time */ > + i2c_write_field(&i2c_regs->scr, U8500_I2C_SCR_DATA_SETUP_TIME, > + U8500_I2C_SCR_SHIFT_DATA_SETUP_TIME, SLAVE_SETUP_TIME); > + > + /* Disable the DMA sync logic */ > + i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_DMA_SLE, > + U8500_I2C_CR_SHIFT_DMA_SLE, 0); > + > + /* Disable interrupts */ > + writel(0, &i2c_regs->imscr); > + > + /* Configure bus master mode */ > + i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_OM, U8500_I2C_CR_SHIFT_OM, > + U8500_I2C_BUS_MASTER_MODE); > + /* Set FIFO threshold values */ > + writel(TX_FIFO_THRESHOLD, &i2c_regs->tftr); > + writel(RX_FIFO_THRESHOLD, &i2c_regs->rftr); > + > + /* Enable the I2C Controller */ > + i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_PE); > + > + bus_initialized[i2c_bus_num] = 1; > +} > + > + > +/* > + * loop_till_bit_clear - polls on a bit till it clears > + * ioreg: register where you want to check status > + * mask: bit mask for the bit you wish to check > + * timeout: timeout in ticks/s > + */ > +static int loop_till_bit_clear(void *io_reg, u32 mask, unsigned long timeout) > +{ > + unsigned long timebase = get_timer(0); > + > + do { > + if ((readl(io_reg) & mask) == 0x0UL) > + return 0; > + } while (get_timer(timebase) < timeout); > + > + debug("loop_till_bit_clear timed out\n"); > + return -1; > +} > + > +/* > + * loop_till_bit_set - polls on a bit till it is set. > + * ioreg: register where you want to check status > + * mask: bit mask for the bit you wish to check > + * timeout: timeout in ticks/s > + */ > +static int loop_till_bit_set(void *io_reg, u32 mask, unsigned long timeout) > +{ > + unsigned long timebase = get_timer(0); > + > + do { > + if ((readl(io_reg) & mask) != 0x0UL) > + return 0; > + } while (get_timer(timebase) < timeout); > + > + debug("loop_till_bit_set timed out\n"); > + return -1; > +} > + > +/* > + * flush_fifo - flush the I2C TX and RX FIFOs > + */ > +static void flush_fifo(struct u8500_i2c_regs *i2c_regs) > +{ > + int counter = U8500_I2C_FIFO_FLUSH_COUNTER; > + > + /* Flush Tx FIFO */ > + i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_FTX); > + /* Flush Rx FIFO */ > + i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_FRX); > + while (counter--) { > + if (!(readl(&i2c_regs->cr) & > + (U8500_I2C_CR_FTX | U8500_I2C_CR_FRX))) > + break; > + } > + return; > +} > + > +#ifdef DEBUG > +static void print_abort_reason(struct u8500_i2c_regs *i2c_regs) > +{ > + int cause; > + > + printf("abort: risr %08x, sr %08x\n", i2c_regs->risr, i2c_regs->sr); > + cause = (readl(&i2c_regs->sr) & U8500_I2C_SR_CAUSE) >> > + U8500_I2C_SR_SHIFT_CAUSE; > + switch (cause) { > + case U8500_I2C_NACK_ADDR: > + printf("No Ack received after Slave Address xmission\n"); > + break; > + case U8500_I2C_NACK_DATA: > + printf("Valid for MASTER_WRITE: No Ack received " > + "during data phase\n"); > + break; > + case U8500_I2C_ACK_MCODE: > + printf("Master recv ack after xmission of master code" > + "in hs mode\n"); > + break; > + case U8500_I2C_ARB_LOST: > + printf("Master Lost arbitration\n"); > + break; > + case U8500_I2C_BERR_START: > + printf("Slave restarts\n"); > + break; > + case U8500_I2C_BERR_STOP: > + printf("Slave reset\n"); > + break; > + case U8500_I2C_OVFL: > + printf("Overflow\n"); > + break; > + default: > + printf("Unknown error type\n"); > + } > +} > +#endif > + > +/* > + * i2c_abort - called when a I2C transaction failed > + */ > +static void i2c_abort(struct u8500_i2c_regs *i2c_regs) > +{ > +#ifdef DEBUG > + print_abort_reason(i2c_regs); > +#endif > + /* flush RX and TX fifos */ > + flush_fifo(i2c_regs); > + > + /* Acknowledge the Master Transaction Done */ > + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); > + > + /* Acknowledge the Master Transaction Done Without Stop */ > + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); > + > + i2c_init(i2c_bus_speed[i2c_bus_num], CONFIG_SYS_I2C_SLAVE); > +} > + > +/* > + * write addr, alias index, to I2C bus. > + */ > +static int i2c_write_addr(struct u8500_i2c_regs *i2c_regs, uint addr, int alen) > +{ > + while (alen--) { > + /* Wait until the Tx Fifo is not full */ > + if (loop_till_bit_clear((void *)&i2c_regs->risr, > + U8500_I2C_INT_TXFF, > + U8500_I2C_ENDAD_COUNTER)) { > + i2c_abort(i2c_regs); > + return -1; > + } > + > + /* MSB first */ > + writeb((addr >> (alen * 8)) & 0xff, &i2c_regs->tfr); > + } > + > + return 0; > +} > + > +/* > + * Internal simplified read function: > + * i2c_regs: Pointer to I2C registers for current bus > + * chip: I2C chip address, range 0..127 > + * addr: Memory (register) address within the chip > + * alen: Number of bytes to use for addr (typically 1, 2 for larger > + * memories, 0 for register type devices with only one register) > + * value: Where to put the data > + * > + * Returns: 0 on success, not 0 on failure > + */ > +static int i2c_read_byte(struct u8500_i2c_regs *i2c_regs, uchar chip, > + uint addr, int alen, uchar *value) > +{ > + u32 mcr = 0; > + > + /* Set the address mode to 7 bit */ > + WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); > + > + /* Store the slave address in the master control register */ > + WRITE_FIELD(mcr, U8500_I2C_MCR_A7, U8500_I2C_MCR_SHIFT_A7, chip); > + > + if (alen != 0) { > + /* Master write operation */ > + mcr &= ~(U8500_I2C_MCR_OP); > + > + /* Configure the Frame length to one byte */ > + WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, > + U8500_I2C_MCR_SHIFT_LENGTH, 1); > + > + /* Repeated start, no stop */ > + mcr &= ~(U8500_I2C_MCR_STOP); > + > + /* Write Master Control Register */ > + writel(mcr, &i2c_regs->mcr); > + > + /* send addr/index */ > + if (i2c_write_addr(i2c_regs, addr, alen) != 0) > + return -1; > + > + /* Check for the Master Transaction Done Without Stop */ > + if (loop_till_bit_set((void *)&i2c_regs->risr, > + U8500_I2C_INT_MTDWS, > + U8500_I2C_ENDAD_COUNTER)) { > + return -1; > + } > + > + /* Acknowledge the Master Transaction Done Without Stop */ > + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); > + } > + > + /* Master control configuration for read operation */ > + mcr |= U8500_I2C_MCR_OP; > + > + /* Configure the STOP condition, we read only one byte */ > + mcr |= U8500_I2C_MCR_STOP; > + > + /* Set the frame length to one byte, we support only 1 byte reads */ > + WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, 1); > + > + i2c_write_field(&i2c_regs->mcr, U8500_I2C_MCR_LENGTH_STOP_OP, > + U8500_I2C_MCR_SHIFT_LENGTH_STOP_OP, mcr); > + > + /* > + * receive_data_polling > + */ > + > + /* Wait until the Rx FIFO is not empty */ > + if (loop_till_bit_clear((void *)&i2c_regs->risr, > + U8500_I2C_INT_RXFE, > + U8500_I2C_ENDAD_COUNTER)) > + return -1; > + > + /* Read the data byte from Rx FIFO */ > + *value = readb(&i2c_regs->rfr); > + > + /* Wait until the work is done */ > + if (loop_till_bit_set((void *)&i2c_regs->risr, U8500_I2C_INT_MTD, > + U8500_I2C_ENDAD_COUNTER)) > + return -1; > + > + /* Acknowledge the Master Transaction Done */ > + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); > + > + /* If MTD is set, Master Transaction Done Without Stop is set too */ > + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); > + > + return 0; > +} > + > +/* > + * Internal simplified write function: > + * i2c_regs: Pointer to I2C registers for current bus > + * chip: I2C chip address, range 0..127 > + * addr: Memory (register) address within the chip > + * alen: Number of bytes to use for addr (typically 1, 2 for larger > + * memories, 0 for register type devices with only one register) > + * data: Where to read the data > + * len: How many bytes to write > + * > + * Returns: 0 on success, not 0 on failure > + */ > +static int __i2c_write(struct u8500_i2c_regs *i2c_regs, u8 chip, uint addr, > + int alen, u8 *data, int len) > +{ > + int i; > + u32 mcr = 0; > + > + /* Set the address mode to 7 bit */ > + WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); > + > + /* Store the slave address in the master control register */ > + WRITE_FIELD(mcr, U8500_I2C_MCR_A7, U8500_I2C_MCR_SHIFT_A7, chip); > + > + /* Write operation */ > + mcr &= ~(U8500_I2C_MCR_OP); > + > + /* Current transaction is terminated by STOP condition */ > + mcr |= U8500_I2C_MCR_STOP; > + > + /* Frame length: addr byte + len */ > + WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, > + (alen + len)); > + > + /* Write MCR register */ > + writel(mcr, &i2c_regs->mcr); > + > + if (i2c_write_addr(i2c_regs, addr, alen) != 0) > + return -1; > + > + for (i = 0; i < len; i++) { > + /* Wait until the Tx FIFO is not full */ > + if (loop_till_bit_clear((void *)&i2c_regs->risr, > + U8500_I2C_INT_TXFF, > + U8500_I2C_ENDAD_COUNTER)) > + return -1; > + > + /* it is a 32 bit register with upper 24 reserved R/O */ > + writeb(data[i], &i2c_regs->tfr); > + } > + > + /* Check for Master Transaction Done */ > + if (loop_till_bit_set((void *)&i2c_regs->risr, > + U8500_I2C_INT_MTD, > + U8500_I2C_ENDAD_COUNTER)) { > + printf("i2c_write_byte error2: risr %08x\n", > + i2c_regs->risr); > + return -1; > + } > + > + /* Acknowledge Master Transaction Done */ > + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); > + > + /* Acknowledge Master Transaction Done Without Stop */ > + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); > + > + return 0; > +} > + > +/* > + * Probe the given I2C chip address. Returns 0 if a chip responded, > + * not 0 on failure. > + */ > +int i2c_probe(uchar chip) > +{ > + u32 mcr = 0; > + struct u8500_i2c_regs *i2c_regs; > + > + if (chip == CONFIG_SYS_I2C_SLAVE) > + return 1; > + > + i2c_regs = i2c_dev[i2c_bus_num]; > + > + /* Set the address mode to 7 bit */ > + WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); > + > + /* Store the slave address in the master control register */ > + WRITE_FIELD(mcr, U8500_I2C_MCR_A10, U8500_I2C_MCR_SHIFT_A7, chip); > + > + /* Read operation */ > + mcr |= U8500_I2C_MCR_OP; > + > + /* Set the frame length to one byte */ > + WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, 1); > + > + /* Current transaction is terminated by STOP condition */ > + mcr |= U8500_I2C_MCR_STOP; > + > + /* Write MCR register */ > + writel(mcr, &i2c_regs->mcr); > + > + /* Wait until the Rx Fifo is not empty */ > + if (loop_till_bit_clear((void *)&i2c_regs->risr, > + U8500_I2C_INT_RXFE, > + U8500_I2C_ENDAD_COUNTER)) { > + i2c_abort(i2c_regs); > + return -1; > + } > + > + flush_fifo(i2c_regs); > + > + /* Acknowledge the Master Transaction Done */ > + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); > + > + /* Acknowledge the Master Transaction Done Without Stop */ > + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); > + > + return 0; > +} > + > +/* > + * Read/Write interface: > + * chip: I2C chip address, range 0..127 > + * addr: Memory (register) address within the chip > + * alen: Number of bytes to use for addr (typically 1, 2 for larger > + * memories, 0 for register type devices with only one > + * register) > + * buffer: Where to read/write the data > + * len: How many bytes to read/write > + * > + * Returns: 0 on success, not 0 on failure > + */ > +int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) > +{ > + int i; > + int rc; > + struct u8500_i2c_regs *i2c_regs; > + > + if (alen > 2) { > + debug("I2C read: addr len %d not supported\n", alen); > + return 1; > + } > + > + i2c_regs = i2c_dev[i2c_bus_num]; > + > + for (i = 0; i < len; i++) { > + rc = i2c_read_byte(i2c_regs, chip, addr + i, alen, &buffer[i]); > + if (rc != 0) { > + debug("I2C read: I/O error: %d\n", rc); > + i2c_abort(i2c_regs); > + return rc; > + } > + } > + > + return 0; > +} > + > +int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) > +{ > + int rc; > + struct u8500_i2c_regs *i2c_regs; > + i2c_regs = i2c_dev[i2c_bus_num]; > + > + rc = __i2c_write(i2c_regs, chip, addr, alen, buffer, > + len); > + if (rc != 0) { > + debug("I2C write: I/O error\n"); > + i2c_abort(i2c_regs); > + return rc; > + } > + return 0; > +} > + > +int i2c_set_bus_num(unsigned int bus) > +{ > + if (bus > ARRAY_SIZE(i2c_dev) - 1) { > + debug("i2c_set_bus_num: only up to bus %d supported\n", > + ARRAY_SIZE(i2c_dev)-1); > + return -1; > + } > + > + i2c_bus_num = bus; > + > + if (!bus_initialized[i2c_bus_num]) > + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); > + > + return 0; > +} > + > +int i2c_set_bus_speed(unsigned int speed) > +{ > + > + if (speed > U8500_I2C_MAX_STANDARD_SCL) { > + debug("i2c_set_bus_speed: only up to %d supported\n", > + U8500_I2C_MAX_STANDARD_SCL); > + return -1; > + } > + > + /* sets as side effect i2c_bus_speed[i2c_bus_num] */ > + i2c_init(speed, CONFIG_SYS_I2C_SLAVE); > + > + return 0; > +} > + > +unsigned int i2c_get_bus_num(void) > +{ > + return i2c_bus_num; > +} > + > +unsigned int i2c_get_bus_speed(void) > +{ > + return i2c_bus_speed[i2c_bus_num]; > +} > diff --git a/drivers/i2c/u8500_i2c.h b/drivers/i2c/u8500_i2c.h > new file mode 100644 > index 0000000..91dbd3e > --- /dev/null > +++ b/drivers/i2c/u8500_i2c.h > @@ -0,0 +1,194 @@ > +/* > + * Copyright (C) ST-Ericsson SA 2009 > + * > + * 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 _U8500_I2C_H_ > +#define _U8500_I2C_H_ > + > +#include <asm/types.h> > +#include <asm/io.h> > +#include <asm/errno.h> > +#include <asm/arch/u8500.h> > + > +struct u8500_i2c_regs { > + u32 cr; /* Control Register 0x00 */ > + u32 scr; /* Slave Address Register 0x04 */ > + u32 hsmcr; /* HS Master code Register 0x08 */ > + u32 mcr; /* Master Control Register 0x0C */ > + u32 tfr; /* Transmit Fifo Register 0x10 */ > + u32 sr; /* Status Register 0x14 */ > + u32 rfr; /* Receiver Fifo Register 0x18 */ > + u32 tftr; /* Transmit Fifo Threshold Register 0x1C */ > + u32 rftr; /* Receiver Fifo Threshold Register 0x20 */ > + u32 dmar; /* DMA register 0x24 */ > + u32 brcr; /* Baud Rate Counter Register 0x28 */ > + u32 imscr; /* Interrupt Mask Set and Clear Register 0x2C */ > + u32 risr; /* Raw interrupt status register 0x30 */ > + u32 misr; /* Masked interrupt status register 0x34 */ > + u32 icr; /* Interrupt Set and Clear Register 0x38 */ > + u32 reserved_1[(0xFE0 - 0x3c) >> 2]; /* Reserved 0x03C to 0xFE0 */ > + u32 periph_id_0; /* peripheral ID 0 0xFE0 */ > + u32 periph_id_1; /* peripheral ID 1 0xFE4 */ > + u32 periph_id_2; /* peripheral ID 2 0xFE8 */ > + u32 periph_id_3; /* peripheral ID 3 0xFEC */ > + u32 cell_id_0; /* I2C cell ID 0 0xFF0 */ > + u32 cell_id_1; /* I2C cell ID 1 0xFF4 */ > + u32 cell_id_2; /* I2C cell ID 2 0xFF8 */ > + u32 cell_id_3; /* I2C cell ID 3 0xFFC */ > +}; > + > + > +/* Control Register */ > + > +/* Mask values for control register mask */ > +#define U8500_I2C_CR_PE 0x0001 /* Peripheral enable */ > +#define U8500_I2C_CR_OM 0x0006 /* Operation mode */ > +#define U8500_I2C_CR_SAM 0x0008 /* Slave Addressing mode */ > +#define U8500_I2C_CR_SM 0x0030 /* Speed mode */ > +#define U8500_I2C_CR_SGCM 0x0040 /* Slave General call mode */ > +#define U8500_I2C_CR_FTX 0x0080 /* Flush Transmit */ > +#define U8500_I2C_CR_FRX 0x0100 /* Flush Receive */ > +#define U8500_I2C_CR_DMA_TX_EN 0x0200 /* DMA TX Enable */ > +#define U8500_I2C_CR_DMA_RX_EN 0x0400 /* DMA Rx Enable */ > +#define U8500_I2C_CR_DMA_SLE 0x0800 /* DMA Synchronization Logic enable */ > +#define U8500_I2C_CR_LM 0x1000 /* Loop back mode */ > +#define U8500_I2C_CR_FON 0x6000 /* Filtering On */ > + > +/* shift valus for control register bit fields */ > +#define U8500_I2C_CR_SHIFT_PE 0 /* Peripheral enable */ > +#define U8500_I2C_CR_SHIFT_OM 1 /* Operation mode */ > +#define U8500_I2C_CR_SHIFT_SAM 3 /* Slave Addressing mode */ > +#define U8500_I2C_CR_SHIFT_SM 4 /* Speed mode */ > +#define U8500_I2C_CR_SHIFT_SGCM 6 /* Slave General call mode */ > +#define U8500_I2C_CR_SHIFT_FTX 7 /* Flush Transmit */ > +#define U8500_I2C_CR_SHIFT_FRX 8 /* Flush Receive */ > +#define U8500_I2C_CR_SHIFT_DMA_TX_EN 9 /* DMA TX Enable */ > +#define U8500_I2C_CR_SHIFT_DMA_RX_EN 10 /* DMA Rx Enable */ > +#define U8500_I2C_CR_SHIFT_DMA_SLE 11 /* DMA Synch Logic enable */ > +#define U8500_I2C_CR_SHIFT_LM 12 /* Loop back mode */ > +#define U8500_I2C_CR_SHIFT_FON 13 /* Filtering On */ > + > +/* bus operation modes */ > +#define U8500_I2C_BUS_SLAVE_MODE 0 > +#define U8500_I2C_BUS_MASTER_MODE 1 > +#define U8500_I2C_BUS_MASTER_SLAVE_MODE 2 > + > + > +/* Slave control register*/ > + > +/* Mask values slave control register */ > +#define U8500_I2C_SCR_ADDR 0x3FF > +#define U8500_I2C_SCR_DATA_SETUP_TIME 0xFFFF0000 > + > +/* Shift values for Slave control register */ > +#define U8500_I2C_SCR_SHIFT_ADDR 0 > +#define U8500_I2C_SCR_SHIFT_DATA_SETUP_TIME 16 > + > + > +/* Master Control Register */ > + > +/* Mask values for Master control register */ > +#define U8500_I2C_MCR_OP 0x00000001 /* Operation */ > +#define U8500_I2C_MCR_A7 0x000000FE /* LSB bits of Address */ > +#define U8500_I2C_MCR_EA10 0x00000700 /* Extended Address */ > +#define U8500_I2C_MCR_SB 0x00000800 /* Start byte procedure */ > +#define U8500_I2C_MCR_AM 0x00003000 /* Address type */ > +#define U8500_I2C_MCR_STOP 0x00004000 /* stop condition */ > +#define U8500_I2C_MCR_LENGTH 0x03FF8000 /* Frame length */ > +#define U8500_I2C_MCR_A10 0x000007FE /* Enable 10 bit address */ > +/* mask for length field,stop and operation */ > +#define U8500_I2C_MCR_LENGTH_STOP_OP 0x3FFC001 > + > +/* Shift values for Master control values */ > +#define U8500_I2C_MCR_SHIFT_OP 0 /* Operation */ > +#define U8500_I2C_MCR_SHIFT_A7 1 /* LSB bits of Address */ > +#define U8500_I2C_MCR_SHIFT_EA10 8 /* Extended Address */ > +#define U8500_I2C_MCR_SHIFT_SB 11 /* Start byte procedure */ > +#define U8500_I2C_MCR_SHIFT_AM 12 /* Address type */ > +#define U8500_I2C_MCR_SHIFT_STOP 14 /* stop condition */ > +#define U8500_I2C_MCR_SHIFT_LENGTH 15 /* Frame length */ > +#define U8500_I2C_MCR_SHIFT_A10 1 /* Enable 10 bit address */ > + > +#define U8500_I2C_MCR_SHIFT_LENGTH_STOP_OP 0 > + > + > +/* Status Register */ > + > +/* Mask values for Status register */ > +#define U8500_I2C_SR_OP 0x00000003 /* Operation */ > +#define U8500_I2C_SR_STATUS 0x0000000C /* Controller Status */ > +#define U8500_I2C_SR_CAUSE 0x00000070 /* Abort Cause */ > +#define U8500_I2C_SR_TYPE 0x00000180 /* Receive Type */ > +#define U8500_I2C_SR_LENGTH 0x000FF700 /* Transfer length */ > + > +/* Shift values for Status register */ > +#define U8500_I2C_SR_SHIFT_OP 0 /* Operation */ > +#define U8500_I2C_SR_SHIFT_STATUS 2 /* Controller Status */ > +#define U8500_I2C_SR_SHIFT_CAUSE 4 /* Abort Cause */ > +#define U8500_I2C_SR_SHIFT_TYPE 7 /* Receive Type */ > +#define U8500_I2C_SR_SHIFT_LENGTH 9 /* Transfer length */ > + > +/* abort cause */ > +#define U8500_I2C_NACK_ADDR 0 > +#define U8500_I2C_NACK_DATA 1 > +#define U8500_I2C_ACK_MCODE 2 > +#define U8500_I2C_ARB_LOST 3 > +#define U8500_I2C_BERR_START 4 > +#define U8500_I2C_BERR_STOP 5 > +#define U8500_I2C_OVFL 6 > + > + > +/* Baud rate counter registers */ > + > +/* Mask values for Baud rate counter register */ > +#define U8500_I2C_BRCR_BRCNT2 0xFFFF /* Baud Rate Cntr BRCR for HS */ > +#define U8500_I2C_BRCR_BRCNT1 0xFFFF0000 /* BRCR for Standard and Fast */ > + > +/* Shift values for the Baud rate counter register */ > +#define U8500_I2C_BRCR_SHIFT_BRCNT2 0 > +#define U8500_I2C_BRCR_SHIFT_BRCNT1 16 > + > + > +/* Interrupt Register */ > + > +/* Mask values for Interrupt registers */ > +#define U8500_I2C_INT_TXFE 0x00000001 /* Tx fifo empty */ > +#define U8500_I2C_INT_TXFNE 0x00000002 /* Tx Fifo nearly empty */ > +#define U8500_I2C_INT_TXFF 0x00000004 /* Tx Fifo Full */ > +#define U8500_I2C_INT_TXFOVR 0x00000008 /* Tx Fifo over run */ > +#define U8500_I2C_INT_RXFE 0x00000010 /* Rx Fifo Empty */ > +#define U8500_I2C_INT_RXFNF 0x00000020 /* Rx Fifo nearly empty */ > +#define U8500_I2C_INT_RXFF 0x00000040 /* Rx Fifo Full */ > +#define U8500_I2C_INT_RFSR 0x00010000 /* Read From slave request */ > +#define U8500_I2C_INT_RFSE 0x00020000 /* Read from slave empty */ > +#define U8500_I2C_INT_WTSR 0x00040000 /* Write to Slave request */ > +#define U8500_I2C_INT_MTD 0x00080000 /* Master Transcation Done*/ > +#define U8500_I2C_INT_STD 0x00100000 /* Slave Transaction Done */ > +#define U8500_I2C_INT_MAL 0x01000000 /* Master Arbitation Lost */ > +#define U8500_I2C_INT_BERR 0x02000000 /* Bus Error */ > +#define U8500_I2C_INT_MTDWS 0x10000000 /* Master Tran Done wo/ Stop */ > + > +/* Max clocks (Hz) */ > +#define U8500_I2C_MAX_STANDARD_SCL 100000 > +#define U8500_I2C_MAX_FAST_SCL 400000 > +#define U8500_I2C_MAX_HIGH_SPEED_SCL 3400000 > + > +#endif /* _U8500_I2C_H_ */ > -- > 1.7.1 > > Heiko, can you commit this to the i2c tree? Thanks, it is needed for the board patches in this series.
Hello John, John Rigby wrote: > On Tue, Apr 19, 2011 at 2:42 PM, John Rigby <john.rigby@linaro.org> wrote: >> From: Michael Brandt <michael.brandt@stericsson.com> >> >> Signed-off-by: John Rigby <john.rigby@linaro.org> >> CC: Heiko Schocher <hs@denx.de> >> --- >> v2: Incorporate suggestions from Heiko Schocher >> v3: Fix line length problem reported by Heiko Schocher >> v4: No changes just rebased to latest and included for completeness >> drivers/i2c/Makefile | 1 + >> drivers/i2c/u8500_i2c.c | 613 +++++++++++++++++++++++++++++++++++++++++++++++ >> drivers/i2c/u8500_i2c.h | 194 +++++++++++++++ >> 3 files changed, 808 insertions(+), 0 deletions(-) >> create mode 100644 drivers/i2c/u8500_i2c.c >> create mode 100644 drivers/i2c/u8500_i2c.h >> [...] > > Heiko, can you commit this to the i2c tree? Thanks, it is needed for > the board patches in this series. I gave this patch my Acked-by here: http://lists.denx.de/pipermail/u-boot/2011-April/090241.html so, it can picked up, from the custodian, who applies the whole series. I think Albert Aribaud will pick it up (Actually for some days on vacation). bye, Heiko
Hi John, Le 19/04/2011 22:42, John Rigby a écrit : > From: Michael Brandt<michael.brandt@stericsson.com> > > Signed-off-by: John Rigby<john.rigby@linaro.org> > CC: Heiko Schocher<hs@denx.de> > --- > v2: Incorporate suggestions from Heiko Schocher > v3: Fix line length problem reported by Heiko Schocher > v4: No changes just rebased to latest and included for completeness Applied to u-boot-arm/master, thanks. Amicalement,
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 052fe36..43507fc 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -40,6 +40,7 @@ COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o COBJS-$(CONFIG_SPEAR_I2C) += spr_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o +COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/i2c/u8500_i2c.c b/drivers/i2c/u8500_i2c.c new file mode 100644 index 0000000..ea8a71d --- /dev/null +++ b/drivers/i2c/u8500_i2c.c @@ -0,0 +1,613 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Basic U-Boot I2C interface for STn8500/DB8500 + * Author: Michael Brandt <Michael.Brandt@stericsson.com> for ST-Ericsson + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Only 7-bit I2C device addresses are supported. + */ + +#include <common.h> +#include <i2c.h> + +#include "u8500_i2c.h" +#include <asm/io.h> +#include <asm/arch/clock.h> + +#define U8500_I2C_ENDAD_COUNTER (CONFIG_SYS_HZ/100) /* I2C bus timeout */ +#define U8500_I2C_FIFO_FLUSH_COUNTER 500000 /* flush "timeout" */ +#define U8500_I2C_SCL_FREQ 100000 /* I2C bus clock freq */ +#define U8500_I2C_INPUT_FREQ 48000000 /* Input clock freq */ +#define TX_FIFO_THRESHOLD 0x4 +#define RX_FIFO_THRESHOLD 0x4 +#define SLAVE_SETUP_TIME 14 /* Slave data setup time, 250ns for 48MHz i2c_clk */ + +#define WRITE_FIELD(var, mask, shift, value) \ + (var = ((var & ~(mask)) | ((value) << (shift)))) + +static unsigned int bus_initialized[CONFIG_SYS_U8500_I2C_BUS_MAX]; +static unsigned int i2c_bus_num; +static unsigned int i2c_bus_speed[] = { + CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED, + CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED +}; +static struct u8500_i2c_regs *i2c_dev[] = { + (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C0_BASE, + (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C1_BASE, + (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C2_BASE, + (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C3_BASE, +}; + +static struct { + int periph; + int pcken; + int kcken; +} i2c_clock_bits[] = { + {3, 3, 3}, /* I2C0 */ + {1, 2, 2}, /* I2C1 */ + {1, 6, 6}, /* I2C2 */ + {2, 0, 0}, /* I2C3 */ +}; + +static void i2c_set_bit(void *reg, u32 mask) +{ + writel(readl(reg) | mask, reg); +} + +static void i2c_clr_bit(void *reg, u32 mask) +{ + writel(readl(reg) & ~mask, reg); +} + +static void i2c_write_field(void *reg, u32 mask, uint shift, u32 value) +{ + writel((readl(reg) & ~mask) | (value << shift), reg); +} + +static int __i2c_set_bus_speed(unsigned int speed) +{ + u32 value; + struct u8500_i2c_regs *i2c_regs; + + i2c_regs = i2c_dev[i2c_bus_num]; + + /* Select standard (100 kbps) speed mode */ + i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_SM, + U8500_I2C_CR_SHIFT_SM, 0x0); + + /* + * Set the Baud Rate Counter 2 value + * Baud rate (standard) = fi2cclk / ( (BRCNT2 x 2) + Foncycle ) + * Foncycle = 0 (no digital filtering) + */ + value = (u32) (U8500_I2C_INPUT_FREQ / (speed * 2)); + i2c_write_field(&i2c_regs->brcr, U8500_I2C_BRCR_BRCNT2, + U8500_I2C_BRCR_SHIFT_BRCNT2, value); + + /* ensure that BRCNT value is zero */ + i2c_write_field(&i2c_regs->brcr, U8500_I2C_BRCR_BRCNT1, + U8500_I2C_BRCR_SHIFT_BRCNT1, 0); + + return U8500_I2C_INPUT_FREQ/(value * 2); +} + +/* + * i2c_init - initialize the i2c bus + * + * speed: bus speed (in HZ) + * slaveaddr: address of device in slave mode + * + * Slave mode is not implemented. + */ +void i2c_init(int speed, int slaveaddr) +{ + struct u8500_i2c_regs *i2c_regs; + + debug("i2c_init bus %d, speed %d\n", i2c_bus_num, speed); + + u8500_clock_enable(i2c_clock_bits[i2c_bus_num].periph, + i2c_clock_bits[i2c_bus_num].pcken, + i2c_clock_bits[i2c_bus_num].kcken); + + i2c_regs = i2c_dev[i2c_bus_num]; + + /* Disable the controller */ + i2c_clr_bit(&i2c_regs->cr, U8500_I2C_CR_PE); + + /* Clear registers */ + writel(0, &i2c_regs->cr); + writel(0, &i2c_regs->scr); + writel(0, &i2c_regs->hsmcr); + writel(0, &i2c_regs->tftr); + writel(0, &i2c_regs->rftr); + writel(0, &i2c_regs->dmar); + + i2c_bus_speed[i2c_bus_num] = __i2c_set_bus_speed(speed); + + /* + * Set our own address. + * Set slave address mode to 7 bit addressing mode + */ + i2c_clr_bit(&i2c_regs->cr, U8500_I2C_CR_SAM); + i2c_write_field(&i2c_regs->scr, U8500_I2C_SCR_ADDR, + U8500_I2C_SCR_SHIFT_ADDR, slaveaddr); + /* Slave Data Set up Time */ + i2c_write_field(&i2c_regs->scr, U8500_I2C_SCR_DATA_SETUP_TIME, + U8500_I2C_SCR_SHIFT_DATA_SETUP_TIME, SLAVE_SETUP_TIME); + + /* Disable the DMA sync logic */ + i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_DMA_SLE, + U8500_I2C_CR_SHIFT_DMA_SLE, 0); + + /* Disable interrupts */ + writel(0, &i2c_regs->imscr); + + /* Configure bus master mode */ + i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_OM, U8500_I2C_CR_SHIFT_OM, + U8500_I2C_BUS_MASTER_MODE); + /* Set FIFO threshold values */ + writel(TX_FIFO_THRESHOLD, &i2c_regs->tftr); + writel(RX_FIFO_THRESHOLD, &i2c_regs->rftr); + + /* Enable the I2C Controller */ + i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_PE); + + bus_initialized[i2c_bus_num] = 1; +} + + +/* + * loop_till_bit_clear - polls on a bit till it clears + * ioreg: register where you want to check status + * mask: bit mask for the bit you wish to check + * timeout: timeout in ticks/s + */ +static int loop_till_bit_clear(void *io_reg, u32 mask, unsigned long timeout) +{ + unsigned long timebase = get_timer(0); + + do { + if ((readl(io_reg) & mask) == 0x0UL) + return 0; + } while (get_timer(timebase) < timeout); + + debug("loop_till_bit_clear timed out\n"); + return -1; +} + +/* + * loop_till_bit_set - polls on a bit till it is set. + * ioreg: register where you want to check status + * mask: bit mask for the bit you wish to check + * timeout: timeout in ticks/s + */ +static int loop_till_bit_set(void *io_reg, u32 mask, unsigned long timeout) +{ + unsigned long timebase = get_timer(0); + + do { + if ((readl(io_reg) & mask) != 0x0UL) + return 0; + } while (get_timer(timebase) < timeout); + + debug("loop_till_bit_set timed out\n"); + return -1; +} + +/* + * flush_fifo - flush the I2C TX and RX FIFOs + */ +static void flush_fifo(struct u8500_i2c_regs *i2c_regs) +{ + int counter = U8500_I2C_FIFO_FLUSH_COUNTER; + + /* Flush Tx FIFO */ + i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_FTX); + /* Flush Rx FIFO */ + i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_FRX); + while (counter--) { + if (!(readl(&i2c_regs->cr) & + (U8500_I2C_CR_FTX | U8500_I2C_CR_FRX))) + break; + } + return; +} + +#ifdef DEBUG +static void print_abort_reason(struct u8500_i2c_regs *i2c_regs) +{ + int cause; + + printf("abort: risr %08x, sr %08x\n", i2c_regs->risr, i2c_regs->sr); + cause = (readl(&i2c_regs->sr) & U8500_I2C_SR_CAUSE) >> + U8500_I2C_SR_SHIFT_CAUSE; + switch (cause) { + case U8500_I2C_NACK_ADDR: + printf("No Ack received after Slave Address xmission\n"); + break; + case U8500_I2C_NACK_DATA: + printf("Valid for MASTER_WRITE: No Ack received " + "during data phase\n"); + break; + case U8500_I2C_ACK_MCODE: + printf("Master recv ack after xmission of master code" + "in hs mode\n"); + break; + case U8500_I2C_ARB_LOST: + printf("Master Lost arbitration\n"); + break; + case U8500_I2C_BERR_START: + printf("Slave restarts\n"); + break; + case U8500_I2C_BERR_STOP: + printf("Slave reset\n"); + break; + case U8500_I2C_OVFL: + printf("Overflow\n"); + break; + default: + printf("Unknown error type\n"); + } +} +#endif + +/* + * i2c_abort - called when a I2C transaction failed + */ +static void i2c_abort(struct u8500_i2c_regs *i2c_regs) +{ +#ifdef DEBUG + print_abort_reason(i2c_regs); +#endif + /* flush RX and TX fifos */ + flush_fifo(i2c_regs); + + /* Acknowledge the Master Transaction Done */ + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); + + /* Acknowledge the Master Transaction Done Without Stop */ + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); + + i2c_init(i2c_bus_speed[i2c_bus_num], CONFIG_SYS_I2C_SLAVE); +} + +/* + * write addr, alias index, to I2C bus. + */ +static int i2c_write_addr(struct u8500_i2c_regs *i2c_regs, uint addr, int alen) +{ + while (alen--) { + /* Wait until the Tx Fifo is not full */ + if (loop_till_bit_clear((void *)&i2c_regs->risr, + U8500_I2C_INT_TXFF, + U8500_I2C_ENDAD_COUNTER)) { + i2c_abort(i2c_regs); + return -1; + } + + /* MSB first */ + writeb((addr >> (alen * 8)) & 0xff, &i2c_regs->tfr); + } + + return 0; +} + +/* + * Internal simplified read function: + * i2c_regs: Pointer to I2C registers for current bus + * chip: I2C chip address, range 0..127 + * addr: Memory (register) address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one register) + * value: Where to put the data + * + * Returns: 0 on success, not 0 on failure + */ +static int i2c_read_byte(struct u8500_i2c_regs *i2c_regs, uchar chip, + uint addr, int alen, uchar *value) +{ + u32 mcr = 0; + + /* Set the address mode to 7 bit */ + WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); + + /* Store the slave address in the master control register */ + WRITE_FIELD(mcr, U8500_I2C_MCR_A7, U8500_I2C_MCR_SHIFT_A7, chip); + + if (alen != 0) { + /* Master write operation */ + mcr &= ~(U8500_I2C_MCR_OP); + + /* Configure the Frame length to one byte */ + WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, + U8500_I2C_MCR_SHIFT_LENGTH, 1); + + /* Repeated start, no stop */ + mcr &= ~(U8500_I2C_MCR_STOP); + + /* Write Master Control Register */ + writel(mcr, &i2c_regs->mcr); + + /* send addr/index */ + if (i2c_write_addr(i2c_regs, addr, alen) != 0) + return -1; + + /* Check for the Master Transaction Done Without Stop */ + if (loop_till_bit_set((void *)&i2c_regs->risr, + U8500_I2C_INT_MTDWS, + U8500_I2C_ENDAD_COUNTER)) { + return -1; + } + + /* Acknowledge the Master Transaction Done Without Stop */ + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); + } + + /* Master control configuration for read operation */ + mcr |= U8500_I2C_MCR_OP; + + /* Configure the STOP condition, we read only one byte */ + mcr |= U8500_I2C_MCR_STOP; + + /* Set the frame length to one byte, we support only 1 byte reads */ + WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, 1); + + i2c_write_field(&i2c_regs->mcr, U8500_I2C_MCR_LENGTH_STOP_OP, + U8500_I2C_MCR_SHIFT_LENGTH_STOP_OP, mcr); + + /* + * receive_data_polling + */ + + /* Wait until the Rx FIFO is not empty */ + if (loop_till_bit_clear((void *)&i2c_regs->risr, + U8500_I2C_INT_RXFE, + U8500_I2C_ENDAD_COUNTER)) + return -1; + + /* Read the data byte from Rx FIFO */ + *value = readb(&i2c_regs->rfr); + + /* Wait until the work is done */ + if (loop_till_bit_set((void *)&i2c_regs->risr, U8500_I2C_INT_MTD, + U8500_I2C_ENDAD_COUNTER)) + return -1; + + /* Acknowledge the Master Transaction Done */ + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); + + /* If MTD is set, Master Transaction Done Without Stop is set too */ + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); + + return 0; +} + +/* + * Internal simplified write function: + * i2c_regs: Pointer to I2C registers for current bus + * chip: I2C chip address, range 0..127 + * addr: Memory (register) address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one register) + * data: Where to read the data + * len: How many bytes to write + * + * Returns: 0 on success, not 0 on failure + */ +static int __i2c_write(struct u8500_i2c_regs *i2c_regs, u8 chip, uint addr, + int alen, u8 *data, int len) +{ + int i; + u32 mcr = 0; + + /* Set the address mode to 7 bit */ + WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); + + /* Store the slave address in the master control register */ + WRITE_FIELD(mcr, U8500_I2C_MCR_A7, U8500_I2C_MCR_SHIFT_A7, chip); + + /* Write operation */ + mcr &= ~(U8500_I2C_MCR_OP); + + /* Current transaction is terminated by STOP condition */ + mcr |= U8500_I2C_MCR_STOP; + + /* Frame length: addr byte + len */ + WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, + (alen + len)); + + /* Write MCR register */ + writel(mcr, &i2c_regs->mcr); + + if (i2c_write_addr(i2c_regs, addr, alen) != 0) + return -1; + + for (i = 0; i < len; i++) { + /* Wait until the Tx FIFO is not full */ + if (loop_till_bit_clear((void *)&i2c_regs->risr, + U8500_I2C_INT_TXFF, + U8500_I2C_ENDAD_COUNTER)) + return -1; + + /* it is a 32 bit register with upper 24 reserved R/O */ + writeb(data[i], &i2c_regs->tfr); + } + + /* Check for Master Transaction Done */ + if (loop_till_bit_set((void *)&i2c_regs->risr, + U8500_I2C_INT_MTD, + U8500_I2C_ENDAD_COUNTER)) { + printf("i2c_write_byte error2: risr %08x\n", + i2c_regs->risr); + return -1; + } + + /* Acknowledge Master Transaction Done */ + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); + + /* Acknowledge Master Transaction Done Without Stop */ + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); + + return 0; +} + +/* + * Probe the given I2C chip address. Returns 0 if a chip responded, + * not 0 on failure. + */ +int i2c_probe(uchar chip) +{ + u32 mcr = 0; + struct u8500_i2c_regs *i2c_regs; + + if (chip == CONFIG_SYS_I2C_SLAVE) + return 1; + + i2c_regs = i2c_dev[i2c_bus_num]; + + /* Set the address mode to 7 bit */ + WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); + + /* Store the slave address in the master control register */ + WRITE_FIELD(mcr, U8500_I2C_MCR_A10, U8500_I2C_MCR_SHIFT_A7, chip); + + /* Read operation */ + mcr |= U8500_I2C_MCR_OP; + + /* Set the frame length to one byte */ + WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, 1); + + /* Current transaction is terminated by STOP condition */ + mcr |= U8500_I2C_MCR_STOP; + + /* Write MCR register */ + writel(mcr, &i2c_regs->mcr); + + /* Wait until the Rx Fifo is not empty */ + if (loop_till_bit_clear((void *)&i2c_regs->risr, + U8500_I2C_INT_RXFE, + U8500_I2C_ENDAD_COUNTER)) { + i2c_abort(i2c_regs); + return -1; + } + + flush_fifo(i2c_regs); + + /* Acknowledge the Master Transaction Done */ + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); + + /* Acknowledge the Master Transaction Done Without Stop */ + i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); + + return 0; +} + +/* + * Read/Write interface: + * chip: I2C chip address, range 0..127 + * addr: Memory (register) address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one + * register) + * buffer: Where to read/write the data + * len: How many bytes to read/write + * + * Returns: 0 on success, not 0 on failure + */ +int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) +{ + int i; + int rc; + struct u8500_i2c_regs *i2c_regs; + + if (alen > 2) { + debug("I2C read: addr len %d not supported\n", alen); + return 1; + } + + i2c_regs = i2c_dev[i2c_bus_num]; + + for (i = 0; i < len; i++) { + rc = i2c_read_byte(i2c_regs, chip, addr + i, alen, &buffer[i]); + if (rc != 0) { + debug("I2C read: I/O error: %d\n", rc); + i2c_abort(i2c_regs); + return rc; + } + } + + return 0; +} + +int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +{ + int rc; + struct u8500_i2c_regs *i2c_regs; + i2c_regs = i2c_dev[i2c_bus_num]; + + rc = __i2c_write(i2c_regs, chip, addr, alen, buffer, + len); + if (rc != 0) { + debug("I2C write: I/O error\n"); + i2c_abort(i2c_regs); + return rc; + } + return 0; +} + +int i2c_set_bus_num(unsigned int bus) +{ + if (bus > ARRAY_SIZE(i2c_dev) - 1) { + debug("i2c_set_bus_num: only up to bus %d supported\n", + ARRAY_SIZE(i2c_dev)-1); + return -1; + } + + i2c_bus_num = bus; + + if (!bus_initialized[i2c_bus_num]) + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + return 0; +} + +int i2c_set_bus_speed(unsigned int speed) +{ + + if (speed > U8500_I2C_MAX_STANDARD_SCL) { + debug("i2c_set_bus_speed: only up to %d supported\n", + U8500_I2C_MAX_STANDARD_SCL); + return -1; + } + + /* sets as side effect i2c_bus_speed[i2c_bus_num] */ + i2c_init(speed, CONFIG_SYS_I2C_SLAVE); + + return 0; +} + +unsigned int i2c_get_bus_num(void) +{ + return i2c_bus_num; +} + +unsigned int i2c_get_bus_speed(void) +{ + return i2c_bus_speed[i2c_bus_num]; +} diff --git a/drivers/i2c/u8500_i2c.h b/drivers/i2c/u8500_i2c.h new file mode 100644 index 0000000..91dbd3e --- /dev/null +++ b/drivers/i2c/u8500_i2c.h @@ -0,0 +1,194 @@ +/* + * Copyright (C) ST-Ericsson SA 2009 + * + * 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 _U8500_I2C_H_ +#define _U8500_I2C_H_ + +#include <asm/types.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/arch/u8500.h> + +struct u8500_i2c_regs { + u32 cr; /* Control Register 0x00 */ + u32 scr; /* Slave Address Register 0x04 */ + u32 hsmcr; /* HS Master code Register 0x08 */ + u32 mcr; /* Master Control Register 0x0C */ + u32 tfr; /* Transmit Fifo Register 0x10 */ + u32 sr; /* Status Register 0x14 */ + u32 rfr; /* Receiver Fifo Register 0x18 */ + u32 tftr; /* Transmit Fifo Threshold Register 0x1C */ + u32 rftr; /* Receiver Fifo Threshold Register 0x20 */ + u32 dmar; /* DMA register 0x24 */ + u32 brcr; /* Baud Rate Counter Register 0x28 */ + u32 imscr; /* Interrupt Mask Set and Clear Register 0x2C */ + u32 risr; /* Raw interrupt status register 0x30 */ + u32 misr; /* Masked interrupt status register 0x34 */ + u32 icr; /* Interrupt Set and Clear Register 0x38 */ + u32 reserved_1[(0xFE0 - 0x3c) >> 2]; /* Reserved 0x03C to 0xFE0 */ + u32 periph_id_0; /* peripheral ID 0 0xFE0 */ + u32 periph_id_1; /* peripheral ID 1 0xFE4 */ + u32 periph_id_2; /* peripheral ID 2 0xFE8 */ + u32 periph_id_3; /* peripheral ID 3 0xFEC */ + u32 cell_id_0; /* I2C cell ID 0 0xFF0 */ + u32 cell_id_1; /* I2C cell ID 1 0xFF4 */ + u32 cell_id_2; /* I2C cell ID 2 0xFF8 */ + u32 cell_id_3; /* I2C cell ID 3 0xFFC */ +}; + + +/* Control Register */ + +/* Mask values for control register mask */ +#define U8500_I2C_CR_PE 0x0001 /* Peripheral enable */ +#define U8500_I2C_CR_OM 0x0006 /* Operation mode */ +#define U8500_I2C_CR_SAM 0x0008 /* Slave Addressing mode */ +#define U8500_I2C_CR_SM 0x0030 /* Speed mode */ +#define U8500_I2C_CR_SGCM 0x0040 /* Slave General call mode */ +#define U8500_I2C_CR_FTX 0x0080 /* Flush Transmit */ +#define U8500_I2C_CR_FRX 0x0100 /* Flush Receive */ +#define U8500_I2C_CR_DMA_TX_EN 0x0200 /* DMA TX Enable */ +#define U8500_I2C_CR_DMA_RX_EN 0x0400 /* DMA Rx Enable */ +#define U8500_I2C_CR_DMA_SLE 0x0800 /* DMA Synchronization Logic enable */ +#define U8500_I2C_CR_LM 0x1000 /* Loop back mode */ +#define U8500_I2C_CR_FON 0x6000 /* Filtering On */ + +/* shift valus for control register bit fields */ +#define U8500_I2C_CR_SHIFT_PE 0 /* Peripheral enable */ +#define U8500_I2C_CR_SHIFT_OM 1 /* Operation mode */ +#define U8500_I2C_CR_SHIFT_SAM 3 /* Slave Addressing mode */ +#define U8500_I2C_CR_SHIFT_SM 4 /* Speed mode */ +#define U8500_I2C_CR_SHIFT_SGCM 6 /* Slave General call mode */ +#define U8500_I2C_CR_SHIFT_FTX 7 /* Flush Transmit */ +#define U8500_I2C_CR_SHIFT_FRX 8 /* Flush Receive */ +#define U8500_I2C_CR_SHIFT_DMA_TX_EN 9 /* DMA TX Enable */ +#define U8500_I2C_CR_SHIFT_DMA_RX_EN 10 /* DMA Rx Enable */ +#define U8500_I2C_CR_SHIFT_DMA_SLE 11 /* DMA Synch Logic enable */ +#define U8500_I2C_CR_SHIFT_LM 12 /* Loop back mode */ +#define U8500_I2C_CR_SHIFT_FON 13 /* Filtering On */ + +/* bus operation modes */ +#define U8500_I2C_BUS_SLAVE_MODE 0 +#define U8500_I2C_BUS_MASTER_MODE 1 +#define U8500_I2C_BUS_MASTER_SLAVE_MODE 2 + + +/* Slave control register*/ + +/* Mask values slave control register */ +#define U8500_I2C_SCR_ADDR 0x3FF +#define U8500_I2C_SCR_DATA_SETUP_TIME 0xFFFF0000 + +/* Shift values for Slave control register */ +#define U8500_I2C_SCR_SHIFT_ADDR 0 +#define U8500_I2C_SCR_SHIFT_DATA_SETUP_TIME 16 + + +/* Master Control Register */ + +/* Mask values for Master control register */ +#define U8500_I2C_MCR_OP 0x00000001 /* Operation */ +#define U8500_I2C_MCR_A7 0x000000FE /* LSB bits of Address */ +#define U8500_I2C_MCR_EA10 0x00000700 /* Extended Address */ +#define U8500_I2C_MCR_SB 0x00000800 /* Start byte procedure */ +#define U8500_I2C_MCR_AM 0x00003000 /* Address type */ +#define U8500_I2C_MCR_STOP 0x00004000 /* stop condition */ +#define U8500_I2C_MCR_LENGTH 0x03FF8000 /* Frame length */ +#define U8500_I2C_MCR_A10 0x000007FE /* Enable 10 bit address */ +/* mask for length field,stop and operation */ +#define U8500_I2C_MCR_LENGTH_STOP_OP 0x3FFC001 + +/* Shift values for Master control values */ +#define U8500_I2C_MCR_SHIFT_OP 0 /* Operation */ +#define U8500_I2C_MCR_SHIFT_A7 1 /* LSB bits of Address */ +#define U8500_I2C_MCR_SHIFT_EA10 8 /* Extended Address */ +#define U8500_I2C_MCR_SHIFT_SB 11 /* Start byte procedure */ +#define U8500_I2C_MCR_SHIFT_AM 12 /* Address type */ +#define U8500_I2C_MCR_SHIFT_STOP 14 /* stop condition */ +#define U8500_I2C_MCR_SHIFT_LENGTH 15 /* Frame length */ +#define U8500_I2C_MCR_SHIFT_A10 1 /* Enable 10 bit address */ + +#define U8500_I2C_MCR_SHIFT_LENGTH_STOP_OP 0 + + +/* Status Register */ + +/* Mask values for Status register */ +#define U8500_I2C_SR_OP 0x00000003 /* Operation */ +#define U8500_I2C_SR_STATUS 0x0000000C /* Controller Status */ +#define U8500_I2C_SR_CAUSE 0x00000070 /* Abort Cause */ +#define U8500_I2C_SR_TYPE 0x00000180 /* Receive Type */ +#define U8500_I2C_SR_LENGTH 0x000FF700 /* Transfer length */ + +/* Shift values for Status register */ +#define U8500_I2C_SR_SHIFT_OP 0 /* Operation */ +#define U8500_I2C_SR_SHIFT_STATUS 2 /* Controller Status */ +#define U8500_I2C_SR_SHIFT_CAUSE 4 /* Abort Cause */ +#define U8500_I2C_SR_SHIFT_TYPE 7 /* Receive Type */ +#define U8500_I2C_SR_SHIFT_LENGTH 9 /* Transfer length */ + +/* abort cause */ +#define U8500_I2C_NACK_ADDR 0 +#define U8500_I2C_NACK_DATA 1 +#define U8500_I2C_ACK_MCODE 2 +#define U8500_I2C_ARB_LOST 3 +#define U8500_I2C_BERR_START 4 +#define U8500_I2C_BERR_STOP 5 +#define U8500_I2C_OVFL 6 + + +/* Baud rate counter registers */ + +/* Mask values for Baud rate counter register */ +#define U8500_I2C_BRCR_BRCNT2 0xFFFF /* Baud Rate Cntr BRCR for HS */ +#define U8500_I2C_BRCR_BRCNT1 0xFFFF0000 /* BRCR for Standard and Fast */ + +/* Shift values for the Baud rate counter register */ +#define U8500_I2C_BRCR_SHIFT_BRCNT2 0 +#define U8500_I2C_BRCR_SHIFT_BRCNT1 16 + + +/* Interrupt Register */ + +/* Mask values for Interrupt registers */ +#define U8500_I2C_INT_TXFE 0x00000001 /* Tx fifo empty */ +#define U8500_I2C_INT_TXFNE 0x00000002 /* Tx Fifo nearly empty */ +#define U8500_I2C_INT_TXFF 0x00000004 /* Tx Fifo Full */ +#define U8500_I2C_INT_TXFOVR 0x00000008 /* Tx Fifo over run */ +#define U8500_I2C_INT_RXFE 0x00000010 /* Rx Fifo Empty */ +#define U8500_I2C_INT_RXFNF 0x00000020 /* Rx Fifo nearly empty */ +#define U8500_I2C_INT_RXFF 0x00000040 /* Rx Fifo Full */ +#define U8500_I2C_INT_RFSR 0x00010000 /* Read From slave request */ +#define U8500_I2C_INT_RFSE 0x00020000 /* Read from slave empty */ +#define U8500_I2C_INT_WTSR 0x00040000 /* Write to Slave request */ +#define U8500_I2C_INT_MTD 0x00080000 /* Master Transcation Done*/ +#define U8500_I2C_INT_STD 0x00100000 /* Slave Transaction Done */ +#define U8500_I2C_INT_MAL 0x01000000 /* Master Arbitation Lost */ +#define U8500_I2C_INT_BERR 0x02000000 /* Bus Error */ +#define U8500_I2C_INT_MTDWS 0x10000000 /* Master Tran Done wo/ Stop */ + +/* Max clocks (Hz) */ +#define U8500_I2C_MAX_STANDARD_SCL 100000 +#define U8500_I2C_MAX_FAST_SCL 400000 +#define U8500_I2C_MAX_HIGH_SPEED_SCL 3400000 + +#endif /* _U8500_I2C_H_ */