#endif
#ifdef CONFIG_I2C0_RK30
+static int i2c0_check_idle(void)
+{
+ int sda_level, scl_level;
+ rk30_mux_api_set(GPIO2D5_I2C0SCL_NAME, GPIO2D_GPIO2D5);
+ rk30_mux_api_set(GPIO2D4_I2C0SDA_NAME, GPIO2D_GPIO2D4);
+
+ gpio_request(RK30_PIN2_PD5, "i2c.0");
+ gpio_request(RK30_PIN2_PD4, "i2c.0");
+
+ gpio_direction_input(RK30_PIN2_PD5);
+ gpio_direction_input(RK30_PIN2_PD4);
+
+ scl_level = gpio_get_value(RK30_PIN2_PD5);
+ sda_level = gpio_get_value(RK30_PIN2_PD4);
+
+ gpio_free(RK30_PIN2_PD5);
+ gpio_free(RK30_PIN2_PD4);
+
+ rk30_mux_api_set(GPIO2D5_I2C0SCL_NAME, GPIO2D_I2C0_SCL);
+ rk30_mux_api_set(GPIO2D4_I2C0SDA_NAME, GPIO2D_I2C0_SDA);
+
+ if(sda_level == 1 && scl_level == 1)
+ return I2C_IDLE;
+ else if(sda_level == 0 && scl_level == 1)
+ return I2C_SDA_LOW;
+ else if(sda_level == 1 && scl_level == 0)
+ return I2C_SCL_LOW;
+ else
+ return BOTH_LOW;
+}
+
static struct rk30_i2c_platform_data default_i2c0_data = {
.bus_num = 0,
.is_div_from_arm = 1,
.adap_type = I2C0_ADAP_TYPE,
+ .check_idle = &i2c0_check_idle,
};
static struct resource resources_i2c0[] = {
#endif
#ifdef CONFIG_I2C1_RK30
+static int i2c1_check_idle(void)
+{
+ int sda_level, scl_level;
+ rk30_mux_api_set(GPIO2D7_I2C1SCL_NAME, GPIO2D_GPIO2D7);
+ rk30_mux_api_set(GPIO2D6_I2C1SDA_NAME, GPIO2D_GPIO2D6);
+
+ gpio_request(RK30_PIN2_PD7, "i2c.1");
+ gpio_request(RK30_PIN2_PD6, "i2c.1");
+
+ gpio_direction_input(RK30_PIN2_PD7);
+ gpio_direction_input(RK30_PIN2_PD6);
+
+ sda_level = gpio_get_value(RK30_PIN2_PD7);
+ scl_level = gpio_get_value(RK30_PIN2_PD6);
+
+ gpio_free(RK30_PIN2_PD7);
+ gpio_free(RK30_PIN2_PD6);
+
+ rk30_mux_api_set(GPIO2D7_I2C1SCL_NAME, GPIO2D_I2C1_SCL);
+ rk30_mux_api_set(GPIO2D6_I2C1SDA_NAME, GPIO2D_I2C1_SDA);
+
+ if(sda_level == 1 && scl_level == 1)
+ return I2C_IDLE;
+ else if(sda_level == 0 && scl_level == 1)
+ return I2C_SDA_LOW;
+ else if(sda_level == 1 && scl_level == 0)
+ return I2C_SCL_LOW;
+ else
+ return BOTH_LOW;
+}
+
static struct rk30_i2c_platform_data default_i2c1_data = {
.bus_num = 1,
.is_div_from_arm = 1,
.adap_type = I2C1_ADAP_TYPE,
+ .check_idle = &i2c1_check_idle,
};
static struct resource resources_i2c1[] = {
#endif
#ifdef CONFIG_I2C2_RK30
+static int i2c2_check_idle(void)
+{
+ int sda_level, scl_level;
+ rk30_mux_api_set(GPIO3A1_I2C2SCL_NAME, GPIO3A_GPIO3A1);
+ rk30_mux_api_set(GPIO3A0_I2C2SDA_NAME, GPIO3A_GPIO3A0);
+
+ gpio_request(RK30_PIN3_PA1, "i2c.2");
+ gpio_request(RK30_PIN3_PA0, "i2c.2");
+
+ gpio_direction_input(RK30_PIN3_PA1);
+ gpio_direction_input(RK30_PIN3_PA0);
+
+ sda_level = gpio_get_value(RK30_PIN3_PA1);
+ scl_level = gpio_get_value(RK30_PIN3_PA0);
+
+ gpio_free(RK30_PIN3_PA1);
+ gpio_free(RK30_PIN3_PA0);
+
+ rk30_mux_api_set(GPIO3A1_I2C2SCL_NAME, GPIO3A_I2C2_SCL);
+ rk30_mux_api_set(GPIO3A0_I2C2SDA_NAME, GPIO3A_I2C2_SDA);
+
+ if(sda_level == 1 && scl_level == 1)
+ return I2C_IDLE;
+ else if(sda_level == 0 && scl_level == 1)
+ return I2C_SDA_LOW;
+ else if(sda_level == 1 && scl_level == 0)
+ return I2C_SCL_LOW;
+ else
+ return BOTH_LOW;
+}
+
+
static struct rk30_i2c_platform_data default_i2c2_data = {
.bus_num = 2,
.is_div_from_arm = 0,
.adap_type = I2C2_ADAP_TYPE,
+ .check_idle = &i2c2_check_idle,
};
static struct resource resources_i2c2[] = {
#endif
#ifdef CONFIG_I2C3_RK30
+static int i2c3_check_idle(void)
+{
+ int sda_level, scl_level;
+ rk30_mux_api_set(GPIO3A3_I2C3SCL_NAME, GPIO3A_GPIO3A3);
+ rk30_mux_api_set(GPIO3A2_I2C3SDA_NAME, GPIO3A_GPIO3A2);
+
+ gpio_request(RK30_PIN3_PA3, "i2c.3");
+ gpio_request(RK30_PIN3_PA2, "i2c.3");
+
+ gpio_direction_input(RK30_PIN3_PA3);
+ gpio_direction_input(RK30_PIN3_PA2);
+
+ sda_level = gpio_get_value(RK30_PIN3_PA3);
+ scl_level = gpio_get_value(RK30_PIN3_PA2);
+
+ gpio_free(RK30_PIN3_PA3);
+ gpio_free(RK30_PIN3_PA2);
+
+ rk30_mux_api_set(GPIO3A3_I2C3SCL_NAME, GPIO3A_I2C3_SCL);
+ rk30_mux_api_set(GPIO3A2_I2C3SDA_NAME, GPIO3A_I2C3_SDA);
+
+ if(sda_level == 1 && scl_level == 1)
+ return I2C_IDLE;
+ else if(sda_level == 0 && scl_level == 1)
+ return I2C_SDA_LOW;
+ else if(sda_level == 1 && scl_level == 0)
+ return I2C_SCL_LOW;
+ else
+ return BOTH_LOW;
+}
+
+
static struct rk30_i2c_platform_data default_i2c3_data = {
.bus_num = 3,
.is_div_from_arm = 0,
.adap_type = I2C3_ADAP_TYPE,
+ .check_idle = &i2c3_check_idle,
};
static struct resource resources_i2c3[] = {
#endif
#ifdef CONFIG_I2C4_RK30
+static int i2c4_check_idle(void)
+{
+ int sda_level, scl_level;
+ rk30_mux_api_set(GPIO3A5_I2C4SCL_NAME, GPIO3A_GPIO3A5);
+ rk30_mux_api_set(GPIO3A4_I2C4SDA_NAME, GPIO3A_GPIO3A4);
+
+ gpio_request(RK30_PIN3_PA5, "i2c.4");
+ gpio_request(RK30_PIN3_PA4, "i2c.4");
+
+ gpio_direction_input(RK30_PIN3_PA5);
+ gpio_direction_input(RK30_PIN3_PA4);
+
+ scl_level = gpio_get_value(RK30_PIN3_PA5);
+ sda_level = gpio_get_value(RK30_PIN3_PA4);
+
+ gpio_free(RK30_PIN3_PA5);
+ gpio_free(RK30_PIN3_PA4);
+
+ rk30_mux_api_set(GPIO3A5_I2C4SCL_NAME, GPIO3A_I2C4_SCL);
+ rk30_mux_api_set(GPIO3A4_I2C4SDA_NAME, GPIO3A_I2C4_SDA);
+
+ if(sda_level == 1 && scl_level == 1)
+ return I2C_IDLE;
+ else if(sda_level == 0 && scl_level == 1)
+ return I2C_SDA_LOW;
+ else if(sda_level == 1 && scl_level == 0)
+ return I2C_SCL_LOW;
+ else
+ return BOTH_LOW;
+}
+
static struct rk30_i2c_platform_data default_i2c4_data = {
.bus_num = 4,
.is_div_from_arm = 0,
.adap_type = I2C4_ADAP_TYPE,
+ .check_idle = &i2c4_check_idle,
};
static struct resource resources_i2c4[] = {
#include <linux/device.h>
#include <linux/rk_screen.h>
+enum {
+ I2C_IDLE = 0,
+ I2C_SDA_LOW,
+ I2C_SCL_LOW,
+ BOTH_LOW,
+};
struct rk30_i2c_platform_data {
char *name;
int bus_num;
u32 flags;
int (*io_init)(void);
int (*io_deinit)(void);
+ int (*check_idle)(void);
};
struct spi_cs_gpio {
*/
#include "i2c-rk30.h"
+#define COMPLETE_READ (1<<STATE_START|1<<STATE_READ|1<<STATE_STOP)
+#define COMPLETE_WRITE (1<<STATE_START|1<<STATE_WRITE|1<<STATE_STOP)
+
/* Control register */
#define I2C_CON 0x000
#define I2C_CON_EN (1 << 0)
#define I2C_CON_MOD(mod) ((mod) << 1)
#define I2C_CON_MASK (3 << 1)
enum{
- I2C_CON_MOD_TX = 0,
- I2C_CON_MOD_TRX,
- I2C_CON_MOD_RX,
- I2C_CON_MOD_RRX,
+ I2C_CON_MOD_TX = 0,
+ I2C_CON_MOD_TRX,
+ I2C_CON_MOD_RX,
+ I2C_CON_MOD_RRX,
};
#define I2C_CON_START (1 << 3)
#define I2C_CON_STOP (1 << 4)
static void rk30_show_regs(struct rk30_i2c *i2c)
{
int i;
- i2c_dbg(i2c->dev, "i2c->start = %d\n", i2c->state);
- i2c_dbg(i2c->dev, "I2C_CON: 0x%08x\n", i2c_readl(i2c->regs + I2C_CON));
- i2c_dbg(i2c->dev, "I2C_CLKDIV: 0x%08x\n", i2c_readl(i2c->regs + I2C_CLKDIV));
- i2c_dbg(i2c->dev, "I2C_MRXADDR: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXADDR));
- i2c_dbg(i2c->dev, "I2C_MRXRADDR: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXRADDR));
- i2c_dbg(i2c->dev, "I2C_MTXCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_MTXCNT));
- i2c_dbg(i2c->dev, "I2C_MRXCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXCNT));
- i2c_dbg(i2c->dev, "I2C_IEN: 0x%08x\n", i2c_readl(i2c->regs + I2C_IEN));
- i2c_dbg(i2c->dev, "I2C_IPD: 0x%08x\n", i2c_readl(i2c->regs + I2C_IPD));
- i2c_dbg(i2c->dev, "I2C_FCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_FCNT));
+ dev_info(i2c->dev, "i2c->clk = %lu\n", clk_get_rate(i2c->clk));
+ dev_info(i2c->dev, "i2c->start = %d\n", i2c->state);
+ dev_info(i2c->dev, "I2C_CON: 0x%08x\n", i2c_readl(i2c->regs + I2C_CON));
+ dev_info(i2c->dev, "I2C_CLKDIV: 0x%08x\n", i2c_readl(i2c->regs + I2C_CLKDIV));
+ dev_info(i2c->dev, "I2C_MRXADDR: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXADDR));
+ dev_info(i2c->dev, "I2C_MRXRADDR: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXRADDR));
+ dev_info(i2c->dev, "I2C_MTXCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_MTXCNT));
+ dev_info(i2c->dev, "I2C_MRXCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXCNT));
+ dev_info(i2c->dev, "I2C_IEN: 0x%08x\n", i2c_readl(i2c->regs + I2C_IEN));
+ dev_info(i2c->dev, "I2C_IPD: 0x%08x\n", i2c_readl(i2c->regs + I2C_IPD));
+ dev_info(i2c->dev, "I2C_FCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_FCNT));
for( i = 0; i < 8; i ++)
- i2c_dbg(i2c->dev, "I2C_TXDATA%d: 0x%08x\n", i, i2c_readl(i2c->regs + I2C_TXDATA_BASE + i * 4));
+ dev_info(i2c->dev, "I2C_TXDATA%d: 0x%08x\n", i, i2c_readl(i2c->regs + I2C_TXDATA_BASE + i * 4));
for( i = 0; i < 8; i ++)
- i2c_dbg(i2c->dev, "I2C_RXDATA%d: 0x%08x\n", i, i2c_readl(i2c->regs + I2C_RXDATA_BASE + i * 4));
+ dev_info(i2c->dev, "I2C_RXDATA%d: 0x%08x\n", i, i2c_readl(i2c->regs + I2C_RXDATA_BASE + i * 4));
}
static inline void rk30_i2c_enable(struct rk30_i2c *i2c, unsigned int lastnak)
{
}
rk30_i2c_clean_stop(i2c);
i2c_writel(I2C_STOPIPD, i2c->regs + I2C_IPD);
- i2c->state = STATE_IDLE;
i2c->is_busy = 0;
i2c->complete_what |= 1<<i2c->state;
+ i2c->state = STATE_IDLE;
wake_up(&i2c->wait);
break;
default:
struct i2c_msg *msgs, int num)
{
unsigned long timeout, flags;
-
- if (i2c->suspended)
+ int error = 0;
+ /* 32 -- max transfer bytes
+ * 2 -- addr bytes * 2
+ * 3 -- max reg addr bytes
+ * 9 -- cycles per bytes
+ * max cycles: (32 + 2 + 3) * 9 --> 400 cycles
+ */
+ int msleep_time = 400 * 1000/ i2c->scl_rate; // ms
+
+ if (i2c->suspended){
+ dev_err(i2c->dev, "i2c is suspended\n");
return -EIO;
+ }
spin_lock_irqsave(&i2c->lock, flags);
if(rk30_i2c_set_master(i2c, msgs, num) < 0){
timeout = wait_event_timeout(i2c->wait, (i2c->is_busy == 0), msecs_to_jiffies(I2C_WAIT_TIMEOUT));
spin_lock_irqsave(&i2c->lock, flags);
- i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD);
+ i2c->state = STATE_IDLE;
+ error = i2c->error;
spin_unlock_irqrestore(&i2c->lock, flags);
if (timeout == 0){
- dev_err(i2c->dev, "addr[0x%02x] wait event timeout, state: %d, is_busy: %d, error: %d, complete_what: 0x%x\n",
- msgs[0].addr, i2c->state, i2c->is_busy, i2c->error, i2c->complete_what);
- i2c->state = STATE_IDLE;
- if((i2c->error < 0) || (i2c->is_busy != 0) || !(i2c->complete_what & (1 << STATE_STOP)))
- i2c->error = -ETIMEDOUT;
- rk30_i2c_send_stop(i2c);
-
+ if(error < 0)
+ i2c_dbg(i2c->dev, "error = %d\n", error);
+ else if((i2c->complete_what !=COMPLETE_READ && i2c->complete_what != COMPLETE_WRITE)){
+ dev_err(i2c->dev, "Addr[0x%02x] wait event timeout, state: %d, is_busy: %d, error: %d, complete_what: 0x%x, ipd: 0x%x\n",
+ msgs[0].addr, i2c->state, i2c->is_busy, error, i2c->complete_what, i2c_readl(i2c->regs + I2C_IPD));
+ //rk30_show_regs(i2c);
+ error = -ETIMEDOUT;
+ msleep(msleep_time);
+ rk30_i2c_send_stop(i2c);
+ msleep(1);
+ }
+ else
+ i2c_dbg(i2c->dev, "Addr[0x%02x] wait event timeout, but transfer complete\n", i2c->addr);
}
+ i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD);
rk30_i2c_disable_irq(i2c);
rk30_i2c_disable(i2c);
- if(i2c->error == -EAGAIN)
- dev_err(i2c->dev, "No ack(retry: %d, complete_what: 0x%x), Maybe slave(addr: 0x%02x) not exist or abnormal power-on\n",
- i2c->adap.retries + 1, i2c->complete_what, i2c->addr);
- return i2c->error;
+ if(error == -EAGAIN)
+ i2c_dbg(i2c->dev, "No ack(complete_what: 0x%x), Maybe slave(addr: 0x%02x) not exist or abnormal power-on\n",
+ i2c->complete_what, i2c->addr);
+ return error;
}
/* rk30_i2c_xfer
static int rk30_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
- int ret = 0;
+ int ret = 0, state, retry = 10;
unsigned long scl_rate;
struct rk30_i2c *i2c = (struct rk30_i2c *)adap->algo_data;
clk_enable(i2c->clk);
+ while(retry-- && ((state = i2c->check_idle()) != I2C_IDLE)){
+ msleep(10);
+ }
+ if(retry == 0){
+ dev_err(i2c->dev, "i2c is not in idle(state = %d)\n", state);
+ return -EIO;
+ }
if(msgs[0].scl_rate <= 400000 && msgs[0].scl_rate >= 10000)
scl_rate = msgs[0].scl_rate;
if(pdata->io_init)
pdata->io_init();
+ if(pdata->check_idle){
+ i2c->check_idle = pdata->check_idle;
+ }
strlcpy(i2c->adap.name, "rk30_i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;
i2c_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
- //clk_enable(i2c->clk);
+ clk_enable(i2c->clk);
/* map the registers */
};
union {
unsigned int msg_idx;
- unsigned int error;
+ int error;
};
unsigned int msg_ptr;
void (*i2c_init_hw)(struct rk30_i2c *, unsigned long scl_rate);
void (*i2c_set_clk)(struct rk30_i2c *, unsigned long);
+ int (*check_idle)(void);
irqreturn_t (*i2c_irq)(int, void *);
};
void i2c_adap_sel(struct rk30_i2c *i2c, int nr, int adap_type);
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
+ dev_err(&adap->dev, "No ack, Maybe slave(addr: 0x%x) not exist or abnormal power-on, retry %d...\n",
+ msgs[0].addr, adap->retries - try);
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}