1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter.git synced 2025-03-09 15:40:20 +00:00

Fix for RUTX platform

This commit is contained in:
Ycarus (Yannick Chabanois) 2022-03-28 18:17:07 +02:00
parent ccdb64ad45
commit 59bc57d5d5
7254 changed files with 1810270 additions and 7 deletions

View file

@ -0,0 +1,67 @@
#
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# 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 $(TOPDIR)/config.mk
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
COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
COBJS-$(CONFIG_I2C_MXS) += mxs_i2c.o
COBJS-$(CONFIG_DRIVER_OMAP1510_I2C) += omap1510_i2c.o
COBJS-$(CONFIG_DRIVER_OMAP24XX_I2C) += omap24xx_i2c.o
COBJS-$(CONFIG_DRIVER_OMAP34XX_I2C) += omap24xx_i2c.o
COBJS-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o
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_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-$(CONFIG_IPQ806X_I2C) += ipq_i2c.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
all: $(LIB)
$(LIB): $(obj).depend $(OBJS)
$(call cmd_link_o_target, $(OBJS))
#########################################################################
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################

View file

@ -0,0 +1,378 @@
/*
* i2c.c - driver for Blackfin on-chip TWI/I2C
*
* Copyright (c) 2006-2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <common.h>
#include <i2c.h>
#include <asm/blackfin.h>
#include <asm/mach-common/bits/twi.h>
/* Every register is 32bit aligned, but only 16bits in size */
#define ureg(name) u16 name; u16 __pad_##name;
struct twi_regs {
ureg(clkdiv);
ureg(control);
ureg(slave_ctl);
ureg(slave_stat);
ureg(slave_addr);
ureg(master_ctl);
ureg(master_stat);
ureg(master_addr);
ureg(int_stat);
ureg(int_mask);
ureg(fifo_ctl);
ureg(fifo_stat);
char __pad[0x50];
ureg(xmt_data8);
ureg(xmt_data16);
ureg(rcv_data8);
ureg(rcv_data16);
};
#undef ureg
/* U-Boot I2C framework allows only one active device at a time. */
#ifdef TWI_CLKDIV
#define TWI0_CLKDIV TWI_CLKDIV
#endif
static volatile struct twi_regs *twi = (void *)TWI0_CLKDIV;
#ifdef DEBUG
# define dmemset(s, c, n) memset(s, c, n)
#else
# define dmemset(s, c, n)
#endif
#define debugi(fmt, args...) \
debug( \
"MSTAT:0x%03x FSTAT:0x%x ISTAT:0x%02x\t%-20s:%-3i: " fmt "\n", \
twi->master_stat, twi->fifo_stat, twi->int_stat, \
__func__, __LINE__, ## args)
#ifdef CONFIG_TWICLK_KHZ
# error do not define CONFIG_TWICLK_KHZ ... use CONFIG_SYS_I2C_SPEED
#endif
/*
* The way speed is changed into duty often results in integer truncation
* with 50% duty, so we'll force rounding up to the next duty by adding 1
* to the max. In practice this will get us a speed of something like
* 385 KHz. The other limit is easy to handle as it is only 8 bits.
*/
#define I2C_SPEED_MAX 400000
#define I2C_SPEED_TO_DUTY(speed) (5000000 / (speed))
#define I2C_DUTY_MAX (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1)
#define I2C_DUTY_MIN 0xff /* 8 bit limited */
#define SYS_I2C_DUTY I2C_SPEED_TO_DUTY(CONFIG_SYS_I2C_SPEED)
/* Note: duty is inverse of speed, so the comparisons below are correct */
#if SYS_I2C_DUTY < I2C_DUTY_MAX || SYS_I2C_DUTY > I2C_DUTY_MIN
# error "The Blackfin I2C hardware can only operate 20KHz - 400KHz"
#endif
/* All transfers are described by this data structure */
struct i2c_msg {
u8 flags;
#define I2C_M_COMBO 0x4
#define I2C_M_STOP 0x2
#define I2C_M_READ 0x1
int len; /* msg length */
u8 *buf; /* pointer to msg data */
int alen; /* addr length */
u8 *abuf; /* addr buffer */
};
/* Allow msec timeout per ~byte transfer */
#define I2C_TIMEOUT 10
/**
* wait_for_completion - manage the actual i2c transfer
* @msg: the i2c msg
*/
static int wait_for_completion(struct i2c_msg *msg)
{
uint16_t int_stat;
ulong timebase = get_timer(0);
do {
int_stat = twi->int_stat;
if (int_stat & XMTSERV) {
debugi("processing XMTSERV");
twi->int_stat = XMTSERV;
SSYNC();
if (msg->alen) {
twi->xmt_data8 = *(msg->abuf++);
--msg->alen;
} else if (!(msg->flags & I2C_M_COMBO) && msg->len) {
twi->xmt_data8 = *(msg->buf++);
--msg->len;
} else {
twi->master_ctl |= (msg->flags & I2C_M_COMBO) ? RSTART | MDIR : STOP;
SSYNC();
}
}
if (int_stat & RCVSERV) {
debugi("processing RCVSERV");
twi->int_stat = RCVSERV;
SSYNC();
if (msg->len) {
*(msg->buf++) = twi->rcv_data8;
--msg->len;
} else if (msg->flags & I2C_M_STOP) {
twi->master_ctl |= STOP;
SSYNC();
}
}
if (int_stat & MERR) {
debugi("processing MERR");
twi->int_stat = MERR;
SSYNC();
return msg->len;
}
if (int_stat & MCOMP) {
debugi("processing MCOMP");
twi->int_stat = MCOMP;
SSYNC();
if (msg->flags & I2C_M_COMBO && msg->len) {
twi->master_ctl = (twi->master_ctl & ~RSTART) |
(min(msg->len, 0xff) << 6) | MEN | MDIR;
SSYNC();
} else
break;
}
/* If we were able to do something, reset timeout */
if (int_stat)
timebase = get_timer(0);
} while (get_timer(timebase) < I2C_TIMEOUT);
return msg->len;
}
/**
* i2c_transfer - setup an i2c transfer
* @return: 0 if things worked, non-0 if things failed
*
* Here we just get the i2c stuff all prepped and ready, and then tail off
* into wait_for_completion() for all the bits to go.
*/
static int i2c_transfer(uchar chip, uint addr, int alen, uchar *buffer, int len, u8 flags)
{
uchar addr_buffer[] = {
(addr >> 0),
(addr >> 8),
(addr >> 16),
};
struct i2c_msg msg = {
.flags = flags | (len >= 0xff ? I2C_M_STOP : 0),
.buf = buffer,
.len = len,
.abuf = addr_buffer,
.alen = alen,
};
int ret;
dmemset(buffer, 0xff, len);
debugi("chip=0x%x addr=0x%02x alen=%i buf[0]=0x%02x len=%i flags=0x%02x[%s] ",
chip, addr, alen, buffer[0], len, flags, (flags & I2C_M_READ ? "rd" : "wr"));
/* wait for things to settle */
while (twi->master_stat & BUSBUSY)
if (ctrlc())
return 1;
/* Set Transmit device address */
twi->master_addr = chip;
/* Clear the FIFO before starting things */
twi->fifo_ctl = XMTFLUSH | RCVFLUSH;
SSYNC();
twi->fifo_ctl = 0;
SSYNC();
/* prime the pump */
if (msg.alen) {
len = (msg.flags & I2C_M_COMBO) ? msg.alen : msg.alen + len;
debugi("first byte=0x%02x", *msg.abuf);
twi->xmt_data8 = *(msg.abuf++);
--msg.alen;
} else if (!(msg.flags & I2C_M_READ) && msg.len) {
debugi("first byte=0x%02x", *msg.buf);
twi->xmt_data8 = *(msg.buf++);
--msg.len;
}
/* clear int stat */
twi->master_stat = -1;
twi->int_stat = -1;
twi->int_mask = 0;
SSYNC();
/* Master enable */
twi->master_ctl =
(twi->master_ctl & FAST) |
(min(len, 0xff) << 6) | MEN |
((msg.flags & I2C_M_READ) ? MDIR : 0);
SSYNC();
debugi("CTL=0x%04x", twi->master_ctl);
/* process the rest */
ret = wait_for_completion(&msg);
debugi("ret=%d", ret);
if (ret) {
twi->master_ctl &= ~MEN;
twi->control &= ~TWI_ENA;
SSYNC();
twi->control |= TWI_ENA;
SSYNC();
}
return ret;
}
/**
* i2c_set_bus_speed - set i2c bus speed
* @speed: bus speed (in HZ)
*/
int i2c_set_bus_speed(unsigned int speed)
{
u16 clkdiv = I2C_SPEED_TO_DUTY(speed);
/* Set TWI interface clock */
if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN)
return -1;
twi->clkdiv = (clkdiv << 8) | (clkdiv & 0xff);
/* Don't turn it on */
twi->master_ctl = (speed > 100000 ? FAST : 0);
return 0;
}
/**
* i2c_get_bus_speed - get i2c bus speed
* @speed: bus speed (in HZ)
*/
unsigned int i2c_get_bus_speed(void)
{
/* 10 MHz / (2 * CLKDIV) -> 5 MHz / CLKDIV */
return 5000000 / (twi->clkdiv & 0xff);
}
/**
* i2c_init - initialize the i2c bus
* @speed: bus speed (in HZ)
* @slaveaddr: address of device in slave mode (0 - not slave)
*
* Slave mode isn't actually implemented. It'll stay that way until
* we get a real request for it.
*/
void i2c_init(int speed, int slaveaddr)
{
uint8_t prescale = ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F;
/* Set TWI internal clock as 10MHz */
twi->control = prescale;
/* Set TWI interface clock as specified */
i2c_set_bus_speed(speed);
/* Enable it */
twi->control = TWI_ENA | prescale;
SSYNC();
debugi("CONTROL:0x%04x CLKDIV:0x%04x", twi->control, twi->clkdiv);
#if CONFIG_SYS_I2C_SLAVE
# error I2C slave support not tested/supported
/* If they want us as a slave, do it */
if (slaveaddr) {
twi->slave_addr = slaveaddr;
twi->slave_ctl = SEN;
}
#endif
}
/**
* i2c_probe - test if a chip exists at a given i2c address
* @chip: i2c chip addr to search for
* @return: 0 if found, non-0 if not found
*/
int i2c_probe(uchar chip)
{
u8 byte;
return i2c_read(chip, 0, 0, &byte, 1);
}
/**
* i2c_read - read data from an i2c device
* @chip: i2c chip addr
* @addr: memory (register) address in the chip
* @alen: byte size of address
* @buffer: buffer to store data read from chip
* @len: how many bytes to read
* @return: 0 on success, non-0 on failure
*/
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
return i2c_transfer(chip, addr, alen, buffer, len, (alen ? I2C_M_COMBO : I2C_M_READ));
}
/**
* i2c_write - write data to an i2c device
* @chip: i2c chip addr
* @addr: memory (register) address in the chip
* @alen: byte size of address
* @buffer: buffer holding data to write to chip
* @len: how many bytes to write
* @return: 0 on success, non-0 on failure
*/
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
return i2c_transfer(chip, addr, alen, buffer, len, 0);
}
/**
* 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) {
#if CONFIG_SYS_MAX_I2C_BUS > 0
case 0: twi = (void *)TWI0_CLKDIV; return 0;
#endif
#if CONFIG_SYS_MAX_I2C_BUS > 1
case 1: twi = (void *)TWI1_CLKDIV; return 0;
#endif
#if CONFIG_SYS_MAX_I2C_BUS > 2
case 2: twi = (void *)TWI2_CLKDIV; return 0;
#endif
default: return -1;
}
}
/**
* i2c_get_bus_num - returns index of active I2C bus
*/
unsigned int i2c_get_bus_num(void)
{
switch ((unsigned long)twi) {
#if CONFIG_SYS_MAX_I2C_BUS > 0
case TWI0_CLKDIV: return 0;
#endif
#if CONFIG_SYS_MAX_I2C_BUS > 1
case TWI1_CLKDIV: return 1;
#endif
#if CONFIG_SYS_MAX_I2C_BUS > 2
case TWI2_CLKDIV: return 2;
#endif
default: return -1;
}
}

View file

@ -0,0 +1,332 @@
/*
* TI DaVinci (TMS320DM644x) I2C driver.
*
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
*
* --------------------------------------------------------
*
* 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 <i2c.h>
#include <asm/arch/hardware.h>
#include <asm/arch/i2c_defs.h>
#define CHECK_NACK() \
do {\
if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\
REG(I2C_CON) = 0;\
return(1);\
}\
} while (0)
static int wait_for_bus(void)
{
int stat, timeout;
REG(I2C_STAT) = 0xffff;
for (timeout = 0; timeout < 10; timeout++) {
if (!((stat = REG(I2C_STAT)) & I2C_STAT_BB)) {
REG(I2C_STAT) = 0xffff;
return(0);
}
REG(I2C_STAT) = stat;
udelay(50000);
}
REG(I2C_STAT) = 0xffff;
return(1);
}
static int poll_i2c_irq(int mask)
{
int stat, timeout;
for (timeout = 0; timeout < 10; timeout++) {
udelay(1000);
stat = REG(I2C_STAT);
if (stat & mask) {
return(stat);
}
}
REG(I2C_STAT) = 0xffff;
return(stat | I2C_TIMEOUT);
}
void flush_rx(void)
{
while (1) {
if (!(REG(I2C_STAT) & I2C_STAT_RRDY))
break;
REG(I2C_DRR);
REG(I2C_STAT) = I2C_STAT_RRDY;
udelay(1000);
}
}
void i2c_init(int speed, int slaveadd)
{
u_int32_t div, psc;
if (REG(I2C_CON) & I2C_CON_EN) {
REG(I2C_CON) = 0;
udelay (50000);
}
psc = 2;
div = (CONFIG_SYS_HZ_CLOCK / ((psc + 1) * speed)) - 10; /* SCLL + SCLH */
REG(I2C_PSC) = psc; /* 27MHz / (2 + 1) = 9MHz */
REG(I2C_SCLL) = (div * 50) / 100; /* 50% Duty */
REG(I2C_SCLH) = div - REG(I2C_SCLL);
REG(I2C_OA) = slaveadd;
REG(I2C_CNT) = 0;
/* Interrupts must be enabled or I2C module won't work */
REG(I2C_IE) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE |
I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE;
/* Now enable I2C controller (get it out of reset) */
REG(I2C_CON) = I2C_CON_EN;
udelay(1000);
}
int i2c_set_bus_speed(unsigned int speed)
{
i2c_init(speed, CONFIG_SYS_I2C_SLAVE);
return 0;
}
int i2c_probe(u_int8_t chip)
{
int rc = 1;
if (chip == REG(I2C_OA)) {
return(rc);
}
REG(I2C_CON) = 0;
if (wait_for_bus()) {return(1);}
/* try to read one byte from current (or only) address */
REG(I2C_CNT) = 1;
REG(I2C_SA) = chip;
REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP);
udelay (50000);
if (!(REG(I2C_STAT) & I2C_STAT_NACK)) {
rc = 0;
flush_rx();
REG(I2C_STAT) = 0xffff;
} else {
REG(I2C_STAT) = 0xffff;
REG(I2C_CON) |= I2C_CON_STP;
udelay(20000);
if (wait_for_bus()) {return(1);}
}
flush_rx();
REG(I2C_STAT) = 0xffff;
REG(I2C_CNT) = 0;
return(rc);
}
int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
{
u_int32_t tmp;
int i;
if ((alen < 0) || (alen > 2)) {
printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
return(1);
}
if (wait_for_bus()) {return(1);}
if (alen != 0) {
/* Start address phase */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
REG(I2C_CNT) = alen;
REG(I2C_SA) = chip;
REG(I2C_CON) = tmp;
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
switch (alen) {
case 2:
/* Send address MSByte */
if (tmp & I2C_STAT_XRDY) {
REG(I2C_DXR) = (addr >> 8) & 0xff;
} else {
REG(I2C_CON) = 0;
return(1);
}
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
/* No break, fall through */
case 1:
/* Send address LSByte */
if (tmp & I2C_STAT_XRDY) {
REG(I2C_DXR) = addr & 0xff;
} else {
REG(I2C_CON) = 0;
return(1);
}
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY);
CHECK_NACK();
if (!(tmp & I2C_STAT_ARDY)) {
REG(I2C_CON) = 0;
return(1);
}
}
}
/* Address phase is over, now read 'len' bytes and stop */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
REG(I2C_CNT) = len & 0xffff;
REG(I2C_SA) = chip;
REG(I2C_CON) = tmp;
for (i = 0; i < len; i++) {
tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR);
CHECK_NACK();
if (tmp & I2C_STAT_RRDY) {
buf[i] = REG(I2C_DRR);
} else {
REG(I2C_CON) = 0;
return(1);
}
}
tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
if (!(tmp & I2C_STAT_SCD)) {
REG(I2C_CON) = 0;
return(1);
}
flush_rx();
REG(I2C_STAT) = 0xffff;
REG(I2C_CNT) = 0;
REG(I2C_CON) = 0;
return(0);
}
int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
{
u_int32_t tmp;
int i;
if ((alen < 0) || (alen > 2)) {
printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
return(1);
}
if (len < 0) {
printf("%s(): bogus length %x\n", __FUNCTION__, len);
return(1);
}
if (wait_for_bus()) {return(1);}
/* Start address phase */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP;
REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen;
REG(I2C_SA) = chip;
REG(I2C_CON) = tmp;
switch (alen) {
case 2:
/* Send address MSByte */
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(I2C_DXR) = (addr >> 8) & 0xff;
} else {
REG(I2C_CON) = 0;
return(1);
}
/* No break, fall through */
case 1:
/* Send address LSByte */
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(I2C_DXR) = addr & 0xff;
} else {
REG(I2C_CON) = 0;
return(1);
}
}
for (i = 0; i < len; i++) {
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(I2C_DXR) = buf[i];
} else {
return(1);
}
}
tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
if (!(tmp & I2C_STAT_SCD)) {
REG(I2C_CON) = 0;
return(1);
}
flush_rx();
REG(I2C_STAT) = 0xffff;
REG(I2C_CNT) = 0;
REG(I2C_CON) = 0;
return(0);
}

View file

@ -0,0 +1,346 @@
/*
* (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 <common.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#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;
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));
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);
/* re-enable i2c ctrl back now that speed is set */
enbl |= IC_ENABLE_0B;
writel(enbl, &i2c_regs_p->ic_enable);
}
/*
* i2c_set_bus_speed - Set the i2c speed
* @speed: required i2c speed
*
* Set the i2c speed.
*/
int 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);
return 0;
}
/*
* 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())
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) {
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;
int ret;
/*
* Try to read the first location of the chip.
*/
ret = i2c_read(chip, 0, 1, (uchar *)&tmp, 1);
if (ret)
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return ret;
}

View file

@ -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_ */

View file

@ -0,0 +1,495 @@
/*
* Copyright 2006,2009 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* Version 2 as published by the Free Software Foundation.
*
* 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>
#ifdef CONFIG_HARD_I2C
#include <command.h>
#include <i2c.h> /* Functional interface */
#include <asm/io.h>
#include <asm/fsl_i2c.h> /* HW definitions */
/* The maximum number of microseconds we will wait until another master has
* released the bus. If not defined in the board header file, then use a
* generic value.
*/
#ifndef CONFIG_I2C_MBB_TIMEOUT
#define CONFIG_I2C_MBB_TIMEOUT 100000
#endif
/* The maximum number of microseconds we will wait for a read or write
* operation to complete. If not defined in the board header file, then use a
* generic value.
*/
#ifndef CONFIG_I2C_TIMEOUT
#define CONFIG_I2C_TIMEOUT 10000
#endif
#define I2C_READ_BIT 1
#define I2C_WRITE_BIT 0
DECLARE_GLOBAL_DATA_PTR;
/* Initialize the bus pointer to whatever one the SPD EEPROM is on.
* Default is bus 0. This is necessary because the DDR initialization
* runs from ROM, and we can't switch buses because we can't modify
* the global variables.
*/
#ifndef CONFIG_SYS_SPD_BUS_NUM
#define CONFIG_SYS_SPD_BUS_NUM 0
#endif
static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = CONFIG_SYS_SPD_BUS_NUM;
#if defined(CONFIG_I2C_MUX)
static unsigned int i2c_bus_num_mux __attribute__ ((section ("data"))) = 0;
#endif
static unsigned int i2c_bus_speed[2] = {CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED};
static const struct fsl_i2c *i2c_dev[2] = {
(struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET),
#ifdef CONFIG_SYS_I2C2_OFFSET
(struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C2_OFFSET)
#endif
};
/* I2C speed map for a DFSR value of 1 */
/*
* Map I2C frequency dividers to FDR and DFSR values
*
* This structure is used to define the elements of a table that maps I2C
* frequency divider (I2C clock rate divided by I2C bus speed) to a value to be
* programmed into the Frequency Divider Ratio (FDR) and Digital Filter
* Sampling Rate (DFSR) registers.
*
* The actual table should be defined in the board file, and it must be called
* fsl_i2c_speed_map[].
*
* The last entry of the table must have a value of {-1, X}, where X is same
* FDR/DFSR values as the second-to-last entry. This guarantees that any
* search through the array will always find a match.
*
* The values of the divider must be in increasing numerical order, i.e.
* fsl_i2c_speed_map[x+1].divider > fsl_i2c_speed_map[x].divider.
*
* For this table, the values are based on a value of 1 for the DFSR
* register. See the application note AN2919 "Determining the I2C Frequency
* Divider Ratio for SCL"
*
* ColdFire I2C frequency dividers for FDR values are different from
* PowerPC. The protocol to use the I2C module is still the same.
* A different table is defined and are based on MCF5xxx user manual.
*
*/
static const struct {
unsigned short divider;
u8 fdr;
} fsl_i2c_speed_map[] = {
#ifdef __M68K__
{20, 32}, {22, 33}, {24, 34}, {26, 35},
{28, 0}, {28, 36}, {30, 1}, {32, 37},
{34, 2}, {36, 38}, {40, 3}, {40, 39},
{44, 4}, {48, 5}, {48, 40}, {56, 6},
{56, 41}, {64, 42}, {68, 7}, {72, 43},
{80, 8}, {80, 44}, {88, 9}, {96, 41},
{104, 10}, {112, 42}, {128, 11}, {128, 43},
{144, 12}, {160, 13}, {160, 48}, {192, 14},
{192, 49}, {224, 50}, {240, 15}, {256, 51},
{288, 16}, {320, 17}, {320, 52}, {384, 18},
{384, 53}, {448, 54}, {480, 19}, {512, 55},
{576, 20}, {640, 21}, {640, 56}, {768, 22},
{768, 57}, {960, 23}, {896, 58}, {1024, 59},
{1152, 24}, {1280, 25}, {1280, 60}, {1536, 26},
{1536, 61}, {1792, 62}, {1920, 27}, {2048, 63},
{2304, 28}, {2560, 29}, {3072, 30}, {3840, 31},
{-1, 31}
#endif
};
/**
* Set the I2C bus speed for a given I2C device
*
* @param dev: the I2C device
* @i2c_clk: I2C bus clock frequency
* @speed: the desired speed of the bus
*
* The I2C device must be stopped before calling this function.
*
* The return value is the actual bus speed that is set.
*/
static unsigned int set_i2c_bus_speed(const struct fsl_i2c *dev,
unsigned int i2c_clk, unsigned int speed)
{
unsigned short divider = min(i2c_clk / speed, (unsigned short) -1);
/*
* We want to choose an FDR/DFSR that generates an I2C bus speed that
* is equal to or lower than the requested speed. That means that we
* want the first divider that is equal to or greater than the
* calculated divider.
*/
#ifdef __PPC__
u8 dfsr, fdr = 0x31; /* Default if no FDR found */
/* a, b and dfsr matches identifiers A,B and C respectively in AN2919 */
unsigned short a, b, ga, gb;
unsigned long c_div, est_div;
#ifdef CONFIG_FSL_I2C_CUSTOM_DFSR
dfsr = CONFIG_FSL_I2C_CUSTOM_DFSR;
#else
/* Condition 1: dfsr <= 50/T */
dfsr = (5 * (i2c_clk / 1000)) / 100000;
#endif
#ifdef CONFIG_FSL_I2C_CUSTOM_FDR
fdr = CONFIG_FSL_I2C_CUSTOM_FDR;
speed = i2c_clk / divider; /* Fake something */
#else
debug("Requested speed:%d, i2c_clk:%d\n", speed, i2c_clk);
if (!dfsr)
dfsr = 1;
est_div = ~0;
for (ga = 0x4, a = 10; a <= 30; ga++, a += 2) {
for (gb = 0; gb < 8; gb++) {
b = 16 << gb;
c_div = b * (a + ((3*dfsr)/b)*2);
if ((c_div > divider) && (c_div < est_div)) {
unsigned short bin_gb, bin_ga;
est_div = c_div;
bin_gb = gb << 2;
bin_ga = (ga & 0x3) | ((ga & 0x4) << 3);
fdr = bin_gb | bin_ga;
speed = i2c_clk / est_div;
debug("FDR:0x%.2x, div:%ld, ga:0x%x, gb:0x%x, "
"a:%d, b:%d, speed:%d\n",
fdr, est_div, ga, gb, a, b, speed);
/* Condition 2 not accounted for */
debug("Tr <= %d ns\n",
(b - 3 * dfsr) * 1000000 /
(i2c_clk / 1000));
}
}
if (a == 20)
a += 2;
if (a == 24)
a += 4;
}
debug("divider:%d, est_div:%ld, DFSR:%d\n", divider, est_div, dfsr);
debug("FDR:0x%.2x, speed:%d\n", fdr, speed);
#endif
writeb(dfsr, &dev->dfsrr); /* set default filter */
writeb(fdr, &dev->fdr); /* set bus speed */
#else
unsigned int i;
for (i = 0; i < ARRAY_SIZE(fsl_i2c_speed_map); i++)
if (fsl_i2c_speed_map[i].divider >= divider) {
u8 fdr;
fdr = fsl_i2c_speed_map[i].fdr;
speed = i2c_clk / fsl_i2c_speed_map[i].divider;
writeb(fdr, &dev->fdr); /* set bus speed */
break;
}
#endif
return speed;
}
unsigned int get_i2c_clock(int bus)
{
if (bus)
return gd->i2c2_clk; /* I2C2 clock */
else
return gd->i2c1_clk; /* I2C1 clock */
}
void
i2c_init(int speed, int slaveadd)
{
const struct fsl_i2c *dev;
unsigned int temp;
int bus_num, i;
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/* Call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*/
i2c_init_board();
#endif
#ifdef CONFIG_SYS_I2C2_OFFSET
bus_num = 2;
#else
bus_num = 1;
#endif
for (i = 0; i < bus_num; i++) {
dev = i2c_dev[i];
writeb(0, &dev->cr); /* stop I2C controller */
udelay(5); /* let it shutdown in peace */
temp = set_i2c_bus_speed(dev, get_i2c_clock(i), speed);
if (gd->flags & GD_FLG_RELOC)
i2c_bus_speed[i] = temp;
writeb(slaveadd << 1, &dev->adr);/* write slave address */
writeb(0x0, &dev->sr); /* clear status register */
writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */
}
#ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT
/* Call board specific i2c bus reset routine AFTER the bus has been
* initialized. Use either this callpoint or i2c_init_board;
* which is called before i2c_init operations.
* For details about this problem see doc/I2C_Edge_Conditions.
*/
i2c_board_late_init();
#endif
}
static int
i2c_wait4bus(void)
{
unsigned long long timeval = get_ticks();
const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
while (readb(&i2c_dev[i2c_bus_num]->sr) & I2C_SR_MBB) {
if ((get_ticks() - timeval) > timeout)
return -1;
}
return 0;
}
static __inline__ int
i2c_wait(int write)
{
u32 csr;
unsigned long long timeval = get_ticks();
const unsigned long long timeout = usec2ticks(CONFIG_I2C_TIMEOUT);
do {
csr = readb(&i2c_dev[i2c_bus_num]->sr);
if (!(csr & I2C_SR_MIF))
continue;
/* Read again to allow register to stabilise */
csr = readb(&i2c_dev[i2c_bus_num]->sr);
writeb(0x0, &i2c_dev[i2c_bus_num]->sr);
if (csr & I2C_SR_MAL) {
debug("i2c_wait: MAL\n");
return -1;
}
if (!(csr & I2C_SR_MCF)) {
debug("i2c_wait: unfinished\n");
return -1;
}
if (write == I2C_WRITE_BIT && (csr & I2C_SR_RXAK)) {
debug("i2c_wait: No RXACK\n");
return -1;
}
return 0;
} while ((get_ticks() - timeval) < timeout);
debug("i2c_wait: timed out\n");
return -1;
}
static __inline__ int
i2c_write_addr (u8 dev, u8 dir, int rsta)
{
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX
| (rsta ? I2C_CR_RSTA : 0),
&i2c_dev[i2c_bus_num]->cr);
writeb((dev << 1) | dir, &i2c_dev[i2c_bus_num]->dr);
if (i2c_wait(I2C_WRITE_BIT) < 0)
return 0;
return 1;
}
static __inline__ int
__i2c_write(u8 *data, int length)
{
int i;
for (i = 0; i < length; i++) {
writeb(data[i], &i2c_dev[i2c_bus_num]->dr);
if (i2c_wait(I2C_WRITE_BIT) < 0)
break;
}
return i;
}
static __inline__ int
__i2c_read(u8 *data, int length)
{
int i;
writeb(I2C_CR_MEN | I2C_CR_MSTA | ((length == 1) ? I2C_CR_TXAK : 0),
&i2c_dev[i2c_bus_num]->cr);
/* dummy read */
readb(&i2c_dev[i2c_bus_num]->dr);
for (i = 0; i < length; i++) {
if (i2c_wait(I2C_READ_BIT) < 0)
break;
/* Generate ack on last next to last byte */
if (i == length - 2)
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_TXAK,
&i2c_dev[i2c_bus_num]->cr);
/* Do not generate stop on last byte */
if (i == length - 1)
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX,
&i2c_dev[i2c_bus_num]->cr);
data[i] = readb(&i2c_dev[i2c_bus_num]->dr);
}
return i;
}
int
i2c_read(u8 dev, uint addr, int alen, u8 *data, int length)
{
int i = -1; /* signal error */
u8 *a = (u8*)&addr;
if (i2c_wait4bus() >= 0
&& i2c_write_addr(dev, I2C_WRITE_BIT, 0) != 0
&& __i2c_write(&a[4 - alen], alen) == alen)
i = 0; /* No error so far */
if (length
&& i2c_write_addr(dev, I2C_READ_BIT, 1) != 0)
i = __i2c_read(data, length);
writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr);
if (i2c_wait4bus()) /* Wait until STOP */
debug("i2c_read: wait4bus timed out\n");
if (i == length)
return 0;
return -1;
}
int
i2c_write(u8 dev, uint addr, int alen, u8 *data, int length)
{
int i = -1; /* signal error */
u8 *a = (u8*)&addr;
if (i2c_wait4bus() >= 0
&& i2c_write_addr(dev, I2C_WRITE_BIT, 0) != 0
&& __i2c_write(&a[4 - alen], alen) == alen) {
i = __i2c_write(data, length);
}
writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr);
if (i2c_wait4bus()) /* Wait until STOP */
debug("i2c_write: wait4bus timed out\n");
if (i == length)
return 0;
return -1;
}
int
i2c_probe(uchar chip)
{
/* For unknow reason the controller will ACK when
* probing for a slave with the same address, so skip
* it.
*/
if (chip == (readb(&i2c_dev[i2c_bus_num]->adr) >> 1))
return -1;
return i2c_read(chip, 0, 0, NULL, 0);
}
int i2c_set_bus_num(unsigned int bus)
{
#if defined(CONFIG_I2C_MUX)
if (bus < CONFIG_SYS_MAX_I2C_BUS) {
i2c_bus_num = bus;
} else {
int ret;
ret = i2x_mux_select_mux(bus);
if (ret)
return ret;
i2c_bus_num = 0;
}
i2c_bus_num_mux = bus;
#else
#ifdef CONFIG_SYS_I2C2_OFFSET
if (bus > 1) {
#else
if (bus > 0) {
#endif
return -1;
}
i2c_bus_num = bus;
#endif
return 0;
}
int i2c_set_bus_speed(unsigned int speed)
{
unsigned int i2c_clk = (i2c_bus_num == 1) ? gd->i2c2_clk : gd->i2c1_clk;
writeb(0, &i2c_dev[i2c_bus_num]->cr); /* stop controller */
i2c_bus_speed[i2c_bus_num] =
set_i2c_bus_speed(i2c_dev[i2c_bus_num], i2c_clk, speed);
writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr); /* start controller */
return 0;
}
unsigned int i2c_get_bus_num(void)
{
#if defined(CONFIG_I2C_MUX)
return i2c_bus_num_mux;
#else
return i2c_bus_num;
#endif
}
unsigned int i2c_get_bus_speed(void)
{
return i2c_bus_speed[i2c_bus_num];
}
#endif /* CONFIG_HARD_I2C */

View file

@ -0,0 +1,414 @@
/*
* Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <common.h>
#include <i2c.h>
#include "ipq_i2c.h"
#include <asm/io.h>
#include <asm/errno.h>
#include <asm/arch-ipq806x/gsbi.h>
#include <asm/arch-ipq806x/gpio.h>
#include <asm/arch-ipq806x/iomap.h>
#include <asm/arch-ipq806x/clock.h>
static int gsbi_port;
static int gsbi_base_addr;
static int i2c_hw_initialized;
static int i2c_board_initialized;
static uint32_t i2c_master_clk_ctl;
/*
* Reset entire QUP and all mini cores
*/
static void i2c_reset(void)
{
writel(0x1, GSBI_QUP_BASE(gsbi_port) + QUP_SW_RESET_OFFSET);
udelay(5);
}
static int check_bit_state(uint32_t reg_addr, int bit_num, int val,
int us_delay)
{
unsigned int count = TIMEOUT_CNT;
unsigned int bit_val = ((readl(reg_addr) >> bit_num) & 0x01);
while (bit_val != val) {
count--;
if (count == 0) {
return -ETIMEDOUT;
}
udelay(us_delay);
bit_val = ((readl(reg_addr) >> bit_num) & 0x01);
}
return SUCCESS;
}
/*
* Check whether GSBIn_QUP State is valid
*/
static int check_qup_state_valid(void)
{
return check_bit_state(GSBI_QUP_BASE(gsbi_port) + QUP_STATE_OFFSET,
QUP_STATE_VALID_BIT,
QUP_STATE_VALID, 1);
}
/*
* Configure GSBIn Core state
*/
static int config_i2c_state(unsigned int state)
{
uint32_t val;
int ret = SUCCESS;
ret = check_qup_state_valid();
if (ret != SUCCESS)
return ret;
/* Set the state */
val = readl(GSBI_QUP_BASE(gsbi_port) + QUP_STATE_OFFSET);
val = ((val & ~QUP_STATE_MASK) | state);
writel(val, GSBI_QUP_BASE(gsbi_port) + QUP_STATE_OFFSET);
ret = check_qup_state_valid();
return ret;
}
/*
* Configure I2C IO Mode.
*/
void config_i2c_mode(void)
{
int cfg;
cfg = readl(GSBI_QUP_BASE(gsbi_port) + QUP_IO_MODES_OFFSET);
cfg |= (INPUT_FIFO_MODE |
OUTPUT_FIFO_MODE |
OUTPUT_BIT_SHIFT_EN);
writel(cfg, GSBI_QUP_BASE(gsbi_port) + QUP_IO_MODES_OFFSET);
}
void i2c_ipq_board_init(void)
{
gsbi_base_addr = gboard_param->i2c_gsbi_base;
gsbi_port = gboard_param->i2c_gsbi;
/*
* Currently I2C GPIO lines (12(SDA), 13(SCLK)) are configured by
* RPM firmware for PMIC. Trustzone firmware configures the TLMM
* RPU in such a way that only RPM will be able to configure those
* GPIOs. If Krait non secure (u-boot) tries to write to those GPIO
* registers will lead to Master port L2 error.
* GSBI4 uses GPIO 12 and 13 lines for I2C.
* So for GSBI4 we will not update the GPIO configs. RPM would have
* already configured this.`
*/
/* Configure the GPIOs */
if (gsbi_port != GSBI_4)
ipq_configure_gpio(gboard_param->i2c_gpio, NO_OF_I2C_GPIOS);
/* Configure the I2C clock */
i2c_clock_config(gboard_param->i2c_gsbi,
gboard_param->i2c_mnd_value.m_value,
gboard_param->i2c_mnd_value.n_value,
gboard_param->i2c_mnd_value.d_value,
gboard_param->clk_dummy);
i2c_hw_initialized = 0;
i2c_board_initialized = 1;
}
/*
* GSBIn I2C Hardware Initialisation
*/
static int i2c_hw_init(void)
{
int ret, cfg;
/* GSBI module configuration */
i2c_reset();
/* Set the GSBIn QUP state */
ret = config_i2c_state(QUP_STATE_RESET);
if (ret)
return ret;
/* Configure GSBI_CTRL register to set protocol_mode to I2C_UART:110 */
writel(GSBI_PROTOCOL_CODE_I2C_UART <<
GSBI_CTRL_REG_PROTOCOL_CODE_S,
GSBI_CTRL_REG(gsbi_base_addr));
/* Configure Mini core to I2C core */
cfg = readl(GSBI_QUP_BASE(gsbi_port) + QUP_CONFIG_OFFSET);
cfg |= (QUP_CONFIG_MINI_CORE_I2C |
I2C_BIT_WORD);
writel(cfg, GSBI_QUP_BASE(gsbi_port) + QUP_CONFIG_OFFSET);
/* Configure I2C mode */
config_i2c_mode();
/* Enable QUP Error Flags */
writel(ERROR_FLAGS_EN,
GSBI_QUP_BASE(gsbi_port) + QUP_ERROR_FLAGS_EN_OFFSET);
/* Clear the MASTER_CTL_STATUS */
writel(I2C_MASTER_STATUS_CLEAR,
GSBI_QUP_BASE(gsbi_port) + QUP_I2C_MASTER_STATUS_OFFSET);
/* Set to RUN STATE */
ret = config_i2c_state(QUP_STATE_RUN);
if (ret)
return ret;
/* Configure the I2C Master clock */
i2c_master_clk_ctl = ((QUP_INPUT_CLK / (CONFIG_I2C_CLK_FREQ * 2)) - 3) & 0xff;
writel(i2c_master_clk_ctl, GSBI_QUP_BASE(gsbi_port) + QUP_I2C_MASTER_CLK_CTL_OFFSET);
i2c_hw_initialized = 1;
return SUCCESS;
}
/*
* Function to check wheather Input or Output FIFO
* has data to be serviced. For invalid slaves, this
* flag will not be set.
*/
static int check_fifo_status(uint dir)
{
unsigned int count = TIMEOUT_CNT;
unsigned int status_flag;
unsigned int val;
if (dir == READ) {
do {
val = readl(GSBI_QUP_BASE(gsbi_port)
+ QUP_OPERATIONAL_OFFSET);
count--;
if (count == 0)
return -ETIMEDOUT;
status_flag = val & INPUT_SERVICE_FLAG;
udelay(10);
} while (!status_flag);
} else if (dir == WRITE) {
do {
val = readl(GSBI_QUP_BASE(gsbi_port)
+ QUP_OPERATIONAL_OFFSET);
count--;
if (count == 0)
return -ETIMEDOUT;
status_flag = val & OUTPUT_FIFO_FULL;
udelay(10);
} while (status_flag);
/*
* Clear the flag and Acknowledge that the
* software has or will write the data.
*/
if (readl(GSBI_QUP_BASE(gsbi_port) + QUP_OPERATIONAL_OFFSET)
& OUTPUT_SERVICE_FLAG) {
writel(OUTPUT_SERVICE_FLAG, GSBI_QUP_BASE(gsbi_port)
+ QUP_OPERATIONAL_OFFSET);
}
}
return SUCCESS;
}
/*
* Check whether the values in the OUTPUT FIFO are shifted out.
*/
static int check_write_done(void)
{
unsigned int count = TIMEOUT_CNT;
unsigned int status_flag;
unsigned int val;
do {
val = readl(GSBI_QUP_BASE(gsbi_port)
+ QUP_OPERATIONAL_OFFSET);
count--;
if (count == 0)
return -ETIMEDOUT;
status_flag = val & OUTPUT_FIFO_NOT_EMPTY;
udelay(10);
} while (status_flag);
return SUCCESS;
}
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int ret = 0;
unsigned int data = 0;
if (!i2c_board_initialized) {
i2c_ipq_board_init();
}
if(!i2c_hw_initialized) {
i2c_hw_init();
}
writel(0xFF, GSBI_QUP_BASE(gsbi_port)
+ QUP_ERROR_FLAGS_OFFSET);
writel(0, GSBI_QUP_BASE(gsbi_port)
+ QUP_I2C_MASTER_STATUS_OFFSET);
/* Set to RUN state */
ret = config_i2c_state(QUP_STATE_RUN);
if (ret != SUCCESS)
goto out;
/* Configure the I2C Master clock */
writel(i2c_master_clk_ctl, GSBI_QUP_BASE(gsbi_port) + QUP_I2C_MASTER_CLK_CTL_OFFSET);
/* Send a write request to the chip */
writel((QUP_I2C_START_SEQ | QUP_I2C_ADDR(chip)),
GSBI_QUP_BASE(gsbi_port) + QUP_OUTPUT_FIFO_OFFSET);
writel((QUP_I2C_DATA_SEQ | QUP_I2C_DATA(addr)),
GSBI_QUP_BASE(gsbi_port) + QUP_OUTPUT_FIFO_OFFSET);
ret = check_write_done();
if (ret != SUCCESS)
goto out;
ret = check_fifo_status(WRITE);
if (ret != SUCCESS)
goto out;
/* Send read request */
writel((QUP_I2C_START_SEQ |
(QUP_I2C_ADDR(chip)|
QUP_I2C_SLAVE_READ)),
GSBI_QUP_BASE(gsbi_port) + QUP_OUTPUT_FIFO_OFFSET);
writel((QUP_I2C_RECV_SEQ | len),
GSBI_QUP_BASE(gsbi_port) + QUP_OUTPUT_FIFO_OFFSET);
while (len--) {
ret = check_fifo_status(READ);
if (ret != SUCCESS)
goto out;
/* Read the data from the FIFO */
data = readl(GSBI_QUP_BASE(gsbi_port) + QUP_INPUT_FIFO_OFFSET);
*buffer = QUP_I2C_DATA(data);
/*
* Clear the flag and Acknowledge that the
* software has or will read the data.
*/
writel(INPUT_SERVICE_FLAG,
GSBI_QUP_BASE(gsbi_port) + QUP_OPERATIONAL_OFFSET);
buffer++;
}
/* Set to PAUSE state */
ret = config_i2c_state(QUP_STATE_PAUSE);
if (ret != SUCCESS)
goto out;
out:
/*
* Put the I2C Core back in the Reset State to end the transfer.
*/
(void)config_i2c_state(QUP_STATE_RESET);
return ret;
}
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int ret = 0;
int idx = 0;
if (!i2c_board_initialized) {
i2c_ipq_board_init();
}
if(!i2c_hw_initialized) {
i2c_hw_init();
}
/* Set to RUN state */
ret = config_i2c_state(QUP_STATE_RUN);
if (ret != SUCCESS)
goto out;
/* Configure the I2C Master clock */
writel(i2c_master_clk_ctl, GSBI_QUP_BASE(gsbi_port) + QUP_I2C_MASTER_CLK_CTL_OFFSET);
/* Send the write request */
writel((QUP_I2C_START_SEQ | QUP_I2C_ADDR(chip)),
GSBI_QUP_BASE(gsbi_port) + QUP_OUTPUT_FIFO_OFFSET);
writel((QUP_I2C_DATA_SEQ | QUP_I2C_DATA(addr)),
GSBI_QUP_BASE(gsbi_port) + QUP_OUTPUT_FIFO_OFFSET);
while (len) {
if (len == 1) {
writel((QUP_I2C_STOP_SEQ | QUP_I2C_DATA(buffer[idx])),
GSBI_QUP_BASE(gsbi_port) + QUP_OUTPUT_FIFO_OFFSET);
} else {
writel((QUP_I2C_DATA_SEQ | QUP_I2C_DATA(buffer[idx])),
GSBI_QUP_BASE(gsbi_port) + QUP_OUTPUT_FIFO_OFFSET);
}
len--;
idx++;
ret = check_fifo_status(WRITE);
if (ret != SUCCESS)
goto out;
}
ret = check_write_done();
if (ret != SUCCESS)
goto out;
/* Set to PAUSE state */
ret = config_i2c_state(QUP_STATE_PAUSE);
if (ret != SUCCESS)
goto out;
return ret;
out:
/*
* Put the I2C Core back in the Reset State to end the transfer.
*/
(void)config_i2c_state(QUP_STATE_RESET);
return ret;
}
/*
* Probe the given I2C chip address.
* Returns 0 if a chip responded.
*/
int i2c_probe(uchar chip)
{
uchar buf;
return i2c_read(chip, 0x0, 0x1, &buf, 0x1);
}
void i2c_init(int speed, int slaveaddr)
{
debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
}

View file

@ -0,0 +1,155 @@
/*
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
static int gsbi_base[] = {
0x12440000,
0x12480000,
0x16200000,
0x16300000,
0x1A200000,
0x16500000,
0x16600000
};
/* GSBI QUP devices base address */
static int qup_offset[] = {
0x20000,
0x20000,
0x80000,
0x80000,
0x80000,
0x80000,
0x80000,
};
/* QUP Registers Base Address */
#define GSBI_QUP_BASE(x) (gsbi_base[x-1] + qup_offset[x-1])
#define GSBI_RESET(N) (0x009029DC + (32*(N-1)))
#define I2C_STATUS_ERROR_MASK 0x38000FC
/* QUP Core register offsets */
#define QUP_CONFIG_OFFSET 0x0
#define QUP_STATE_OFFSET 0x4
#define QUP_IO_MODES_OFFSET 0x8
#define QUP_SW_RESET_OFFSET 0xc
#define QUP_TIME_OUT_OFFSET 0x10
#define QUP_TIME_OUT_CURRENT_OFFSET 0x14
#define QUP_OPERATIONAL_OFFSET 0x18
#define QUP_ERROR_FLAGS_OFFSET 0x1c
#define QUP_ERROR_FLAGS_EN_OFFSET 0x20
#define QUP_TEST_CTRL_OFFSET 0x24
#define QUP_MX_OUTPUT_COUNT_OFFSET 0x100
#define QUP_MX_OUTPUT_CNT_CURRENT_OFFSET 0x104
#define QUP_OUTPUT_DEBUG_OFFSET 0x108
#define QUP_OUTPUT_FIFO_WORD_CNT_OFFSET 0x10c
#define QUP_OUTPUT_FIFO_OFFSET 0x110
#define QUP_MX_WRITE_COUNT_OFFSET 0x150
#define QUP_WRITE_CNT_CURRENT_OFFSET 0x154
#define QUP_MX_INPUT_COUNT_OFFSET 0x200
#define QUP_MX_READ_COUNT_OFFSET 0x208
#define QUP_MX_READ_CNT_CURRENT_OFFSET 0x20c
#define QUP_INPUT_DEBUG_OFFSET 0x210
#define QUP_INPUT_FIFO_WORD_CNT_OFFSET 0x214
#define QUP_INPUT_FIFO_OFFSET 0x218
#define QUP_I2C_MASTER_CLK_CTL_OFFSET 0x400
#define QUP_I2C_MASTER_STATUS_OFFSET 0x404
#define QUP_MAX_OFFSET 0xfff
#define SUCCESS 0
#define TIMEOUT_CNT 100
#define QUP_STATE_RESET 0x0
#define QUP_STATE_RUN 0x1D
#define QUP_STATE_PAUSE 0x1F
#define QUP_STATE_VALID_BIT 2
#define QUP_STATE_VALID 1
#define QUP_STATE_MASK 0x3
#define QUP_CONFIG_MINI_CORE_I2C (2 << 8)
#define I2C_BIT_WORD 0xF
#define INPUT_FIFO_MODE (0x0 << 12)
#define OUTPUT_FIFO_MODE (0x0 << 10)
#define INPUT_BLOCK_MODE (0x01 << 12)
#define OUTPUT_BLOCK_MODE (0x01 << 10)
#define PACK_EN (0x01 << 15)
#define UNPACK_EN (0x01 << 14)
#define OUTPUT_BIT_SHIFT_EN (0x01 << 16)
#define ERROR_FLAGS_EN 0x7C
#define I2C_MASTER_STATUS_CLEAR 0xFFFFFC
#define QUP_DATA_AVAILABLE_FOR_READ (1 << 5)
#define QUP_OUTPUT_FIFO_NOT_EMPTY (1 << 4)
#define OUTPUT_SERVICE_FLAG (1 << 8)
#define INPUT_SERVICE_FLAG (1 << 9)
#define QUP_OUTPUT_FIFO_FULL (1 << 6)
#define MAX_OUTPUT_DONE_FLAG (1 << 10)
#define MAX_INPUT_DONE_FLAG (1 << 11)
#define QUP_DATA_AVAILABLE_FOR_READ (1 << 5)
#define OUTPUT_FIFO_NOT_EMPTY (1 << 4)
#define OUTPUT_FIFO_FULL (1 << 6)
#define QUP_I2C_START_SEQ (0x1 << 8)
#define QUP_I2C_DATA_SEQ (0x2 << 8)
#define QUP_I2C_STOP_SEQ (0x3 << 8)
#define QUP_I2C_RECV_SEQ (0x4 << 8)
/* Tags for input FIFO */
#define QUP_I2C_MIDATA_SEQ (0x5 << 8)
#define QUP_I2C_MISTOP_SEQ (0x6 << 8)
#define QUP_I2C_MINACK_SEQ (0x7 << 8)
#define QUP_I2C_ADDR(x) ((x & 0xFF) << 1)
#define QUP_I2C_DATA(x) (x & 0xFF)
#define QUP_I2C_MI_TAG(x) (x & 0xFF00)
#define QUP_I2C_SLAVE_READ (0x1)
enum dir {
READ,
WRITE,
};
typedef enum
{
QUPI2C_NOP,
QUPI2C_START,
QUPI2C_MO_DATA,
QUPI2C_MO_STOP,
QUPI2C_MI_REC,
QUPI2C_MI_DATA,
QUPI2C_MI_STOP,
QUPI2C_MI_NACK,
QUPI2C_SO_DATA,
QUPI2C_SI_START,
QUPI2C_SI_DATA
} qupi2c_TagType;
#define qupi2c_NumberOfNops(c) ((QUPI2C_NOP << 8) | c)
#define qupi2c_StartWrite(c) ((QUPI2C_START << 8) | (c << 1) | 0)
#define qupi2c_StartRead(c) ((QUPI2C_START << 8) | (c << 1) | 1)
#define qupi2c_ByteWrite(c) ((QUPI2C_MO_DATA << 8) | c)
#define qupi2c_LastByteWrite(c) ((QUPI2C_MO_STOP << 8) | c)
#define qupi2c_NumberofReads(c) ((QUPI2C_MI_REC << 8) | c)
/* I2C some pre-defined frequencies */
#define I2C_CLK_1KHZ 1
#define I2C_CLK_100KHZ 100
#define I2C_CLK_400KHZ 400
#define I2C_CLK_1MHZ 1000
#define QUP_INPUT_CLK_TCXO 19200
#define QUP_INPUT_CLK_PLL8 24000
#define I2C_INPUT_CLK_TCXO_DIV4 ((I2C_INPUT_CLK_TCXO)/4)
#define QUP_INPUT_CLK QUP_INPUT_CLK_PLL8
#define CONFIG_I2C_CLK_FREQ I2C_CLK_100KHZ

View file

@ -0,0 +1,487 @@
/*
* (C) Copyright 2000
* Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
*
* (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2003 Pengutronix e.K.
* Robert Schwebel <r.schwebel@pengutronix.de>
*
* (C) Copyright 2011 Marvell Inc.
* Lei Wen <leiwen@marvell.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
*
* Back ported to the 8xx platform (from the 8260 platform) by
* Murray.Jensen@cmst.csiro.au, 27-Jan-01.
*/
#include <common.h>
#include <asm/io.h>
#ifdef CONFIG_HARD_I2C
#include <i2c.h>
#include "mv_i2c.h"
#ifdef DEBUG_I2C
#define PRINTD(x) printf x
#else
#define PRINTD(x)
#endif
/* All transfers are described by this data structure */
struct i2c_msg {
u8 condition;
u8 acknack;
u8 direction;
u8 data;
};
struct mv_i2c {
u32 ibmr;
u32 pad0;
u32 idbr;
u32 pad1;
u32 icr;
u32 pad2;
u32 isr;
u32 pad3;
u32 isar;
};
static struct mv_i2c *base;
static void i2c_board_init(struct mv_i2c *base)
{
#ifdef CONFIG_SYS_I2C_INIT_BOARD
u32 icr;
/*
* call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*
* disable I2C controller first, otherwhise it thinks we want to
* talk to the slave port...
*/
icr = readl(&base->icr);
writel(readl(&base->icr) & ~(ICR_SCLE | ICR_IUE), &base->icr);
i2c_init_board();
writel(icr, &base->icr);
#endif
}
#ifdef CONFIG_I2C_MULTI_BUS
static u32 i2c_regs[CONFIG_MV_I2C_NUM] = CONFIG_MV_I2C_REG;
static unsigned int bus_initialized[CONFIG_MV_I2C_NUM];
static unsigned int current_bus;
int i2c_set_bus_num(unsigned int bus)
{
if ((bus < 0) || (bus >= CONFIG_MV_I2C_NUM)) {
printf("Bad bus: %d\n", bus);
return -1;
}
base = (struct mv_i2c *)i2c_regs[bus];
current_bus = bus;
if (!bus_initialized[current_bus]) {
i2c_board_init(base);
bus_initialized[current_bus] = 1;
}
return 0;
}
unsigned int i2c_get_bus_num(void)
{
return current_bus;
}
#endif
/*
* i2c_reset: - reset the host controller
*
*/
static void i2c_reset(void)
{
writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */
writel(readl(&base->icr) | ICR_UR, &base->icr); /* reset the unit */
udelay(100);
writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */
i2c_clk_enable();
writel(CONFIG_SYS_I2C_SLAVE, &base->isar); /* set our slave address */
writel(I2C_ICR_INIT, &base->icr); /* set control reg values */
writel(I2C_ISR_INIT, &base->isr); /* set clear interrupt bits */
writel(readl(&base->icr) | ICR_IUE, &base->icr); /* enable unit */
udelay(100);
}
/*
* i2c_isr_set_cleared: - wait until certain bits of the I2C status register
* are set and cleared
*
* @return: 1 in case of success, 0 means timeout (no match within 10 ms).
*/
static int i2c_isr_set_cleared(unsigned long set_mask,
unsigned long cleared_mask)
{
int timeout = 1000, isr;
do {
isr = readl(&base->isr);
udelay(10);
if (timeout-- < 0)
return 0;
} while (((isr & set_mask) != set_mask)
|| ((isr & cleared_mask) != 0));
return 1;
}
/*
* i2c_transfer: - Transfer one byte over the i2c bus
*
* This function can tranfer a byte over the i2c bus in both directions.
* It is used by the public API functions.
*
* @return: 0: transfer successful
* -1: message is empty
* -2: transmit timeout
* -3: ACK missing
* -4: receive timeout
* -5: illegal parameters
* -6: bus is busy and couldn't be aquired
*/
int i2c_transfer(struct i2c_msg *msg)
{
int ret;
if (!msg)
goto transfer_error_msg_empty;
switch (msg->direction) {
case I2C_WRITE:
/* check if bus is not busy */
if (!i2c_isr_set_cleared(0, ISR_IBB))
goto transfer_error_bus_busy;
/* start transmission */
writel(readl(&base->icr) & ~ICR_START, &base->icr);
writel(readl(&base->icr) & ~ICR_STOP, &base->icr);
writel(msg->data, &base->idbr);
if (msg->condition == I2C_COND_START)
writel(readl(&base->icr) | ICR_START, &base->icr);
if (msg->condition == I2C_COND_STOP)
writel(readl(&base->icr) | ICR_STOP, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDNAK)
writel(readl(&base->icr) | ICR_ACKNAK, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDACK)
writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr);
writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr);
writel(readl(&base->icr) | ICR_TB, &base->icr);
/* transmit register empty? */
if (!i2c_isr_set_cleared(ISR_ITE, 0))
goto transfer_error_transmit_timeout;
/* clear 'transmit empty' state */
writel(readl(&base->isr) | ISR_ITE, &base->isr);
/* wait for ACK from slave */
if (msg->acknack == I2C_ACKNAK_WAITACK)
if (!i2c_isr_set_cleared(0, ISR_ACKNAK))
goto transfer_error_ack_missing;
break;
case I2C_READ:
/* check if bus is not busy */
if (!i2c_isr_set_cleared(0, ISR_IBB))
goto transfer_error_bus_busy;
/* start receive */
writel(readl(&base->icr) & ~ICR_START, &base->icr);
writel(readl(&base->icr) & ~ICR_STOP, &base->icr);
if (msg->condition == I2C_COND_START)
writel(readl(&base->icr) | ICR_START, &base->icr);
if (msg->condition == I2C_COND_STOP)
writel(readl(&base->icr) | ICR_STOP, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDNAK)
writel(readl(&base->icr) | ICR_ACKNAK, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDACK)
writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr);
writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr);
writel(readl(&base->icr) | ICR_TB, &base->icr);
/* receive register full? */
if (!i2c_isr_set_cleared(ISR_IRF, 0))
goto transfer_error_receive_timeout;
msg->data = readl(&base->idbr);
/* clear 'receive empty' state */
writel(readl(&base->isr) | ISR_IRF, &base->isr);
break;
default:
goto transfer_error_illegal_param;
}
return 0;
transfer_error_msg_empty:
PRINTD(("i2c_transfer: error: 'msg' is empty\n"));
ret = -1; goto i2c_transfer_finish;
transfer_error_transmit_timeout:
PRINTD(("i2c_transfer: error: transmit timeout\n"));
ret = -2; goto i2c_transfer_finish;
transfer_error_ack_missing:
PRINTD(("i2c_transfer: error: ACK missing\n"));
ret = -3; goto i2c_transfer_finish;
transfer_error_receive_timeout:
PRINTD(("i2c_transfer: error: receive timeout\n"));
ret = -4; goto i2c_transfer_finish;
transfer_error_illegal_param:
PRINTD(("i2c_transfer: error: illegal parameters\n"));
ret = -5; goto i2c_transfer_finish;
transfer_error_bus_busy:
PRINTD(("i2c_transfer: error: bus is busy\n"));
ret = -6; goto i2c_transfer_finish;
i2c_transfer_finish:
PRINTD(("i2c_transfer: ISR: 0x%04x\n", readl(&base->isr)));
i2c_reset();
return ret;
}
/* ------------------------------------------------------------------------ */
/* API Functions */
/* ------------------------------------------------------------------------ */
void i2c_init(int speed, int slaveaddr)
{
#ifdef CONFIG_I2C_MULTI_BUS
current_bus = 0;
base = (struct mv_i2c *)i2c_regs[current_bus];
#else
base = (struct mv_i2c *)CONFIG_MV_I2C_REG;
#endif
i2c_board_init(base);
}
/*
* 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(uchar chip)
{
struct i2c_msg msg;
i2c_reset();
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1) + 1;
if (i2c_transfer(&msg))
return -1;
msg.condition = I2C_COND_STOP;
msg.acknack = I2C_ACKNAK_SENDNAK;
msg.direction = I2C_READ;
msg.data = 0x00;
if (i2c_transfer(&msg))
return -1;
return 0;
}
/*
* 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(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
struct i2c_msg msg;
u8 addr_bytes[3]; /* lowest...highest byte of data address */
PRINTD(("i2c_read(chip=0x%02x, addr=0x%02x, alen=0x%02x, "
"len=0x%02x)\n", chip, addr, alen, len));
i2c_reset();
/* dummy chip address write */
PRINTD(("i2c_read: dummy chip address write\n"));
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1);
msg.data &= 0xFE;
if (i2c_transfer(&msg))
return -1;
/*
* send memory address bytes;
* alen defines how much bytes we have to send.
*/
/*addr &= ((1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS)-1); */
addr_bytes[0] = (u8)((addr >> 0) & 0x000000FF);
addr_bytes[1] = (u8)((addr >> 8) & 0x000000FF);
addr_bytes[2] = (u8)((addr >> 16) & 0x000000FF);
while (--alen >= 0) {
PRINTD(("i2c_read: send memory word address byte %1d\n", alen));
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = addr_bytes[alen];
if (i2c_transfer(&msg))
return -1;
}
/* start read sequence */
PRINTD(("i2c_read: start read sequence\n"));
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1);
msg.data |= 0x01;
if (i2c_transfer(&msg))
return -1;
/* read bytes; send NACK at last byte */
while (len--) {
if (len == 0) {
msg.condition = I2C_COND_STOP;
msg.acknack = I2C_ACKNAK_SENDNAK;
} else {
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_SENDACK;
}
msg.direction = I2C_READ;
msg.data = 0x00;
if (i2c_transfer(&msg))
return -1;
*buffer = msg.data;
PRINTD(("i2c_read: reading byte (0x%08x)=0x%02x\n",
(unsigned int)buffer, *buffer));
buffer++;
}
i2c_reset();
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(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
struct i2c_msg msg;
u8 addr_bytes[3]; /* lowest...highest byte of data address */
PRINTD(("i2c_write(chip=0x%02x, addr=0x%02x, alen=0x%02x, "
"len=0x%02x)\n", chip, addr, alen, len));
i2c_reset();
/* chip address write */
PRINTD(("i2c_write: chip address write\n"));
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1);
msg.data &= 0xFE;
if (i2c_transfer(&msg))
return -1;
/*
* send memory address bytes;
* alen defines how much bytes we have to send.
*/
addr_bytes[0] = (u8)((addr >> 0) & 0x000000FF);
addr_bytes[1] = (u8)((addr >> 8) & 0x000000FF);
addr_bytes[2] = (u8)((addr >> 16) & 0x000000FF);
while (--alen >= 0) {
PRINTD(("i2c_write: send memory word address\n"));
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = addr_bytes[alen];
if (i2c_transfer(&msg))
return -1;
}
/* write bytes; send NACK at last byte */
while (len--) {
PRINTD(("i2c_write: writing byte (0x%08x)=0x%02x\n",
(unsigned int)buffer, *buffer));
if (len == 0)
msg.condition = I2C_COND_STOP;
else
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = *(buffer++);
if (i2c_transfer(&msg))
return -1;
}
i2c_reset();
return 0;
}
#endif /* CONFIG_HARD_I2C */

View file

@ -0,0 +1,83 @@
/*
* (C) Copyright 2011
* Marvell Inc, <www.marvell.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 _MV_I2C_H_
#define _MV_I2C_H_
extern void i2c_clk_enable(void);
/* Shall the current transfer have a start/stop condition? */
#define I2C_COND_NORMAL 0
#define I2C_COND_START 1
#define I2C_COND_STOP 2
/* Shall the current transfer be ack/nacked or being waited for it? */
#define I2C_ACKNAK_WAITACK 1
#define I2C_ACKNAK_SENDACK 2
#define I2C_ACKNAK_SENDNAK 4
/* Specify who shall transfer the data (master or slave) */
#define I2C_READ 0
#define I2C_WRITE 1
#if (CONFIG_SYS_I2C_SPEED == 400000)
#define I2C_ICR_INIT (ICR_FM | ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD \
| ICR_SCLE)
#else
#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
#endif
#define I2C_ISR_INIT 0x7FF
/* ----- Control register bits ---------------------------------------- */
#define ICR_START 0x1 /* start bit */
#define ICR_STOP 0x2 /* stop bit */
#define ICR_ACKNAK 0x4 /* send ACK(0) or NAK(1) */
#define ICR_TB 0x8 /* transfer byte bit */
#define ICR_MA 0x10 /* master abort */
#define ICR_SCLE 0x20 /* master clock enable, mona SCLEA */
#define ICR_IUE 0x40 /* unit enable */
#define ICR_GCD 0x80 /* general call disable */
#define ICR_ITEIE 0x100 /* enable tx interrupts */
#define ICR_IRFIE 0x200 /* enable rx interrupts, mona: DRFIE */
#define ICR_BEIE 0x400 /* enable bus error ints */
#define ICR_SSDIE 0x800 /* slave STOP detected int enable */
#define ICR_ALDIE 0x1000 /* enable arbitration interrupt */
#define ICR_SADIE 0x2000 /* slave address detected int enable */
#define ICR_UR 0x4000 /* unit reset */
#define ICR_FM 0x8000 /* Fast Mode */
/* ----- Status register bits ----------------------------------------- */
#define ISR_RWM 0x1 /* read/write mode */
#define ISR_ACKNAK 0x2 /* ack/nak status */
#define ISR_UB 0x4 /* unit busy */
#define ISR_IBB 0x8 /* bus busy */
#define ISR_SSD 0x10 /* slave stop detected */
#define ISR_ALD 0x20 /* arbitration loss detected */
#define ISR_ITE 0x40 /* tx buffer empty */
#define ISR_IRF 0x80 /* rx buffer full */
#define ISR_GCAD 0x100 /* general call address detected */
#define ISR_SAD 0x200 /* slave address detected */
#define ISR_BED 0x400 /* bus error no ACK/NAK */
#endif

View file

@ -0,0 +1,428 @@
/*
* Driver for the TWSI (i2c) controller found on the Marvell
* orion5x and kirkwood SoC families.
*
* Author: Albert Aribaud <albert.u.boot@aribaud.net>
* Copyright (c) 2010 Albert Aribaud.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <common.h>
#include <i2c.h>
#include <asm/errno.h>
#include <asm/io.h>
/*
* include a file that will provide CONFIG_I2C_MVTWSI_BASE
* and possibly other settings
*/
#if defined(CONFIG_ORION5X)
#include <asm/arch/orion5x.h>
#elif defined(CONFIG_KIRKWOOD)
#include <asm/arch/kirkwood.h>
#else
#error Driver mvtwsi not supported by SoC or board
#endif
/*
* TWSI register structure
*/
struct mvtwsi_registers {
u32 slave_address;
u32 data;
u32 control;
union {
u32 status; /* when reading */
u32 baudrate; /* when writing */
};
u32 xtnd_slave_addr;
u32 reserved[2];
u32 soft_reset;
};
/*
* Control register fields
*/
#define MVTWSI_CONTROL_ACK 0x00000004
#define MVTWSI_CONTROL_IFLG 0x00000008
#define MVTWSI_CONTROL_STOP 0x00000010
#define MVTWSI_CONTROL_START 0x00000020
#define MVTWSI_CONTROL_TWSIEN 0x00000040
#define MVTWSI_CONTROL_INTEN 0x00000080
/*
* Status register values -- only those expected in normal master
* operation on non-10-bit-address devices; whatever status we don't
* expect in nominal conditions (bus errors, arbitration losses,
* missing ACKs...) we just pass back to the caller as an error
* code.
*/
#define MVTWSI_STATUS_START 0x08
#define MVTWSI_STATUS_REPEATED_START 0x10
#define MVTWSI_STATUS_ADDR_W_ACK 0x18
#define MVTWSI_STATUS_DATA_W_ACK 0x28
#define MVTWSI_STATUS_ADDR_R_ACK 0x40
#define MVTWSI_STATUS_ADDR_R_NAK 0x48
#define MVTWSI_STATUS_DATA_R_ACK 0x50
#define MVTWSI_STATUS_DATA_R_NAK 0x58
#define MVTWSI_STATUS_IDLE 0xF8
/*
* The single instance of the controller we'll be dealing with
*/
static struct mvtwsi_registers *twsi =
(struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE;
/*
* Returned statuses are 0 for success and nonzero otherwise.
* Currently, cmd_i2c and cmd_eeprom do not interpret an error status.
* Thus to ease debugging, the return status contains some debug info:
* - bits 31..24 are error class: 1 is timeout, 2 is 'status mismatch'.
* - bits 23..16 are the last value of the control register.
* - bits 15..8 are the last value of the status register.
* - bits 7..0 are the expected value of the status register.
*/
#define MVTWSI_ERROR_WRONG_STATUS 0x01
#define MVTWSI_ERROR_TIMEOUT 0x02
#define MVTWSI_ERROR(ec, lc, ls, es) (((ec << 24) & 0xFF000000) | \
((lc << 16) & 0x00FF0000) | ((ls<<8) & 0x0000FF00) | (es & 0xFF))
/*
* Wait for IFLG to raise, or return 'timeout'; then if status is as expected,
* return 0 (ok) or return 'wrong status'.
*/
static int twsi_wait(int expected_status)
{
int control, status;
int timeout = 1000;
do {
control = readl(&twsi->control);
if (control & MVTWSI_CONTROL_IFLG) {
status = readl(&twsi->status);
if (status == expected_status)
return 0;
else
return MVTWSI_ERROR(
MVTWSI_ERROR_WRONG_STATUS,
control, status, expected_status);
}
udelay(10); /* one clock cycle at 100 kHz */
} while (timeout--);
status = readl(&twsi->status);
return MVTWSI_ERROR(
MVTWSI_ERROR_TIMEOUT, control, status, expected_status);
}
/*
* These flags are ORed to any write to the control register
* They allow global setting of TWSIEN and ACK.
* By default none are set.
* twsi_start() sets TWSIEN (in case the controller was disabled)
* twsi_recv() sets ACK or resets it depending on expected status.
*/
static u8 twsi_control_flags = MVTWSI_CONTROL_TWSIEN;
/*
* Assert the START condition, either in a single I2C transaction
* or inside back-to-back ones (repeated starts).
*/
static int twsi_start(int expected_status)
{
/* globally set TWSIEN in case it was not */
twsi_control_flags |= MVTWSI_CONTROL_TWSIEN;
/* assert START */
writel(twsi_control_flags | MVTWSI_CONTROL_START, &twsi->control);
/* wait for controller to process START */
return twsi_wait(expected_status);
}
/*
* Send a byte (i2c address or data).
*/
static int twsi_send(u8 byte, int expected_status)
{
/* put byte in data register for sending */
writel(byte, &twsi->data);
/* clear any pending interrupt -- that'll cause sending */
writel(twsi_control_flags, &twsi->control);
/* wait for controller to receive byte and check ACK */
return twsi_wait(expected_status);
}
/*
* Receive a byte.
* Global mvtwsi_control_flags variable says if we should ack or nak.
*/
static int twsi_recv(u8 *byte)
{
int expected_status, status;
/* compute expected status based on ACK bit in global control flags */
if (twsi_control_flags & MVTWSI_CONTROL_ACK)
expected_status = MVTWSI_STATUS_DATA_R_ACK;
else
expected_status = MVTWSI_STATUS_DATA_R_NAK;
/* acknowledge *previous state* and launch receive */
writel(twsi_control_flags, &twsi->control);
/* wait for controller to receive byte and assert ACK or NAK */
status = twsi_wait(expected_status);
/* if we did receive expected byte then store it */
if (status == 0)
*byte = readl(&twsi->data);
/* return status */
return status;
}
/*
* Assert the STOP condition.
* This is also used to force the bus back in idle (SDA=SCL=1).
*/
static int twsi_stop(int status)
{
int control, stop_status;
int timeout = 1000;
/* assert STOP */
control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
writel(control, &twsi->control);
/* wait for IDLE; IFLG won't rise so twsi_wait() is no use. */
do {
stop_status = readl(&twsi->status);
if (stop_status == MVTWSI_STATUS_IDLE)
break;
udelay(10); /* one clock cycle at 100 kHz */
} while (timeout--);
control = readl(&twsi->control);
if (stop_status != MVTWSI_STATUS_IDLE)
if (status == 0)
status = MVTWSI_ERROR(
MVTWSI_ERROR_TIMEOUT,
control, status, MVTWSI_STATUS_IDLE);
return status;
}
/*
* Ugly formula to convert m and n values to a frequency comes from
* TWSI specifications
*/
#define TWSI_FREQUENCY(m, n) \
((u8) (CONFIG_SYS_TCLK / (10 * (m + 1) * 2 * (1 << n))))
/*
* These are required to be reprogrammed before enabling the controller
* because a reset loses them.
* Default values come from the spec, but a twsi_reset will change them.
* twsi_slave_address left uninitialized lest checkpatch.pl complains.
*/
/* Baudrate generator: m (bits 7..4) =4, n (bits 3..0) =4 */
static u8 twsi_baud_rate = 0x44; /* baudrate at controller reset */
/* Default frequency corresponding to default m=4, n=4 */
static u8 twsi_actual_speed = TWSI_FREQUENCY(4, 4);
/* Default slave address is 0 (so is an uninitialized static) */
static u8 twsi_slave_address;
/*
* Reset controller.
* Called at end of i2c_init unsuccessful i2c transactions.
* Controller reset also resets the baud rate and slave address, so
* re-establish them.
*/
static void twsi_reset(void)
{
/* ensure controller will be enabled by any twsi*() function */
twsi_control_flags = MVTWSI_CONTROL_TWSIEN;
/* reset controller */
writel(0, &twsi->soft_reset);
/* wait 2 ms -- this is what the Marvell LSP does */
udelay(20000);
/* set baud rate */
writel(twsi_baud_rate, &twsi->baudrate);
/* set slave address even though we don't use it */
writel(twsi_slave_address, &twsi->slave_address);
writel(0, &twsi->xtnd_slave_addr);
/* assert STOP but don't care for the result */
(void) twsi_stop(0);
}
/*
* I2C init called by cmd_i2c when doing 'i2c reset'.
* Sets baud to the highest possible value not exceeding requested one.
*/
void i2c_init(int requested_speed, int slaveadd)
{
int tmp_speed, highest_speed, n, m;
int baud = 0x44; /* baudrate at controller reset */
/* use actual speed to collect progressively higher values */
highest_speed = 0;
/* compute m, n setting for highest speed not above requested speed */
for (n = 0; n < 8; n++) {
for (m = 0; m < 16; m++) {
tmp_speed = TWSI_FREQUENCY(m, n);
if ((tmp_speed <= requested_speed)
&& (tmp_speed > highest_speed)) {
highest_speed = tmp_speed;
baud = (m << 3) | n;
}
}
}
/* save baud rate and slave for later calls to twsi_reset */
twsi_baud_rate = baud;
twsi_actual_speed = highest_speed;
twsi_slave_address = slaveadd;
/* reset controller */
twsi_reset();
}
/*
* Begin I2C transaction with expected start status, at given address.
* Common to i2c_probe, i2c_read and i2c_write.
* Expected address status will derive from direction bit (bit 0) in addr.
*/
static int i2c_begin(int expected_start_status, u8 addr)
{
int status, expected_addr_status;
/* compute expected address status from direction bit in addr */
if (addr & 1) /* reading */
expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
else /* writing */
expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
/* assert START */
status = twsi_start(expected_start_status);
/* send out the address if the start went well */
if (status == 0)
status = twsi_send(addr, expected_addr_status);
/* return ok or status of first failure to caller */
return status;
}
/*
* I2C probe called by cmd_i2c when doing 'i2c probe'.
* Begin read, nak data byte, end.
*/
int i2c_probe(uchar chip)
{
u8 dummy_byte;
int status;
/* begin i2c read */
status = i2c_begin(MVTWSI_STATUS_START, (chip << 1) | 1);
/* dummy read was accepted: receive byte but NAK it. */
if (status == 0)
status = twsi_recv(&dummy_byte);
/* Stop transaction */
twsi_stop(0);
/* return 0 or status of first failure */
return status;
}
/*
* I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
* Begin write, send address byte(s), begin read, receive data bytes, end.
*
* NOTE: some EEPROMS want a stop right before the second start, while
* some will choke if it is there. Deciding which we should do is eeprom
* stuff, not i2c, but at the moment the APIs won't let us put it in
* cmd_eeprom, so we have to choose here, and for the moment that'll be
* a repeated start without a preceding stop.
*/
int i2c_read(u8 dev, uint addr, int alen, u8 *data, int length)
{
int status;
/* begin i2c write to send the address bytes */
status = i2c_begin(MVTWSI_STATUS_START, (dev << 1));
/* send addr bytes */
while ((status == 0) && alen--)
status = twsi_send(addr >> (8*alen),
MVTWSI_STATUS_DATA_W_ACK);
/* begin i2c read to receive eeprom data bytes */
if (status == 0)
status = i2c_begin(
MVTWSI_STATUS_REPEATED_START, (dev << 1) | 1);
/* prepare ACK if at least one byte must be received */
if (length > 0)
twsi_control_flags |= MVTWSI_CONTROL_ACK;
/* now receive actual bytes */
while ((status == 0) && length--) {
/* reset NAK if we if no more to read now */
if (length == 0)
twsi_control_flags &= ~MVTWSI_CONTROL_ACK;
/* read current byte */
status = twsi_recv(data++);
}
/* Stop transaction */
status = twsi_stop(status);
/* return 0 or status of first failure */
return status;
}
/*
* I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
* Begin write, send address byte(s), send data bytes, end.
*/
int i2c_write(u8 dev, uint addr, int alen, u8 *data, int length)
{
int status;
/* begin i2c write to send the eeprom adress bytes then data bytes */
status = i2c_begin(MVTWSI_STATUS_START, (dev << 1));
/* send addr bytes */
while ((status == 0) && alen--)
status = twsi_send(addr >> (8*alen),
MVTWSI_STATUS_DATA_W_ACK);
/* send data bytes */
while ((status == 0) && (length-- > 0))
status = twsi_send(*(data++), MVTWSI_STATUS_DATA_W_ACK);
/* Stop transaction */
status = twsi_stop(status);
/* return 0 or status of first failure */
return status;
}
/*
* Bus set routine: we only support bus 0.
*/
int i2c_set_bus_num(unsigned int bus)
{
if (bus > 0) {
return -1;
}
return 0;
}
/*
* Bus get routine: hard-return bus 0.
*/
unsigned int i2c_get_bus_num(void)
{
return 0;
}

View file

@ -0,0 +1,449 @@
/*
* i2c driver for Freescale i.MX series
*
* (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
* (c) 2011 Marek Vasut <marek.vasut@gmail.com>
*
* Based on i2c-imx.c from linux kernel:
* Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de>
* Copyright (C) 2005 Matthias Blaschke <blaschke at synertronixx.de>
* Copyright (C) 2007 RightHand Technologies, Inc.
* Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
*
*
* 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>
#if defined(CONFIG_HARD_I2C)
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <i2c.h>
struct mxc_i2c_regs {
uint32_t iadr;
uint32_t ifdr;
uint32_t i2cr;
uint32_t i2sr;
uint32_t i2dr;
};
#define I2CR_IEN (1 << 7)
#define I2CR_IIEN (1 << 6)
#define I2CR_MSTA (1 << 5)
#define I2CR_MTX (1 << 4)
#define I2CR_TX_NO_AK (1 << 3)
#define I2CR_RSTA (1 << 2)
#define I2SR_ICF (1 << 7)
#define I2SR_IBB (1 << 5)
#define I2SR_IIF (1 << 1)
#define I2SR_RX_NO_AK (1 << 0)
#ifdef CONFIG_SYS_I2C_BASE
#define I2C_BASE CONFIG_SYS_I2C_BASE
#else
#error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver"
#endif
#define I2C_MAX_TIMEOUT 10000
static u16 i2c_clk_div[50][2] = {
{ 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 },
{ 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 },
{ 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 },
{ 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B },
{ 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A },
{ 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 },
{ 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 },
{ 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 },
{ 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 },
{ 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B },
{ 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E },
{ 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
{ 3072, 0x1E }, { 3840, 0x1F }
};
/*
* Calculate and set proper clock divider
*/
static uint8_t i2c_imx_get_clk(unsigned int rate)
{
unsigned int i2c_clk_rate;
unsigned int div;
u8 clk_div;
#if defined(CONFIG_MX31)
struct clock_control_regs *sc_regs =
(struct clock_control_regs *)CCM_BASE;
/* start the required I2C clock */
writel(readl(&sc_regs->cgr0) | (3 << CONFIG_SYS_I2C_CLK_OFFSET),
&sc_regs->cgr0);
#endif
/* Divider value calculation */
i2c_clk_rate = mxc_get_clock(MXC_IPG_PERCLK);
div = (i2c_clk_rate + rate - 1) / rate;
if (div < i2c_clk_div[0][0])
clk_div = 0;
else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
clk_div = ARRAY_SIZE(i2c_clk_div) - 1;
else
for (clk_div = 0; i2c_clk_div[clk_div][0] < div; clk_div++)
;
/* Store divider value */
return clk_div;
}
/*
* Reset I2C Controller
*/
void i2c_reset(void)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
writeb(0, &i2c_regs->i2cr); /* Reset module */
writeb(0, &i2c_regs->i2sr);
}
/*
* Init I2C Bus
*/
void i2c_init(int speed, int unused)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
u8 clk_idx = i2c_imx_get_clk(speed);
u8 idx = i2c_clk_div[clk_idx][1];
/* Store divider value */
writeb(idx, &i2c_regs->ifdr);
i2c_reset();
}
/*
* Set I2C Speed
*/
int i2c_set_bus_speed(unsigned int speed)
{
i2c_init(speed, 0);
return 0;
}
/*
* Get I2C Speed
*/
unsigned int i2c_get_bus_speed(void)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
u8 clk_idx = readb(&i2c_regs->ifdr);
u8 clk_div;
for (clk_div = 0; i2c_clk_div[clk_div][1] != clk_idx; clk_div++)
;
return mxc_get_clock(MXC_IPG_PERCLK) / i2c_clk_div[clk_div][0];
}
/*
* Wait for bus to be busy (or free if for_busy = 0)
*
* for_busy = 1: Wait for IBB to be asserted
* for_busy = 0: Wait for IBB to be de-asserted
*/
int i2c_imx_bus_busy(int for_busy)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
unsigned int temp;
int timeout = I2C_MAX_TIMEOUT;
while (timeout--) {
temp = readb(&i2c_regs->i2sr);
if (for_busy && (temp & I2SR_IBB))
return 0;
if (!for_busy && !(temp & I2SR_IBB))
return 0;
udelay(1);
}
return 1;
}
/*
* Wait for transaction to complete
*/
int i2c_imx_trx_complete(void)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
int timeout = I2C_MAX_TIMEOUT;
while (timeout--) {
if (readb(&i2c_regs->i2sr) & I2SR_IIF) {
writeb(0, &i2c_regs->i2sr);
return 0;
}
udelay(1);
}
return 1;
}
/*
* Check if the transaction was ACKed
*/
int i2c_imx_acked(void)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
return readb(&i2c_regs->i2sr) & I2SR_RX_NO_AK;
}
/*
* Start the controller
*/
int i2c_imx_start(void)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
unsigned int temp = 0;
int result;
/* Enable I2C controller */
writeb(0, &i2c_regs->i2sr);
writeb(I2CR_IEN, &i2c_regs->i2cr);
/* Wait controller to be stable */
udelay(50);
/* Start I2C transaction */
temp = readb(&i2c_regs->i2cr);
temp |= I2CR_MSTA;
writeb(temp, &i2c_regs->i2cr);
result = i2c_imx_bus_busy(1);
if (result)
return result;
temp |= I2CR_MTX | I2CR_TX_NO_AK;
writeb(temp, &i2c_regs->i2cr);
return 0;
}
/*
* Stop the controller
*/
void i2c_imx_stop(void)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
unsigned int temp = 0;
/* Stop I2C transaction */
temp = readb(&i2c_regs->i2cr);
temp |= ~(I2CR_MSTA | I2CR_MTX);
writeb(temp, &i2c_regs->i2cr);
i2c_imx_bus_busy(0);
/* Disable I2C controller */
writeb(0, &i2c_regs->i2cr);
}
/*
* Set chip address and access mode
*
* read = 1: READ access
* read = 0: WRITE access
*/
int i2c_imx_set_chip_addr(uchar chip, int read)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
int ret;
writeb((chip << 1) | read, &i2c_regs->i2dr);
ret = i2c_imx_trx_complete();
if (ret)
return ret;
ret = i2c_imx_acked();
if (ret)
return ret;
return ret;
}
/*
* Write register address
*/
int i2c_imx_set_reg_addr(uint addr, int alen)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
int ret = 0;
while (alen--) {
writeb((addr >> (alen * 8)) & 0xff, &i2c_regs->i2dr);
ret = i2c_imx_trx_complete();
if (ret)
break;
ret = i2c_imx_acked();
if (ret)
break;
}
return ret;
}
/*
* Try if a chip add given address responds (probe the chip)
*/
int i2c_probe(uchar chip)
{
int ret;
ret = i2c_imx_start();
if (ret)
return ret;
ret = i2c_imx_set_chip_addr(chip, 0);
if (ret)
return ret;
i2c_imx_stop();
return ret;
}
/*
* Read data from I2C device
*/
int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
int ret;
unsigned int temp;
int i;
ret = i2c_imx_start();
if (ret)
return ret;
/* write slave address */
ret = i2c_imx_set_chip_addr(chip, 0);
if (ret)
return ret;
ret = i2c_imx_set_reg_addr(addr, alen);
if (ret)
return ret;
temp = readb(&i2c_regs->i2cr);
temp |= I2CR_RSTA;
writeb(temp, &i2c_regs->i2cr);
ret = i2c_imx_set_chip_addr(chip, 1);
if (ret)
return ret;
/* setup bus to read data */
temp = readb(&i2c_regs->i2cr);
temp &= ~(I2CR_MTX | I2CR_TX_NO_AK);
if (len == 1)
temp |= I2CR_TX_NO_AK;
writeb(temp, &i2c_regs->i2cr);
readb(&i2c_regs->i2dr);
/* read data */
for (i = 0; i < len; i++) {
ret = i2c_imx_trx_complete();
if (ret)
return ret;
/*
* It must generate STOP before read I2DR to prevent
* controller from generating another clock cycle
*/
if (i == (len - 1)) {
temp = readb(&i2c_regs->i2cr);
temp &= ~(I2CR_MSTA | I2CR_MTX);
writeb(temp, &i2c_regs->i2cr);
i2c_imx_bus_busy(0);
} else if (i == (len - 2)) {
temp = readb(&i2c_regs->i2cr);
temp |= I2CR_TX_NO_AK;
writeb(temp, &i2c_regs->i2cr);
}
buf[i] = readb(&i2c_regs->i2dr);
}
i2c_imx_stop();
return ret;
}
/*
* Write data to I2C device
*/
int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
{
struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
int ret;
int i;
ret = i2c_imx_start();
if (ret)
return ret;
/* write slave address */
ret = i2c_imx_set_chip_addr(chip, 0);
if (ret)
return ret;
ret = i2c_imx_set_reg_addr(addr, alen);
if (ret)
return ret;
for (i = 0; i < len; i++) {
writeb(buf[i], &i2c_regs->i2dr);
ret = i2c_imx_trx_complete();
if (ret)
return ret;
ret = i2c_imx_acked();
if (ret)
return ret;
}
i2c_imx_stop();
return ret;
}
#endif /* CONFIG_HARD_I2C */

View file

@ -0,0 +1,246 @@
/*
* Freescale i.MX28 I2C Driver
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* Partly based on Linux kernel i2c-mxs.c driver:
* Copyright (C) 2011 Wolfram Sang, Pengutronix e.K.
*
* Which was based on a (non-working) driver which was:
* Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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 <malloc.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sys_proto.h>
#define MXS_I2C_MAX_TIMEOUT 1000000
void mxs_i2c_reset(void)
{
struct mx28_i2c_regs *i2c_regs = (struct mx28_i2c_regs *)MXS_I2C0_BASE;
int ret;
ret = mx28_reset_block(&i2c_regs->hw_i2c_ctrl0_reg);
if (ret) {
debug("MXS I2C: Block reset timeout\n");
return;
}
writel(I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | I2C_CTRL1_NO_SLAVE_ACK_IRQ |
I2C_CTRL1_EARLY_TERM_IRQ | I2C_CTRL1_MASTER_LOSS_IRQ |
I2C_CTRL1_SLAVE_STOP_IRQ | I2C_CTRL1_SLAVE_IRQ,
&i2c_regs->hw_i2c_ctrl1_clr);
writel(I2C_QUEUECTRL_PIO_QUEUE_MODE, &i2c_regs->hw_i2c_queuectrl_set);
}
void mxs_i2c_setup_read(uint8_t chip, int len)
{
struct mx28_i2c_regs *i2c_regs = (struct mx28_i2c_regs *)MXS_I2C0_BASE;
writel(I2C_QUEUECMD_RETAIN_CLOCK | I2C_QUEUECMD_PRE_SEND_START |
I2C_QUEUECMD_MASTER_MODE | I2C_QUEUECMD_DIRECTION |
(1 << I2C_QUEUECMD_XFER_COUNT_OFFSET),
&i2c_regs->hw_i2c_queuecmd);
writel((chip << 1) | 1, &i2c_regs->hw_i2c_data);
writel(I2C_QUEUECMD_SEND_NAK_ON_LAST | I2C_QUEUECMD_MASTER_MODE |
(len << I2C_QUEUECMD_XFER_COUNT_OFFSET) |
I2C_QUEUECMD_POST_SEND_STOP, &i2c_regs->hw_i2c_queuecmd);
writel(I2C_QUEUECTRL_QUEUE_RUN, &i2c_regs->hw_i2c_queuectrl_set);
}
void mxs_i2c_write(uchar chip, uint addr, int alen,
uchar *buf, int blen, int stop)
{
struct mx28_i2c_regs *i2c_regs = (struct mx28_i2c_regs *)MXS_I2C0_BASE;
uint32_t data;
int i, remain, off;
if ((alen > 4) || (alen == 0)) {
debug("MXS I2C: Invalid address length\n");
return;
}
if (stop)
stop = I2C_QUEUECMD_POST_SEND_STOP;
writel(I2C_QUEUECMD_PRE_SEND_START |
I2C_QUEUECMD_MASTER_MODE | I2C_QUEUECMD_DIRECTION |
((blen + alen + 1) << I2C_QUEUECMD_XFER_COUNT_OFFSET) | stop,
&i2c_regs->hw_i2c_queuecmd);
data = (chip << 1) << 24;
for (i = 0; i < alen; i++) {
data >>= 8;
data |= ((char *)&addr)[alen - i - 1] << 24;
if ((i & 3) == 2)
writel(data, &i2c_regs->hw_i2c_data);
}
off = i;
for (; i < off + blen; i++) {
data >>= 8;
data |= buf[i - off] << 24;
if ((i & 3) == 2)
writel(data, &i2c_regs->hw_i2c_data);
}
remain = 24 - ((i & 3) * 8);
if (remain)
writel(data >> remain, &i2c_regs->hw_i2c_data);
writel(I2C_QUEUECTRL_QUEUE_RUN, &i2c_regs->hw_i2c_queuectrl_set);
}
int mxs_i2c_wait_for_ack(void)
{
struct mx28_i2c_regs *i2c_regs = (struct mx28_i2c_regs *)MXS_I2C0_BASE;
uint32_t tmp;
int timeout = MXS_I2C_MAX_TIMEOUT;
for (;;) {
tmp = readl(&i2c_regs->hw_i2c_ctrl1);
if (tmp & I2C_CTRL1_NO_SLAVE_ACK_IRQ) {
debug("MXS I2C: No slave ACK\n");
goto err;
}
if (tmp & (
I2C_CTRL1_EARLY_TERM_IRQ | I2C_CTRL1_MASTER_LOSS_IRQ |
I2C_CTRL1_SLAVE_STOP_IRQ | I2C_CTRL1_SLAVE_IRQ)) {
debug("MXS I2C: Error (CTRL1 = %08x)\n", tmp);
goto err;
}
if (tmp & I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ)
break;
if (!timeout--) {
debug("MXS I2C: Operation timed out\n");
goto err;
}
udelay(1);
}
return 0;
err:
mxs_i2c_reset();
return 1;
}
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
struct mx28_i2c_regs *i2c_regs = (struct mx28_i2c_regs *)MXS_I2C0_BASE;
uint32_t tmp = 0;
int ret;
int i;
mxs_i2c_write(chip, addr, alen, NULL, 0, 0);
ret = mxs_i2c_wait_for_ack();
if (ret) {
debug("MXS I2C: Failed writing address\n");
return ret;
}
mxs_i2c_setup_read(chip, len);
ret = mxs_i2c_wait_for_ack();
if (ret) {
debug("MXS I2C: Failed reading address\n");
return ret;
}
for (i = 0; i < len; i++) {
if (!(i & 3)) {
while (readl(&i2c_regs->hw_i2c_queuestat) &
I2C_QUEUESTAT_RD_QUEUE_EMPTY)
;
tmp = readl(&i2c_regs->hw_i2c_queuedata);
}
buffer[i] = tmp & 0xff;
tmp >>= 8;
}
return 0;
}
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int ret;
mxs_i2c_write(chip, addr, alen, buffer, len, 1);
ret = mxs_i2c_wait_for_ack();
if (ret)
debug("MXS I2C: Failed writing address\n");
return ret;
}
int i2c_probe(uchar chip)
{
int ret;
mxs_i2c_write(chip, 0, 1, NULL, 0, 1);
ret = mxs_i2c_wait_for_ack();
mxs_i2c_reset();
return ret;
}
void i2c_init(int speed, int slaveadd)
{
struct mx28_i2c_regs *i2c_regs = (struct mx28_i2c_regs *)MXS_I2C0_BASE;
mxs_i2c_reset();
switch (speed) {
case 100000:
writel((0x0078 << I2C_TIMING0_HIGH_COUNT_OFFSET) |
(0x0030 << I2C_TIMING0_RCV_COUNT_OFFSET),
&i2c_regs->hw_i2c_timing0);
writel((0x0080 << I2C_TIMING1_LOW_COUNT_OFFSET) |
(0x0030 << I2C_TIMING1_XMIT_COUNT_OFFSET),
&i2c_regs->hw_i2c_timing1);
break;
case 400000:
writel((0x000f << I2C_TIMING0_HIGH_COUNT_OFFSET) |
(0x0007 << I2C_TIMING0_RCV_COUNT_OFFSET),
&i2c_regs->hw_i2c_timing0);
writel((0x001f << I2C_TIMING1_LOW_COUNT_OFFSET) |
(0x000f << I2C_TIMING1_XMIT_COUNT_OFFSET),
&i2c_regs->hw_i2c_timing1);
break;
default:
printf("MXS I2C: Invalid speed selected (%d Hz)\n", speed);
return;
}
writel((0x0015 << I2C_TIMING2_BUS_FREE_OFFSET) |
(0x000d << I2C_TIMING2_LEADIN_COUNT_OFFSET),
&i2c_regs->hw_i2c_timing2);
return;
}

View file

@ -0,0 +1,277 @@
/*
* Basic I2C functions
*
* Copyright (c) 2003 Texas Instruments
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Author: Jian Zhang jzhang@ti.com, Texas Instruments
*
* Copyright (c) 2003 Wolfgang Denk, wd@denx.de
* Rewritten to fit into the current U-Boot framework
*
*/
#include <common.h>
static void wait_for_bb (void);
static u16 wait_for_pin (void);
void i2c_init (int speed, int slaveadd)
{
u16 scl;
if (inw (I2C_CON) & I2C_CON_EN) {
outw (0, I2C_CON);
udelay (5000);
}
/* 12MHz I2C module clock */
outw (0, I2C_PSC);
outw (I2C_CON_EN, I2C_CON);
outw (0, I2C_SYSTEST);
/* have to enable intrrupts or OMAP i2c module doesn't work */
outw (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
I2C_IE_NACK_IE | I2C_IE_AL_IE, I2C_IE);
scl = (12000000 / 2) / speed - 6;
outw (scl, I2C_SCLL);
outw (scl, I2C_SCLH);
/* own address */
outw (slaveadd, I2C_OA);
outw (0, I2C_CNT);
udelay (1000);
}
static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
{
int i2c_error = 0;
u16 status;
/* wait until bus not busy */
wait_for_bb ();
/* one byte only */
outw (1, I2C_CNT);
/* set slave address */
outw (devaddr, I2C_SA);
/* no stop bit needed here */
outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, I2C_CON);
status = wait_for_pin ();
if (status & I2C_STAT_XRDY) {
/* Important: have to use byte access */
*(volatile u8 *) (I2C_DATA) = regoffset;
udelay (20000);
if (inw (I2C_STAT) & I2C_STAT_NACK) {
i2c_error = 1;
}
} else {
i2c_error = 1;
}
if (!i2c_error) {
/* free bus, otherwise we can't use a combined transction */
outw (0, I2C_CON);
while (inw (I2C_STAT) || (inw (I2C_CON) & I2C_CON_MST)) {
udelay (10000);
/* Have to clear pending interrupt to clear I2C_STAT */
inw (I2C_IV);
}
wait_for_bb ();
/* set slave address */
outw (devaddr, I2C_SA);
/* read one byte from slave */
outw (1, I2C_CNT);
/* need stop bit here */
outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
I2C_CON);
status = wait_for_pin ();
if (status & I2C_STAT_RRDY) {
*value = inw (I2C_DATA);
udelay (20000);
} else {
i2c_error = 1;
}
if (!i2c_error) {
outw (I2C_CON_EN, I2C_CON);
while (inw (I2C_STAT)
|| (inw (I2C_CON) & I2C_CON_MST)) {
udelay (10000);
inw (I2C_IV);
}
}
}
return i2c_error;
}
static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
{
int i2c_error = 0;
u16 status;
/* wait until bus not busy */
wait_for_bb ();
/* two bytes */
outw (2, I2C_CNT);
/* set slave address */
outw (devaddr, I2C_SA);
/* stop bit needed here */
outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
I2C_CON_STP, I2C_CON);
/* wait until state change */
status = wait_for_pin ();
if (status & I2C_STAT_XRDY) {
/* send out two bytes */
outw ((value << 8) + regoffset, I2C_DATA);
/* must have enough delay to allow BB bit to go low */
udelay (30000);
if (inw (I2C_STAT) & I2C_STAT_NACK) {
i2c_error = 1;
}
} else {
i2c_error = 1;
}
if (!i2c_error) {
outw (I2C_CON_EN, I2C_CON);
while (inw (I2C_STAT) || (inw (I2C_CON) & I2C_CON_MST)) {
udelay (1000);
/* have to read to clear intrrupt */
inw (I2C_IV);
}
}
return i2c_error;
}
int i2c_probe (uchar chip)
{
int res = 1;
if (chip == inw (I2C_OA)) {
return res;
}
/* wait until bus not busy */
wait_for_bb ();
/* try to read one byte */
outw (1, I2C_CNT);
/* set slave address */
outw (chip, I2C_SA);
/* stop bit needed here */
outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, I2C_CON);
/* enough delay for the NACK bit set */
udelay (2000);
if (!(inw (I2C_STAT) & I2C_STAT_NACK)) {
res = 0;
} else {
outw (inw (I2C_CON) | I2C_CON_STP, I2C_CON);
udelay (20);
wait_for_bb ();
}
return res;
}
int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
{
int i;
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;
}
for (i = 0; i < len; i++) {
if (i2c_read_byte (chip, addr + i, &buffer[i])) {
printf ("I2C read: I/O error\n");
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 1;
}
}
return 0;
}
int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
{
int i;
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;
}
for (i = 0; i < len; i++) {
if (i2c_write_byte (chip, addr + i, buffer[i])) {
printf ("I2C read: I/O error\n");
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 1;
}
}
return 0;
}
static void wait_for_bb (void)
{
int timeout = 10;
while ((inw (I2C_STAT) & I2C_STAT_BB) && timeout--) {
inw (I2C_IV);
udelay (1000);
}
if (timeout <= 0) {
printf ("timed out in wait_for_bb: I2C_STAT=%x\n",
inw (I2C_STAT));
}
}
static u16 wait_for_pin (void)
{
u16 status, iv;
int timeout = 10;
do {
udelay (1000);
status = inw (I2C_STAT);
iv = inw (I2C_IV);
} while (!iv &&
!(status &
(I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
I2C_STAT_AL)) && timeout--);
if (timeout <= 0) {
printf ("timed out in wait_for_pin: I2C_STAT=%x\n",
inw (I2C_STAT));
}
return status;
}

View file

@ -0,0 +1,472 @@
/*
* Basic I2C functions
*
* Copyright (c) 2004 Texas Instruments
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Author: Jian Zhang jzhang@ti.com, Texas Instruments
*
* Copyright (c) 2003 Wolfgang Denk, wd@denx.de
* Rewritten to fit into the current U-Boot framework
*
* Adapted for OMAP2420 I2C, r-woodruff2@ti.com
*
*/
#include <common.h>
#include <asm/arch/i2c.h>
#include <asm/io.h>
#include "omap24xx_i2c.h"
DECLARE_GLOBAL_DATA_PTR;
#define I2C_TIMEOUT 1000
static void wait_for_bb(void);
static u16 wait_for_pin(void);
static void flush_fifo(void);
/*
* For SPL boot some boards need i2c before SDRAM is initialised so force
* variables to live in SRAM
*/
static struct i2c __attribute__((section (".data"))) *i2c_base =
(struct i2c *)I2C_DEFAULT_BASE;
static unsigned int __attribute__((section (".data"))) bus_initialized[I2C_BUS_MAX] =
{ [0 ... (I2C_BUS_MAX-1)] = 0 };
static unsigned int __attribute__((section (".data"))) current_bus = 0;
void i2c_init(int speed, int slaveadd)
{
int psc, fsscll, fssclh;
int hsscll = 0, hssclh = 0;
u32 scll, sclh;
int timeout = I2C_TIMEOUT;
/* Only handle standard, fast and high speeds */
if ((speed != OMAP_I2C_STANDARD) &&
(speed != OMAP_I2C_FAST_MODE) &&
(speed != OMAP_I2C_HIGH_SPEED)) {
printf("Error : I2C unsupported speed %d\n", speed);
return;
}
psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK;
psc -= 1;
if (psc < I2C_PSC_MIN) {
printf("Error : I2C unsupported prescalar %d\n", psc);
return;
}
if (speed == OMAP_I2C_HIGH_SPEED) {
/* High speed */
/* For first phase of HS mode */
fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK /
(2 * OMAP_I2C_FAST_MODE);
fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM;
fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM;
if (((fsscll < 0) || (fssclh < 0)) ||
((fsscll > 255) || (fssclh > 255))) {
puts("Error : I2C initializing first phase clock\n");
return;
}
/* For second phase of HS mode */
hsscll = hssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
hsscll -= I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM;
hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM;
if (((fsscll < 0) || (fssclh < 0)) ||
((fsscll > 255) || (fssclh > 255))) {
puts("Error : I2C initializing second phase clock\n");
return;
}
scll = (unsigned int)hsscll << 8 | (unsigned int)fsscll;
sclh = (unsigned int)hssclh << 8 | (unsigned int)fssclh;
} else {
/* Standard and fast speed */
fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
fsscll -= I2C_FASTSPEED_SCLL_TRIM;
fssclh -= I2C_FASTSPEED_SCLH_TRIM;
if (((fsscll < 0) || (fssclh < 0)) ||
((fsscll > 255) || (fssclh > 255))) {
puts("Error : I2C initializing clock\n");
return;
}
scll = (unsigned int)fsscll;
sclh = (unsigned int)fssclh;
}
if (readw(&i2c_base->con) & I2C_CON_EN) {
writew(0, &i2c_base->con);
udelay(50000);
}
writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */
udelay(1000);
writew(I2C_CON_EN, &i2c_base->con);
while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) {
if (timeout <= 0) {
puts("ERROR: Timeout in soft-reset\n");
return;
}
udelay(1000);
}
writew(0, &i2c_base->con);
writew(psc, &i2c_base->psc);
writew(scll, &i2c_base->scll);
writew(sclh, &i2c_base->sclh);
/* own address */
writew(slaveadd, &i2c_base->oa);
writew(I2C_CON_EN, &i2c_base->con);
/* have to enable intrrupts or OMAP i2c module doesn't work */
writew(I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
udelay(1000);
flush_fifo();
writew(0xFFFF, &i2c_base->stat);
writew(0, &i2c_base->cnt);
if (gd->flags & GD_FLG_RELOC)
bus_initialized[current_bus] = 1;
}
static int i2c_read_byte(u8 devaddr, u8 regoffset, u8 *value)
{
int i2c_error = 0;
u16 status;
/* wait until bus not busy */
wait_for_bb();
/* one byte only */
writew(1, &i2c_base->cnt);
/* set slave address */
writew(devaddr, &i2c_base->sa);
/* no stop bit needed here */
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
I2C_CON_TRX, &i2c_base->con);
/* send register offset */
while (1) {
status = wait_for_pin();
if (status == 0 || status & I2C_STAT_NACK) {
i2c_error = 1;
goto read_exit;
}
if (status & I2C_STAT_XRDY) {
/* Important: have to use byte access */
writeb(regoffset, &i2c_base->data);
writew(I2C_STAT_XRDY, &i2c_base->stat);
}
if (status & I2C_STAT_ARDY) {
writew(I2C_STAT_ARDY, &i2c_base->stat);
break;
}
}
/* set slave address */
writew(devaddr, &i2c_base->sa);
/* read one byte from slave */
writew(1, &i2c_base->cnt);
/* need stop bit here */
writew(I2C_CON_EN | I2C_CON_MST |
I2C_CON_STT | I2C_CON_STP,
&i2c_base->con);
/* receive data */
while (1) {
status = wait_for_pin();
if (status == 0 || status & I2C_STAT_NACK) {
i2c_error = 1;
goto read_exit;
}
if (status & I2C_STAT_RRDY) {
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
*value = readb(&i2c_base->data);
#else
*value = readw(&i2c_base->data);
#endif
writew(I2C_STAT_RRDY, &i2c_base->stat);
}
if (status & I2C_STAT_ARDY) {
writew(I2C_STAT_ARDY, &i2c_base->stat);
break;
}
}
read_exit:
flush_fifo();
writew(0xFFFF, &i2c_base->stat);
writew(0, &i2c_base->cnt);
return i2c_error;
}
static void flush_fifo(void)
{ u16 stat;
/* note: if you try and read data when its not there or ready
* you get a bus error
*/
while (1) {
stat = readw(&i2c_base->stat);
if (stat == I2C_STAT_RRDY) {
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
readb(&i2c_base->data);
#else
readw(&i2c_base->data);
#endif
writew(I2C_STAT_RRDY, &i2c_base->stat);
udelay(1000);
} else
break;
}
}
int i2c_probe(uchar chip)
{
u16 status;
int res = 1; /* default = fail */
if (chip == readw(&i2c_base->oa))
return res;
/* wait until bus not busy */
wait_for_bb();
/* try to read one byte */
writew(1, &i2c_base->cnt);
/* set slave address */
writew(chip, &i2c_base->sa);
/* stop bit needed here */
writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con);
while (1) {
status = wait_for_pin();
if (status == 0 || status & I2C_STAT_AL) {
res = 1;
goto probe_exit;
}
if (status & I2C_STAT_NACK) {
res = 1;
writew(0xff, &i2c_base->stat);
writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con);
wait_for_bb ();
break;
}
if (status & I2C_STAT_ARDY) {
writew(I2C_STAT_ARDY, &i2c_base->stat);
break;
}
if (status & I2C_STAT_RRDY) {
res = 0;
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
readb(&i2c_base->data);
#else
readw(&i2c_base->data);
#endif
writew(I2C_STAT_RRDY, &i2c_base->stat);
}
}
probe_exit:
flush_fifo();
/* don't allow any more data in... we don't want it. */
writew(0, &i2c_base->cnt);
writew(0xFFFF, &i2c_base->stat);
return res;
}
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int i;
if (alen > 1) {
printf("I2C read: addr len %d not supported\n", alen);
return 1;
}
if (addr + len > 256) {
puts("I2C read: address out of range\n");
return 1;
}
for (i = 0; i < len; i++) {
if (i2c_read_byte(chip, addr + i, &buffer[i])) {
puts("I2C read: I/O error\n");
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 1;
}
}
return 0;
}
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int i;
u16 status;
int i2c_error = 0;
if (alen > 1) {
printf("I2C write: addr len %d not supported\n", alen);
return 1;
}
if (addr + len > 256) {
printf("I2C write: address 0x%x + 0x%x out of range\n",
addr, len);
return 1;
}
/* wait until bus not busy */
wait_for_bb();
/* start address phase - will write regoffset + len bytes data */
/* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */
writew(alen + len, &i2c_base->cnt);
/* set slave address */
writew(chip, &i2c_base->sa);
/* stop bit needed here */
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
I2C_CON_STP, &i2c_base->con);
/* Send address byte */
status = wait_for_pin();
if (status == 0 || status & I2C_STAT_NACK) {
i2c_error = 1;
printf("error waiting for i2c address ACK (status=0x%x)\n",
status);
goto write_exit;
}
if (status & I2C_STAT_XRDY) {
writeb(addr & 0xFF, &i2c_base->data);
writew(I2C_STAT_XRDY, &i2c_base->stat);
} else {
i2c_error = 1;
printf("i2c bus not ready for transmit (status=0x%x)\n",
status);
goto write_exit;
}
/* address phase is over, now write data */
for (i = 0; i < len; i++) {
status = wait_for_pin();
if (status == 0 || status & I2C_STAT_NACK) {
i2c_error = 1;
printf("i2c error waiting for data ACK (status=0x%x)\n",
status);
goto write_exit;
}
if (status & I2C_STAT_XRDY) {
writeb(buffer[i], &i2c_base->data);
writew(I2C_STAT_XRDY, &i2c_base->stat);
} else {
i2c_error = 1;
printf("i2c bus not ready for Tx (i=%d)\n", i);
goto write_exit;
}
}
write_exit:
flush_fifo();
writew(0xFFFF, &i2c_base->stat);
return i2c_error;
}
static void wait_for_bb(void)
{
int timeout = I2C_TIMEOUT;
u16 stat;
writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/
while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
writew(stat, &i2c_base->stat);
udelay(1000);
}
if (timeout <= 0) {
printf("timed out in wait_for_bb: I2C_STAT=%x\n",
readw(&i2c_base->stat));
}
writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/
}
static u16 wait_for_pin(void)
{
u16 status;
int timeout = I2C_TIMEOUT;
do {
udelay(1000);
status = readw(&i2c_base->stat);
} while (!(status &
(I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
I2C_STAT_AL)) && timeout--);
if (timeout <= 0) {
printf("timed out in wait_for_pin: I2C_STAT=%x\n",
readw(&i2c_base->stat));
writew(0xFFFF, &i2c_base->stat);
status = 0;
}
return status;
}
int i2c_set_bus_num(unsigned int bus)
{
if ((bus < 0) || (bus >= I2C_BUS_MAX)) {
printf("Bad bus: %d\n", bus);
return -1;
}
#if I2C_BUS_MAX == 3
if (bus == 2)
i2c_base = (struct i2c *)I2C_BASE3;
else
#endif
if (bus == 1)
i2c_base = (struct i2c *)I2C_BASE2;
else
i2c_base = (struct i2c *)I2C_BASE1;
current_bus = bus;
if (!bus_initialized[current_bus])
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 0;
}
int i2c_get_bus_num(void)
{
return (int) current_bus;
}

View file

@ -0,0 +1,170 @@
/*
* (C) Copyright 2004-2010
* Texas Instruments, <www.ti.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 _OMAP2PLUS_I2C_H_
#define _OMAP2PLUS_I2C_H_
/* I2C masks */
/* I2C Interrupt Enable Register (I2C_IE): */
#define I2C_IE_GC_IE (1 << 5)
#define I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */
#define I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */
#define I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */
#define I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Status Register (I2C_STAT): */
#define I2C_STAT_SBD (1 << 15) /* Single byte data */
#define I2C_STAT_BB (1 << 12) /* Bus busy */
#define I2C_STAT_ROVR (1 << 11) /* Receive overrun */
#define I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
#define I2C_STAT_AAS (1 << 9) /* Address as slave */
#define I2C_STAT_GC (1 << 5)
#define I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
#define I2C_STAT_RRDY (1 << 3) /* Receive data ready */
#define I2C_STAT_ARDY (1 << 2) /* Register access ready */
#define I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Interrupt Code Register (I2C_INTCODE): */
#define I2C_INTCODE_MASK 7
#define I2C_INTCODE_NONE 0
#define I2C_INTCODE_AL 1 /* Arbitration lost */
#define I2C_INTCODE_NAK 2 /* No acknowledgement/general call */
#define I2C_INTCODE_ARDY 3 /* Register access ready */
#define I2C_INTCODE_RRDY 4 /* Rcv data ready */
#define I2C_INTCODE_XRDY 5 /* Xmit data ready */
/* I2C Buffer Configuration Register (I2C_BUF): */
#define I2C_BUF_RDMA_EN (1 << 15) /* Receive DMA channel enable */
#define I2C_BUF_XDMA_EN (1 << 7) /* Transmit DMA channel enable */
/* I2C Configuration Register (I2C_CON): */
#define I2C_CON_EN (1 << 15) /* I2C module enable */
#define I2C_CON_BE (1 << 14) /* Big endian mode */
#define I2C_CON_STB (1 << 11) /* Start byte mode (master mode only) */
#define I2C_CON_MST (1 << 10) /* Master/slave mode */
#define I2C_CON_TRX (1 << 9) /* Transmitter/receiver mode */
/* (master mode only) */
#define I2C_CON_XA (1 << 8) /* Expand address */
#define I2C_CON_STP (1 << 1) /* Stop condition (master mode only) */
#define I2C_CON_STT (1 << 0) /* Start condition (master mode only) */
/* I2C System Test Register (I2C_SYSTEST): */
#define I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
#define I2C_SYSTEST_FREE (1 << 14) /* Free running mode, on brkpoint) */
#define I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
#define I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
#define I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense input value */
#define I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive output value */
#define I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense input value */
#define I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive output value */
/* I2C System Status Register (I2C_SYSS): */
#define I2C_SYSS_RDONE (1 << 0) /* Internel reset monitoring */
#define I2C_SCLL_SCLL 0
#define I2C_SCLL_SCLL_M 0xFF
#define I2C_SCLL_HSSCLL 8
#define I2C_SCLH_HSSCLL_M 0xFF
#define I2C_SCLH_SCLH 0
#define I2C_SCLH_SCLH_M 0xFF
#define I2C_SCLH_HSSCLH 8
#define I2C_SCLH_HSSCLH_M 0xFF
#define OMAP_I2C_STANDARD 100000
#define OMAP_I2C_FAST_MODE 400000
#define OMAP_I2C_HIGH_SPEED 3400000
#define SYSTEM_CLOCK_12 12000000
#define SYSTEM_CLOCK_13 13000000
#define SYSTEM_CLOCK_192 19200000
#define SYSTEM_CLOCK_96 96000000
/* Use the reference value of 96MHz if not explicitly set by the board */
#ifndef I2C_IP_CLK
#define I2C_IP_CLK SYSTEM_CLOCK_96
#endif
/*
* The reference minimum clock for high speed is 19.2MHz.
* The linux 2.6.30 kernel uses this value.
* The reference minimum clock for fast mode is 9.6MHz
* The reference minimum clock for standard mode is 4MHz
* In TRM, the value of 12MHz is used.
*/
#ifndef I2C_INTERNAL_SAMPLING_CLK
#define I2C_INTERNAL_SAMPLING_CLK 19200000
#endif
/*
* The equation for the low and high time is
* tlow = scll + scll_trim = (sampling clock * tlow_duty) / speed
* thigh = sclh + sclh_trim = (sampling clock * (1 - tlow_duty)) / speed
*
* If the duty cycle is 50%
*
* tlow = scll + scll_trim = sampling clock / (2 * speed)
* thigh = sclh + sclh_trim = sampling clock / (2 * speed)
*
* In TRM
* scll_trim = 7
* sclh_trim = 5
*
* The linux 2.6.30 kernel uses
* scll_trim = 6
* sclh_trim = 6
*
* These are the trim values for standard and fast speed
*/
#ifndef I2C_FASTSPEED_SCLL_TRIM
#define I2C_FASTSPEED_SCLL_TRIM 6
#endif
#ifndef I2C_FASTSPEED_SCLH_TRIM
#define I2C_FASTSPEED_SCLH_TRIM 6
#endif
/* These are the trim values for high speed */
#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM
#define I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM
#define I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM
#define I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM
#define I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
#endif
#define I2C_PSC_MAX 0x0f
#define I2C_PSC_MIN 0x00
#endif /* _OMAP24XX_I2C_H_ */

View file

@ -0,0 +1,189 @@
/*
* File: drivers/i2c/pca9564.c
* Based on: drivers/i2c/s3c44b0_i2c.c
* Author:
*
* Created: 2009-06-23
* Description: PCA9564 i2c bridge driver
*
* Modified:
* Copyright 2009 CJSC "NII STT", http://www.niistt.ru/
*
* Bugs:
*
* 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, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <common.h>
#include <i2c.h>
#include <pca9564.h>
#include <asm/io.h>
#define PCA_STA (CONFIG_PCA9564_BASE + 0)
#define PCA_TO (CONFIG_PCA9564_BASE + 0)
#define PCA_DAT (CONFIG_PCA9564_BASE + (1 << 2))
#define PCA_ADR (CONFIG_PCA9564_BASE + (2 << 2))
#define PCA_CON (CONFIG_PCA9564_BASE + (3 << 2))
static unsigned char pca_read_reg(unsigned int reg)
{
return readb((void *)reg);
}
static void pca_write_reg(unsigned int reg, unsigned char value)
{
writeb(value, (void *)reg);
}
static int pca_wait_busy(void)
{
unsigned int timeout = 10000;
while (!(pca_read_reg(PCA_CON) & PCA_CON_SI) && --timeout)
udelay(1);
if (timeout == 0)
debug("I2C timeout!\n");
debug("CON = 0x%02x, STA = 0x%02x\n", pca_read_reg(PCA_CON),
pca_read_reg(PCA_STA));
return timeout ? 0 : 1;
}
/*=====================================================================*/
/* Public Functions */
/*=====================================================================*/
/*-----------------------------------------------------------------------
* Initialization
*/
void i2c_init(int speed, int slaveaddr)
{
pca_write_reg(PCA_CON, PCA_CON_ENSIO | speed);
}
/*
* Probe the given I2C chip address. Returns 0 if a chip responded,
* not 0 on failure.
*/
int i2c_probe(uchar chip)
{
unsigned char res;
pca_write_reg(PCA_CON, PCA_CON_STA | PCA_CON_ENSIO);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_STA | PCA_CON_ENSIO);
pca_write_reg(PCA_DAT, (chip << 1) | 1);
res = pca_wait_busy();
if ((res == 0) && (pca_read_reg(PCA_STA) == 0x48))
res = 1;
pca_write_reg(PCA_CON, PCA_CON_STO | PCA_CON_ENSIO);
return res;
}
/*
* 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;
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STA);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
pca_write_reg(PCA_DAT, (chip << 1));
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
if (alen > 0) {
pca_write_reg(PCA_DAT, addr);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
}
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STO);
udelay(500);
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STA);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
pca_write_reg(PCA_DAT, (chip << 1) | 1);
pca_wait_busy();
for (i = 0; i < len; ++i) {
if (i == len - 1)
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
else
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_AA);
pca_wait_busy();
buffer[i] = pca_read_reg(PCA_DAT);
}
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STO);
return 0;
}
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int i;
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STA);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
pca_write_reg(PCA_DAT, chip << 1);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
if (alen > 0) {
pca_write_reg(PCA_DAT, addr);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
}
for (i = 0; i < len; ++i) {
pca_write_reg(PCA_DAT, buffer[i]);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
}
pca_write_reg(PCA_CON, PCA_CON_STO | PCA_CON_ENSIO);
return 0;
}

View file

@ -0,0 +1,436 @@
/*
* (C) Copyright 2007-2009
* Stefan Roese, DENX Software Engineering, sr@denx.de.
*
* based on work by Anne Sophie Harnois <anne-sophie.harnois@nextream.fr>
*
* (C) Copyright 2001
* Bill Hunter, Wave 7 Optics, williamhunter@mediaone.net
*
* 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/ppc4xx.h>
#include <asm/ppc4xx-i2c.h>
#include <i2c.h>
#include <asm/io.h>
#ifdef CONFIG_HARD_I2C
DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_I2C_MULTI_BUS)
/*
* Initialize the bus pointer to whatever one the SPD EEPROM is on.
* Default is bus 0. This is necessary because the DDR initialization
* runs from ROM, and we can't switch buses because we can't modify
* the global variables.
*/
#ifndef CONFIG_SYS_SPD_BUS_NUM
#define CONFIG_SYS_SPD_BUS_NUM 0
#endif
static unsigned int i2c_bus_num __attribute__ ((section (".data"))) =
CONFIG_SYS_SPD_BUS_NUM;
#endif /* CONFIG_I2C_MULTI_BUS */
static void _i2c_bus_reset(void)
{
struct ppc4xx_i2c *i2c = (struct ppc4xx_i2c *)I2C_BASE_ADDR;
int i;
u8 dc;
/* Reset status register */
/* write 1 in SCMP and IRQA to clear these fields */
out_8(&i2c->sts, 0x0A);
/* write 1 in IRQP IRQD LA ICT XFRA to clear these fields */
out_8(&i2c->extsts, 0x8F);
/* Place chip in the reset state */
out_8(&i2c->xtcntlss, IIC_XTCNTLSS_SRST);
/* Check if bus is free */
dc = in_8(&i2c->directcntl);
if (!DIRCTNL_FREE(dc)){
/* Try to set bus free state */
out_8(&i2c->directcntl, IIC_DIRCNTL_SDAC | IIC_DIRCNTL_SCC);
/* Wait until we regain bus control */
for (i = 0; i < 100; ++i) {
dc = in_8(&i2c->directcntl);
if (DIRCTNL_FREE(dc))
break;
/* Toggle SCL line */
dc ^= IIC_DIRCNTL_SCC;
out_8(&i2c->directcntl, dc);
udelay(10);
dc ^= IIC_DIRCNTL_SCC;
out_8(&i2c->directcntl, dc);
}
}
/* Remove reset */
out_8(&i2c->xtcntlss, 0);
}
void i2c_init(int speed, int slaveaddr)
{
struct ppc4xx_i2c *i2c;
int val, divisor;
int bus;
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/*
* Call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*/
i2c_init_board();
#endif
for (bus = 0; bus < CONFIG_SYS_MAX_I2C_BUS; bus++) {
I2C_SET_BUS(bus);
/* Set i2c pointer after calling I2C_SET_BUS() */
i2c = (struct ppc4xx_i2c *)I2C_BASE_ADDR;
/* Handle possible failed I2C state */
/* FIXME: put this into i2c_init_board()? */
_i2c_bus_reset();
/* clear lo master address */
out_8(&i2c->lmadr, 0);
/* clear hi master address */
out_8(&i2c->hmadr, 0);
/* clear lo slave address */
out_8(&i2c->lsadr, 0);
/* clear hi slave address */
out_8(&i2c->hsadr, 0);
/* Clock divide Register */
/* set divisor according to freq_opb */
divisor = (get_OPB_freq() - 1) / 10000000;
if (divisor == 0)
divisor = 1;
out_8(&i2c->clkdiv, divisor);
/* no interrupts */
out_8(&i2c->intrmsk, 0);
/* clear transfer count */
out_8(&i2c->xfrcnt, 0);
/* clear extended control & stat */
/* write 1 in SRC SRS SWC SWS to clear these fields */
out_8(&i2c->xtcntlss, 0xF0);
/* Mode Control Register
Flush Slave/Master data buffer */
out_8(&i2c->mdcntl, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
val = in_8(&i2c->mdcntl);
/* Ignore General Call, slave transfers are ignored,
* disable interrupts, exit unknown bus state, enable hold
* SCL 100kHz normaly or FastMode for 400kHz and above
*/
val |= IIC_MDCNTL_EUBS | IIC_MDCNTL_HSCL;
if (speed >= 400000)
val |= IIC_MDCNTL_FSM;
out_8(&i2c->mdcntl, val);
/* clear control reg */
out_8(&i2c->cntl, 0x00);
}
/* set to SPD bus as default bus upon powerup */
I2C_SET_BUS(CONFIG_SYS_SPD_BUS_NUM);
}
/*
* This code tries to use the features of the 405GP i2c
* controller. It will transfer up to 4 bytes in one pass
* on the loop. It only does out_8((u8 *)lbz) to the buffer when it
* is possible to do out16(lhz) transfers.
*
* cmd_type is 0 for write 1 for read.
*
* addr_len can take any value from 0-255, it is only limited
* by the char, we could make it larger if needed. If it is
* 0 we skip the address write cycle.
*
* Typical case is a Write of an addr followd by a Read. The
* IBM FAQ does not cover this. On the last byte of the write
* we don't set the creg CHT bit, and on the first bytes of the
* read we set the RPST bit.
*
* It does not support address only transfers, there must be
* a data part. If you want to write the address yourself, put
* it in the data pointer.
*
* It does not support transfer to/from address 0.
*
* It does not check XFRCNT.
*/
static int i2c_transfer(unsigned char cmd_type,
unsigned char chip,
unsigned char addr[],
unsigned char addr_len,
unsigned char data[],
unsigned short data_len)
{
struct ppc4xx_i2c *i2c = (struct ppc4xx_i2c *)I2C_BASE_ADDR;
u8 *ptr;
int reading;
int tran, cnt;
int result;
int status;
int i;
u8 creg;
if (data == 0 || data_len == 0) {
/* Don't support data transfer of no length or to address 0 */
printf( "i2c_transfer: bad call\n" );
return IIC_NOK;
}
if (addr && addr_len) {
ptr = addr;
cnt = addr_len;
reading = 0;
} else {
ptr = data;
cnt = data_len;
reading = cmd_type;
}
/* Clear Stop Complete Bit */
out_8(&i2c->sts, IIC_STS_SCMP);
/* Check init */
i = 10;
do {
/* Get status */
status = in_8(&i2c->sts);
i--;
} while ((status & IIC_STS_PT) && (i > 0));
if (status & IIC_STS_PT) {
result = IIC_NOK_TOUT;
return(result);
}
/* flush the Master/Slave Databuffers */
out_8(&i2c->mdcntl, in_8(&i2c->mdcntl) |
IIC_MDCNTL_FMDB | IIC_MDCNTL_FSDB);
/* need to wait 4 OPB clocks? code below should take that long */
/* 7-bit adressing */
out_8(&i2c->hmadr, 0);
out_8(&i2c->lmadr, chip);
tran = 0;
result = IIC_OK;
creg = 0;
while (tran != cnt && (result == IIC_OK)) {
int bc,j;
/*
* Control register =
* Normal transfer, 7-bits adressing, Transfer up to
* bc bytes, Normal start, Transfer is a sequence of transfers
*/
creg |= IIC_CNTL_PT;
bc = (cnt - tran) > 4 ? 4 : cnt - tran;
creg |= (bc - 1) << 4;
/* if the real cmd type is write continue trans */
if ((!cmd_type && (ptr == addr)) || ((tran + bc) != cnt))
creg |= IIC_CNTL_CHT;
if (reading) {
creg |= IIC_CNTL_READ;
} else {
for(j = 0; j < bc; j++) {
/* Set buffer */
out_8(&i2c->mdbuf, ptr[tran + j]);
}
}
out_8(&i2c->cntl, creg);
/*
* Transfer is in progress
* we have to wait for upto 5 bytes of data
* 1 byte chip address+r/w bit then bc bytes
* of data.
* udelay(10) is 1 bit time at 100khz
* Doubled for slop. 20 is too small.
*/
i = 2 * 5 * 8;
do {
/* Get status */
status = in_8(&i2c->sts);
udelay(10);
i--;
} while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR) &&
(i > 0));
if (status & IIC_STS_ERR) {
result = IIC_NOK;
status = in_8(&i2c->extsts);
/* Lost arbitration? */
if (status & IIC_EXTSTS_LA)
result = IIC_NOK_LA;
/* Incomplete transfer? */
if (status & IIC_EXTSTS_ICT)
result = IIC_NOK_ICT;
/* Transfer aborted? */
if (status & IIC_EXTSTS_XFRA)
result = IIC_NOK_XFRA;
} else if ( status & IIC_STS_PT) {
result = IIC_NOK_TOUT;
}
/* Command is reading => get buffer */
if ((reading) && (result == IIC_OK)) {
/* Are there data in buffer */
if (status & IIC_STS_MDBS) {
/*
* even if we have data we have to wait 4OPB
* clocks for it to hit the front of the FIFO,
* after that we can just read. We should check
* XFCNT here and if the FIFO is full there is
* no need to wait.
*/
udelay(1);
for (j = 0; j < bc; j++)
ptr[tran + j] = in_8(&i2c->mdbuf);
} else
result = IIC_NOK_DATA;
}
creg = 0;
tran += bc;
if (ptr == addr && tran == cnt) {
ptr = data;
cnt = data_len;
tran = 0;
reading = cmd_type;
if (reading)
creg = IIC_CNTL_RPST;
}
}
return result;
}
int i2c_probe(uchar chip)
{
uchar buf[1];
buf[0] = 0;
/*
* What is needed is to send the chip address and verify that the
* address was <ACK>ed (i.e. there was a chip at that address which
* drove the data line low).
*/
return (i2c_transfer(1, chip << 1, 0, 0, buf, 1) != 0);
}
static int ppc4xx_i2c_transfer(uchar chip, uint addr, int alen, uchar *buffer,
int len, int read)
{
uchar xaddr[4];
int ret;
if (alen > 4) {
printf("I2C: addr len %d not supported\n", alen);
return 1;
}
if (alen > 0) {
xaddr[0] = (addr >> 24) & 0xFF;
xaddr[1] = (addr >> 16) & 0xFF;
xaddr[2] = (addr >> 8) & 0xFF;
xaddr[3] = addr & 0xFF;
}
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
if (alen > 0)
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
if ((ret = i2c_transfer(read, chip << 1, &xaddr[4 - alen], alen,
buffer, len)) != 0) {
printf("I2C %s: failed %d\n", read ? "read" : "write", ret);
return 1;
}
return 0;
}
int i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len)
{
return ppc4xx_i2c_transfer(chip, addr, alen, buffer, len, 1);
}
int i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len)
{
return ppc4xx_i2c_transfer(chip, addr, alen, buffer, len, 0);
}
#if defined(CONFIG_I2C_MULTI_BUS)
/*
* Functions for multiple I2C bus handling
*/
unsigned int i2c_get_bus_num(void)
{
return i2c_bus_num;
}
int i2c_set_bus_num(unsigned int bus)
{
if (bus >= CONFIG_SYS_MAX_I2C_BUS)
return -1;
i2c_bus_num = bus;
return 0;
}
#endif /* CONFIG_I2C_MULTI_BUS */
#endif /* CONFIG_HARD_I2C */

View file

@ -0,0 +1,443 @@
/*
* (C) Copyright 2002
* David Mueller, ELSOFT AG, d.mueller@elsoft.ch
*
* 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
*/
/* This code should work for both the S3C2400 and the S3C2410
* as they seem to have the same I2C controller inside.
* The different address mapping is handled by the s3c24xx.h files below.
*/
#include <common.h>
#include <asm/arch/s3c24x0_cpu.h>
#include <asm/io.h>
#include <i2c.h>
#ifdef CONFIG_HARD_I2C
#define I2C_WRITE 0
#define I2C_READ 1
#define I2C_OK 0
#define I2C_NOK 1
#define I2C_NACK 2
#define I2C_NOK_LA 3 /* Lost arbitration */
#define I2C_NOK_TOUT 4 /* time out */
#define I2CSTAT_BSY 0x20 /* Busy bit */
#define I2CSTAT_NACK 0x01 /* Nack bit */
#define I2CCON_IRPND 0x10 /* Interrupt pending bit */
#define I2C_MODE_MT 0xC0 /* Master Transmit Mode */
#define I2C_MODE_MR 0x80 /* Master Receive Mode */
#define I2C_START_STOP 0x20 /* START / STOP */
#define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
#define I2C_TIMEOUT 1 /* 1 second */
static int GetI2CSDA(void)
{
struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
#ifdef CONFIG_S3C2410
return (readl(&gpio->gpedat) & 0x8000) >> 15;
#endif
#ifdef CONFIG_S3C2400
return (readl(&gpio->pgdat) & 0x0020) >> 5;
#endif
}
#if 0
static void SetI2CSDA(int x)
{
rGPEDAT = (rGPEDAT & ~0x8000) | (x & 1) << 15;
}
#endif
static void SetI2CSCL(int x)
{
struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
#ifdef CONFIG_S3C2410
writel((readl(&gpio->gpedat) & ~0x4000) | (x & 1) << 14, &gpio->gpedat);
#endif
#ifdef CONFIG_S3C2400
writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat);
#endif
}
static int WaitForXfer(void)
{
struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
int i;
i = I2C_TIMEOUT * 10000;
while (!(readl(&i2c->iiccon) & I2CCON_IRPND) && (i > 0)) {
udelay(100);
i--;
}
return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
}
static int IsACK(void)
{
struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
}
static void ReadWriteByte(void)
{
struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
}
void i2c_init(int speed, int slaveadd)
{
struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
ulong freq, pres = 16, div;
int i;
/* wait for some time to give previous transfer a chance to finish */
i = I2C_TIMEOUT * 1000;
while ((readl(&i2c->iicstat) && I2CSTAT_BSY) && (i > 0)) {
udelay(1000);
i--;
}
if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) {
#ifdef CONFIG_S3C2410
ulong old_gpecon = readl(&gpio->gpecon);
#endif
#ifdef CONFIG_S3C2400
ulong old_gpecon = readl(&gpio->pgcon);
#endif
/* bus still busy probably by (most) previously interrupted
transfer */
#ifdef CONFIG_S3C2410
/* set I2CSDA and I2CSCL (GPE15, GPE14) to GPIO */
writel((readl(&gpio->gpecon) & ~0xF0000000) | 0x10000000,
&gpio->gpecon);
#endif
#ifdef CONFIG_S3C2400
/* set I2CSDA and I2CSCL (PG5, PG6) to GPIO */
writel((readl(&gpio->pgcon) & ~0x00003c00) | 0x00001000,
&gpio->pgcon);
#endif
/* toggle I2CSCL until bus idle */
SetI2CSCL(0);
udelay(1000);
i = 10;
while ((i > 0) && (GetI2CSDA() != 1)) {
SetI2CSCL(1);
udelay(1000);
SetI2CSCL(0);
udelay(1000);
i--;
}
SetI2CSCL(1);
udelay(1000);
/* restore pin functions */
#ifdef CONFIG_S3C2410
writel(old_gpecon, &gpio->gpecon);
#endif
#ifdef CONFIG_S3C2400
writel(old_gpecon, &gpio->pgcon);
#endif
}
/* calculate prescaler and divisor values */
freq = get_PCLK();
if ((freq / pres / (16 + 1)) > speed)
/* set prescaler to 512 */
pres = 512;
div = 0;
while ((freq / pres / (div + 1)) > speed)
div++;
/* set prescaler, divisor according to freq, also set
* ACKGEN, IRQ */
writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
/* init to SLAVE REVEIVE and set slaveaddr */
writel(0, &i2c->iicstat);
writel(slaveadd, &i2c->iicadd);
/* program Master Transmit (and implicit STOP) */
writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
}
/*
* cmd_type is 0 for write, 1 for read.
*
* addr_len can take any value from 0-255, it is only limited
* by the char, we could make it larger if needed. If it is
* 0 we skip the address write cycle.
*/
static
int i2c_transfer(unsigned char cmd_type,
unsigned char chip,
unsigned char addr[],
unsigned char addr_len,
unsigned char data[], unsigned short data_len)
{
struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
int i, result;
if (data == 0 || data_len == 0) {
/*Don't support data transfer of no length or to address 0 */
printf("i2c_transfer: bad call\n");
return I2C_NOK;
}
/* Check I2C bus idle */
i = I2C_TIMEOUT * 1000;
while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) {
udelay(1000);
i--;
}
if (readl(&i2c->iicstat) & I2CSTAT_BSY)
return I2C_NOK_TOUT;
writel(readl(&i2c->iiccon) | 0x80, &i2c->iiccon);
result = I2C_OK;
switch (cmd_type) {
case I2C_WRITE:
if (addr && addr_len) {
writel(chip, &i2c->iicds);
/* send START */
writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
&i2c->iicstat);
i = 0;
while ((i < addr_len) && (result == I2C_OK)) {
result = WaitForXfer();
writel(addr[i], &i2c->iicds);
ReadWriteByte();
i++;
}
i = 0;
while ((i < data_len) && (result == I2C_OK)) {
result = WaitForXfer();
writel(data[i], &i2c->iicds);
ReadWriteByte();
i++;
}
} else {
writel(chip, &i2c->iicds);
/* send START */
writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
&i2c->iicstat);
i = 0;
while ((i < data_len) && (result = I2C_OK)) {
result = WaitForXfer();
writel(data[i], &i2c->iicds);
ReadWriteByte();
i++;
}
}
if (result == I2C_OK)
result = WaitForXfer();
/* send STOP */
writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
ReadWriteByte();
break;
case I2C_READ:
if (addr && addr_len) {
writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
writel(chip, &i2c->iicds);
/* send START */
writel(readl(&i2c->iicstat) | I2C_START_STOP,
&i2c->iicstat);
result = WaitForXfer();
if (IsACK()) {
i = 0;
while ((i < addr_len) && (result == I2C_OK)) {
writel(addr[i], &i2c->iicds);
ReadWriteByte();
result = WaitForXfer();
i++;
}
writel(chip, &i2c->iicds);
/* resend START */
writel(I2C_MODE_MR | I2C_TXRX_ENA |
I2C_START_STOP, &i2c->iicstat);
ReadWriteByte();
result = WaitForXfer();
i = 0;
while ((i < data_len) && (result == I2C_OK)) {
/* disable ACK for final READ */
if (i == data_len - 1)
writel(readl(&i2c->iiccon)
& ~0x80, &i2c->iiccon);
ReadWriteByte();
result = WaitForXfer();
data[i] = readl(&i2c->iicds);
i++;
}
} else {
result = I2C_NACK;
}
} else {
writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
writel(chip, &i2c->iicds);
/* send START */
writel(readl(&i2c->iicstat) | I2C_START_STOP,
&i2c->iicstat);
result = WaitForXfer();
if (IsACK()) {
i = 0;
while ((i < data_len) && (result == I2C_OK)) {
/* disable ACK for final READ */
if (i == data_len - 1)
writel(readl(&i2c->iiccon) &
~0x80, &i2c->iiccon);
ReadWriteByte();
result = WaitForXfer();
data[i] = readl(&i2c->iicds);
i++;
}
} else {
result = I2C_NACK;
}
}
/* send STOP */
writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
ReadWriteByte();
break;
default:
printf("i2c_transfer: bad call\n");
result = I2C_NOK;
break;
}
return (result);
}
int i2c_probe(uchar chip)
{
uchar buf[1];
buf[0] = 0;
/*
* What is needed is to send the chip address and verify that the
* address was <ACK>ed (i.e. there was a chip at that address which
* drove the data line low).
*/
return i2c_transfer(I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
}
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
uchar xaddr[4];
int ret;
if (alen > 4) {
printf("I2C read: addr len %d not supported\n", alen);
return 1;
}
if (alen > 0) {
xaddr[0] = (addr >> 24) & 0xFF;
xaddr[1] = (addr >> 16) & 0xFF;
xaddr[2] = (addr >> 8) & 0xFF;
xaddr[3] = addr & 0xFF;
}
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
if (alen > 0)
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
if ((ret =
i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen,
buffer, len)) != 0) {
printf("I2c read: failed %d\n", ret);
return 1;
}
return 0;
}
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
uchar xaddr[4];
if (alen > 4) {
printf("I2C write: addr len %d not supported\n", alen);
return 1;
}
if (alen > 0) {
xaddr[0] = (addr >> 24) & 0xFF;
xaddr[1] = (addr >> 16) & 0xFF;
xaddr[2] = (addr >> 8) & 0xFF;
xaddr[3] = addr & 0xFF;
}
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
if (alen > 0)
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
return (i2c_transfer
(I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
len) != 0);
}
#endif /* CONFIG_HARD_I2C */

View file

@ -0,0 +1,315 @@
/*
* (C) Copyright 2004
* DAVE Srl
* http://www.dave-tech.it
* http://www.wawnet.biz
* mailto:info@wawnet.biz
*
* 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 <command.h>
#include <asm/hardware.h>
/*
* Initialization, must be called once on start up, may be called
* repeatedly to change the speed and slave addresses.
*/
void i2c_init(int speed, int slaveaddr)
{
/*
setting up I2C support
*/
unsigned int save_F,save_PF,rIICCON,rPCONA,rPDATA,rPCONF,rPUPF;
save_F = PCONF;
save_PF = PUPF;
rPCONF = ((save_F & ~(0xF))| 0xa);
rPUPF = (save_PF | 0x3);
PCONF = rPCONF; /*PF0:IICSCL, PF1:IICSDA*/
PUPF = rPUPF; /* Disable pull-up */
/* Configuring pin for WC pin of EEprom */
rPCONA = PCONA;
rPCONA &= ~(1<<9);
PCONA = rPCONA;
rPDATA = PDATA;
rPDATA &= ~(1<<9);
PDATA = rPDATA;
/*
Enable ACK, IICCLK=MCLK/16, enable interrupt
75MHz/16/(12+1) = 390625 Hz
*/
rIICCON=(1<<7)|(0<<6)|(1<<5)|(0xC);
IICCON = rIICCON;
IICADD = slaveaddr;
}
/*
* Probe the given I2C chip address. Returns 0 if a chip responded,
* not 0 on failure.
*/
int i2c_probe(uchar chip)
{
/*
not implemented
*/
printf("i2c_probe chip %d\n", (int) chip);
return -1;
}
/*
* 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
*/
#define S3C44B0X_rIIC_INTPEND (1<<4)
#define S3C44B0X_rIIC_LAST_RECEIV_BIT (1<<0)
#define S3C44B0X_rIIC_INTERRUPT_ENABLE (1<<5)
#define S3C44B0_IIC_TIMEOUT 100
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int k, j, temp;
u32 rIICSTAT;
/*
send the device offset
*/
rIICSTAT = 0xD0;
IICSTAT = rIICSTAT;
IICDS = chip; /* this is a write operation... */
rIICSTAT |= (1<<5);
IICSTAT = rIICSTAT;
for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
temp = IICCON;
if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
break;
udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
return -1;
/* wait and check ACK */
temp = IICSTAT;
if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
return -1;
IICDS = addr;
IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
/* wait and check ACK */
for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
temp = IICCON;
if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
break;
udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
return -1;
temp = IICSTAT;
if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
return -1;
/*
now we can start with the read operation...
*/
IICDS = chip | 0x01; /* this is a read operation... */
rIICSTAT = 0x90; /*master recv*/
rIICSTAT |= (1<<5);
IICSTAT = rIICSTAT;
IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
/* wait and check ACK */
for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
temp = IICCON;
if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
break;
udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
return -1;
temp = IICSTAT;
if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
return -1;
for (j=0; j<len-1; j++) {
/*clear pending bit to resume */
temp = IICCON & ~(S3C44B0X_rIIC_INTPEND);
IICCON = temp;
/* wait and check ACK */
for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
temp = IICCON;
if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
break;
udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
return -1;
buffer[j] = IICDS; /*save readed data*/
} /*end for(j)*/
/*
reading the last data
unset ACK generation
*/
temp = IICCON & ~(S3C44B0X_rIIC_INTPEND | (1<<7));
IICCON = temp;
/* wait but NOT check ACK */
for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
temp = IICCON;
if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
break;
udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
return -1;
buffer[j] = IICDS; /*save readed data*/
rIICSTAT = 0x90; /*master recv*/
/* Write operation Terminate sending STOP */
IICSTAT = rIICSTAT;
/*Clear Int Pending Bit to RESUME*/
temp = IICCON;
IICCON = temp & (~S3C44B0X_rIIC_INTPEND);
IICCON = IICCON | (1<<7); /*restore ACK generation*/
return 0;
}
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int j, k;
u32 rIICSTAT, temp;
/*
send the device offset
*/
rIICSTAT = 0xD0;
IICSTAT = rIICSTAT;
IICDS = chip; /* this is a write operation... */
rIICSTAT |= (1<<5);
IICSTAT = rIICSTAT;
IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
/* wait and check ACK */
for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
temp = IICCON;
if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
break;
udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
return -1;
temp = IICSTAT;
if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
return -1;
IICDS = addr;
IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
/* wait and check ACK */
for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
temp = IICCON;
if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
break;
udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
return -1;
temp = IICSTAT;
if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
return -1;
/*
now we can start with the read write operation
*/
for (j=0; j<len; j++) {
IICDS = buffer[j]; /*prerare data to write*/
/*clear pending bit to resume*/
temp = IICCON & ~(S3C44B0X_rIIC_INTPEND);
IICCON = temp;
/* wait but NOT check ACK */
for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
temp = IICCON;
if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
break;
udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
return -1;
} /* end for(j) */
/* sending stop to terminate */
rIICSTAT = 0xD0; /*master send*/
IICSTAT = rIICSTAT;
/*Clear Int Pending Bit to RESUME*/
temp = IICCON;
IICCON = temp & (~S3C44B0X_rIIC_INTPEND);
return 0;
}

View file

@ -0,0 +1,292 @@
/*
* Copyright (C) 2011 Renesas Solutions Corp.
* Copyright (C) 2011 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
*
* 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>
/* Every register is 32bit aligned, but only 8bits in size */
#define ureg(name) u8 name; u8 __pad_##name##0; u16 __pad_##name##1;
struct sh_i2c {
ureg(icdr);
ureg(iccr);
ureg(icsr);
ureg(icic);
ureg(iccl);
ureg(icch);
};
#undef ureg
static struct sh_i2c *base;
/* ICCR */
#define SH_I2C_ICCR_ICE (1 << 7)
#define SH_I2C_ICCR_RACK (1 << 6)
#define SH_I2C_ICCR_RTS (1 << 4)
#define SH_I2C_ICCR_BUSY (1 << 2)
#define SH_I2C_ICCR_SCP (1 << 0)
/* ICSR / ICIC */
#define SH_IC_BUSY (1 << 3)
#define SH_IC_TACK (1 << 2)
#define SH_IC_WAIT (1 << 1)
#define SH_IC_DTE (1 << 0)
static u8 iccl, icch;
#define IRQ_WAIT 1000
static void irq_wait(struct sh_i2c *base)
{
int i;
u8 status;
for (i = 0 ; i < IRQ_WAIT ; i++) {
status = readb(&base->icsr);
if (SH_IC_WAIT & status)
break;
udelay(10);
}
writeb(status & ~SH_IC_WAIT, &base->icsr);
}
static void irq_dte(struct sh_i2c *base)
{
int i;
for (i = 0 ; i < IRQ_WAIT ; i++) {
if (SH_IC_DTE & readb(&base->icsr))
break;
udelay(10);
}
}
static void irq_busy(struct sh_i2c *base)
{
int i;
for (i = 0 ; i < IRQ_WAIT ; i++) {
if (!(SH_IC_BUSY & readb(&base->icsr)))
break;
udelay(10);
}
}
static void i2c_set_addr(struct sh_i2c *base, u8 id, u8 reg, int stop)
{
writeb(readb(&base->iccr) & ~SH_I2C_ICCR_ICE, &base->iccr);
writeb(readb(&base->iccr) | SH_I2C_ICCR_ICE, &base->iccr);
writeb(iccl, &base->iccl);
writeb(icch, &base->icch);
writeb(0, &base->icic);
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &base->iccr);
irq_dte(base);
writeb(id << 1, &base->icdr);
irq_dte(base);
writeb(reg, &base->icdr);
if (stop)
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS), &base->iccr);
irq_dte(base);
}
static void i2c_finish(struct sh_i2c *base)
{
writeb(0, &base->icsr);
writeb(readb(&base->iccr) & ~SH_I2C_ICCR_ICE, &base->iccr);
}
static void i2c_raw_write(struct sh_i2c *base, u8 id, u8 reg, u8 val)
{
i2c_set_addr(base, id, reg, 0);
udelay(10);
writeb(val, &base->icdr);
irq_dte(base);
writeb((SH_I2C_ICCR_ICE | SH_I2C_ICCR_RTS), &base->iccr);
irq_dte(base);
irq_busy(base);
i2c_finish(base);
}
static u8 i2c_raw_read(struct sh_i2c *base, u8 id, u8 reg)
{
u8 ret;
i2c_set_addr(base, id, reg, 1);
udelay(100);
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &base->iccr);
irq_dte(base);
writeb(id << 1 | 0x01, &base->icdr);
irq_dte(base);
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_SCP), &base->iccr);
irq_dte(base);
ret = readb(&base->icdr);
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RACK), &base->iccr);
readb(&base->icdr); /* Dummy read */
irq_busy(base);
i2c_finish(base);
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)
{
if ((bus < 0) || (bus >= CONFIG_SYS_MAX_I2C_BUS)) {
printf("Bad bus: %d\n", bus);
return -1;
}
switch (bus) {
case 0:
base = (void *)CONFIG_SH_I2C_BASE0;
break;
case 1:
base = (void *)CONFIG_SH_I2C_BASE1;
break;
default:
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
#define SH_I2C_ICCL_CALC(clk, date, t_low, t_high) \
((clk / rate) * (t_low / t_low + t_high))
#define SH_I2C_ICCH_CALC(clk, date, t_low, t_high) \
((clk / rate) * (t_high / t_low + t_high))
void i2c_init(int speed, int slaveaddr)
{
int num, denom, tmp;
#ifdef CONFIG_I2C_MULTI_BUS
current_bus = 0;
#endif
base = (struct sh_i2c *)CONFIG_SH_I2C_BASE0;
/*
* Calculate the value for iccl. From the data sheet:
* iccl = (p-clock / transfer-rate) * (L / (L + H))
* where L and H are the SCL low and high ratio.
*/
num = CONFIG_SH_I2C_CLOCK * CONFIG_SH_I2C_DATA_LOW;
denom = speed * (CONFIG_SH_I2C_DATA_HIGH + CONFIG_SH_I2C_DATA_LOW);
tmp = num * 10 / denom;
if (tmp % 10 >= 5)
iccl = (u8)((num/denom) + 1);
else
iccl = (u8)(num/denom);
/* Calculate the value for icch. From the data sheet:
icch = (p clock / transfer rate) * (H / (L + H)) */
num = CONFIG_SH_I2C_CLOCK * CONFIG_SH_I2C_DATA_HIGH;
tmp = num * 10 / denom;
if (tmp % 10 >= 5)
icch = (u8)((num/denom) + 1);
else
icch = (u8)(num/denom);
}
/*
* 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)
{
int i = 0;
for (i = 0; i < len ; i++)
i2c_raw_write(base, chip, addr + i, buffer[i]);
return 0;
}
/*
* 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)
{
return 0;
}

View file

@ -0,0 +1,387 @@
/*
* Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
* 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 <common.h>
#include <i2c.h>
#include <asm/io.h>
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);
}

View file

@ -0,0 +1,484 @@
/*
* (C) Copyright 2001, 2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* 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
*
* This has been changed substantially by Gerald Van Baren, Custom IDEAS,
* vanbaren@cideas.com. It was heavily influenced by LiMon, written by
* Neil Russell.
*/
#include <common.h>
#ifdef CONFIG_MPC8260 /* only valid for MPC8260 */
#include <ioports.h>
#include <asm/io.h>
#endif
#if defined(CONFIG_AT91FAMILY)
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/at91_pio.h>
#ifdef CONFIG_AT91_LEGACY
#include <asm/arch/gpio.h>
#endif
#endif
#ifdef CONFIG_IXP425 /* only valid for IXP425 */
#include <asm/arch/ixp425.h>
#endif
#ifdef CONFIG_LPC2292
#include <asm/arch/hardware.h>
#endif
#if defined(CONFIG_MPC852T) || defined(CONFIG_MPC866)
#include <asm/io.h>
#endif
#include <i2c.h>
#if defined(CONFIG_SOFT_I2C_GPIO_SCL)
# include <asm/gpio.h>
# ifndef I2C_GPIO_SYNC
# define I2C_GPIO_SYNC
# endif
# ifndef I2C_INIT
# define I2C_INIT \
do { \
gpio_request(CONFIG_SOFT_I2C_GPIO_SCL, "soft_i2c"); \
gpio_request(CONFIG_SOFT_I2C_GPIO_SDA, "soft_i2c"); \
} while (0)
# endif
# ifndef I2C_ACTIVE
# define I2C_ACTIVE do { } while (0)
# endif
# ifndef I2C_TRISTATE
# define I2C_TRISTATE do { } while (0)
# endif
# ifndef I2C_READ
# define I2C_READ gpio_get_value(CONFIG_SOFT_I2C_GPIO_SDA)
# endif
# ifndef I2C_SDA
# define I2C_SDA(bit) \
do { \
if (bit) \
gpio_direction_input(CONFIG_SOFT_I2C_GPIO_SDA); \
else \
gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SDA, 0); \
I2C_GPIO_SYNC; \
} while (0)
# endif
# ifndef I2C_SCL
# define I2C_SCL(bit) \
do { \
gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SCL, bit); \
I2C_GPIO_SYNC; \
} while (0)
# endif
# ifndef I2C_DELAY
# define I2C_DELAY udelay(5) /* 1/4 I2C clock duration */
# endif
#endif
/* #define DEBUG_I2C */
#ifdef DEBUG_I2C
DECLARE_GLOBAL_DATA_PTR;
#endif
/*-----------------------------------------------------------------------
* Definitions
*/
#define RETRIES 0
#define I2C_ACK 0 /* PD_SDA level to ack a byte */
#define I2C_NOACK 1 /* PD_SDA level to noack a byte */
#ifdef DEBUG_I2C
#define PRINTD(fmt,args...) do { \
printf (fmt ,##args); \
} while (0)
#else
#define PRINTD(fmt,args...)
#endif
#if defined(CONFIG_I2C_MULTI_BUS)
static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = 0;
#endif /* CONFIG_I2C_MULTI_BUS */
/*-----------------------------------------------------------------------
* Local functions
*/
#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
static void send_reset (void);
#endif
static void send_start (void);
static void send_stop (void);
static void send_ack (int);
static int write_byte (uchar byte);
static uchar read_byte (int);
#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
/*-----------------------------------------------------------------------
* Send a reset sequence consisting of 9 clocks with the data signal high
* to clock any confused device back into an idle state. Also send a
* <stop> at the end of the sequence for belts & suspenders.
*/
static void send_reset(void)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
int j;
I2C_SCL(1);
I2C_SDA(1);
#ifdef I2C_INIT
I2C_INIT;
#endif
I2C_TRISTATE;
for(j = 0; j < 9; j++) {
I2C_SCL(0);
I2C_DELAY;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
}
send_stop();
I2C_TRISTATE;
}
#endif
/*-----------------------------------------------------------------------
* START: High -> Low on SDA while SCL is High
*/
static void send_start(void)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_DELAY;
I2C_SDA(1);
I2C_ACTIVE;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_SDA(0);
I2C_DELAY;
}
/*-----------------------------------------------------------------------
* STOP: Low -> High on SDA while SCL is High
*/
static void send_stop(void)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_SCL(0);
I2C_DELAY;
I2C_SDA(0);
I2C_ACTIVE;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_SDA(1);
I2C_DELAY;
I2C_TRISTATE;
}
/*-----------------------------------------------------------------------
* ack should be I2C_ACK or I2C_NOACK
*/
static void send_ack(int ack)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_SCL(0);
I2C_DELAY;
I2C_ACTIVE;
I2C_SDA(ack);
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
I2C_SCL(0);
I2C_DELAY;
}
/*-----------------------------------------------------------------------
* Send 8 bits and look for an acknowledgement.
*/
static int write_byte(uchar data)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
int j;
int nack;
I2C_ACTIVE;
for(j = 0; j < 8; j++) {
I2C_SCL(0);
I2C_DELAY;
I2C_SDA(data & 0x80);
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
data <<= 1;
}
/*
* Look for an <ACK>(negative logic) and return it.
*/
I2C_SCL(0);
I2C_DELAY;
I2C_SDA(1);
I2C_TRISTATE;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
nack = I2C_READ;
I2C_SCL(0);
I2C_DELAY;
I2C_ACTIVE;
return(nack); /* not a nack is an ack */
}
#if defined(CONFIG_I2C_MULTI_BUS)
/*
* Functions for multiple I2C bus handling
*/
unsigned int i2c_get_bus_num(void)
{
return i2c_bus_num;
}
int i2c_set_bus_num(unsigned int bus)
{
#if defined(CONFIG_I2C_MUX)
if (bus < CONFIG_SYS_MAX_I2C_BUS) {
i2c_bus_num = bus;
} else {
int ret;
ret = i2x_mux_select_mux(bus);
i2c_init_board();
if (ret == 0)
i2c_bus_num = bus;
else
return ret;
}
#else
if (bus >= CONFIG_SYS_MAX_I2C_BUS)
return -1;
i2c_bus_num = bus;
#endif
return 0;
}
#endif
/*-----------------------------------------------------------------------
* if ack == I2C_ACK, ACK the byte so can continue reading, else
* send I2C_NOACK to end the read.
*/
static uchar read_byte(int ack)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
int data;
int j;
/*
* Read 8 bits, MSB first.
*/
I2C_TRISTATE;
I2C_SDA(1);
data = 0;
for(j = 0; j < 8; j++) {
I2C_SCL(0);
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
data <<= 1;
data |= I2C_READ;
I2C_DELAY;
}
send_ack(ack);
return(data);
}
/*=====================================================================*/
/* Public Functions */
/*=====================================================================*/
/*-----------------------------------------------------------------------
* Initialization
*/
void i2c_init (int speed, int slaveaddr)
{
#if defined(CONFIG_SYS_I2C_INIT_BOARD)
/* call board specific i2c bus reset routine before accessing the */
/* environment, which might be in a chip on that bus. For details */
/* about this problem see doc/I2C_Edge_Conditions. */
i2c_init_board();
#else
/*
* WARNING: Do NOT save speed in a static variable: if the
* I2C routines are called before RAM is initialized (to read
* the DIMM SPD, for instance), RAM won't be usable and your
* system will crash.
*/
send_reset ();
#endif
}
/*-----------------------------------------------------------------------
* Probe to see if a chip is present. Also good for checking for the
* completion of EEPROM writes since the chip stops responding until
* the write completes (typically 10mSec).
*/
int i2c_probe(uchar addr)
{
int rc;
/*
* perform 1 byte write transaction with just address byte
* (fake write)
*/
send_start();
rc = write_byte ((addr << 1) | 0);
send_stop();
return (rc ? 1 : 0);
}
/*-----------------------------------------------------------------------
* Read bytes
*/
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int shift;
PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
chip, addr, alen, buffer, len);
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
chip, addr);
#endif
/*
* Do the addressing portion of a write cycle to set the
* chip's address pointer. If the address length is zero,
* don't do the normal write cycle to set the address pointer,
* there is no address pointer in this chip.
*/
send_start();
if(alen > 0) {
if(write_byte(chip << 1)) { /* write cycle */
send_stop();
PRINTD("i2c_read, no chip responded %02X\n", chip);
return(1);
}
shift = (alen-1) * 8;
while(alen-- > 0) {
if(write_byte(addr >> shift)) {
PRINTD("i2c_read, address not <ACK>ed\n");
return(1);
}
shift -= 8;
}
/* Some I2C chips need a stop/start sequence here,
* other chips don't work with a full stop and need
* only a start. Default behaviour is to send the
* stop/start sequence.
*/
#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START
send_start();
#else
send_stop();
send_start();
#endif
}
/*
* Send the chip address again, this time for a read cycle.
* Then read the data. On the last byte, we do a NACK instead
* of an ACK(len == 0) to terminate the read.
*/
write_byte((chip << 1) | 1); /* read cycle */
while(len-- > 0) {
*buffer++ = read_byte(len == 0);
}
send_stop();
return(0);
}
/*-----------------------------------------------------------------------
* Write bytes
*/
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int shift, failures = 0;
PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",
chip, addr, alen, buffer, len);
send_start();
if(write_byte(chip << 1)) { /* write cycle */
send_stop();
PRINTD("i2c_write, no chip responded %02X\n", chip);
return(1);
}
shift = (alen-1) * 8;
while(alen-- > 0) {
if(write_byte(addr >> shift)) {
PRINTD("i2c_write, address not <ACK>ed\n");
return(1);
}
shift -= 8;
}
while(len-- > 0) {
if(write_byte(*buffer++)) {
failures++;
}
}
send_stop();
return(failures);
}

View file

@ -0,0 +1,583 @@
/*
* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Copyright (c) 2010-2011 NVIDIA Corporation
* NVIDIA Corporation <www.nvidia.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 <fdtdec.h>
#include <i2c.h>
#include <asm/io.h>
#include <asm/arch/clk_rst.h>
#include <asm/arch/clock.h>
#include <asm/arch/funcmux.h>
#include <asm/arch/gpio.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/tegra_i2c.h>
DECLARE_GLOBAL_DATA_PTR;
static unsigned int i2c_bus_num;
/* Information about i2c controller */
struct i2c_bus {
int id;
enum periph_id periph_id;
int speed;
int pinmux_config;
struct i2c_control *control;
struct i2c_ctlr *regs;
int is_dvc; /* DVC type, rather than I2C */
int inited; /* bus is inited */
};
static struct i2c_bus i2c_controllers[TEGRA_I2C_NUM_CONTROLLERS];
static void set_packet_mode(struct i2c_bus *i2c_bus)
{
u32 config;
config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK;
if (i2c_bus->is_dvc) {
struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
writel(config, &dvc->cnfg);
} else {
writel(config, &i2c_bus->regs->cnfg);
/*
* program I2C_SL_CNFG.NEWSL to ENABLE. This fixes probe
* issues, i.e., some slaves may be wrongly detected.
*/
setbits_le32(&i2c_bus->regs->sl_cnfg, I2C_SL_CNFG_NEWSL_MASK);
}
}
static void i2c_reset_controller(struct i2c_bus *i2c_bus)
{
/* Reset I2C controller. */
reset_periph(i2c_bus->periph_id, 1);
/* re-program config register to packet mode */
set_packet_mode(i2c_bus);
}
static void i2c_init_controller(struct i2c_bus *i2c_bus)
{
/*
* Use PLLP - DP-04508-001_v06 datasheet indicates a divisor of 8
* here, in section 23.3.1, but in fact we seem to need a factor of
* 16 to get the right frequency.
*/
clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
i2c_bus->speed * 2 * 8);
/* Reset I2C controller. */
i2c_reset_controller(i2c_bus);
/* Configure I2C controller. */
if (i2c_bus->is_dvc) { /* only for DVC I2C */
struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
}
funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config);
}
static void send_packet_headers(
struct i2c_bus *i2c_bus,
struct i2c_trans_info *trans,
u32 packet_id)
{
u32 data;
/* prepare header1: Header size = 0 Protocol = I2C, pktType = 0 */
data = PROTOCOL_TYPE_I2C << PKT_HDR1_PROTOCOL_SHIFT;
data |= packet_id << PKT_HDR1_PKT_ID_SHIFT;
data |= i2c_bus->id << PKT_HDR1_CTLR_ID_SHIFT;
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 1 sent (0x%x)\n", data);
/* prepare header2 */
data = (trans->num_bytes - 1) << PKT_HDR2_PAYLOAD_SIZE_SHIFT;
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 2 sent (0x%x)\n", data);
/* prepare IO specific header: configure the slave address */
data = trans->address << PKT_HDR3_SLAVE_ADDR_SHIFT;
/* Enable Read if it is not a write transaction */
if (!(trans->flags & I2C_IS_WRITE))
data |= PKT_HDR3_READ_MODE_MASK;
/* Write I2C specific header */
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 3 sent (0x%x)\n", data);
}
static int wait_for_tx_fifo_empty(struct i2c_control *control)
{
u32 count;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
count = (readl(&control->fifo_status) & TX_FIFO_EMPTY_CNT_MASK)
>> TX_FIFO_EMPTY_CNT_SHIFT;
if (count == I2C_FIFO_DEPTH)
return 1;
udelay(10);
timeout_us -= 10;
}
return 0;
}
static int wait_for_rx_fifo_notempty(struct i2c_control *control)
{
u32 count;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
count = (readl(&control->fifo_status) & TX_FIFO_FULL_CNT_MASK)
>> TX_FIFO_FULL_CNT_SHIFT;
if (count)
return 1;
udelay(10);
timeout_us -= 10;
}
return 0;
}
static int wait_for_transfer_complete(struct i2c_control *control)
{
int int_status;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
int_status = readl(&control->int_status);
if (int_status & I2C_INT_NO_ACK_MASK)
return -int_status;
if (int_status & I2C_INT_ARBITRATION_LOST_MASK)
return -int_status;
if (int_status & I2C_INT_XFER_COMPLETE_MASK)
return 0;
udelay(10);
timeout_us -= 10;
}
return -1;
}
static int send_recv_packets(struct i2c_bus *i2c_bus,
struct i2c_trans_info *trans)
{
struct i2c_control *control = i2c_bus->control;
u32 int_status;
u32 words;
u8 *dptr;
u32 local;
uchar last_bytes;
int error = 0;
int is_write = trans->flags & I2C_IS_WRITE;
/* clear status from previous transaction, XFER_COMPLETE, NOACK, etc. */
int_status = readl(&control->int_status);
writel(int_status, &control->int_status);
send_packet_headers(i2c_bus, trans, 1);
words = DIV_ROUND_UP(trans->num_bytes, 4);
last_bytes = trans->num_bytes & 3;
dptr = trans->buf;
while (words) {
u32 *wptr = (u32 *)dptr;
if (is_write) {
/* deal with word alignment */
if ((unsigned)dptr & 3) {
memcpy(&local, dptr, sizeof(u32));
writel(local, &control->tx_fifo);
debug("pkt data sent (0x%x)\n", local);
} else {
writel(*wptr, &control->tx_fifo);
debug("pkt data sent (0x%x)\n", *wptr);
}
if (!wait_for_tx_fifo_empty(control)) {
error = -1;
goto exit;
}
} else {
if (!wait_for_rx_fifo_notempty(control)) {
error = -1;
goto exit;
}
/*
* for the last word, we read into our local buffer,
* in case that caller did not provide enough buffer.
*/
local = readl(&control->rx_fifo);
if ((words == 1) && last_bytes)
memcpy(dptr, (char *)&local, last_bytes);
else if ((unsigned)dptr & 3)
memcpy(dptr, &local, sizeof(u32));
else
*wptr = local;
debug("pkt data received (0x%x)\n", local);
}
words--;
dptr += sizeof(u32);
}
if (wait_for_transfer_complete(control)) {
error = -1;
goto exit;
}
return 0;
exit:
/* error, reset the controller. */
i2c_reset_controller(i2c_bus);
return error;
}
static int tegra2_i2c_write_data(u32 addr, u8 *data, u32 len)
{
int error;
struct i2c_trans_info trans_info;
trans_info.address = addr;
trans_info.buf = data;
trans_info.flags = I2C_IS_WRITE;
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
error = send_recv_packets(&i2c_controllers[i2c_bus_num], &trans_info);
if (error)
debug("tegra2_i2c_write_data: Error (%d) !!!\n", error);
return error;
}
static int tegra2_i2c_read_data(u32 addr, u8 *data, u32 len)
{
int error;
struct i2c_trans_info trans_info;
trans_info.address = addr | 1;
trans_info.buf = data;
trans_info.flags = 0;
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
error = send_recv_packets(&i2c_controllers[i2c_bus_num], &trans_info);
if (error)
debug("tegra2_i2c_read_data: Error (%d) !!!\n", error);
return error;
}
#ifndef CONFIG_OF_CONTROL
#error "Please enable device tree support to use this driver"
#endif
unsigned int i2c_get_bus_speed(void)
{
return i2c_controllers[i2c_bus_num].speed;
}
int i2c_set_bus_speed(unsigned int speed)
{
struct i2c_bus *i2c_bus;
i2c_bus = &i2c_controllers[i2c_bus_num];
i2c_bus->speed = speed;
i2c_init_controller(i2c_bus);
return 0;
}
static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
{
i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
/*
* We don't have a binding for pinmux yet. Leave it out for now. So
* far no one needs anything other than the default.
*/
i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
i2c_bus->speed = fdtdec_get_int(blob, node, "clock-frequency", 0);
i2c_bus->periph_id = clock_decode_periph_id(blob, node);
/*
* We can't specify the pinmux config in the fdt, so I2C2 will not
* work on Seaboard. It normally has no devices on it anyway.
* You could add in this little hack if you need to use it.
* The correct solution is a pinmux binding in the fdt.
*
* if (i2c_bus->periph_id == PERIPH_ID_I2C2)
* i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA;
*/
if (i2c_bus->periph_id == -1)
return -FDT_ERR_NOTFOUND;
return 0;
}
/*
* Process a list of nodes, adding them to our list of I2C ports.
*
* @param blob fdt blob
* @param node_list list of nodes to process (any <=0 are ignored)
* @param count number of nodes to process
* @param is_dvc 1 if these are DVC ports, 0 if standard I2C
* @return 0 if ok, -1 on error
*/
static int process_nodes(const void *blob, int node_list[], int count,
int is_dvc)
{
struct i2c_bus *i2c_bus;
int i;
/* build the i2c_controllers[] for each controller */
for (i = 0; i < count; i++) {
int node = node_list[i];
if (node <= 0)
continue;
i2c_bus = &i2c_controllers[i];
i2c_bus->id = i;
if (i2c_get_config(blob, node, i2c_bus)) {
printf("i2c_init_board: failed to decode bus %d\n", i);
return -1;
}
i2c_bus->is_dvc = is_dvc;
if (is_dvc) {
i2c_bus->control =
&((struct dvc_ctlr *)i2c_bus->regs)->control;
} else {
i2c_bus->control = &i2c_bus->regs->control;
}
debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
is_dvc ? "dvc" : "i2c", i, i2c_bus->regs,
i2c_bus->periph_id, i2c_bus->speed);
i2c_init_controller(i2c_bus);
debug("ok\n");
i2c_bus->inited = 1;
/* Mark position as used */
node_list[i] = -1;
}
return 0;
}
/* Sadly there is no error return from this function */
void i2c_init_board(void)
{
int node_list[TEGRA_I2C_NUM_CONTROLLERS];
const void *blob = gd->fdt_blob;
int count;
/* First get the normal i2c ports */
count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_NVIDIA_TEGRA20_I2C, node_list,
TEGRA_I2C_NUM_CONTROLLERS);
if (process_nodes(blob, node_list, count, 0))
return;
/* Now look for dvc ports */
count = fdtdec_add_aliases_for_id(blob, "i2c",
COMPAT_NVIDIA_TEGRA20_DVC, node_list,
TEGRA_I2C_NUM_CONTROLLERS);
if (process_nodes(blob, node_list, count, 1))
return;
}
void i2c_init(int speed, int slaveaddr)
{
/* This will override the speed selected in the fdt for that port */
debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
i2c_set_bus_speed(speed);
}
/* i2c write version without the register address */
int i2c_write_data(uchar chip, uchar *buffer, int len)
{
int rc;
debug("i2c_write_data: chip=0x%x, len=0x%x\n", chip, len);
debug("write_data: ");
/* use rc for counter */
for (rc = 0; rc < len; ++rc)
debug(" 0x%02x", buffer[rc]);
debug("\n");
/* Shift 7-bit address over for lower-level i2c functions */
rc = tegra2_i2c_write_data(chip << 1, buffer, len);
if (rc)
debug("i2c_write_data(): rc=%d\n", rc);
return rc;
}
/* i2c read version without the register address */
int i2c_read_data(uchar chip, uchar *buffer, int len)
{
int rc;
debug("inside i2c_read_data():\n");
/* Shift 7-bit address over for lower-level i2c functions */
rc = tegra2_i2c_read_data(chip << 1, buffer, len);
if (rc) {
debug("i2c_read_data(): rc=%d\n", rc);
return rc;
}
debug("i2c_read_data: ");
/* reuse rc for counter*/
for (rc = 0; rc < len; ++rc)
debug(" 0x%02x", buffer[rc]);
debug("\n");
return 0;
}
/* Probe to see if a chip is present. */
int i2c_probe(uchar chip)
{
int rc;
uchar reg;
debug("i2c_probe: addr=0x%x\n", chip);
reg = 0;
rc = i2c_write_data(chip, &reg, 1);
if (rc) {
debug("Error probing 0x%x.\n", chip);
return 1;
}
return 0;
}
static int i2c_addr_ok(const uint addr, const int alen)
{
/* We support 7 or 10 bit addresses, so one or two bytes each */
return alen == 1 || alen == 2;
}
/* Read bytes */
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
uint offset;
int i;
debug("i2c_read: chip=0x%x, addr=0x%x, len=0x%x\n",
chip, addr, len);
if (!i2c_addr_ok(addr, alen)) {
debug("i2c_read: Bad address %x.%d.\n", addr, alen);
return 1;
}
for (offset = 0; offset < len; offset++) {
if (alen) {
uchar data[alen];
for (i = 0; i < alen; i++) {
data[alen - i - 1] =
(addr + offset) >> (8 * i);
}
if (i2c_write_data(chip, data, alen)) {
debug("i2c_read: error sending (0x%x)\n",
addr);
return 1;
}
}
if (i2c_read_data(chip, buffer + offset, 1)) {
debug("i2c_read: error reading (0x%x)\n", addr);
return 1;
}
}
return 0;
}
/* Write bytes */
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
uint offset;
int i;
debug("i2c_write: chip=0x%x, addr=0x%x, len=0x%x\n",
chip, addr, len);
if (!i2c_addr_ok(addr, alen)) {
debug("i2c_write: Bad address %x.%d.\n", addr, alen);
return 1;
}
for (offset = 0; offset < len; offset++) {
uchar data[alen + 1];
for (i = 0; i < alen; i++)
data[alen - i - 1] = (addr + offset) >> (8 * i);
data[alen] = buffer[offset];
if (i2c_write_data(chip, data, alen + 1)) {
debug("i2c_write: error sending (0x%x)\n", addr);
return 1;
}
}
return 0;
}
#if defined(CONFIG_I2C_MULTI_BUS)
/*
* Functions for multiple I2C bus handling
*/
unsigned int i2c_get_bus_num(void)
{
return i2c_bus_num;
}
int i2c_set_bus_num(unsigned int bus)
{
if (bus >= TEGRA_I2C_NUM_CONTROLLERS || !i2c_controllers[bus].inited)
return -1;
i2c_bus_num = bus;
return 0;
}
#endif
int tegra_i2c_get_dvc_bus_num(void)
{
int i;
for (i = 0; i < CONFIG_SYS_MAX_I2C_BUS; i++) {
struct i2c_bus *bus = &i2c_controllers[i];
if (bus->inited && bus->is_dvc)
return i;
}
return -1;
}

View file

@ -0,0 +1,290 @@
/*
* (C) Copyright 2004 Tundra Semiconductor Corp.
* Author: Alex Bounine
*
* 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 <config.h>
#include <common.h>
#include <tsi108.h>
#if defined(CONFIG_CMD_I2C)
#define I2C_DELAY 100000
#undef DEBUG_I2C
#ifdef DEBUG_I2C
#define DPRINT(x) printf (x)
#else
#define DPRINT(x)
#endif
/* All functions assume that Tsi108 I2C block is the only master on the bus */
/* I2C read helper function */
void i2c_init(int speed, int slaveaddr)
{
/*
* The TSI108 has a fixed I2C clock rate and doesn't support slave
* operation. This function only exists as a stub to fit into the
* U-Boot I2C API.
*/
}
static int i2c_read_byte (
uint i2c_chan, /* I2C channel number: 0 - main, 1 - SDC SPD */
uchar chip_addr,/* I2C device address on the bus */
uint byte_addr, /* Byte address within I2C device */
uchar * buffer /* pointer to data buffer */
)
{
u32 temp;
u32 to_count = I2C_DELAY;
u32 op_status = TSI108_I2C_TIMEOUT_ERR;
u32 chan_offset = TSI108_I2C_OFFSET;
DPRINT (("I2C read_byte() %d 0x%02x 0x%02x\n",
i2c_chan, chip_addr, byte_addr));
if (0 != i2c_chan)
chan_offset = TSI108_I2C_SDRAM_OFFSET;
/* Check if I2C operation is in progress */
temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS |
I2C_CNTRL2_START))) {
/* Set device address and operation (read = 0) */
temp = (byte_addr << 16) | ((chip_addr & 0x07) << 8) |
((chip_addr >> 3) & 0x0F);
*(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL1) =
temp;
/* Issue the read command
* (at this moment all other parameters are 0
* (size = 1 byte, lane = 0)
*/
*(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2) =
(I2C_CNTRL2_START);
/* Wait until operation completed */
do {
/* Read I2C operation status */
temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_START))) {
if (0 == (temp &
(I2C_CNTRL2_I2C_CFGERR |
I2C_CNTRL2_I2C_TO_ERR))
) {
op_status = TSI108_I2C_SUCCESS;
temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE +
chan_offset +
I2C_RD_DATA);
*buffer = (u8) (temp & 0xFF);
} else {
/* report HW error */
op_status = TSI108_I2C_IF_ERROR;
DPRINT (("I2C HW error reported: 0x%02x\n", temp));
}
break;
}
} while (to_count--);
} else {
op_status = TSI108_I2C_IF_BUSY;
DPRINT (("I2C Transaction start failed: 0x%02x\n", temp));
}
DPRINT (("I2C read_byte() status: 0x%02x\n", op_status));
return op_status;
}
/*
* I2C Read interface as defined in "include/i2c.h" :
* chip_addr: I2C chip address, range 0..127
* (to read from SPD channel EEPROM use (0xD0 ... 0xD7)
* NOTE: The bit 7 in the chip_addr serves as a channel select.
* This hack is for enabling "i2c sdram" command on Tsi108 boards
* without changes to common code. Used for I2C reads only.
* byte_addr: Memory or 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: Pointer to destination buffer for data to be read
* len: How many bytes to read
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_read (uchar chip_addr, uint byte_addr, int alen,
uchar * buffer, int len)
{
u32 op_status = TSI108_I2C_PARAM_ERR;
u32 i2c_if = 0;
/* Hack to support second (SPD) I2C controller (SPD EEPROM read only).*/
if (0xD0 == (chip_addr & ~0x07)) {
i2c_if = 1;
chip_addr &= 0x7F;
}
/* Check for valid I2C address */
if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) {
while (len--) {
op_status = i2c_read_byte(i2c_if, chip_addr, byte_addr++, buffer++);
if (TSI108_I2C_SUCCESS != op_status) {
DPRINT (("I2C read_byte() failed: 0x%02x (%d left)\n", op_status, len));
break;
}
}
}
DPRINT (("I2C read() status: 0x%02x\n", op_status));
return op_status;
}
/* I2C write helper function */
static int i2c_write_byte (uchar chip_addr,/* I2C device address on the bus */
uint byte_addr, /* Byte address within I2C device */
uchar * buffer /* pointer to data buffer */
)
{
u32 temp;
u32 to_count = I2C_DELAY;
u32 op_status = TSI108_I2C_TIMEOUT_ERR;
/* Check if I2C operation is in progress */
temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) {
/* Place data into the I2C Tx Register */
*(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
I2C_TX_DATA) = (u32) * buffer;
/* Set device address and operation */
temp =
I2C_CNTRL1_I2CWRITE | (byte_addr << 16) |
((chip_addr & 0x07) << 8) | ((chip_addr >> 3) & 0x0F);
*(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
I2C_CNTRL1) = temp;
/* Issue the write command (at this moment all other parameters
* are 0 (size = 1 byte, lane = 0)
*/
*(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
I2C_CNTRL2) = (I2C_CNTRL2_START);
op_status = TSI108_I2C_TIMEOUT_ERR;
/* Wait until operation completed */
do {
/* Read I2C operation status */
temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) {
if (0 == (temp &
(I2C_CNTRL2_I2C_CFGERR |
I2C_CNTRL2_I2C_TO_ERR))) {
op_status = TSI108_I2C_SUCCESS;
} else {
/* report detected HW error */
op_status = TSI108_I2C_IF_ERROR;
DPRINT (("I2C HW error reported: 0x%02x\n", temp));
}
break;
}
} while (to_count--);
} else {
op_status = TSI108_I2C_IF_BUSY;
DPRINT (("I2C Transaction start failed: 0x%02x\n", temp));
}
return op_status;
}
/*
* I2C Write interface as defined in "include/i2c.h" :
* chip_addr: I2C chip address, range 0..127
* byte_addr: Memory or 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: Pointer to data to be written
* len: How many bytes to write
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_write (uchar chip_addr, uint byte_addr, int alen, uchar * buffer,
int len)
{
u32 op_status = TSI108_I2C_PARAM_ERR;
/* Check for valid I2C address */
if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) {
while (len--) {
op_status =
i2c_write_byte (chip_addr, byte_addr++, buffer++);
if (TSI108_I2C_SUCCESS != op_status) {
DPRINT (("I2C write_byte() failed: 0x%02x (%d left)\n", op_status, len));
break;
}
}
}
return op_status;
}
/*
* I2C interface function as defined in "include/i2c.h".
* Probe the given I2C chip address by reading single byte from offset 0.
* Returns 0 if a chip responded, not 0 on failure.
*/
int i2c_probe (uchar chip)
{
u32 tmp;
/*
* Try to read the first location of the chip.
* The Tsi108 HW doesn't support sending just the chip address
* and checkong for an <ACK> back.
*/
return i2c_read (chip, 0, 1, (uchar *)&tmp, 1);
}
#endif

View file

@ -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];
}

View file

@ -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_ */