Trent Piepho wrote:
> This would work for stv0297, wouldn't it?
>
> --------------------------------------------------------------------
> diff -r 56b4c3e8f350 drivers/i2c/i2c-core.c
> --- a/drivers/i2c/i2c-core.c Sat May 19 05:00:32 2007 +0000
> +++ b/drivers/i2c/i2c-core.c Sat May 19 17:35:19 2007 -0700
> @@ -862,6 +862,7 @@ int i2c_transfer(struct i2c_adapter * ad
> int ret;
>
> if (adap->algo->master_xfer) {
> + int n, total = 0;
> #ifdef DEBUG
> for (ret = 0; ret < num; ret++) {
> dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
> @@ -872,10 +873,28 @@ int i2c_transfer(struct i2c_adapter * ad
> #endif
>
> mutex_lock_nested(&adap->bus_lock, adap->level);
> - ret = adap->algo->master_xfer(adap,msgs,num);
> + for (n=1; n<=num; n++) {
> + /* xfer the message(s) if we want a stop or if
> + it's the last message. */
> + if (n == num || (msgs[n-1].flags & I2C_M_STOP)) {
> + ret = adap->algo->master_xfer(adap,msgs,n);
> +
> + total += ret;
> + if (ret < n) {
> + /* Return error code, if any */
> + if (ret < 0)
> + total = ret;
> + break;
> + }
> +
> + /* Process any remaining messages */
> + msgs += n;
> + num -= n;
> + n = 0;
> + }
> + }
> mutex_unlock(&adap->bus_lock);
> -
> - return ret;
> + return total;
> } else {
> dev_dbg(&adap->dev, "I2C level transfers not supported\n");
> return -ENOSYS;
> diff -r 56b4c3e8f350 include/linux/i2c.h
> --- a/include/linux/i2c.h Sat May 19 05:00:32 2007 +0000
> +++ b/include/linux/i2c.h Sat May 19 17:35:03 2007 -0700
> @@ -448,6 +448,7 @@ struct i2c_msg {
> #define I2C_M_IGNORE_NAK 0x1000
> #define I2C_M_NO_RD_ACK 0x0800
> #define I2C_M_RECV_LEN 0x0400 /* length will be first received
> byte */
> +#define I2C_M_STOP 0x0200 /* send STOP condition after this msg */
> __u16 len; /* msg length */
> __u8 *buf; /* pointer to msg data */
> };
>
With the attached patch, it works for the stv0297 functions. It doesn't solve
the problem, why I've wrote the initial
patch. I need a dump from the registers of the stv0297. I've attach a second
patch. stv0297_attach() inserts a wrapper
between i2ctransfer() and the transfer function of the saa7146. The add/del
functions for the wrapper are a little bit
dirty. I didn't find a clean way for the add/del function.
- Hartmut
diff -r 6785574f5f6e linux/drivers/media/dvb/frontends/stv0297.c
--- a/linux/drivers/media/dvb/frontends/stv0297.c Mon May 14 04:25:57 2007 +0200
+++ b/linux/drivers/media/dvb/frontends/stv0297.c Sun May 20 09:14:50 2007 +0200
@@ -71,7 +71,10 @@ static int stv0297_readreg(struct stv029
struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
};
-
+#ifdef I2C_M_STOP
+ msg[0].flags = I2C_M_STOP;
+ {
+#else
// this device needs a STOP between the register and data
if (state->config->stop_during_read) {
if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
@@ -83,6 +86,7 @@ static int stv0297_readreg(struct stv029
return -1;
}
} else {
+#endif
if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
return -1;
@@ -111,7 +115,10 @@ static int stv0297_readregs(struct stv02
®1,.len = 1},
{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len}
};
-
+#ifdef I2C_M_STOP
+ msg[0].flags = I2C_M_STOP;
+ {
+#else
// this device needs a STOP between the register and data
if (state->config->stop_during_read) {
if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
@@ -123,6 +130,7 @@ static int stv0297_readregs(struct stv02
return -1;
}
} else {
+#endif
if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
return -1;
diff -r 6785574f5f6e linux/drivers/media/dvb/frontends/stv0297.c
--- a/linux/drivers/media/dvb/frontends/stv0297.c Mon May 14 04:25:57 2007 +0200
+++ b/linux/drivers/media/dvb/frontends/stv0297.c Sun May 20 19:05:06 2007 +0200
@@ -31,6 +31,11 @@
#include "stv0297.h"
struct stv0297_state {
+ struct i2c_algorithm algo;
+ const struct i2c_algorithm *old_algo;
+ void *old_algo_data;
+ unsigned char remove:1;
+
struct i2c_adapter *i2c;
const struct stv0297_config *config;
struct dvb_frontend frontend;
@@ -47,7 +52,61 @@ struct stv0297_state {
#define STV0297_CLOCK_KHZ 28900
-
+static int stv0297_readreg(struct stv0297_state *state, u8 reg);
+
+static int stv0297_master_xfer_wrapper(struct i2c_adapter *adapter, struct i2c_msg* msgs, int num)
+{
+ struct stv0297_state *state = (struct stv0297_state*) adapter->algo_data;
+ int ret = 0, i;
+
+ adapter->algo_data = state->old_algo_data;
+ adapter->algo = state->old_algo;
+
+ if (msgs[0].addr == state->config->demod_address) {
+ for (i = 0; i < num; i++) {
+ ret = adapter->algo->master_xfer(adapter, &msgs[i], 1);
+ if (ret != 1) {
+ if (ret == 0)
+ ret = i;
+ break;
+ }
+ }
+ if (i >= num) {
+ ret = num;
+ }
+
+ } else {
+ ret = adapter->algo->master_xfer(adapter, msgs, num);
+ }
+
+ if (!state->remove) {
+ state->old_algo = adapter->algo;
+ state->old_algo_data = adapter->algo_data;
+ adapter->algo_data = (void*)state;
+ adapter->algo = &state->algo;
+ }
+
+ return ret;
+}
+
+static void stv0297_add_wrapper(struct stv0297_state *state)
+{
+ state->remove = 0;
+ memcpy(&state->algo, state->i2c->algo, sizeof(struct i2c_algorithm));
+ state->old_algo = state->i2c->algo;
+ state->algo.master_xfer = stv0297_master_xfer_wrapper;
+ mutex_lock_nested(&state->i2c->bus_lock, i2c->level);
+ state->i2c->algo_data = state;
+ state->i2c->algo = &state->algo;
+ mutex_unlock(&state->i2c->bus_lock);
+}
+
+static void stv0297_del_wrapper(struct stv0297_state *state)
+{
+ state->remove = 1;
+ stv0297_readreg(state, 0x80);
+}
+
static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data)
{
int ret;
@@ -71,22 +130,9 @@ static int stv0297_readreg(struct stv029
struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
};
-
- // this device needs a STOP between the register and data
- if (state->config->stop_during_read) {
- if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
- }
- if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
- }
- } else {
- if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
- }
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
}
return b1[0];
@@ -111,22 +157,9 @@ static int stv0297_readregs(struct stv02
®1,.len = 1},
{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len}
};
-
- // this device needs a STOP between the register and data
- if (state->config->stop_during_read) {
- if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
- }
- if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
- }
- } else {
- if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
- }
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
}
return 0;
@@ -640,6 +673,9 @@ static void stv0297_release(struct dvb_f
static void stv0297_release(struct dvb_frontend *fe)
{
struct stv0297_state *state = fe->demodulator_priv;
+
+ stv0297_del_wrapper(state);
+
kfree(state);
}
@@ -660,6 +696,8 @@ struct dvb_frontend *stv0297_attach(cons
state->i2c = i2c;
state->last_ber = 0;
state->base_freq = 0;
+
+ stv0297_add_wrapper(state);
/* check if the demod is there */
if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20)
@@ -671,6 +709,7 @@ struct dvb_frontend *stv0297_attach(cons
return &state->frontend;
error:
+ stv0297_del_wrapper(state);
kfree(state);
return NULL;
}
_______________________________________________
linux-dvb mailing list
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb