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 {
openSUSE Build Service is sponsored by