u-boot/drivers/i2c/davinci_i2c.c
Cooper Jr., Franklin 602191011f i2c: davinci: Split functions into two parts for future DM support
The i2c driver will be converted to support device model. In preparation
for that change split the various functions into two parts. This will
allow device model specific driver to reuse the majority of the code from
the non device model implementation.

Also rename the probe function to probe_chip to better reflect its
purpose.

Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Heiko Schocher <hs@denx.de>
2017-05-09 09:04:10 +02:00

422 lines
9.4 KiB
C

/*
* TI DaVinci (TMS320DM644x) I2C driver.
*
* (C) Copyright 2012-2014
* Texas Instruments Incorporated, <www.ti.com>
* (C) Copyright 2007 Sergey Kubushyn <ksi@koi8.net>
* --------------------------------------------------------
*
* SPDX-License-Identifier: GPL-2.0+
*
* NOTE: This driver should be converted to driver model before June 2017.
* Please see doc/driver-model/i2c-howto.txt for instructions.
*/
#include <common.h>
#include <i2c.h>
#include <asm/arch/hardware.h>
#include <asm/arch/i2c_defs.h>
#include <asm/io.h>
#include "davinci_i2c.h"
#define CHECK_NACK() \
do {\
if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\
REG(&(i2c_base->i2c_con)) = 0;\
return 1;\
} \
} while (0)
static struct i2c_regs *davinci_get_base(struct i2c_adapter *adap);
static int _wait_for_bus(struct i2c_regs *i2c_base)
{
int stat, timeout;
REG(&(i2c_base->i2c_stat)) = 0xffff;
for (timeout = 0; timeout < 10; timeout++) {
stat = REG(&(i2c_base->i2c_stat));
if (!((stat) & I2C_STAT_BB)) {
REG(&(i2c_base->i2c_stat)) = 0xffff;
return 0;
}
REG(&(i2c_base->i2c_stat)) = stat;
udelay(50000);
}
REG(&(i2c_base->i2c_stat)) = 0xffff;
return 1;
}
static int _poll_i2c_irq(struct i2c_regs *i2c_base, int mask)
{
int stat, timeout;
for (timeout = 0; timeout < 10; timeout++) {
udelay(1000);
stat = REG(&(i2c_base->i2c_stat));
if (stat & mask)
return stat;
}
REG(&(i2c_base->i2c_stat)) = 0xffff;
return stat | I2C_TIMEOUT;
}
static void _flush_rx(struct i2c_regs *i2c_base)
{
while (1) {
if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_RRDY))
break;
REG(&(i2c_base->i2c_drr));
REG(&(i2c_base->i2c_stat)) = I2C_STAT_RRDY;
udelay(1000);
}
}
static uint _davinci_i2c_setspeed(struct i2c_regs *i2c_base,
uint speed)
{
uint32_t div, psc;
psc = 2;
/* SCLL + SCLH */
div = (CONFIG_SYS_HZ_CLOCK / ((psc + 1) * speed)) - 10;
REG(&(i2c_base->i2c_psc)) = psc; /* 27MHz / (2 + 1) = 9MHz */
REG(&(i2c_base->i2c_scll)) = (div * 50) / 100; /* 50% Duty */
REG(&(i2c_base->i2c_sclh)) = div - REG(&(i2c_base->i2c_scll));
return 0;
}
static void _davinci_i2c_init(struct i2c_regs *i2c_base,
uint speed, int slaveadd)
{
if (REG(&(i2c_base->i2c_con)) & I2C_CON_EN) {
REG(&(i2c_base->i2c_con)) = 0;
udelay(50000);
}
_davinci_i2c_setspeed(i2c_base, speed);
REG(&(i2c_base->i2c_oa)) = slaveadd;
REG(&(i2c_base->i2c_cnt)) = 0;
/* Interrupts must be enabled or I2C module won't work */
REG(&(i2c_base->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_base->i2c_con)) = I2C_CON_EN;
udelay(1000);
}
static int _davinci_i2c_read(struct i2c_regs *i2c_base, uint8_t chip,
uint32_t addr, int alen, uint8_t *buf, int len)
{
uint32_t tmp;
int i;
if ((alen < 0) || (alen > 2)) {
printf("%s(): bogus address length %x\n", __func__, alen);
return 1;
}
if (_wait_for_bus(i2c_base))
return 1;
if (alen != 0) {
/* Start address phase */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
REG(&(i2c_base->i2c_cnt)) = alen;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = tmp;
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
switch (alen) {
case 2:
/* Send address MSByte */
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = (addr >> 8) & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
tmp = _poll_i2c_irq(i2c_base,
I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
/* No break, fall through */
case 1:
/* Send address LSByte */
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = addr & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY |
I2C_STAT_NACK | I2C_STAT_ARDY);
CHECK_NACK();
if (!(tmp & I2C_STAT_ARDY)) {
REG(&(i2c_base->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_base->i2c_cnt)) = len & 0xffff;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = tmp;
for (i = 0; i < len; i++) {
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_RRDY | I2C_STAT_NACK |
I2C_STAT_ROVR);
CHECK_NACK();
if (tmp & I2C_STAT_RRDY) {
buf[i] = REG(&(i2c_base->i2c_drr));
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
}
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
if (!(tmp & I2C_STAT_SCD)) {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
_flush_rx(i2c_base);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
REG(&(i2c_base->i2c_con)) = 0;
return 0;
}
static int _davinci_i2c_write(struct i2c_regs *i2c_base, uint8_t chip,
uint32_t addr, int alen, uint8_t *buf, int len)
{
uint32_t tmp;
int i;
if ((alen < 0) || (alen > 2)) {
printf("%s(): bogus address length %x\n", __func__, alen);
return 1;
}
if (len < 0) {
printf("%s(): bogus length %x\n", __func__, len);
return 1;
}
if (_wait_for_bus(i2c_base))
return 1;
/* Start address phase */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
I2C_CON_TRX | I2C_CON_STP;
REG(&(i2c_base->i2c_cnt)) = (alen == 0) ?
len & 0xffff : (len & 0xffff) + alen;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = tmp;
switch (alen) {
case 2:
/* Send address MSByte */
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = (addr >> 8) & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
/* No break, fall through */
case 1:
/* Send address LSByte */
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = addr & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
}
for (i = 0; i < len; i++) {
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY)
REG(&(i2c_base->i2c_dxr)) = buf[i];
else
return 1;
}
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
if (!(tmp & I2C_STAT_SCD)) {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
_flush_rx(i2c_base);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
REG(&(i2c_base->i2c_con)) = 0;
return 0;
}
static int _davinci_i2c_probe_chip(struct i2c_regs *i2c_base, uint8_t chip)
{
int rc = 1;
if (chip == REG(&(i2c_base->i2c_oa)))
return rc;
REG(&(i2c_base->i2c_con)) = 0;
if (_wait_for_bus(i2c_base))
return 1;
/* try to read one byte from current (or only) address */
REG(&(i2c_base->i2c_cnt)) = 1;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
I2C_CON_STP);
udelay(50000);
if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_NACK)) {
rc = 0;
_flush_rx(i2c_base);
REG(&(i2c_base->i2c_stat)) = 0xffff;
} else {
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_con)) |= I2C_CON_STP;
udelay(20000);
if (_wait_for_bus(i2c_base))
return 1;
}
_flush_rx(i2c_base);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
return rc;
}
static struct i2c_regs *davinci_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
#if I2C_BUS_MAX >= 3
case 2:
return (struct i2c_regs *)I2C2_BASE;
#endif
#if I2C_BUS_MAX >= 2
case 1:
return (struct i2c_regs *)I2C1_BASE;
#endif
case 0:
return (struct i2c_regs *)I2C_BASE;
default:
printf("wrong hwadapnr: %d\n", adap->hwadapnr);
}
return NULL;
}
static uint davinci_i2c_setspeed(struct i2c_adapter *adap, uint speed)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
uint ret;
adap->speed = speed;
ret = _davinci_i2c_setspeed(i2c_base, speed);
return ret;
}
static void davinci_i2c_init(struct i2c_adapter *adap, int speed,
int slaveadd)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
adap->speed = speed;
_davinci_i2c_init(i2c_base, speed, slaveadd);
return;
}
static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
uint32_t addr, int alen, uint8_t *buf, int len)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
return _davinci_i2c_read(i2c_base, chip, addr, alen, buf, len);
}
static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
uint32_t addr, int alen, uint8_t *buf, int len)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
return _davinci_i2c_write(i2c_base, chip, addr, alen, buf, len);
}
static int davinci_i2c_probe_chip(struct i2c_adapter *adap, uint8_t chip)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
return _davinci_i2c_probe_chip(i2c_base, chip);
}
U_BOOT_I2C_ADAP_COMPLETE(davinci_0, davinci_i2c_init, davinci_i2c_probe_chip,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED,
CONFIG_SYS_DAVINCI_I2C_SLAVE,
0)
#if I2C_BUS_MAX >= 2
U_BOOT_I2C_ADAP_COMPLETE(davinci_1, davinci_i2c_init, davinci_i2c_probe_chip,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED1,
CONFIG_SYS_DAVINCI_I2C_SLAVE1,
1)
#endif
#if I2C_BUS_MAX >= 3
U_BOOT_I2C_ADAP_COMPLETE(davinci_2, davinci_i2c_init, davinci_i2c_probe_chip,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED2,
CONFIG_SYS_DAVINCI_I2C_SLAVE2,
2)
#endif