From 2d344a2ab27d8704efd09088ee00be194b3556eb Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 1 Mar 2012 17:56:35 +0000 Subject: sh: i2c: Add support I2C controller of SH7734 Renesas SH7734 has two I2C interfaceis. This supports these I2C. V5: - include i2c.h. - Add check of icsr bit polling logic. - Implement i2c_probe. V4: - Remove sh_i2c_dump_reg function. - Use puts() when there's no format. - Chnage check for I2C bus number. - Remove space before the semi-colon. V3: - Fix error for whitespace. V2: - Changed bit control to use the clr|set|clrsetbits_* functions. - Fix wrong comment style. - Add new line before for loop in i2c_read. Signed-off-by: Nobuhiro Iwamatsu Acked-by: Heiko Schocher Signed-off-by: Nobuhiro Iwamatsu Acked-by: Mike Frysinger --- drivers/i2c/Makefile | 1 + drivers/i2c/sh_sh7734_i2c.c | 387 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 388 insertions(+) create mode 100644 drivers/i2c/sh_sh7734_i2c.c diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index f86e46c111..42913f7cbb 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -45,6 +45,7 @@ COBJS-$(CONFIG_TEGRA_I2C) += tegra_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o COBJS-$(CONFIG_SH_I2C) += sh_i2c.o +COBJS-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/i2c/sh_sh7734_i2c.c b/drivers/i2c/sh_sh7734_i2c.c new file mode 100644 index 0000000000..9da173d31e --- /dev/null +++ b/drivers/i2c/sh_sh7734_i2c.c @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2012 Nobuhiro Iwamatsu + * Copyright (C) 2012 Renesas Solutions Corp. + * + * 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 + */ + +#include +#include +#include + +struct sh_i2c { + u8 iccr1; + u8 iccr2; + u8 icmr; + u8 icier; + u8 icsr; + u8 sar; + u8 icdrt; + u8 icdrr; + u8 nf2cyc; + u8 __pad0; + u8 __pad1; +}; + +static struct sh_i2c *base; +static u8 iccr1_cks, nf2cyc; + +/* ICCR1 */ +#define SH_I2C_ICCR1_ICE (1 << 7) +#define SH_I2C_ICCR1_RCVD (1 << 6) +#define SH_I2C_ICCR1_MST (1 << 5) +#define SH_I2C_ICCR1_TRS (1 << 4) +#define SH_I2C_ICCR1_MTRS \ + (SH_I2C_ICCR1_MST | SH_I2C_ICCR1_TRS) + +/* ICCR1 */ +#define SH_I2C_ICCR2_BBSY (1 << 7) +#define SH_I2C_ICCR2_SCP (1 << 6) +#define SH_I2C_ICCR2_SDAO (1 << 5) +#define SH_I2C_ICCR2_SDAOP (1 << 4) +#define SH_I2C_ICCR2_SCLO (1 << 3) +#define SH_I2C_ICCR2_IICRST (1 << 1) + +#define SH_I2C_ICIER_TIE (1 << 7) +#define SH_I2C_ICIER_TEIE (1 << 6) +#define SH_I2C_ICIER_RIE (1 << 5) +#define SH_I2C_ICIER_NAKIE (1 << 4) +#define SH_I2C_ICIER_STIE (1 << 3) +#define SH_I2C_ICIER_ACKE (1 << 2) +#define SH_I2C_ICIER_ACKBR (1 << 1) +#define SH_I2C_ICIER_ACKBT (1 << 0) + +#define SH_I2C_ICSR_TDRE (1 << 7) +#define SH_I2C_ICSR_TEND (1 << 6) +#define SH_I2C_ICSR_RDRF (1 << 5) +#define SH_I2C_ICSR_NACKF (1 << 4) +#define SH_I2C_ICSR_STOP (1 << 3) +#define SH_I2C_ICSR_ALOVE (1 << 2) +#define SH_I2C_ICSR_AAS (1 << 1) +#define SH_I2C_ICSR_ADZ (1 << 0) + +#define IRQ_WAIT 1000 + +static void sh_i2c_send_stop(struct sh_i2c *base) +{ + clrbits_8(&base->iccr2, SH_I2C_ICCR2_BBSY | SH_I2C_ICCR2_SCP); +} + +static int check_icsr_bits(struct sh_i2c *base, u8 bits) +{ + int i; + + for (i = 0; i < IRQ_WAIT; i++) { + if (bits & readb(&base->icsr)) + return 0; + udelay(10); + } + + return 1; +} + +static int check_stop(struct sh_i2c *base) +{ + int ret = check_icsr_bits(base, SH_I2C_ICSR_STOP); + clrbits_8(&base->icsr, SH_I2C_ICSR_STOP); + + return ret; +} + +static int check_tend(struct sh_i2c *base, int stop) +{ + int ret = check_icsr_bits(base, SH_I2C_ICSR_TEND); + + if (stop) { + clrbits_8(&base->icsr, SH_I2C_ICSR_STOP); + sh_i2c_send_stop(base); + } + + clrbits_8(&base->icsr, SH_I2C_ICSR_TEND); + return ret; +} + +static int check_tdre(struct sh_i2c *base) +{ + return check_icsr_bits(base, SH_I2C_ICSR_TDRE); +} + +static int check_rdrf(struct sh_i2c *base) +{ + return check_icsr_bits(base, SH_I2C_ICSR_RDRF); +} + +static int check_bbsy(struct sh_i2c *base) +{ + int i; + + for (i = 0 ; i < IRQ_WAIT ; i++) { + if (!(SH_I2C_ICCR2_BBSY & readb(&base->iccr2))) + return 0; + udelay(10); + } + return 1; +} + +static int check_ackbr(struct sh_i2c *base) +{ + int i; + + for (i = 0 ; i < IRQ_WAIT ; i++) { + if (!(SH_I2C_ICIER_ACKBR & readb(&base->icier))) + return 0; + udelay(10); + } + + return 1; +} + +static void sh_i2c_reset(struct sh_i2c *base) +{ + setbits_8(&base->iccr2, SH_I2C_ICCR2_IICRST); + + udelay(100); + + clrbits_8(&base->iccr2, SH_I2C_ICCR2_IICRST); +} + +static int i2c_set_addr(struct sh_i2c *base, u8 id, u8 reg) +{ + if (check_bbsy(base)) { + puts("i2c bus busy\n"); + goto fail; + } + + setbits_8(&base->iccr1, SH_I2C_ICCR1_MTRS); + clrsetbits_8(&base->iccr2, SH_I2C_ICCR2_SCP, SH_I2C_ICCR2_BBSY); + + writeb((id << 1), &base->icdrt); + + if (check_tend(base, 0)) { + puts("TEND check fail...\n"); + goto fail; + } + + if (check_ackbr(base)) { + check_tend(base, 0); + sh_i2c_send_stop(base); + goto fail; + } + + writeb(reg, &base->icdrt); + + if (check_tdre(base)) { + puts("TDRE check fail...\n"); + goto fail; + } + + if (check_tend(base, 0)) { + puts("TEND check fail...\n"); + goto fail; + } + + return 0; +fail: + + return 1; +} + +static int +i2c_raw_write(struct sh_i2c *base, u8 id, u8 reg, u8 *val, int size) +{ + int i; + + if (i2c_set_addr(base, id, reg)) { + puts("Fail set slave address\n"); + return 1; + } + + for (i = 0; i < size; i++) { + writeb(val[i], &base->icdrt); + check_tdre(base); + } + + check_tend(base, 1); + check_stop(base); + + udelay(100); + + clrbits_8(&base->iccr1, SH_I2C_ICCR1_MTRS); + clrbits_8(&base->icsr, SH_I2C_ICSR_TDRE); + sh_i2c_reset(base); + + return 0; +} + +static u8 i2c_raw_read(struct sh_i2c *base, u8 id, u8 reg) +{ + u8 ret = 0; + + if (i2c_set_addr(base, id, reg)) { + puts("Fail set slave address\n"); + goto fail; + } + + clrsetbits_8(&base->iccr2, SH_I2C_ICCR2_SCP, SH_I2C_ICCR2_BBSY); + writeb((id << 1) | 1, &base->icdrt); + + if (check_tend(base, 0)) + puts("TDRE check fail...\n"); + + clrsetbits_8(&base->iccr1, SH_I2C_ICCR1_TRS, SH_I2C_ICCR1_MST); + clrbits_8(&base->icsr, SH_I2C_ICSR_TDRE); + setbits_8(&base->icier, SH_I2C_ICIER_ACKBT); + setbits_8(&base->iccr1, SH_I2C_ICCR1_RCVD); + + /* read data (dummy) */ + ret = readb(&base->icdrr); + + if (check_rdrf(base)) { + puts("check RDRF error\n"); + goto fail; + } + + clrbits_8(&base->icsr, SH_I2C_ICSR_STOP); + udelay(1000); + + sh_i2c_send_stop(base); + + if (check_stop(base)) { + puts("check STOP error\n"); + goto fail; + } + + clrbits_8(&base->iccr1, SH_I2C_ICCR1_MTRS); + clrbits_8(&base->icsr, SH_I2C_ICSR_TDRE); + + /* data read */ + ret = readb(&base->icdrr); + +fail: + clrbits_8(&base->iccr1, SH_I2C_ICCR1_RCVD); + + return ret; +} + +#ifdef CONFIG_I2C_MULTI_BUS +static unsigned int current_bus; + +/** + * i2c_set_bus_num - change active I2C bus + * @bus: bus index, zero based + * @returns: 0 on success, non-0 on failure + */ +int i2c_set_bus_num(unsigned int bus) +{ + switch (bus) { + case 0: + base = (void *)CONFIG_SH_I2C_BASE0; + break; + case 1: + base = (void *)CONFIG_SH_I2C_BASE1; + break; + default: + printf("Bad bus: %d\n", bus); + return -1; + } + + current_bus = bus; + + return 0; +} + +/** + * i2c_get_bus_num - returns index of active I2C bus + */ +unsigned int i2c_get_bus_num(void) +{ + return current_bus; +} +#endif + +void i2c_init(int speed, int slaveaddr) +{ +#ifdef CONFIG_I2C_MULTI_BUS + current_bus = 0; +#endif + base = (struct sh_i2c *)CONFIG_SH_I2C_BASE0; + + if (speed == 400000) + iccr1_cks = 0x07; + else + iccr1_cks = 0x0F; + + nf2cyc = 1; + + /* Reset */ + sh_i2c_reset(base); + + /* ICE enable and set clock */ + writeb(SH_I2C_ICCR1_ICE | iccr1_cks, &base->iccr1); + writeb(nf2cyc, &base->nf2cyc); +} + +/* + * i2c_read: - Read multiple bytes from an i2c device + * + * The higher level routines take into account that this function is only + * called with len < page length of the device (see configuration file) + * + * @chip: address of the chip which is to be read + * @addr: i2c data address within the chip + * @alen: length of the i2c data address (1..2 bytes) + * @buffer: where to write the data + * @len: how much byte do we want to read + * @return: 0 in case of success + */ +int i2c_read(u8 chip, u32 addr, int alen, u8 *buffer, int len) +{ + int i = 0; + for (i = 0; i < len; i++) + buffer[i] = i2c_raw_read(base, chip, addr + i); + + return 0; +} + +/* + * i2c_write: - Write multiple bytes to an i2c device + * + * The higher level routines take into account that this function is only + * called with len < page length of the device (see configuration file) + * + * @chip: address of the chip which is to be written + * @addr: i2c data address within the chip + * @alen: length of the i2c data address (1..2 bytes) + * @buffer: where to find the data to be written + * @len: how much byte do we want to read + * @return: 0 in case of success + */ +int i2c_write(u8 chip, u32 addr, int alen, u8 *buffer, int len) +{ + return i2c_raw_write(base, chip, addr, buffer, len); +} + +/* + * i2c_probe: - Test if a chip answers for a given i2c address + * + * @chip: address of the chip which is searched for + * @return: 0 if a chip was found, -1 otherwhise + */ +int i2c_probe(u8 chip) +{ + u8 byte; + return i2c_read(chip, 0, 0, &byte, 1); +} -- cgit v1.2.1 From 031ed2fa748ccfc746bd0e0073f8690c84a0d7b6 Mon Sep 17 00:00:00 2001 From: Vipin KUMAR Date: Sun, 26 Feb 2012 23:13:29 +0000 Subject: i2c: Add support for designware i2c controller Earlier, a driver exists in the u-boot source for designware i2c interface. That driver was specific to spear platforms. This patch implements the i2c controller as a generic driver which can be used by multiple platforms The driver files are now renamed to designware_i2c.c and designware_i2c.h and these are moved into drivers/i2c folder for reusability by other platforms Signed-off-by: Vipin Kumar Signed-off-by: Amit Virdi --- arch/arm/include/asm/arch-spear/spr_i2c.h | 146 ------------- drivers/i2c/Makefile | 2 +- drivers/i2c/designware_i2c.c | 331 ++++++++++++++++++++++++++++++ drivers/i2c/designware_i2c.h | 146 +++++++++++++ drivers/i2c/spr_i2c.c | 331 ------------------------------ include/configs/spear-common.h | 2 +- 6 files changed, 479 insertions(+), 479 deletions(-) delete mode 100644 arch/arm/include/asm/arch-spear/spr_i2c.h create mode 100644 drivers/i2c/designware_i2c.c create mode 100644 drivers/i2c/designware_i2c.h delete mode 100644 drivers/i2c/spr_i2c.c diff --git a/arch/arm/include/asm/arch-spear/spr_i2c.h b/arch/arm/include/asm/arch-spear/spr_i2c.h deleted file mode 100644 index 7521ebc6cf..0000000000 --- a/arch/arm/include/asm/arch-spear/spr_i2c.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * (C) Copyright 2009 - * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. - * - * 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 __SPR_I2C_H_ -#define __SPR_I2C_H_ - -struct i2c_regs { - u32 ic_con; - u32 ic_tar; - u32 ic_sar; - u32 ic_hs_maddr; - u32 ic_cmd_data; - u32 ic_ss_scl_hcnt; - u32 ic_ss_scl_lcnt; - u32 ic_fs_scl_hcnt; - u32 ic_fs_scl_lcnt; - u32 ic_hs_scl_hcnt; - u32 ic_hs_scl_lcnt; - u32 ic_intr_stat; - u32 ic_intr_mask; - u32 ic_raw_intr_stat; - u32 ic_rx_tl; - u32 ic_tx_tl; - u32 ic_clr_intr; - u32 ic_clr_rx_under; - u32 ic_clr_rx_over; - u32 ic_clr_tx_over; - u32 ic_clr_rd_req; - u32 ic_clr_tx_abrt; - u32 ic_clr_rx_done; - u32 ic_clr_activity; - u32 ic_clr_stop_det; - u32 ic_clr_start_det; - u32 ic_clr_gen_call; - u32 ic_enable; - u32 ic_status; - u32 ic_txflr; - u32 ix_rxflr; - u32 reserved_1; - u32 ic_tx_abrt_source; -}; - -#define IC_CLK 166 -#define NANO_TO_MICRO 1000 - -/* High and low times in different speed modes (in ns) */ -#define MIN_SS_SCL_HIGHTIME 4000 -#define MIN_SS_SCL_LOWTIME 5000 -#define MIN_FS_SCL_HIGHTIME 800 -#define MIN_FS_SCL_LOWTIME 1700 -#define MIN_HS_SCL_HIGHTIME 60 -#define MIN_HS_SCL_LOWTIME 160 - -/* Worst case timeout for 1 byte is kept as 2ms */ -#define I2C_BYTE_TO (CONFIG_SYS_HZ/500) -#define I2C_STOPDET_TO (CONFIG_SYS_HZ/500) -#define I2C_BYTE_TO_BB (I2C_BYTE_TO * 16) - -/* i2c control register definitions */ -#define IC_CON_SD 0x0040 -#define IC_CON_RE 0x0020 -#define IC_CON_10BITADDRMASTER 0x0010 -#define IC_CON_10BITADDR_SLAVE 0x0008 -#define IC_CON_SPD_MSK 0x0006 -#define IC_CON_SPD_SS 0x0002 -#define IC_CON_SPD_FS 0x0004 -#define IC_CON_SPD_HS 0x0006 -#define IC_CON_MM 0x0001 - -/* i2c target address register definitions */ -#define TAR_ADDR 0x0050 - -/* i2c slave address register definitions */ -#define IC_SLAVE_ADDR 0x0002 - -/* i2c data buffer and command register definitions */ -#define IC_CMD 0x0100 - -/* i2c interrupt status register definitions */ -#define IC_GEN_CALL 0x0800 -#define IC_START_DET 0x0400 -#define IC_STOP_DET 0x0200 -#define IC_ACTIVITY 0x0100 -#define IC_RX_DONE 0x0080 -#define IC_TX_ABRT 0x0040 -#define IC_RD_REQ 0x0020 -#define IC_TX_EMPTY 0x0010 -#define IC_TX_OVER 0x0008 -#define IC_RX_FULL 0x0004 -#define IC_RX_OVER 0x0002 -#define IC_RX_UNDER 0x0001 - -/* fifo threshold register definitions */ -#define IC_TL0 0x00 -#define IC_TL1 0x01 -#define IC_TL2 0x02 -#define IC_TL3 0x03 -#define IC_TL4 0x04 -#define IC_TL5 0x05 -#define IC_TL6 0x06 -#define IC_TL7 0x07 -#define IC_RX_TL IC_TL0 -#define IC_TX_TL IC_TL0 - -/* i2c enable register definitions */ -#define IC_ENABLE_0B 0x0001 - -/* i2c status register definitions */ -#define IC_STATUS_SA 0x0040 -#define IC_STATUS_MA 0x0020 -#define IC_STATUS_RFF 0x0010 -#define IC_STATUS_RFNE 0x0008 -#define IC_STATUS_TFE 0x0004 -#define IC_STATUS_TFNF 0x0002 -#define IC_STATUS_ACT 0x0001 - -/* Speed Selection */ -#define IC_SPEED_MODE_STANDARD 1 -#define IC_SPEED_MODE_FAST 2 -#define IC_SPEED_MODE_MAX 3 - -#define I2C_MAX_SPEED 3400000 -#define I2C_FAST_SPEED 400000 -#define I2C_STANDARD_SPEED 100000 - -#endif /* __SPR_I2C_H_ */ diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 42913f7cbb..5dbdbe3672 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libi2c.o COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o +COBJS-$(CONFIG_DW_I2C) += designware_i2c.o COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o COBJS-$(CONFIG_I2C_MV) += mv_i2c.o @@ -40,7 +41,6 @@ COBJS-$(CONFIG_PPC4XX_I2C) += ppc4xx_i2c.o COBJS-$(CONFIG_DRIVER_S3C24X0_I2C) += s3c24x0_i2c.o COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o -COBJS-$(CONFIG_SPEAR_I2C) += spr_i2c.o COBJS-$(CONFIG_TEGRA_I2C) += tegra_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c new file mode 100644 index 0000000000..d352146081 --- /dev/null +++ b/drivers/i2c/designware_i2c.c @@ -0,0 +1,331 @@ +/* + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. + * + * 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 + */ + +#include +#include +#include +#include "designware_i2c.h" + +static struct i2c_regs *const i2c_regs_p = + (struct i2c_regs *)CONFIG_SYS_I2C_BASE; + +/* + * set_speed - Set the i2c speed mode (standard, high, fast) + * @i2c_spd: required i2c speed mode + * + * Set the i2c speed mode (standard, high, fast) + */ +static void set_speed(int i2c_spd) +{ + unsigned int cntl; + unsigned int hcnt, lcnt; + unsigned int high, low; + + cntl = (readl(&i2c_regs_p->ic_con) & (~IC_CON_SPD_MSK)); + + switch (i2c_spd) { + case IC_SPEED_MODE_MAX: + cntl |= IC_CON_SPD_HS; + high = MIN_HS_SCL_HIGHTIME; + low = MIN_HS_SCL_LOWTIME; + break; + + case IC_SPEED_MODE_STANDARD: + cntl |= IC_CON_SPD_SS; + high = MIN_SS_SCL_HIGHTIME; + low = MIN_SS_SCL_LOWTIME; + break; + + case IC_SPEED_MODE_FAST: + default: + cntl |= IC_CON_SPD_FS; + high = MIN_FS_SCL_HIGHTIME; + low = MIN_FS_SCL_LOWTIME; + break; + } + + writel(cntl, &i2c_regs_p->ic_con); + + hcnt = (IC_CLK * high) / NANO_TO_MICRO; + writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt); + + lcnt = (IC_CLK * low) / NANO_TO_MICRO; + writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt); +} + +/* + * i2c_set_bus_speed - Set the i2c speed + * @speed: required i2c speed + * + * Set the i2c speed. + */ +void i2c_set_bus_speed(int speed) +{ + if (speed >= I2C_MAX_SPEED) + set_speed(IC_SPEED_MODE_MAX); + else if (speed >= I2C_FAST_SPEED) + set_speed(IC_SPEED_MODE_FAST); + else + set_speed(IC_SPEED_MODE_STANDARD); +} + +/* + * i2c_get_bus_speed - Gets the i2c speed + * + * Gets the i2c speed. + */ +int i2c_get_bus_speed(void) +{ + u32 cntl; + + cntl = (readl(&i2c_regs_p->ic_con) & IC_CON_SPD_MSK); + + if (cntl == IC_CON_SPD_HS) + return I2C_MAX_SPEED; + else if (cntl == IC_CON_SPD_FS) + return I2C_FAST_SPEED; + else if (cntl == IC_CON_SPD_SS) + return I2C_STANDARD_SPEED; + + return 0; +} + +/* + * i2c_init - Init function + * @speed: required i2c speed + * @slaveadd: slave address for the device + * + * Initialization function. + */ +void i2c_init(int speed, int slaveadd) +{ + unsigned int enbl; + + /* Disable i2c */ + enbl = readl(&i2c_regs_p->ic_enable); + enbl &= ~IC_ENABLE_0B; + writel(enbl, &i2c_regs_p->ic_enable); + + writel((IC_CON_SD | IC_CON_SPD_FS | IC_CON_MM), &i2c_regs_p->ic_con); + writel(IC_RX_TL, &i2c_regs_p->ic_rx_tl); + writel(IC_TX_TL, &i2c_regs_p->ic_tx_tl); + i2c_set_bus_speed(speed); + writel(IC_STOP_DET, &i2c_regs_p->ic_intr_mask); + writel(slaveadd, &i2c_regs_p->ic_sar); + + /* Enable i2c */ + enbl = readl(&i2c_regs_p->ic_enable); + enbl |= IC_ENABLE_0B; + writel(enbl, &i2c_regs_p->ic_enable); +} + +/* + * i2c_setaddress - Sets the target slave address + * @i2c_addr: target i2c address + * + * Sets the target slave address. + */ +static void i2c_setaddress(unsigned int i2c_addr) +{ + writel(i2c_addr, &i2c_regs_p->ic_tar); +} + +/* + * i2c_flush_rxfifo - Flushes the i2c RX FIFO + * + * Flushes the i2c RX FIFO + */ +static void i2c_flush_rxfifo(void) +{ + while (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) + readl(&i2c_regs_p->ic_cmd_data); +} + +/* + * i2c_wait_for_bb - Waits for bus busy + * + * Waits for bus busy + */ +static int i2c_wait_for_bb(void) +{ + unsigned long start_time_bb = get_timer(0); + + while ((readl(&i2c_regs_p->ic_status) & IC_STATUS_MA) || + !(readl(&i2c_regs_p->ic_status) & IC_STATUS_TFE)) { + + /* Evaluate timeout */ + if (get_timer(start_time_bb) > (unsigned long)(I2C_BYTE_TO_BB)) + return 1; + } + + return 0; +} + +/* check parameters for i2c_read and i2c_write */ +static int check_params(uint addr, int alen, uchar *buffer, int len) +{ + if (buffer == NULL) { + printf("Buffer is invalid\n"); + return 1; + } + + if (alen > 1) { + printf("addr len %d not supported\n", alen); + return 1; + } + + if (addr + len > 256) { + printf("address out of range\n"); + return 1; + } + + return 0; +} + +static int i2c_xfer_init(uchar chip, uint addr) +{ + if (i2c_wait_for_bb()) { + printf("Timed out waiting for bus\n"); + return 1; + } + + i2c_setaddress(chip); + writel(addr, &i2c_regs_p->ic_cmd_data); + + return 0; +} + +static int i2c_xfer_finish(void) +{ + ulong start_stop_det = get_timer(0); + + while (1) { + if ((readl(&i2c_regs_p->ic_raw_intr_stat) & IC_STOP_DET)) { + readl(&i2c_regs_p->ic_clr_stop_det); + break; + } else if (get_timer(start_stop_det) > I2C_STOPDET_TO) { + break; + } + } + + if (i2c_wait_for_bb()) { + printf("Timed out waiting for bus\n"); + return 1; + } + + i2c_flush_rxfifo(); + + /* Wait for read/write operation to complete on actual memory */ + udelay(10000); + + return 0; +} + +/* + * i2c_read - Read from i2c memory + * @chip: target i2c address + * @addr: address to read from + * @alen: + * @buffer: buffer for read data + * @len: no of bytes to be read + * + * Read from i2c memory. + */ +int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) +{ + unsigned long start_time_rx; + + if (check_params(addr, alen, buffer, len)) + return 1; + + if (i2c_xfer_init(chip, addr)) + return 1; + + start_time_rx = get_timer(0); + while (len) { + writel(IC_CMD, &i2c_regs_p->ic_cmd_data); + + if (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) { + *buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data); + len--; + start_time_rx = get_timer(0); + + } else if (get_timer(start_time_rx) > I2C_BYTE_TO) { + printf("Timed out. i2c read Failed\n"); + return 1; + } + } + + return i2c_xfer_finish(); +} + +/* + * i2c_write - Write to i2c memory + * @chip: target i2c address + * @addr: address to read from + * @alen: + * @buffer: buffer for read data + * @len: no of bytes to be read + * + * Write to i2c memory. + */ +int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +{ + int nb = len; + unsigned long start_time_tx; + + if (check_params(addr, alen, buffer, len)) + return 1; + + if (i2c_xfer_init(chip, addr)) + return 1; + + start_time_tx = get_timer(0); + while (len) { + if (readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) { + writel(*buffer, &i2c_regs_p->ic_cmd_data); + buffer++; + len--; + start_time_tx = get_timer(0); + + } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) { + printf("Timed out. i2c write Failed\n"); + return 1; + } + } + + return i2c_xfer_finish(); +} + +/* + * i2c_probe - Probe the i2c chip + */ +int i2c_probe(uchar chip) +{ + u32 tmp; + + /* + * Try to read the first location of the chip. + */ + return i2c_read(chip, 0, 1, (uchar *)&tmp, 1); +} diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h new file mode 100644 index 0000000000..03b520ed43 --- /dev/null +++ b/drivers/i2c/designware_i2c.h @@ -0,0 +1,146 @@ +/* + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. + * + * 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 __DW_I2C_H_ +#define __DW_I2C_H_ + +struct i2c_regs { + u32 ic_con; + u32 ic_tar; + u32 ic_sar; + u32 ic_hs_maddr; + u32 ic_cmd_data; + u32 ic_ss_scl_hcnt; + u32 ic_ss_scl_lcnt; + u32 ic_fs_scl_hcnt; + u32 ic_fs_scl_lcnt; + u32 ic_hs_scl_hcnt; + u32 ic_hs_scl_lcnt; + u32 ic_intr_stat; + u32 ic_intr_mask; + u32 ic_raw_intr_stat; + u32 ic_rx_tl; + u32 ic_tx_tl; + u32 ic_clr_intr; + u32 ic_clr_rx_under; + u32 ic_clr_rx_over; + u32 ic_clr_tx_over; + u32 ic_clr_rd_req; + u32 ic_clr_tx_abrt; + u32 ic_clr_rx_done; + u32 ic_clr_activity; + u32 ic_clr_stop_det; + u32 ic_clr_start_det; + u32 ic_clr_gen_call; + u32 ic_enable; + u32 ic_status; + u32 ic_txflr; + u32 ix_rxflr; + u32 reserved_1; + u32 ic_tx_abrt_source; +}; + +#define IC_CLK 166 +#define NANO_TO_MICRO 1000 + +/* High and low times in different speed modes (in ns) */ +#define MIN_SS_SCL_HIGHTIME 4000 +#define MIN_SS_SCL_LOWTIME 5000 +#define MIN_FS_SCL_HIGHTIME 800 +#define MIN_FS_SCL_LOWTIME 1700 +#define MIN_HS_SCL_HIGHTIME 60 +#define MIN_HS_SCL_LOWTIME 160 + +/* Worst case timeout for 1 byte is kept as 2ms */ +#define I2C_BYTE_TO (CONFIG_SYS_HZ/500) +#define I2C_STOPDET_TO (CONFIG_SYS_HZ/500) +#define I2C_BYTE_TO_BB (I2C_BYTE_TO * 16) + +/* i2c control register definitions */ +#define IC_CON_SD 0x0040 +#define IC_CON_RE 0x0020 +#define IC_CON_10BITADDRMASTER 0x0010 +#define IC_CON_10BITADDR_SLAVE 0x0008 +#define IC_CON_SPD_MSK 0x0006 +#define IC_CON_SPD_SS 0x0002 +#define IC_CON_SPD_FS 0x0004 +#define IC_CON_SPD_HS 0x0006 +#define IC_CON_MM 0x0001 + +/* i2c target address register definitions */ +#define TAR_ADDR 0x0050 + +/* i2c slave address register definitions */ +#define IC_SLAVE_ADDR 0x0002 + +/* i2c data buffer and command register definitions */ +#define IC_CMD 0x0100 + +/* i2c interrupt status register definitions */ +#define IC_GEN_CALL 0x0800 +#define IC_START_DET 0x0400 +#define IC_STOP_DET 0x0200 +#define IC_ACTIVITY 0x0100 +#define IC_RX_DONE 0x0080 +#define IC_TX_ABRT 0x0040 +#define IC_RD_REQ 0x0020 +#define IC_TX_EMPTY 0x0010 +#define IC_TX_OVER 0x0008 +#define IC_RX_FULL 0x0004 +#define IC_RX_OVER 0x0002 +#define IC_RX_UNDER 0x0001 + +/* fifo threshold register definitions */ +#define IC_TL0 0x00 +#define IC_TL1 0x01 +#define IC_TL2 0x02 +#define IC_TL3 0x03 +#define IC_TL4 0x04 +#define IC_TL5 0x05 +#define IC_TL6 0x06 +#define IC_TL7 0x07 +#define IC_RX_TL IC_TL0 +#define IC_TX_TL IC_TL0 + +/* i2c enable register definitions */ +#define IC_ENABLE_0B 0x0001 + +/* i2c status register definitions */ +#define IC_STATUS_SA 0x0040 +#define IC_STATUS_MA 0x0020 +#define IC_STATUS_RFF 0x0010 +#define IC_STATUS_RFNE 0x0008 +#define IC_STATUS_TFE 0x0004 +#define IC_STATUS_TFNF 0x0002 +#define IC_STATUS_ACT 0x0001 + +/* Speed Selection */ +#define IC_SPEED_MODE_STANDARD 1 +#define IC_SPEED_MODE_FAST 2 +#define IC_SPEED_MODE_MAX 3 + +#define I2C_MAX_SPEED 3400000 +#define I2C_FAST_SPEED 400000 +#define I2C_STANDARD_SPEED 100000 + +#endif /* __DW_I2C_H_ */ diff --git a/drivers/i2c/spr_i2c.c b/drivers/i2c/spr_i2c.c deleted file mode 100644 index eabfe843f7..0000000000 --- a/drivers/i2c/spr_i2c.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * (C) Copyright 2009 - * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. - * - * 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 - */ - -#include -#include -#include -#include - -static struct i2c_regs *const i2c_regs_p = - (struct i2c_regs *)CONFIG_SYS_I2C_BASE; - -/* - * set_speed - Set the i2c speed mode (standard, high, fast) - * @i2c_spd: required i2c speed mode - * - * Set the i2c speed mode (standard, high, fast) - */ -static void set_speed(int i2c_spd) -{ - unsigned int cntl; - unsigned int hcnt, lcnt; - unsigned int high, low; - - cntl = (readl(&i2c_regs_p->ic_con) & (~IC_CON_SPD_MSK)); - - switch (i2c_spd) { - case IC_SPEED_MODE_MAX: - cntl |= IC_CON_SPD_HS; - high = MIN_HS_SCL_HIGHTIME; - low = MIN_HS_SCL_LOWTIME; - break; - - case IC_SPEED_MODE_STANDARD: - cntl |= IC_CON_SPD_SS; - high = MIN_SS_SCL_HIGHTIME; - low = MIN_SS_SCL_LOWTIME; - break; - - case IC_SPEED_MODE_FAST: - default: - cntl |= IC_CON_SPD_FS; - high = MIN_FS_SCL_HIGHTIME; - low = MIN_FS_SCL_LOWTIME; - break; - } - - writel(cntl, &i2c_regs_p->ic_con); - - hcnt = (IC_CLK * high) / NANO_TO_MICRO; - writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt); - - lcnt = (IC_CLK * low) / NANO_TO_MICRO; - writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt); -} - -/* - * i2c_set_bus_speed - Set the i2c speed - * @speed: required i2c speed - * - * Set the i2c speed. - */ -void i2c_set_bus_speed(int speed) -{ - if (speed >= I2C_MAX_SPEED) - set_speed(IC_SPEED_MODE_MAX); - else if (speed >= I2C_FAST_SPEED) - set_speed(IC_SPEED_MODE_FAST); - else - set_speed(IC_SPEED_MODE_STANDARD); -} - -/* - * i2c_get_bus_speed - Gets the i2c speed - * - * Gets the i2c speed. - */ -int i2c_get_bus_speed(void) -{ - u32 cntl; - - cntl = (readl(&i2c_regs_p->ic_con) & IC_CON_SPD_MSK); - - if (cntl == IC_CON_SPD_HS) - return I2C_MAX_SPEED; - else if (cntl == IC_CON_SPD_FS) - return I2C_FAST_SPEED; - else if (cntl == IC_CON_SPD_SS) - return I2C_STANDARD_SPEED; - - return 0; -} - -/* - * i2c_init - Init function - * @speed: required i2c speed - * @slaveadd: slave address for the spear device - * - * Initialization function. - */ -void i2c_init(int speed, int slaveadd) -{ - unsigned int enbl; - - /* Disable i2c */ - enbl = readl(&i2c_regs_p->ic_enable); - enbl &= ~IC_ENABLE_0B; - writel(enbl, &i2c_regs_p->ic_enable); - - writel((IC_CON_SD | IC_CON_SPD_FS | IC_CON_MM), &i2c_regs_p->ic_con); - writel(IC_RX_TL, &i2c_regs_p->ic_rx_tl); - writel(IC_TX_TL, &i2c_regs_p->ic_tx_tl); - i2c_set_bus_speed(speed); - writel(IC_STOP_DET, &i2c_regs_p->ic_intr_mask); - writel(slaveadd, &i2c_regs_p->ic_sar); - - /* Enable i2c */ - enbl = readl(&i2c_regs_p->ic_enable); - enbl |= IC_ENABLE_0B; - writel(enbl, &i2c_regs_p->ic_enable); -} - -/* - * i2c_setaddress - Sets the target slave address - * @i2c_addr: target i2c address - * - * Sets the target slave address. - */ -static void i2c_setaddress(unsigned int i2c_addr) -{ - writel(i2c_addr, &i2c_regs_p->ic_tar); -} - -/* - * i2c_flush_rxfifo - Flushes the i2c RX FIFO - * - * Flushes the i2c RX FIFO - */ -static void i2c_flush_rxfifo(void) -{ - while (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) - readl(&i2c_regs_p->ic_cmd_data); -} - -/* - * i2c_wait_for_bb - Waits for bus busy - * - * Waits for bus busy - */ -static int i2c_wait_for_bb(void) -{ - unsigned long start_time_bb = get_timer(0); - - while ((readl(&i2c_regs_p->ic_status) & IC_STATUS_MA) || - !(readl(&i2c_regs_p->ic_status) & IC_STATUS_TFE)) { - - /* Evaluate timeout */ - if (get_timer(start_time_bb) > (unsigned long)(I2C_BYTE_TO_BB)) - return 1; - } - - return 0; -} - -/* check parameters for i2c_read and i2c_write */ -static int check_params(uint addr, int alen, uchar *buffer, int len) -{ - if (buffer == NULL) { - printf("Buffer is invalid\n"); - return 1; - } - - if (alen > 1) { - printf("addr len %d not supported\n", alen); - return 1; - } - - if (addr + len > 256) { - printf("address out of range\n"); - return 1; - } - - return 0; -} - -static int i2c_xfer_init(uchar chip, uint addr) -{ - if (i2c_wait_for_bb()) { - printf("Timed out waiting for bus\n"); - return 1; - } - - i2c_setaddress(chip); - writel(addr, &i2c_regs_p->ic_cmd_data); - - return 0; -} - -static int i2c_xfer_finish(void) -{ - ulong start_stop_det = get_timer(0); - - while (1) { - if ((readl(&i2c_regs_p->ic_raw_intr_stat) & IC_STOP_DET)) { - readl(&i2c_regs_p->ic_clr_stop_det); - break; - } else if (get_timer(start_stop_det) > I2C_STOPDET_TO) { - break; - } - } - - if (i2c_wait_for_bb()) { - printf("Timed out waiting for bus\n"); - return 1; - } - - i2c_flush_rxfifo(); - - /* Wait for read/write operation to complete on actual memory */ - udelay(10000); - - return 0; -} - -/* - * i2c_read - Read from i2c memory - * @chip: target i2c address - * @addr: address to read from - * @alen: - * @buffer: buffer for read data - * @len: no of bytes to be read - * - * Read from i2c memory. - */ -int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) -{ - unsigned long start_time_rx; - - if (check_params(addr, alen, buffer, len)) - return 1; - - if (i2c_xfer_init(chip, addr)) - return 1; - - start_time_rx = get_timer(0); - while (len) { - writel(IC_CMD, &i2c_regs_p->ic_cmd_data); - - if (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) { - *buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data); - len--; - start_time_rx = get_timer(0); - - } else if (get_timer(start_time_rx) > I2C_BYTE_TO) { - printf("Timed out. i2c read Failed\n"); - return 1; - } - } - - return i2c_xfer_finish(); -} - -/* - * i2c_write - Write to i2c memory - * @chip: target i2c address - * @addr: address to read from - * @alen: - * @buffer: buffer for read data - * @len: no of bytes to be read - * - * Write to i2c memory. - */ -int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) -{ - int nb = len; - unsigned long start_time_tx; - - if (check_params(addr, alen, buffer, len)) - return 1; - - if (i2c_xfer_init(chip, addr)) - return 1; - - start_time_tx = get_timer(0); - while (len) { - if (readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) { - writel(*buffer, &i2c_regs_p->ic_cmd_data); - buffer++; - len--; - start_time_tx = get_timer(0); - - } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) { - printf("Timed out. i2c write Failed\n"); - return 1; - } - } - - return i2c_xfer_finish(); -} - -/* - * i2c_probe - Probe the i2c chip - */ -int i2c_probe(uchar chip) -{ - u32 tmp; - - /* - * Try to read the first location of the chip. - */ - return i2c_read(chip, 0, 1, (uchar *)&tmp, 1); -} diff --git a/include/configs/spear-common.h b/include/configs/spear-common.h index 5fef8cce80..a79181565e 100644 --- a/include/configs/spear-common.h +++ b/include/configs/spear-common.h @@ -41,7 +41,7 @@ /* I2C driver configuration */ #define CONFIG_HARD_I2C -#define CONFIG_SPEAR_I2C +#define CONFIG_DW_I2C #define CONFIG_SYS_I2C_SPEED 400000 #define CONFIG_SYS_I2C_SLAVE 0x02 -- cgit v1.2.1 From 5e3e8dda51c46faedb124c0ffd6136e2ef09ae52 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Thu, 29 Mar 2012 20:10:17 +0000 Subject: i2c:designware Turn off the ctrl when setting the speed The designware i2c controller must be turned off before setting the speed in IC_CON register, as stated in the section 6.3.1 of the dw_apb_i2c_db.pdf. Signed-off-by: Michel Sanches Signed-off-by: Armando Visconti Signed-off-by: Amit Virdi --- drivers/i2c/designware_i2c.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index d352146081..6d118acec4 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -40,6 +40,13 @@ static void set_speed(int i2c_spd) unsigned int cntl; unsigned int hcnt, lcnt; unsigned int high, low; + unsigned int enbl; + + /* to set speed cltr must be disabled */ + enbl = readl(&i2c_regs_p->ic_enable); + enbl &= ~IC_ENABLE_0B; + writel(enbl, &i2c_regs_p->ic_enable); + cntl = (readl(&i2c_regs_p->ic_con) & (~IC_CON_SPD_MSK)); @@ -71,6 +78,10 @@ static void set_speed(int i2c_spd) lcnt = (IC_CLK * low) / NANO_TO_MICRO; writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt); + + /* re-enable i2c ctrl back now that speed is set */ + enbl |= IC_ENABLE_0B; + writel(enbl, &i2c_regs_p->ic_enable); } /* -- cgit v1.2.1