Signed-off-by: Vipin <vipin.ku...@st.com> --- drivers/i2c/Makefile | 1 + drivers/i2c/spr_i2c.c | 321 ++++++++++++++++++++++++++++++++++ include/asm-arm/arch-spear/spr_i2c.h | 143 +++++++++++++++ 3 files changed, 465 insertions(+), 0 deletions(-) mode change 100644 => 100755 drivers/i2c/Makefile create mode 100755 drivers/i2c/spr_i2c.c create mode 100755 include/asm-arm/arch-spear/spr_i2c.h
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile old mode 100644 new mode 100755 index b860e89..a65543f --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -38,6 +38,7 @@ COBJS-$(CONFIG_DRIVER_S3C24X0_I2C) += s3c24x0_i2c.o COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o +COBJS-$(CONFIG_SPEARI2C) += spr_i2c.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/i2c/spr_i2c.c b/drivers/i2c/spr_i2c.c new file mode 100755 index 0000000..43a9f35 --- /dev/null +++ b/drivers/i2c/spr_i2c.c @@ -0,0 +1,321 @@ +/* + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.ku...@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 <common.h> +#include <asm/io.h> +#include <asm/arch/spr_i2c.h> + +static struct i2c_regs *const i2c_regs_p = + (struct i2c_regs *)CONFIG_SYS_I2C_BASE; + +/** + * i2c_setfreq - Set i2c working mode frequency + * + * Set i2c working mode frequency + */ +static void i2c_setfreq(unsigned int high, unsigned int low) +{ + unsigned int hcnt, lcnt; + + 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); +} + +/** + * 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; + + if (i2c_spd == IC_SPEED_MODE_MAX) { + cntl = readl(&i2c_regs_p->ic_con); + cntl |= IC_CON_SPH | IC_CON_SPL; + writel(cntl, &i2c_regs_p->ic_con); + i2c_setfreq(MIN_HS_SCL_HIGHTIME, MIN_HS_SCL_LOWTIME); + } else if (i2c_spd == IC_SPEED_MODE_FAST) { + cntl = readl(&i2c_regs_p->ic_con); + cntl |= IC_CON_SPH; + cntl &= ~IC_CON_SPL; + writel(cntl, &i2c_regs_p->ic_con); + i2c_setfreq(MIN_FS_SCL_HIGHTIME, MIN_FS_SCL_LOWTIME); + } else if (i2c_spd == IC_SPEED_MODE_STANDARD) { + cntl = readl(&i2c_regs_p->ic_con); + cntl |= IC_CON_SPF; + cntl &= ~IC_CON_SPL; + writel(cntl, &i2c_regs_p->ic_con); + i2c_setfreq(MIN_SS_SCL_HIGHTIME, MIN_SS_SCL_LOWTIME); + } +} + +/** + * 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) +{ + if (((readl(&i2c_regs_p->ic_con) & IC_CON_SPH) == IC_CON_SPH) && + ((readl(&i2c_regs_p->ic_con) & IC_CON_SPL) == IC_CON_SPL)) { + return I2C_MAX_SPEED; + + } else if (((readl(&i2c_regs_p->ic_con) & IC_CON_SPH) == IC_CON_SPH) && + ((readl(&i2c_regs_p->ic_con) & IC_CON_SPL) == 0)) { + return I2C_FAST_SPEED; + + } else if (((readl(&i2c_regs_p->ic_con) & IC_CON_SPF) == IC_CON_SPF) && + ((readl(&i2c_regs_p->ic_con) & IC_CON_SPL) == 0)) { + 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_SPF | IC_CON_MM), &i2c_regs_p->ic_con); + writel(IC_TL0, &i2c_regs_p->ic_rx_tl); + writel(IC_TL0, &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_probe - Probe the i2c chip + * + * TBD + */ +int i2c_probe(uchar chip) +{ + return 0; +} + +/** + * i2c_flush_rxfifo - Flushes the i2c RX FIFO + * + * Flushes the i2c RX FIFO + */ +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_masked(); + + 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; +} + +/** + * 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 (buffer == NULL) { + printf("I2C read: buffer is invalid\n"); + return 1; + } + + if (alen > 1) { + printf("I2C read: addr len %d not supported\n", alen); + return 1; + } + + if (addr + len > 256) { + printf("I2C read: address out of range\n"); + return 1; + } + + if (i2c_wait_for_bb()) + return 1; + + i2c_setaddress(chip); + writel(addr, &i2c_regs_p->ic_cmd_data); + + start_time_rx = get_timer_masked(); + while (len) { + writel(IC_CMD, &i2c_regs_p->ic_cmd_data); + if ((readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) == + IC_STATUS_RFNE) { + *buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data); + len--; + start_time_rx = get_timer_masked(); + } else { + if (get_timer(start_time_rx) > I2C_BYTE_TO) + return 1; + } + } + + udelay(4000); + if ((readl(&i2c_regs_p->ic_raw_intr_stat) & IC_STOP_DET)) + readl(&i2c_regs_p->ic_clr_stop_det); + + if (i2c_wait_for_bb()) + return 1; + + i2c_flush_rxfifo(); + + return 0; +} + +/** + * 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 (buffer == NULL) { + printf("I2C write: buffer is invalid\n"); + return 1; + } + + if (alen > 1) { + printf("I2C write: addr len %d not supported\n", alen); + return 1; + } + + if (addr + len > 256) { + printf("I2C write: address out of range\n"); + return 1; + } + + if (i2c_wait_for_bb()) + return 1; + + i2c_setaddress(chip); + + writel(addr, &i2c_regs_p->ic_cmd_data); + + start_time_tx = get_timer_masked(); + while (len) { + if ((readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) + == IC_STATUS_TFNF) { + writel(*buffer, &i2c_regs_p->ic_cmd_data); + buffer++; + len--; + start_time_tx = get_timer_masked(); + } else { + if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) + return 1; + } + } + + udelay(4000); + if ((readl(&i2c_regs_p->ic_raw_intr_stat) & IC_STOP_DET)) + readl(&i2c_regs_p->ic_clr_stop_det); + + if (i2c_wait_for_bb()) + return 1; + + i2c_flush_rxfifo(); + + return 0; +} + diff --git a/include/asm-arm/arch-spear/spr_i2c.h b/include/asm-arm/arch-spear/spr_i2c.h new file mode 100755 index 0000000..6fe80e9 --- /dev/null +++ b/include/asm-arm/arch-spear/spr_i2c.h @@ -0,0 +1,143 @@ +/* + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.ku...@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 1ms */ +#define I2C_BYTE_TO (CONFIG_SYS_HZ/1000) +#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_SPH 0x0006 +#define IC_CON_SPF 0x0004 +#define IC_CON_SPL 0x0002 +#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 + +/* 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_ */ -- 1.6.0.2 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot