2007-10-15 13:53:45

by Bryan Wu

[permalink] [raw]
Subject: [PATCH] Blackfin I2C/TWI driver: update for 2.6.24 merge windows

From: Bryan Wu <[email protected]>
Subject: [PATCH] Blackfin I2C/TWI driver: update for 2.6.24 merge windows

(Because "i2c-bfin-twi: Remove useless twi_lock mutex" patch was merged,
my previous 2 twi patch can not be applied. This is the latest one)

- Add repeat start feature to avoid break of a bundle of i2c master xfer operation
Create a new mode TWI_I2C_MODE_REPEAT
No change to smbus operation

- Add platform_resource interface to support multi-port TWI controllers

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/i2c/busses/i2c-bfin-twi.c | 414 +++++++++++++++++++++++--------------
1 files changed, 263 insertions(+), 151 deletions(-)

diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 67224a4..acae7ef 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -7,6 +7,10 @@
*
* Copyright (c) 2005-2007 Analog Devices, Inc.
*
+ * Modified:
+ * Aug 01, 2007 add platform_resource interface to support multi-port
+ * TWI controllers. (Bryan Wu <[email protected]>)
+ *
* 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
@@ -42,6 +46,7 @@
#define TWI_I2C_MODE_STANDARD 0x01
#define TWI_I2C_MODE_STANDARDSUB 0x02
#define TWI_I2C_MODE_COMBINED 0x04
+#define TWI_I2C_MODE_REPEAT 0x08

struct bfin_twi_iface {
int irq;
@@ -58,39 +63,69 @@ struct bfin_twi_iface {
struct timer_list timeout_timer;
struct i2c_adapter adap;
struct completion complete;
+ struct i2c_msg *pmsg;
+ int msg_num;
+ int cur_msg;
+ u32 regs_base;
};

-static struct bfin_twi_iface twi_iface;
+
+#define DEFINE_TWI_REG(reg, off) \
+static inline u16 read_##reg(struct bfin_twi_iface *iface) \
+ { return bfin_read16(iface->regs_base + off); } \
+static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
+ {bfin_write16(iface->regs_base + off, v); }
+
+DEFINE_TWI_REG(CLKDIV, 0x00)
+DEFINE_TWI_REG(CONTROL, 0x04)
+DEFINE_TWI_REG(SLAVE_CTL, 0x08)
+DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
+DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
+DEFINE_TWI_REG(MASTER_CTL, 0x14)
+DEFINE_TWI_REG(MASTER_STAT, 0x18)
+DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
+DEFINE_TWI_REG(INT_STAT, 0x20)
+DEFINE_TWI_REG(INT_MASK, 0x24)
+DEFINE_TWI_REG(FIFO_CTL, 0x28)
+DEFINE_TWI_REG(FIFO_STAT, 0x2C)
+DEFINE_TWI_REG(XMT_DATA8, 0x80)
+DEFINE_TWI_REG(XMT_DATA16, 0x84)
+DEFINE_TWI_REG(RCV_DATA8, 0x88)
+DEFINE_TWI_REG(RCV_DATA16, 0x8C)

static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
{
- unsigned short twi_int_status = bfin_read_TWI_INT_STAT();
- unsigned short mast_stat = bfin_read_TWI_MASTER_STAT();
+ unsigned short twi_int_status = read_INT_STAT(iface);
+ unsigned short mast_stat = read_MASTER_STAT(iface);

if (twi_int_status & XMTSERV) {
/* Transmit next data */
if (iface->writeNum > 0) {
- bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+ write_XMT_DATA8(iface, *(iface->transPtr++));
iface->writeNum--;
}
/* start receive immediately after complete sending in
* combine mode.
*/
- else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
- bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
- | MDIR | RSTART);
- } else if (iface->manual_stop)
- bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
- | STOP);
+ else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | MDIR | RSTART);
+ else if (iface->manual_stop)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | STOP);
+ else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+ iface->cur_msg+1 < iface->msg_num)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | RSTART);
SSYNC();
/* Clear status */
- bfin_write_TWI_INT_STAT(XMTSERV);
+ write_INT_STAT(iface, XMTSERV);
SSYNC();
}
if (twi_int_status & RCVSERV) {
if (iface->readNum > 0) {
/* Receive next data */
- *(iface->transPtr) = bfin_read_TWI_RCV_DATA8();
+ *(iface->transPtr) = read_RCV_DATA8(iface);
if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
/* Change combine mode into sub mode after
* read first data.
@@ -105,28 +140,33 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
iface->transPtr++;
iface->readNum--;
} else if (iface->manual_stop) {
- bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
- | STOP);
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | STOP);
+ SSYNC();
+ } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+ iface->cur_msg+1 < iface->msg_num) {
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | RSTART);
SSYNC();
}
/* Clear interrupt source */
- bfin_write_TWI_INT_STAT(RCVSERV);
+ write_INT_STAT(iface, RCVSERV);
SSYNC();
}
if (twi_int_status & MERR) {
- bfin_write_TWI_INT_STAT(MERR);
- bfin_write_TWI_INT_MASK(0);
- bfin_write_TWI_MASTER_STAT(0x3e);
- bfin_write_TWI_MASTER_CTL(0);
+ write_INT_STAT(iface, MERR);
+ write_INT_MASK(iface, 0);
+ write_MASTER_STAT(iface, 0x3e);
+ write_MASTER_CTL(iface, 0);
SSYNC();
- iface->result = -1;
+ iface->result = -EIO;
/* if both err and complete int stats are set, return proper
* results.
*/
if (twi_int_status & MCOMP) {
- bfin_write_TWI_INT_STAT(MCOMP);
- bfin_write_TWI_INT_MASK(0);
- bfin_write_TWI_MASTER_CTL(0);
+ write_INT_STAT(iface, MCOMP);
+ write_INT_MASK(iface, 0);
+ write_MASTER_CTL(iface, 0);
SSYNC();
/* If it is a quick transfer, only address bug no data,
* not an err, return 1.
@@ -143,7 +183,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
return;
}
if (twi_int_status & MCOMP) {
- bfin_write_TWI_INT_STAT(MCOMP);
+ write_INT_STAT(iface, MCOMP);
SSYNC();
if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
if (iface->readNum == 0) {
@@ -152,28 +192,63 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
*/
iface->readNum = 1;
iface->manual_stop = 1;
- bfin_write_TWI_MASTER_CTL(
- bfin_read_TWI_MASTER_CTL()
- | (0xff << 6));
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | (0xff << 6));
} else {
/* set the readd number in other
* combine mode.
*/
- bfin_write_TWI_MASTER_CTL(
- (bfin_read_TWI_MASTER_CTL() &
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) &
(~(0xff << 6))) |
- ( iface->readNum << 6));
+ (iface->readNum << 6));
+ }
+ /* remove restart bit and enable master receive */
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) & ~RSTART);
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | MEN | MDIR);
+ SSYNC();
+ } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+ iface->cur_msg+1 < iface->msg_num) {
+ iface->cur_msg++;
+ iface->transPtr = iface->pmsg[iface->cur_msg].buf;
+ iface->writeNum = iface->readNum =
+ iface->pmsg[iface->cur_msg].len;
+ /* Set Transmit device address */
+ write_MASTER_ADDR(iface,
+ iface->pmsg[iface->cur_msg].addr);
+ if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
+ iface->read_write = I2C_SMBUS_READ;
+ else {
+ iface->read_write = I2C_SMBUS_WRITE;
+ /* Transmit first data */
+ if (iface->writeNum > 0) {
+ write_XMT_DATA8(iface,
+ *(iface->transPtr++));
+ iface->writeNum--;
+ SSYNC();
+ }
+ }
+
+ if (iface->pmsg[iface->cur_msg].len <= 255)
+ write_MASTER_CTL(iface,
+ iface->pmsg[iface->cur_msg].len << 6);
+ else if (iface->pmsg[iface->cur_msg].len > 255) {
+ write_MASTER_CTL(iface, 0xff << 6);
+ iface->manual_stop = 1;
}
/* remove restart bit and enable master receive */
- bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() &
- ~RSTART);
- bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
- MEN | MDIR);
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) & ~RSTART);
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) |
+ MEN | ((iface->read_write == I2C_SMBUS_READ) ?
+ MDIR : 0));
SSYNC();
} else {
iface->result = 1;
- bfin_write_TWI_INT_MASK(0);
- bfin_write_TWI_MASTER_CTL(0);
+ write_INT_MASK(iface, 0);
+ write_MASTER_CTL(iface, 0);
SSYNC();
complete(&iface->complete);
}
@@ -221,91 +296,85 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
{
struct bfin_twi_iface *iface = adap->algo_data;
struct i2c_msg *pmsg;
- int i, ret;
int rc = 0;

- if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
+ if (!(read_CONTROL(iface) & TWI_ENA))
return -ENXIO;

- while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
+ while (read_MASTER_STAT(iface) & BUSBUSY)
yield();
+
+ iface->pmsg = msgs;
+ iface->msg_num = num;
+ iface->cur_msg = 0;
+
+ pmsg = &msgs[0];
+ if (pmsg->flags & I2C_M_TEN) {
+ dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "
+ "not supported !\n");
+ return -EINVAL;
}

- ret = 0;
- for (i = 0; rc >= 0 && i < num; i++) {
- pmsg = &msgs[i];
- if (pmsg->flags & I2C_M_TEN) {
- dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "
- "not supported !\n");
- rc = -EINVAL;
- break;
- }
+ iface->cur_mode = TWI_I2C_MODE_REPEAT;
+ iface->manual_stop = 0;
+ iface->transPtr = pmsg->buf;
+ iface->writeNum = iface->readNum = pmsg->len;
+ iface->result = 0;
+ iface->timeout_count = 10;
+ /* Set Transmit device address */
+ write_MASTER_ADDR(iface, pmsg->addr);

- iface->cur_mode = TWI_I2C_MODE_STANDARD;
- iface->manual_stop = 0;
- iface->transPtr = pmsg->buf;
- iface->writeNum = iface->readNum = pmsg->len;
- iface->result = 0;
- iface->timeout_count = 10;
- /* Set Transmit device address */
- bfin_write_TWI_MASTER_ADDR(pmsg->addr);
-
- /* FIFO Initiation. Data in FIFO should be
- * discarded before start a new operation.
- */
- bfin_write_TWI_FIFO_CTL(0x3);
- SSYNC();
- bfin_write_TWI_FIFO_CTL(0);
- SSYNC();
+ /* FIFO Initiation. Data in FIFO should be
+ * discarded before start a new operation.
+ */
+ write_FIFO_CTL(iface, 0x3);
+ SSYNC();
+ write_FIFO_CTL(iface, 0);
+ SSYNC();

- if (pmsg->flags & I2C_M_RD)
- iface->read_write = I2C_SMBUS_READ;
- else {
- iface->read_write = I2C_SMBUS_WRITE;
- /* Transmit first data */
- if (iface->writeNum > 0) {
- bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
- iface->writeNum--;
- SSYNC();
- }
+ if (pmsg->flags & I2C_M_RD)
+ iface->read_write = I2C_SMBUS_READ;
+ else {
+ iface->read_write = I2C_SMBUS_WRITE;
+ /* Transmit first data */
+ if (iface->writeNum > 0) {
+ write_XMT_DATA8(iface, *(iface->transPtr++));
+ iface->writeNum--;
+ SSYNC();
}
+ }

- /* clear int stat */
- bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
+ /* clear int stat */
+ write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);

- /* Interrupt mask . Enable XMT, RCV interrupt */
- bfin_write_TWI_INT_MASK(MCOMP | MERR |
- ((iface->read_write == I2C_SMBUS_READ)?
- RCVSERV : XMTSERV));
- SSYNC();
+ /* Interrupt mask . Enable XMT, RCV interrupt */
+ write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
+ SSYNC();

- if (pmsg->len > 0 && pmsg->len <= 255)
- bfin_write_TWI_MASTER_CTL(pmsg->len << 6);
- else if (pmsg->len > 255) {
- bfin_write_TWI_MASTER_CTL(0xff << 6);
- iface->manual_stop = 1;
- } else
- break;
+ if (pmsg->len <= 255)
+ write_MASTER_CTL(iface, pmsg->len << 6);
+ else if (pmsg->len > 255) {
+ write_MASTER_CTL(iface, 0xff << 6);
+ iface->manual_stop = 1;
+ }

- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
+ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+ add_timer(&iface->timeout_timer);

- /* Master enable */
- bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
- ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
- ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
- SSYNC();
+ /* Master enable */
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+ ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+ SSYNC();

- wait_for_completion(&iface->complete);
+ wait_for_completion(&iface->complete);

- rc = iface->result;
- if (rc == 1)
- ret++;
- else if (rc == -1)
- break;
- }
+ rc = iface->result;

- return ret;
+ if (rc == 1)
+ return num;
+ else
+ return rc;
}

/*
@@ -319,12 +388,11 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
struct bfin_twi_iface *iface = adap->algo_data;
int rc = 0;

- if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
+ if (!(read_CONTROL(iface) & TWI_ENA))
return -ENXIO;

- while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
+ while (read_MASTER_STAT(iface) & BUSBUSY)
yield();
- }

iface->writeNum = 0;
iface->readNum = 0;
@@ -396,15 +464,15 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
/* FIFO Initiation. Data in FIFO should be discarded before
* start a new operation.
*/
- bfin_write_TWI_FIFO_CTL(0x3);
+ write_FIFO_CTL(iface, 0x3);
SSYNC();
- bfin_write_TWI_FIFO_CTL(0);
+ write_FIFO_CTL(iface, 0);

/* clear int stat */
- bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
+ write_INT_STAT(iface, MERR|MCOMP|XMTSERV|RCVSERV);

/* Set Transmit device address */
- bfin_write_TWI_MASTER_ADDR(addr);
+ write_MASTER_ADDR(iface, addr);
SSYNC();

iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
@@ -412,60 +480,64 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,

switch (iface->cur_mode) {
case TWI_I2C_MODE_STANDARDSUB:
- bfin_write_TWI_XMT_DATA8(iface->command);
- bfin_write_TWI_INT_MASK(MCOMP | MERR |
+ write_XMT_DATA8(iface, iface->command);
+ write_INT_MASK(iface, MCOMP | MERR |
((iface->read_write == I2C_SMBUS_READ) ?
RCVSERV : XMTSERV));
SSYNC();

if (iface->writeNum + 1 <= 255)
- bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
+ write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
else {
- bfin_write_TWI_MASTER_CTL(0xff << 6);
+ write_MASTER_CTL(iface, 0xff << 6);
iface->manual_stop = 1;
}
/* Master enable */
- bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
break;
case TWI_I2C_MODE_COMBINED:
- bfin_write_TWI_XMT_DATA8(iface->command);
- bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV);
+ write_XMT_DATA8(iface, iface->command);
+ write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
SSYNC();

if (iface->writeNum > 0)
- bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
+ write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
else
- bfin_write_TWI_MASTER_CTL(0x1 << 6);
+ write_MASTER_CTL(iface, 0x1 << 6);
/* Master enable */
- bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
break;
default:
- bfin_write_TWI_MASTER_CTL(0);
+ write_MASTER_CTL(iface, 0);
if (size != I2C_SMBUS_QUICK) {
/* Don't access xmit data register when this is a
* read operation.
*/
if (iface->read_write != I2C_SMBUS_READ) {
if (iface->writeNum > 0) {
- bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+ write_XMT_DATA8(iface,
+ *(iface->transPtr++));
if (iface->writeNum <= 255)
- bfin_write_TWI_MASTER_CTL(iface->writeNum << 6);
+ write_MASTER_CTL(iface,
+ iface->writeNum << 6);
else {
- bfin_write_TWI_MASTER_CTL(0xff << 6);
+ write_MASTER_CTL(iface,
+ 0xff << 6);
iface->manual_stop = 1;
}
iface->writeNum--;
} else {
- bfin_write_TWI_XMT_DATA8(iface->command);
- bfin_write_TWI_MASTER_CTL(1 << 6);
+ write_XMT_DATA8(iface, iface->command);
+ write_MASTER_CTL(iface, 1 << 6);
}
} else {
if (iface->readNum > 0 && iface->readNum <= 255)
- bfin_write_TWI_MASTER_CTL(iface->readNum << 6);
+ write_MASTER_CTL(iface,
+ iface->readNum << 6);
else if (iface->readNum > 255) {
- bfin_write_TWI_MASTER_CTL(0xff << 6);
+ write_MASTER_CTL(iface, 0xff << 6);
iface->manual_stop = 1;
} else {
del_timer(&iface->timeout_timer);
@@ -473,13 +545,13 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
}
}
}
- bfin_write_TWI_INT_MASK(MCOMP | MERR |
+ write_INT_MASK(iface, MCOMP | MERR |
((iface->read_write == I2C_SMBUS_READ) ?
RCVSERV : XMTSERV));
SSYNC();

/* Master enable */
- bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
break;
@@ -514,10 +586,10 @@ static struct i2c_algorithm bfin_twi_algorithm = {

static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)
{
-/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
+ struct bfin_twi_iface *iface = platform_get_drvdata(dev);

/* Disable TWI */
- bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA);
+ write_CONTROL(iface, read_CONTROL(iface) & ~TWI_ENA);
SSYNC();

return 0;
@@ -525,64 +597,106 @@ static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)

static int i2c_bfin_twi_resume(struct platform_device *dev)
{
-/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
+ struct bfin_twi_iface *iface = platform_get_drvdata(dev);

/* Enable TWI */
- bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+ write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
SSYNC();

return 0;
}

-static int i2c_bfin_twi_probe(struct platform_device *dev)
+static int i2c_bfin_twi_probe(struct platform_device *pdev)
{
- struct bfin_twi_iface *iface = &twi_iface;
+ struct bfin_twi_iface *iface;
struct i2c_adapter *p_adap;
+ struct resource *res;
int rc;

+ iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
+ if (!iface) {
+ dev_err(&(pdev->dev), "Cannot allocate memory\n");
+ rc = -ENOMEM;
+ goto out_error_nomem;
+ }
+
spin_lock_init(&(iface->lock));
init_completion(&(iface->complete));
- iface->irq = IRQ_TWI;
+
+ /* Find and map our resources */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&(pdev->dev), "Cannot get IORESOURCE_MEM\n");
+ rc = -ENOENT;
+ goto out_error_get_res;
+ }
+
+ iface->regs_base = (u32) ioremap(res->start, (res->end - res->start)+1);
+ if (!iface->regs_base) {
+ dev_err(&(pdev->dev), "Cannot map IO\n");
+ rc = -ENXIO;
+ goto out_error_ioremap;
+ }
+
+ iface->irq = platform_get_irq(pdev, 0);
+ if (iface->irq < 0) {
+ dev_err(&(pdev->dev), "No DMA channel specified\n");
+ rc = -ENOENT;
+ goto out_error_no_irq;
+ }

init_timer(&(iface->timeout_timer));
iface->timeout_timer.function = bfin_twi_timeout;
iface->timeout_timer.data = (unsigned long)iface;

- p_adap = &iface->adap;
- p_adap->id = I2C_HW_BLACKFIN;
- strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
+ p_adap = &(iface->adap);
+ p_adap->id = I2C_HW_B_BLACKFIN;
+ strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
p_adap->algo = &bfin_twi_algorithm;
p_adap->algo_data = iface;
p_adap->class = I2C_CLASS_ALL;
- p_adap->dev.parent = &dev->dev;
+ p_adap->dev.parent = &pdev->dev;

rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
- IRQF_DISABLED, dev->name, iface);
+ IRQF_DISABLED, pdev->name, iface);
if (rc) {
- dev_err(&(p_adap->dev), "i2c-bfin-twi: can't get IRQ %d !\n",
+ dev_err(&(pdev->dev), "i2c-bfin-twi: can't get IRQ %d !\n",
iface->irq);
- return -ENODEV;
+ rc = -ENODEV;
+ goto out_error_req_irq;
}

/* Set TWI internal clock as 10MHz */
- bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
+ write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);

/* Set Twi interface clock as specified */
- bfin_write_TWI_CLKDIV((( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
- << 8) | (( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
+ write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
+ << 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
& 0xFF));

/* Enable TWI */
- bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+ write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
SSYNC();

rc = i2c_add_adapter(p_adap);
if (rc < 0)
free_irq(iface->irq, iface);
else
- platform_set_drvdata(dev, iface);
+ platform_set_drvdata(pdev, iface);
+
+ dev_info(&(pdev->dev), "Blackfin I2C TWI driver, regs_base @ 0x%08x\n",
+ iface->regs_base);

return rc;
+
+out_error_req_irq:
+out_error_no_irq:
+ iounmap((void *)iface->regs_base);
+out_error_ioremap:
+out_error_get_res:
+ kfree(iface);
+out_error_nomem:
+ return rc;
}

static int i2c_bfin_twi_remove(struct platform_device *pdev)
@@ -610,8 +724,6 @@ static struct platform_driver i2c_bfin_twi_driver = {

static int __init i2c_bfin_twi_init(void)
{
- pr_info("I2C: Blackfin I2C TWI driver\n");
-
return platform_driver_register(&i2c_bfin_twi_driver);
}

--
1.5.3.4


2007-10-18 06:11:47

by Bryan Wu

[permalink] [raw]
Subject: Re: [PATCH] Blackfin I2C/TWI driver: update for 2.6.24 merge windows

Hi Jean,

Could you kindly review this patch?

Thanks a lot
-Bryan

On 10/15/07, Bryan Wu <[email protected]> wrote:
> From: Bryan Wu <[email protected]>
> Subject: [PATCH] Blackfin I2C/TWI driver: update for 2.6.24 merge windows
>
> (Because "i2c-bfin-twi: Remove useless twi_lock mutex" patch was merged,
> my previous 2 twi patch can not be applied. This is the latest one)
>
> - Add repeat start feature to avoid break of a bundle of i2c master xfer operation
> Create a new mode TWI_I2C_MODE_REPEAT
> No change to smbus operation
>
> - Add platform_resource interface to support multi-port TWI controllers
>
> Signed-off-by: Sonic Zhang <[email protected]>
> Signed-off-by: Bryan Wu <[email protected]>
> ---
> drivers/i2c/busses/i2c-bfin-twi.c | 414 +++++++++++++++++++++++--------------
> 1 files changed, 263 insertions(+), 151 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
> index 67224a4..acae7ef 100644
> --- a/drivers/i2c/busses/i2c-bfin-twi.c
> +++ b/drivers/i2c/busses/i2c-bfin-twi.c
> @@ -7,6 +7,10 @@
> *
> * Copyright (c) 2005-2007 Analog Devices, Inc.
> *
> + * Modified:
> + * Aug 01, 2007 add platform_resource interface to support multi-port
> + * TWI controllers. (Bryan Wu <[email protected]>)
> + *
> * 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
> @@ -42,6 +46,7 @@
> #define TWI_I2C_MODE_STANDARD 0x01
> #define TWI_I2C_MODE_STANDARDSUB 0x02
> #define TWI_I2C_MODE_COMBINED 0x04
> +#define TWI_I2C_MODE_REPEAT 0x08
>
> struct bfin_twi_iface {
> int irq;
> @@ -58,39 +63,69 @@ struct bfin_twi_iface {
> struct timer_list timeout_timer;
> struct i2c_adapter adap;
> struct completion complete;
> + struct i2c_msg *pmsg;
> + int msg_num;
> + int cur_msg;
> + u32 regs_base;
> };
>
> -static struct bfin_twi_iface twi_iface;
> +
> +#define DEFINE_TWI_REG(reg, off) \
> +static inline u16 read_##reg(struct bfin_twi_iface *iface) \
> + { return bfin_read16(iface->regs_base + off); } \
> +static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
> + {bfin_write16(iface->regs_base + off, v); }
> +
> +DEFINE_TWI_REG(CLKDIV, 0x00)
> +DEFINE_TWI_REG(CONTROL, 0x04)
> +DEFINE_TWI_REG(SLAVE_CTL, 0x08)
> +DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
> +DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
> +DEFINE_TWI_REG(MASTER_CTL, 0x14)
> +DEFINE_TWI_REG(MASTER_STAT, 0x18)
> +DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
> +DEFINE_TWI_REG(INT_STAT, 0x20)
> +DEFINE_TWI_REG(INT_MASK, 0x24)
> +DEFINE_TWI_REG(FIFO_CTL, 0x28)
> +DEFINE_TWI_REG(FIFO_STAT, 0x2C)
> +DEFINE_TWI_REG(XMT_DATA8, 0x80)
> +DEFINE_TWI_REG(XMT_DATA16, 0x84)
> +DEFINE_TWI_REG(RCV_DATA8, 0x88)
> +DEFINE_TWI_REG(RCV_DATA16, 0x8C)
>
> static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
> {
> - unsigned short twi_int_status = bfin_read_TWI_INT_STAT();
> - unsigned short mast_stat = bfin_read_TWI_MASTER_STAT();
> + unsigned short twi_int_status = read_INT_STAT(iface);
> + unsigned short mast_stat = read_MASTER_STAT(iface);
>
> if (twi_int_status & XMTSERV) {
> /* Transmit next data */
> if (iface->writeNum > 0) {
> - bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
> + write_XMT_DATA8(iface, *(iface->transPtr++));
> iface->writeNum--;
> }
> /* start receive immediately after complete sending in
> * combine mode.
> */
> - else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
> - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
> - | MDIR | RSTART);
> - } else if (iface->manual_stop)
> - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
> - | STOP);
> + else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
> + write_MASTER_CTL(iface,
> + read_MASTER_CTL(iface) | MDIR | RSTART);
> + else if (iface->manual_stop)
> + write_MASTER_CTL(iface,
> + read_MASTER_CTL(iface) | STOP);
> + else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
> + iface->cur_msg+1 < iface->msg_num)
> + write_MASTER_CTL(iface,
> + read_MASTER_CTL(iface) | RSTART);
> SSYNC();
> /* Clear status */
> - bfin_write_TWI_INT_STAT(XMTSERV);
> + write_INT_STAT(iface, XMTSERV);
> SSYNC();
> }
> if (twi_int_status & RCVSERV) {
> if (iface->readNum > 0) {
> /* Receive next data */
> - *(iface->transPtr) = bfin_read_TWI_RCV_DATA8();
> + *(iface->transPtr) = read_RCV_DATA8(iface);
> if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
> /* Change combine mode into sub mode after
> * read first data.
> @@ -105,28 +140,33 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
> iface->transPtr++;
> iface->readNum--;
> } else if (iface->manual_stop) {
> - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
> - | STOP);
> + write_MASTER_CTL(iface,
> + read_MASTER_CTL(iface) | STOP);
> + SSYNC();
> + } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
> + iface->cur_msg+1 < iface->msg_num) {
> + write_MASTER_CTL(iface,
> + read_MASTER_CTL(iface) | RSTART);
> SSYNC();
> }
> /* Clear interrupt source */
> - bfin_write_TWI_INT_STAT(RCVSERV);
> + write_INT_STAT(iface, RCVSERV);
> SSYNC();
> }
> if (twi_int_status & MERR) {
> - bfin_write_TWI_INT_STAT(MERR);
> - bfin_write_TWI_INT_MASK(0);
> - bfin_write_TWI_MASTER_STAT(0x3e);
> - bfin_write_TWI_MASTER_CTL(0);
> + write_INT_STAT(iface, MERR);
> + write_INT_MASK(iface, 0);
> + write_MASTER_STAT(iface, 0x3e);
> + write_MASTER_CTL(iface, 0);
> SSYNC();
> - iface->result = -1;
> + iface->result = -EIO;
> /* if both err and complete int stats are set, return proper
> * results.
> */
> if (twi_int_status & MCOMP) {
> - bfin_write_TWI_INT_STAT(MCOMP);
> - bfin_write_TWI_INT_MASK(0);
> - bfin_write_TWI_MASTER_CTL(0);
> + write_INT_STAT(iface, MCOMP);
> + write_INT_MASK(iface, 0);
> + write_MASTER_CTL(iface, 0);
> SSYNC();
> /* If it is a quick transfer, only address bug no data,
> * not an err, return 1.
> @@ -143,7 +183,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
> return;
> }
> if (twi_int_status & MCOMP) {
> - bfin_write_TWI_INT_STAT(MCOMP);
> + write_INT_STAT(iface, MCOMP);
> SSYNC();
> if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
> if (iface->readNum == 0) {
> @@ -152,28 +192,63 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
> */
> iface->readNum = 1;
> iface->manual_stop = 1;
> - bfin_write_TWI_MASTER_CTL(
> - bfin_read_TWI_MASTER_CTL()
> - | (0xff << 6));
> + write_MASTER_CTL(iface,
> + read_MASTER_CTL(iface) | (0xff << 6));
> } else {
> /* set the readd number in other
> * combine mode.
> */
> - bfin_write_TWI_MASTER_CTL(
> - (bfin_read_TWI_MASTER_CTL() &
> + write_MASTER_CTL(iface,
> + (read_MASTER_CTL(iface) &
> (~(0xff << 6))) |
> - ( iface->readNum << 6));
> + (iface->readNum << 6));
> + }
> + /* remove restart bit and enable master receive */
> + write_MASTER_CTL(iface,
> + read_MASTER_CTL(iface) & ~RSTART);
> + write_MASTER_CTL(iface,
> + read_MASTER_CTL(iface) | MEN | MDIR);
> + SSYNC();
> + } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
> + iface->cur_msg+1 < iface->msg_num) {
> + iface->cur_msg++;
> + iface->transPtr = iface->pmsg[iface->cur_msg].buf;
> + iface->writeNum = iface->readNum =
> + iface->pmsg[iface->cur_msg].len;
> + /* Set Transmit device address */
> + write_MASTER_ADDR(iface,
> + iface->pmsg[iface->cur_msg].addr);
> + if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
> + iface->read_write = I2C_SMBUS_READ;
> + else {
> + iface->read_write = I2C_SMBUS_WRITE;
> + /* Transmit first data */
> + if (iface->writeNum > 0) {
> + write_XMT_DATA8(iface,
> + *(iface->transPtr++));
> + iface->writeNum--;
> + SSYNC();
> + }
> + }
> +
> + if (iface->pmsg[iface->cur_msg].len <= 255)
> + write_MASTER_CTL(iface,
> + iface->pmsg[iface->cur_msg].len << 6);
> + else if (iface->pmsg[iface->cur_msg].len > 255) {
> + write_MASTER_CTL(iface, 0xff << 6);
> + iface->manual_stop = 1;
> }
> /* remove restart bit and enable master receive */
> - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() &
> - ~RSTART);
> - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
> - MEN | MDIR);
> + write_MASTER_CTL(iface,
> + read_MASTER_CTL(iface) & ~RSTART);
> + write_MASTER_CTL(iface, read_MASTER_CTL(iface) |
> + MEN | ((iface->read_write == I2C_SMBUS_READ) ?
> + MDIR : 0));
> SSYNC();
> } else {
> iface->result = 1;
> - bfin_write_TWI_INT_MASK(0);
> - bfin_write_TWI_MASTER_CTL(0);
> + write_INT_MASK(iface, 0);
> + write_MASTER_CTL(iface, 0);
> SSYNC();
> complete(&iface->complete);
> }
> @@ -221,91 +296,85 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
> {
> struct bfin_twi_iface *iface = adap->algo_data;
> struct i2c_msg *pmsg;
> - int i, ret;
> int rc = 0;
>
> - if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
> + if (!(read_CONTROL(iface) & TWI_ENA))
> return -ENXIO;
>
> - while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
> + while (read_MASTER_STAT(iface) & BUSBUSY)
> yield();
> +
> + iface->pmsg = msgs;
> + iface->msg_num = num;
> + iface->cur_msg = 0;
> +
> + pmsg = &msgs[0];
> + if (pmsg->flags & I2C_M_TEN) {
> + dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "
> + "not supported !\n");
> + return -EINVAL;
> }
>
> - ret = 0;
> - for (i = 0; rc >= 0 && i < num; i++) {
> - pmsg = &msgs[i];
> - if (pmsg->flags & I2C_M_TEN) {
> - dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "
> - "not supported !\n");
> - rc = -EINVAL;
> - break;
> - }
> + iface->cur_mode = TWI_I2C_MODE_REPEAT;
> + iface->manual_stop = 0;
> + iface->transPtr = pmsg->buf;
> + iface->writeNum = iface->readNum = pmsg->len;
> + iface->result = 0;
> + iface->timeout_count = 10;
> + /* Set Transmit device address */
> + write_MASTER_ADDR(iface, pmsg->addr);
>
> - iface->cur_mode = TWI_I2C_MODE_STANDARD;
> - iface->manual_stop = 0;
> - iface->transPtr = pmsg->buf;
> - iface->writeNum = iface->readNum = pmsg->len;
> - iface->result = 0;
> - iface->timeout_count = 10;
> - /* Set Transmit device address */
> - bfin_write_TWI_MASTER_ADDR(pmsg->addr);
> -
> - /* FIFO Initiation. Data in FIFO should be
> - * discarded before start a new operation.
> - */
> - bfin_write_TWI_FIFO_CTL(0x3);
> - SSYNC();
> - bfin_write_TWI_FIFO_CTL(0);
> - SSYNC();
> + /* FIFO Initiation. Data in FIFO should be
> + * discarded before start a new operation.
> + */
> + write_FIFO_CTL(iface, 0x3);
> + SSYNC();
> + write_FIFO_CTL(iface, 0);
> + SSYNC();
>
> - if (pmsg->flags & I2C_M_RD)
> - iface->read_write = I2C_SMBUS_READ;
> - else {
> - iface->read_write = I2C_SMBUS_WRITE;
> - /* Transmit first data */
> - if (iface->writeNum > 0) {
> - bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
> - iface->writeNum--;
> - SSYNC();
> - }
> + if (pmsg->flags & I2C_M_RD)
> + iface->read_write = I2C_SMBUS_READ;
> + else {
> + iface->read_write = I2C_SMBUS_WRITE;
> + /* Transmit first data */
> + if (iface->writeNum > 0) {
> + write_XMT_DATA8(iface, *(iface->transPtr++));
> + iface->writeNum--;
> + SSYNC();
> }
> + }
>
> - /* clear int stat */
> - bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
> + /* clear int stat */
> + write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
>
> - /* Interrupt mask . Enable XMT, RCV interrupt */
> - bfin_write_TWI_INT_MASK(MCOMP | MERR |
> - ((iface->read_write == I2C_SMBUS_READ)?
> - RCVSERV : XMTSERV));
> - SSYNC();
> + /* Interrupt mask . Enable XMT, RCV interrupt */
> + write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
> + SSYNC();
>
> - if (pmsg->len > 0 && pmsg->len <= 255)
> - bfin_write_TWI_MASTER_CTL(pmsg->len << 6);
> - else if (pmsg->len > 255) {
> - bfin_write_TWI_MASTER_CTL(0xff << 6);
> - iface->manual_stop = 1;
> - } else
> - break;
> + if (pmsg->len <= 255)
> + write_MASTER_CTL(iface, pmsg->len << 6);
> + else if (pmsg->len > 255) {
> + write_MASTER_CTL(iface, 0xff << 6);
> + iface->manual_stop = 1;
> + }
>
> - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
> - add_timer(&iface->timeout_timer);
> + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
> + add_timer(&iface->timeout_timer);
>
> - /* Master enable */
> - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
> - ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
> - ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
> - SSYNC();
> + /* Master enable */
> + write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
> + ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
> + ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
> + SSYNC();
>
> - wait_for_completion(&iface->complete);
> + wait_for_completion(&iface->complete);
>
> - rc = iface->result;
> - if (rc == 1)
> - ret++;
> - else if (rc == -1)
> - break;
> - }
> + rc = iface->result;
>
> - return ret;
> + if (rc == 1)
> + return num;
> + else
> + return rc;
> }
>
> /*
> @@ -319,12 +388,11 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
> struct bfin_twi_iface *iface = adap->algo_data;
> int rc = 0;
>
> - if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
> + if (!(read_CONTROL(iface) & TWI_ENA))
> return -ENXIO;
>
> - while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
> + while (read_MASTER_STAT(iface) & BUSBUSY)
> yield();
> - }
>
> iface->writeNum = 0;
> iface->readNum = 0;
> @@ -396,15 +464,15 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
> /* FIFO Initiation. Data in FIFO should be discarded before
> * start a new operation.
> */
> - bfin_write_TWI_FIFO_CTL(0x3);
> + write_FIFO_CTL(iface, 0x3);
> SSYNC();
> - bfin_write_TWI_FIFO_CTL(0);
> + write_FIFO_CTL(iface, 0);
>
> /* clear int stat */
> - bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
> + write_INT_STAT(iface, MERR|MCOMP|XMTSERV|RCVSERV);
>
> /* Set Transmit device address */
> - bfin_write_TWI_MASTER_ADDR(addr);
> + write_MASTER_ADDR(iface, addr);
> SSYNC();
>
> iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
> @@ -412,60 +480,64 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
>
> switch (iface->cur_mode) {
> case TWI_I2C_MODE_STANDARDSUB:
> - bfin_write_TWI_XMT_DATA8(iface->command);
> - bfin_write_TWI_INT_MASK(MCOMP | MERR |
> + write_XMT_DATA8(iface, iface->command);
> + write_INT_MASK(iface, MCOMP | MERR |
> ((iface->read_write == I2C_SMBUS_READ) ?
> RCVSERV : XMTSERV));
> SSYNC();
>
> if (iface->writeNum + 1 <= 255)
> - bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
> + write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
> else {
> - bfin_write_TWI_MASTER_CTL(0xff << 6);
> + write_MASTER_CTL(iface, 0xff << 6);
> iface->manual_stop = 1;
> }
> /* Master enable */
> - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
> + write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
> ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
> break;
> case TWI_I2C_MODE_COMBINED:
> - bfin_write_TWI_XMT_DATA8(iface->command);
> - bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV);
> + write_XMT_DATA8(iface, iface->command);
> + write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
> SSYNC();
>
> if (iface->writeNum > 0)
> - bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
> + write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
> else
> - bfin_write_TWI_MASTER_CTL(0x1 << 6);
> + write_MASTER_CTL(iface, 0x1 << 6);
> /* Master enable */
> - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
> + write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
> ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
> break;
> default:
> - bfin_write_TWI_MASTER_CTL(0);
> + write_MASTER_CTL(iface, 0);
> if (size != I2C_SMBUS_QUICK) {
> /* Don't access xmit data register when this is a
> * read operation.
> */
> if (iface->read_write != I2C_SMBUS_READ) {
> if (iface->writeNum > 0) {
> - bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
> + write_XMT_DATA8(iface,
> + *(iface->transPtr++));
> if (iface->writeNum <= 255)
> - bfin_write_TWI_MASTER_CTL(iface->writeNum << 6);
> + write_MASTER_CTL(iface,
> + iface->writeNum << 6);
> else {
> - bfin_write_TWI_MASTER_CTL(0xff << 6);
> + write_MASTER_CTL(iface,
> + 0xff << 6);
> iface->manual_stop = 1;
> }
> iface->writeNum--;
> } else {
> - bfin_write_TWI_XMT_DATA8(iface->command);
> - bfin_write_TWI_MASTER_CTL(1 << 6);
> + write_XMT_DATA8(iface, iface->command);
> + write_MASTER_CTL(iface, 1 << 6);
> }
> } else {
> if (iface->readNum > 0 && iface->readNum <= 255)
> - bfin_write_TWI_MASTER_CTL(iface->readNum << 6);
> + write_MASTER_CTL(iface,
> + iface->readNum << 6);
> else if (iface->readNum > 255) {
> - bfin_write_TWI_MASTER_CTL(0xff << 6);
> + write_MASTER_CTL(iface, 0xff << 6);
> iface->manual_stop = 1;
> } else {
> del_timer(&iface->timeout_timer);
> @@ -473,13 +545,13 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
> }
> }
> }
> - bfin_write_TWI_INT_MASK(MCOMP | MERR |
> + write_INT_MASK(iface, MCOMP | MERR |
> ((iface->read_write == I2C_SMBUS_READ) ?
> RCVSERV : XMTSERV));
> SSYNC();
>
> /* Master enable */
> - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
> + write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
> ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
> ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
> break;
> @@ -514,10 +586,10 @@ static struct i2c_algorithm bfin_twi_algorithm = {
>
> static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)
> {
> -/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
> + struct bfin_twi_iface *iface = platform_get_drvdata(dev);
>
> /* Disable TWI */
> - bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA);
> + write_CONTROL(iface, read_CONTROL(iface) & ~TWI_ENA);
> SSYNC();
>
> return 0;
> @@ -525,64 +597,106 @@ static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)
>
> static int i2c_bfin_twi_resume(struct platform_device *dev)
> {
> -/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
> + struct bfin_twi_iface *iface = platform_get_drvdata(dev);
>
> /* Enable TWI */
> - bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
> + write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
> SSYNC();
>
> return 0;
> }
>
> -static int i2c_bfin_twi_probe(struct platform_device *dev)
> +static int i2c_bfin_twi_probe(struct platform_device *pdev)
> {
> - struct bfin_twi_iface *iface = &twi_iface;
> + struct bfin_twi_iface *iface;
> struct i2c_adapter *p_adap;
> + struct resource *res;
> int rc;
>
> + iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
> + if (!iface) {
> + dev_err(&(pdev->dev), "Cannot allocate memory\n");
> + rc = -ENOMEM;
> + goto out_error_nomem;
> + }
> +
> spin_lock_init(&(iface->lock));
> init_completion(&(iface->complete));
> - iface->irq = IRQ_TWI;
> +
> + /* Find and map our resources */
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (res == NULL) {
> + dev_err(&(pdev->dev), "Cannot get IORESOURCE_MEM\n");
> + rc = -ENOENT;
> + goto out_error_get_res;
> + }
> +
> + iface->regs_base = (u32) ioremap(res->start, (res->end - res->start)+1);
> + if (!iface->regs_base) {
> + dev_err(&(pdev->dev), "Cannot map IO\n");
> + rc = -ENXIO;
> + goto out_error_ioremap;
> + }
> +
> + iface->irq = platform_get_irq(pdev, 0);
> + if (iface->irq < 0) {
> + dev_err(&(pdev->dev), "No DMA channel specified\n");
> + rc = -ENOENT;
> + goto out_error_no_irq;
> + }
>
> init_timer(&(iface->timeout_timer));
> iface->timeout_timer.function = bfin_twi_timeout;
> iface->timeout_timer.data = (unsigned long)iface;
>
> - p_adap = &iface->adap;
> - p_adap->id = I2C_HW_BLACKFIN;
> - strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
> + p_adap = &(iface->adap);
> + p_adap->id = I2C_HW_B_BLACKFIN;
> + strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
> p_adap->algo = &bfin_twi_algorithm;
> p_adap->algo_data = iface;
> p_adap->class = I2C_CLASS_ALL;
> - p_adap->dev.parent = &dev->dev;
> + p_adap->dev.parent = &pdev->dev;
>
> rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
> - IRQF_DISABLED, dev->name, iface);
> + IRQF_DISABLED, pdev->name, iface);
> if (rc) {
> - dev_err(&(p_adap->dev), "i2c-bfin-twi: can't get IRQ %d !\n",
> + dev_err(&(pdev->dev), "i2c-bfin-twi: can't get IRQ %d !\n",
> iface->irq);
> - return -ENODEV;
> + rc = -ENODEV;
> + goto out_error_req_irq;
> }
>
> /* Set TWI internal clock as 10MHz */
> - bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
> + write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
>
> /* Set Twi interface clock as specified */
> - bfin_write_TWI_CLKDIV((( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
> - << 8) | (( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
> + write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
> + << 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
> & 0xFF));
>
> /* Enable TWI */
> - bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
> + write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
> SSYNC();
>
> rc = i2c_add_adapter(p_adap);
> if (rc < 0)
> free_irq(iface->irq, iface);
> else
> - platform_set_drvdata(dev, iface);
> + platform_set_drvdata(pdev, iface);
> +
> + dev_info(&(pdev->dev), "Blackfin I2C TWI driver, regs_base @ 0x%08x\n",
> + iface->regs_base);
>
> return rc;
> +
> +out_error_req_irq:
> +out_error_no_irq:
> + iounmap((void *)iface->regs_base);
> +out_error_ioremap:
> +out_error_get_res:
> + kfree(iface);
> +out_error_nomem:
> + return rc;
> }
>
> static int i2c_bfin_twi_remove(struct platform_device *pdev)
> @@ -610,8 +724,6 @@ static struct platform_driver i2c_bfin_twi_driver = {
>
> static int __init i2c_bfin_twi_init(void)
> {
> - pr_info("I2C: Blackfin I2C TWI driver\n");
> -
> return platform_driver_register(&i2c_bfin_twi_driver);
> }
>
> --
> 1.5.3.4
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

2007-10-19 09:08:01

by Jean Delvare

[permalink] [raw]
Subject: Re: [PATCH] Blackfin I2C/TWI driver: update for 2.6.24 merge windows

Hi Bryan,

On Thu, 18 Oct 2007 14:11:35 +0800, Bryan Wu wrote:
> Could you kindly review this patch?

I'm pretty busy these days, I don't have much spare time for reviews.

BTW, as a rule of thumb, I am ignoring patches that are sent to the
LKML in addition to the i2c list. If you think that your patch is so
important that it has to be send to a list with over 4500 subscribers
that sees 120.000 messages each year, then who am I to dare to comment
on it?

If you want me to consider your patches as something that needs my
attention, send them to the i2c list only, do not add LKML. This is
general advice for everyone sending i2c patches, not just you, of
course.

Back to your patch... Originally you posted two patches, and I see that
they are now merged into a single patch, why? It's much better to have
separate patches, it makes reviews and testing way easier. If you
provide separate patches I'll try to find some time to review them.

Note that this won't be for 2.6.24 anyway, it's too late for that, I've
already sent my i2c patches to Linus. From now on, only bugfixes can go
in 2.6.24, improvements will have to wait for 2.6.25.

--
Jean Delvare

2007-10-19 09:23:33

by Bryan Wu

[permalink] [raw]
Subject: Re: [PATCH] Blackfin I2C/TWI driver: update for 2.6.24 merge windows

On 10/19/07, Jean Delvare <[email protected]> wrote:
> Hi Bryan,
>
> On Thu, 18 Oct 2007 14:11:35 +0800, Bryan Wu wrote:
> > Could you kindly review this patch?
>
> I'm pretty busy these days, I don't have much spare time for reviews.
>
> BTW, as a rule of thumb, I am ignoring patches that are sent to the
> LKML in addition to the i2c list. If you think that your patch is so
> important that it has to be send to a list with over 4500 subscribers
> that sees 120.000 messages each year, then who am I to dare to comment
> on it?
>
> If you want me to consider your patches as something that needs my
> attention, send them to the i2c list only, do not add LKML. This is
> general advice for everyone sending i2c patches, not just you, of
> course.
>
I see. Actually this is the first time I was told about it.
Thanks for the clarification.

> Back to your patch... Originally you posted two patches, and I see that
> they are now merged into a single patch, why? It's much better to have
> separate patches, it makes reviews and testing way easier. If you
> provide separate patches I'll try to find some time to review them.
>
OK, I will send separate patch later.


> Note that this won't be for 2.6.24 anyway, it's too late for that, I've
> already sent my i2c patches to Linus. From now on, only bugfixes can go
> in 2.6.24, improvements will have to wait for 2.6.25.
>
I know it missed the merge window.

Thanks again
-Bryan Wu

2007-10-19 09:24:33

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] Blackfin I2C/TWI driver: update for 2.6.24 merge windows

On Fri, 19 Oct 2007 11:07:50 +0200 Jean Delvare <[email protected]> wrote:

> BTW, as a rule of thumb, I am ignoring patches that are sent to the
> LKML in addition to the i2c list. If you think that your patch is so
> important that it has to be send to a list with over 4500 subscribers
> that sees 120.000 messages each year, then who am I to dare to comment
> on it?
>
> If you want me to consider your patches as something that needs my
> attention, send them to the i2c list only, do not add LKML. This is
> general advice for everyone sending i2c patches, not just you, of
> course.

Disagree. I don't think there's any benefit to anyone for developers to
hide their stuff on remote mailing lists. Copying lkml increases the
changes that someone will spot a bug or some improvement and it generally
keeps people informed as to what's going on.

yeah, 120,000 messages/year. But a lot of them are just noise. Patches
are important.


And I really don't understand this huffy attitude and putting more
roadblocks in the way of our contributors. People like Bryan are doing a
lot of work to improve Linux and most people are (or should be) grateful
for that and should be prepared to go the extra yard to help them.

2007-10-19 10:19:41

by Jean Delvare

[permalink] [raw]
Subject: Re: [PATCH] Blackfin I2C/TWI driver: update for 2.6.24 merge windows

On Fri, 19 Oct 2007 17:23:24 +0800, Bryan Wu wrote:
> On 10/19/07, Jean Delvare <[email protected]> wrote:
> > If you want me to consider your patches as something that needs my
> > attention, send them to the i2c list only, do not add LKML. This is
> > general advice for everyone sending i2c patches, not just you, of
> > course.
>
> I see. Actually this is the first time I was told about it.
> Thanks for the clarification.

I probably had not been clear about it so far. I've added it to my
"Linux 2.6 I2C development FAQ" now.

--
Jean Delvare

2007-10-19 11:52:56

by Jean Delvare

[permalink] [raw]
Subject: Re: [PATCH] Blackfin I2C/TWI driver: update for 2.6.24 merge windows

Hi Andrew,

On Fri, 19 Oct 2007 02:23:34 -0700, Andrew Morton wrote:
> On Fri, 19 Oct 2007 11:07:50 +0200 Jean Delvare <[email protected]> wrote:
>
> > BTW, as a rule of thumb, I am ignoring patches that are sent to the
> > LKML in addition to the i2c list. If you think that your patch is so
> > important that it has to be send to a list with over 4500 subscribers
> > that sees 120.000 messages each year, then who am I to dare to comment
> > on it?
> >
> > If you want me to consider your patches as something that needs my
> > attention, send them to the i2c list only, do not add LKML. This is
> > general advice for everyone sending i2c patches, not just you, of
> > course.
>
> Disagree. I don't think there's any benefit to anyone for developers to
> hide their stuff on remote mailing lists.

Hiding? These are lists _dedicated_ to the matter.

> Copying lkml increases the
> changes that someone will spot a bug or some improvement and it generally
> keeps people informed as to what's going on.

Sending spam to millions of people increases the chances than someone
will buy your product. Does it make spam a good thing?

> yeah, 120,000 messages/year. But a lot of them are just noise. Patches
> are important.

Lot of noise, yes. Counting 1 second on average to process posts you're
not interested in, that's 33 hours a year. This is completely insane
and that's why I unsubscribed from LKML long ago. And the situation is
only getting worse every year. You may fail to realize the problem just
because you aren't completely human ;)

> And I really don't understand this huffy attitude and putting more
> roadblocks in the way of our contributors.

Quite on the contrary, I am trying to educate people into targeting
their posts to the right lists so that they get more appropriate
responses in a shorter time.

In a world where we would have infinite work power and time would grow
on trees, I would be fine with everyone sending everything to every
mailing list. But in the real world, time spent to do one thing isn't
spent on another. If we don't learn, collectively, to target our posts
to the right people, then we end up wasting a significant amount of our
precious time.

> People like Bryan are doing a
> lot of work to improve Linux and most people are (or should be) grateful
> for that and should be prepared to go the extra yard to help them.

My comment is general and absolutely not targeted at Bryan personally.
I thought it was clear. I fully agree that Bryan is a really pleasant
and easy person to work with and I do appreciate his contributions.

--
Jean Delvare

2007-10-19 12:49:51

by Manu Abraham

[permalink] [raw]
Subject: Re: [PATCH] Blackfin I2C/TWI driver: update for 2.6.24 merge windows

Jean Delvare wrote:

> BTW, as a rule of thumb, I am ignoring patches that are sent to the
> LKML in addition to the i2c list.

Why ? The statement would have made sense if the i2c list was not CC 'd,
but stating that if LK is CC 'd additionally sounds ...