File saa716x_simplify_and_improve_i2c_handling.diff of Package v4l-dvb-saa716x
diff --git a/drivers/media/pci/saa716x/saa716x_budget.c b/drivers/media/pci/saa716x/saa716x_budget.c
index 60094d0b16bdb7..31f1142f58d318 100644
--- a/drivers/media/pci/saa716x/saa716x_budget.c
+++ b/drivers/media/pci/saa716x/saa716x_budget.c
@@ -369,7 +369,6 @@ static const struct saa716x_config saa716x_tbs6281_config = {
.frontend_attach = saa716x_tbs6281_frontend_attach,
.irq_handler = saa716x_budget_pci_irq,
.i2c_rate = SAA716x_I2C_RATE_400,
- .i2c_mode = SAA716x_I2C_MODE_POLLING,
.adap_config = {
{
/* adapter 0 */
@@ -444,7 +443,6 @@ static const struct saa716x_config saa716x_tbs6285_config = {
.frontend_attach = saa716x_tbs6285_frontend_attach,
.irq_handler = saa716x_budget_pci_irq,
.i2c_rate = SAA716x_I2C_RATE_400,
- .i2c_mode = SAA716x_I2C_MODE_POLLING,
.adap_config = {
{
/* adapter 0 */
diff --git a/drivers/media/pci/saa716x/saa716x_ff_main.c b/drivers/media/pci/saa716x/saa716x_ff_main.c
index cc7f187c1edc02..eaeb6601cc050f 100644
--- a/drivers/media/pci/saa716x/saa716x_ff_main.c
+++ b/drivers/media/pci/saa716x/saa716x_ff_main.c
@@ -1205,15 +1205,6 @@ static irqreturn_t saa716x_ff_pci_irq(int irq, void *dev_id)
if (msiStatusL & MSI_INT_TAGACK_FGPI_3)
tasklet_schedule(&saa716x->fgpi[3].tasklet);
- if (msiStatusH & MSI_INT_I2CINT_0) {
- saa716x->i2c[0].i2c_op = 0;
- wake_up(&saa716x->i2c[0].i2c_wq);
- }
- if (msiStatusH & MSI_INT_I2CINT_1) {
- saa716x->i2c[1].i2c_op = 0;
- wake_up(&saa716x->i2c[1].i2c_wq);
- }
-
if (msiStatusH & MSI_INT_EXTINT_0) {
phiISR = SAA716x_EPRD(PHI_1, FPGA_ADDR_EMI_ISR);
@@ -1548,7 +1539,6 @@ static const struct saa716x_config saa716x_s26400_config = {
.frontend_attach = saa716x_s26400_frontend_attach,
.irq_handler = saa716x_ff_pci_irq,
.i2c_rate = SAA716x_I2C_RATE_100,
- .i2c_mode = SAA716x_I2C_MODE_IRQ_BUFFERED,
.adap_config = {
{
diff --git a/drivers/media/pci/saa716x/saa716x_i2c.c b/drivers/media/pci/saa716x/saa716x_i2c.c
index dd6fbd80e70d16..6db79ae6d56c9a 100644
--- a/drivers/media/pci/saa716x/saa716x_i2c.c
+++ b/drivers/media/pci/saa716x/saa716x_i2c.c
@@ -17,25 +17,6 @@
#include "saa716x_i2c.h"
#include "saa716x_priv.h"
-#define SAA716x_I2C_TXFAIL (I2C_ERROR_IBE | \
- I2C_ACK_INTER_MTNA | \
- I2C_FAILURE_INTER_MAF)
-
-#define SAA716x_I2C_TXBUSY (I2C_TRANSMIT | \
- I2C_TRANSMIT_PROG)
-
-#define SAA716x_I2C_RXBUSY (I2C_RECEIVE | \
- I2C_RECEIVE_CLEAR)
-
-static void saa716x_i2c_hwdeinit(struct saa716x_i2c *i2c, u32 I2C_DEV)
-{
- struct saa716x_dev *saa716x = i2c->saa716x;
-
- /* Disable all interrupts and clear status */
- SAA716x_EPWR(I2C_DEV, INT_CLR_ENABLE, 0x1fff);
- SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
-}
-
static int saa716x_i2c_hwinit(struct saa716x_i2c *i2c, u32 I2C_DEV)
{
struct saa716x_dev *saa716x = i2c->saa716x;
@@ -92,20 +73,6 @@ static int saa716x_i2c_hwinit(struct saa716x_i2c *i2c, u32 I2C_DEV)
break;
}
- /* Disable all interrupts and clear status */
- SAA716x_EPWR(I2C_DEV, INT_CLR_ENABLE, 0x1fff);
- SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
-
- if (i2c->i2c_mode >= SAA716x_I2C_MODE_IRQ) {
- /*
- * Enabled interrupts:
- * Master Transaction Done,
- * Master Transaction Data Request
- */
- SAA716x_EPWR(I2C_DEV, INT_SET_ENABLE,
- I2C_SET_ENABLE_MTDR | I2C_SET_ENABLE_MTD);
- }
-
/* Some slave may be in read state, force bus release */
SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0xc0); /* SCL/SDA high */
usleep_range(50, 200);
@@ -131,252 +98,111 @@ static int saa716x_i2c_hwinit(struct saa716x_i2c *i2c, u32 I2C_DEV)
static int saa716x_i2c_send(struct saa716x_i2c *i2c, u32 I2C_DEV, u32 data)
{
struct saa716x_dev *saa716x = i2c->saa716x;
- int i, err = 0;
u32 reg;
- if (i2c->i2c_mode >= SAA716x_I2C_MODE_IRQ) {
- /* Write to FIFO */
- SAA716x_EPWR(I2C_DEV, TX_FIFO, data);
- return 0;
- }
-
/* Check FIFO status before TX */
reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
- if (reg & SAA716x_I2C_TXBUSY) {
- for (i = 0; i < 100; i++) {
- /* TODO! check for hotplug devices */
- msleep(10);
- reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
-
- if (reg & SAA716x_I2C_TXBUSY) {
- pci_err(saa716x->pdev, "FIFO full or Blocked");
-
- err = saa716x_i2c_hwinit(i2c, I2C_DEV);
- if (err < 0) {
- pci_err(saa716x->pdev, "Error Reinit");
- err = -EIO;
- goto exit;
- }
- } else {
- break;
- }
- }
- }
+ if (reg & I2C_TRANSMIT_PROG)
+ return -EIO; /* fifo full */
/* Write to FIFO */
SAA716x_EPWR(I2C_DEV, TX_FIFO, data);
- /* Check for data write */
- for (i = 0; i < 1000; i++) {
- /* TODO! check for hotplug devices */
- reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
- if (reg & I2C_TRANSMIT_CLEAR)
- break;
- }
-
- if (!(reg & I2C_TRANSMIT_CLEAR)) {
- pci_err(saa716x->pdev, "TXFIFO not empty after Timeout");
- err = -EIO;
- goto exit;
- }
-
- return err;
-
-exit:
- pci_err(saa716x->pdev, "I2C Send failed (Err=%d)", err);
- return err;
+ return 0;
}
static int saa716x_i2c_recv(struct saa716x_i2c *i2c, u32 I2C_DEV, u32 *data)
{
struct saa716x_dev *saa716x = i2c->saa716x;
- int i, err = 0;
u32 reg;
+ int i;
- /* Check FIFO status before RX */
- for (i = 0; i < 1000; i++) {
+ for (i = 0; i < 50; i++) {
reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
- if (!(reg & SAA716x_I2C_RXBUSY))
- break;
- }
- if (reg & SAA716x_I2C_RXBUSY) {
- pci_err(saa716x->pdev, "FIFO empty");
- err = -EIO;
- goto exit;
+ if (!(reg & I2C_RECEIVE_CLEAR)) {
+ /* Read from FIFO */
+ *data = SAA716x_EPRD(I2C_DEV, RX_FIFO);
+ return 0;
+ }
+ usleep_range(10, 20);
}
-
- /* Read from FIFO */
- *data = SAA716x_EPRD(I2C_DEV, RX_FIFO);
-
- return 0;
-exit:
- pci_err(saa716x->pdev, "Error Reading data, err=%d", err);
- return err;
+ return -ETIMEDOUT;
}
-static void saa716x_i2c_irq_start(struct saa716x_i2c *i2c, u32 I2C_DEV)
+static int saa716x_i2c_wait(struct saa716x_i2c *i2c, u32 I2C_DEV)
{
struct saa716x_dev *saa716x = i2c->saa716x;
-
- if (i2c->i2c_mode == SAA716x_I2C_MODE_POLLING)
- return;
-
- i2c->i2c_op = 1;
- SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
-}
-
-static int saa716x_i2c_irq_wait(struct saa716x_i2c *i2c, u32 I2C_DEV)
-{
- struct saa716x_dev *saa716x = i2c->saa716x;
- unsigned long timeout;
- int err = 0;
-
- if (i2c->i2c_mode == SAA716x_I2C_MODE_POLLING)
- return 0;
-
- timeout = HZ/100 + 1; /* 10ms */
- timeout = wait_event_interruptible_timeout(i2c->i2c_wq,
- i2c->i2c_op == 0, timeout);
- if (timeout == -ERESTARTSYS || i2c->i2c_op) {
- SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
- if (timeout == -ERESTARTSYS) {
- /* a signal arrived */
- err = -ERESTARTSYS;
- } else {
- pci_dbg(saa716x->pdev, "timed out waiting for end of xfer!");
- err = -EIO;
+ int i;
+ u32 i2c_status, int_status;
+
+ /* Wait for transfer done */
+ for (i = 0; i < 50; i++) {
+ i2c_status = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
+ int_status = SAA716x_EPRD(I2C_DEV, INT_STATUS);
+ if (int_status & I2C_ERROR_IBE)
+ return -EIO;
+ if (i2c_status & I2C_TRANSMIT_CLEAR) {
+ if (int_status & I2C_ACK_INTER_MTNA)
+ return -ENXIO; /* NACK */
+ return 0;
}
+ usleep_range(100, 200);
}
- return err;
+ return -ETIMEDOUT;
}
-static int saa716x_i2c_write_msg(struct saa716x_i2c *i2c, u32 I2C_DEV,
- u16 addr, u8 *buf, u16 len, u8 add_stop)
+static int saa716x_i2c_xfer_msg(struct saa716x_i2c *i2c, u32 I2C_DEV,
+ u16 addr, u8 *buf, u16 len, u8 read, u8 add_stop)
{
struct saa716x_dev *saa716x = i2c->saa716x;
u32 data;
int err;
int i;
- int bytes;
- saa716x_i2c_irq_start(i2c, I2C_DEV);
+ SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
/* first write START with I2C address */
- data = I2C_START_BIT | (addr << 1);
+ data = I2C_START_BIT | (addr << 1) | ((read) ? 1 : 0);
pci_dbg(saa716x->pdev, "length=%d Addr:0x%02x", len, data);
err = saa716x_i2c_send(i2c, I2C_DEV, data);
if (err < 0) {
pci_err(saa716x->pdev, "Address write failed");
- goto exit;
+ return err;
}
+ err = saa716x_i2c_wait(i2c, I2C_DEV);
+ if (err < 0)
+ return err;
- bytes = i2c->block_size - 1;
+ SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
/* now write the data */
- while (len > 0) {
- if (bytes == i2c->block_size) {
- /* this is not the first round, so restart irq */
- saa716x_i2c_irq_start(i2c, I2C_DEV);
- }
-
- if (bytes > len)
- bytes = len;
-
- for (i = 0; i < bytes; i++) {
- data = buf[i];
+ for (i = 0; i < len; i++) {
+ data = buf[i]; /* dummy data for read */
+ if (read == 0)
pci_dbg(saa716x->pdev, " <W %04x> 0x%02x", i, data);
- if (add_stop && i == (len - 1))
- data |= I2C_STOP_BIT;
- err = saa716x_i2c_send(i2c, I2C_DEV, data);
- if (err < 0) {
- pci_err(saa716x->pdev, "Data send failed");
- goto exit;
- }
+ if (add_stop && i == (len - 1))
+ data |= I2C_STOP_BIT;
+ err = saa716x_i2c_send(i2c, I2C_DEV, data);
+ if (err < 0) {
+ pci_err(saa716x->pdev, "Data send failed");
+ return err;
}
-
- err = saa716x_i2c_irq_wait(i2c, I2C_DEV);
- if (err < 0)
- goto exit;
-
- len -= bytes;
- buf += bytes;
- bytes = i2c->block_size;
- }
-
- return 0;
-
-exit:
- pci_dbg(saa716x->pdev, "Error writing data, err=%d", err);
- return err;
-}
-
-static int saa716x_i2c_read_msg(struct saa716x_i2c *i2c, u32 I2C_DEV,
- u16 addr, u8 *buf, u16 len, u8 add_stop)
-{
- struct saa716x_dev *saa716x = i2c->saa716x;
- u32 data;
- int err;
- int i;
- int bytes;
-
- saa716x_i2c_irq_start(i2c, I2C_DEV);
-
- /* first write START with I2C address */
- data = I2C_START_BIT | (addr << 1) | 1;
- pci_dbg(saa716x->pdev, "length=%d Addr:0x%02x", len, data);
- err = saa716x_i2c_send(i2c, I2C_DEV, data);
- if (err < 0) {
- pci_err(saa716x->pdev, "Address write failed");
- goto exit;
}
-
- bytes = i2c->block_size - 1;
+ err = saa716x_i2c_wait(i2c, I2C_DEV);
+ if (err < 0 || !read)
+ return err;
/* now read the data */
- while (len > 0) {
- if (bytes == i2c->block_size) {
- /* this is not the first round, so restart irq */
- saa716x_i2c_irq_start(i2c, I2C_DEV);
+ for (i = 0; i < len; i++) {
+ err = saa716x_i2c_recv(i2c, I2C_DEV, &data);
+ if (err < 0) {
+ pci_err(saa716x->pdev, "Data receive failed");
+ return err;
}
-
- if (bytes > len)
- bytes = len;
-
- for (i = 0; i < bytes; i++) {
- data = 0x00; /* dummy write for reading */
- if (add_stop && i == (len - 1))
- data |= I2C_STOP_BIT;
- err = saa716x_i2c_send(i2c, I2C_DEV, data);
- if (err < 0) {
- pci_err(saa716x->pdev, "Data send failed");
- goto exit;
- }
- }
-
- err = saa716x_i2c_irq_wait(i2c, I2C_DEV);
- if (err < 0)
- goto exit;
-
- for (i = 0; i < bytes; i++) {
- err = saa716x_i2c_recv(i2c, I2C_DEV, &data);
- if (err < 0) {
- pci_err(saa716x->pdev, "Data receive failed");
- goto exit;
- }
- pci_dbg(saa716x->pdev, " <R %04x> 0x%02x", i, data);
- buf[i] = data;
- }
-
- len -= bytes;
- buf += bytes;
- bytes = i2c->block_size;
+ pci_dbg(saa716x->pdev, " <R %04x> 0x%02x", i, data);
+ buf[i] = data;
}
-
return 0;
-
-exit:
- pci_dbg(saa716x->pdev, "Error reading data, err=%d", err);
- return err;
}
static int saa716x_i2c_xfer(struct i2c_adapter *adapter,
@@ -386,40 +212,31 @@ static int saa716x_i2c_xfer(struct i2c_adapter *adapter,
struct saa716x_dev *saa716x = i2c->saa716x;
u32 DEV = SAA716x_I2C_BUS(i2c->i2c_dev);
- int i, t, err;
+ int i, err;
pci_dbg(saa716x->pdev, "Bus(%02x) I2C transfer", DEV);
mutex_lock(&i2c->i2c_lock);
- for (t = 0; t < 3; t++) {
- for (i = 0; i < num; i++) {
- if (msgs[i].flags & I2C_M_RD)
- err = saa716x_i2c_read_msg(i2c, DEV,
- msgs[i].addr, msgs[i].buf, msgs[i].len,
- i == (num - 1));
- else
- err = saa716x_i2c_write_msg(i2c, DEV,
- msgs[i].addr, msgs[i].buf, msgs[i].len,
- i == (num - 1));
- if (err < 0)
- goto retry;
- }
- break;
-retry:
- err = saa716x_i2c_hwinit(i2c, DEV);
+ for (i = 0; i < num; i++) {
+ err = saa716x_i2c_xfer_msg(i2c, DEV,
+ msgs[i].addr, msgs[i].buf, msgs[i].len,
+ msgs[i].flags & I2C_M_RD, i == (num - 1));
if (err < 0)
break;
}
mutex_unlock(&i2c->i2c_lock);
- if ((t < 3) && (err >= 0))
+ if (err >= 0)
return num;
- pci_err(saa716x->pdev,
- "I2C transfer error, msg %d, addr = 0x%02x, len=%d, flags=0x%x",
- i, msgs[i].addr, msgs[i].len, msgs[i].flags);
- return -EIO;
+ if (err != -ENXIO) {
+ pci_err(saa716x->pdev,
+ "I2C transfer error, msg %d, addr = 0x%02x, len=%d, flags=0x%x, %pe",
+ i, msgs[i].addr, msgs[i].len, msgs[i].flags, ERR_PTR(err));
+ saa716x_i2c_hwinit(i2c, DEV);
+ }
+ return err;
}
static u32 saa716x_i2c_func(struct i2c_adapter *adapter)
@@ -447,19 +264,10 @@ int saa716x_i2c_init(struct saa716x_dev *saa716x)
mutex_init(&i2c->i2c_lock);
- init_waitqueue_head(&i2c->i2c_wq);
- i2c->i2c_op = 0;
-
i2c->i2c_dev = i;
i2c->i2c_rate = saa716x->config->i2c_rate;
- i2c->i2c_mode = saa716x->config->i2c_mode;
adapter = &i2c->i2c_adapter;
- if (i2c->i2c_mode == SAA716x_I2C_MODE_IRQ_BUFFERED)
- i2c->block_size = 8;
- else
- i2c->block_size = 1;
-
if (adapter != NULL) {
i2c_set_adapdata(adapter, i2c);
@@ -469,8 +277,6 @@ int saa716x_i2c_init(struct saa716x_dev *saa716x)
adapter->owner = saa716x->module;
adapter->algo = &saa716x_algo;
adapter->algo_data = NULL;
- adapter->timeout = 500; /* FIXME ! */
- adapter->retries = 3; /* FIXME ! */
adapter->dev.parent = &pdev->dev;
pci_dbg(saa716x->pdev, "Initializing adapter (%d) %s",
@@ -487,11 +293,6 @@ int saa716x_i2c_init(struct saa716x_dev *saa716x)
i2c++;
}
- if (saa716x->config->i2c_mode >= SAA716x_I2C_MODE_IRQ) {
- SAA716x_EPWR(MSI, MSI_INT_ENA_SET_H, MSI_INT_I2CINT_0);
- SAA716x_EPWR(MSI, MSI_INT_ENA_SET_H, MSI_INT_I2CINT_1);
- }
-
pci_dbg(saa716x->pdev, "SAA%02x I2C Core succesfully initialized",
saa716x->pdev->device);
@@ -514,7 +315,6 @@ void saa716x_i2c_exit(struct saa716x_dev *saa716x)
for (i = 0; i < SAA716x_I2C_ADAPTERS; i++) {
adapter = &i2c->i2c_adapter;
- saa716x_i2c_hwdeinit(i2c, SAA716x_I2C_BUS(i));
pci_dbg(saa716x->pdev, "Removing adapter (%d) %s", i,
adapter->name);
diff --git a/drivers/media/pci/saa716x/saa716x_i2c.h b/drivers/media/pci/saa716x/saa716x_i2c.h
index c8bd9da7203fff..bc85e75b1a2cd1 100644
--- a/drivers/media/pci/saa716x/saa716x_i2c.h
+++ b/drivers/media/pci/saa716x/saa716x_i2c.h
@@ -24,26 +24,12 @@ enum saa716x_i2c_rate {
SAA716x_I2C_RATE_100,
};
-enum saa716x_i2c_mode {
- SAA716x_I2C_MODE_POLLING = 0,
- SAA716x_I2C_MODE_IRQ,
- SAA716x_I2C_MODE_IRQ_BUFFERED
-};
-
struct saa716x_i2c {
struct i2c_adapter i2c_adapter;
struct mutex i2c_lock;
struct saa716x_dev *saa716x;
u8 i2c_dev;
-
enum saa716x_i2c_rate i2c_rate;
- enum saa716x_i2c_mode i2c_mode;
-
- /* block size for buffered mode, 1 otherwise */
- u32 block_size;
-
- wait_queue_head_t i2c_wq;
- int i2c_op;
};
extern int saa716x_i2c_init(struct saa716x_dev *saa716x);
diff --git a/drivers/media/pci/saa716x/saa716x_priv.h b/drivers/media/pci/saa716x/saa716x_priv.h
index 7db944fbc01e02..710eaf2ab4dd6f 100644
--- a/drivers/media/pci/saa716x/saa716x_priv.h
+++ b/drivers/media/pci/saa716x/saa716x_priv.h
@@ -57,7 +57,6 @@ struct saa716x_config {
struct saa716x_adap_config adap_config[SAA716x_MAX_ADAPTERS];
enum saa716x_i2c_rate i2c_rate;
- enum saa716x_i2c_mode i2c_mode;
};
struct saa716x_adapter {