From f7a77ebf08536da5cafd4494855001be74176efb Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 28 Apr 2015 02:47:42 -0300 Subject: [PATCH] [media] cx24120: i2c-max-write-size is now configurable Some i2c-hosts are quite limited regarding maximum i2c-burst-write-sizes. This patch makes the previously hardcoded field configurable by users of the driver. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/b2c2/flexcop-fe-tuner.c | 1 + drivers/media/dvb-frontends/cx24120.c | 38 +++++++++++--------- drivers/media/dvb-frontends/cx24120.h | 3 ++ 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c index 66f6910a1810..9305266d0ac0 100644 --- a/drivers/media/common/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c @@ -630,6 +630,7 @@ static const struct cx24120_config skystar2_rev3_3_cx24120_config = { .xtal_khz = 10111, .initial_mpeg_config = { 0xa1, 0x76, 0x07 }, .request_firmware = flexcop_fe_request_firmware, + .i2c_wr_max = 4, }; static int skystarS2_rev33_attach(struct flexcop_device *fc, diff --git a/drivers/media/dvb-frontends/cx24120.c b/drivers/media/dvb-frontends/cx24120.c index ff7f21496186..2ed3fbc81e29 100644 --- a/drivers/media/dvb-frontends/cx24120.c +++ b/drivers/media/dvb-frontends/cx24120.c @@ -209,46 +209,53 @@ static int cx24120_writereg(struct cx24120_state *state, u8 reg, u8 data) } -/* Write multiple registers */ +/* Write multiple registers in chunks of i2c_wr_max-sized buffers */ static int cx24120_writeregN(struct cx24120_state *state, u8 reg, const u8 *values, u16 len, u8 incr) { int ret; - u8 buf[5]; /* maximum 4 data bytes at once - flexcop limitation - (very limited i2c-interface this one) */ + u16 max = state->config->i2c_wr_max > 0 ? + state->config->i2c_wr_max : + len; struct i2c_msg msg = { .addr = state->config->i2c_addr, .flags = 0, - .buf = buf, - .len = len }; + }; + + msg.buf = kmalloc(max + 1, GFP_KERNEL); + if (msg.buf == NULL) + return -ENOMEM; while (len) { - buf[0] = reg; - msg.len = len > 4 ? 4 : len; - memcpy(&buf[1], values, msg.len); + msg.buf[0] = reg; + msg.len = len > max ? max : len; + memcpy(&msg.buf[1], values, msg.len); - len -= msg.len; /* data length revers counter */ - values += msg.len; /* incr data pointer */ + len -= msg.len; /* data length revers counter */ + values += msg.len; /* incr data pointer */ if (incr) reg += msg.len; - msg.len++; /* don't forget the addr byte */ + msg.len++; /* don't forget the addr byte */ ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) { err("i2c_write error(err == %i, 0x%02x)\n", ret, reg); - return ret; + goto out; } dev_dbg(&state->i2c->dev, "%s: reg=0x%02x; data=0x%02x,0x%02x,0x%02x,0x%02x\n", __func__, reg, - buf[1], buf[2], buf[3], buf[4]); - + msg.buf[1], msg.buf[2], msg.buf[3], msg.buf[4]); } - return 0; + ret = 0; + +out: + kfree(msg.buf); + return ret; } @@ -1434,7 +1441,6 @@ int cx24120_init(struct dvb_frontend *fe) } info("FW version %i.%i.%i.%i\n", vers[0], vers[1], vers[2], vers[3]); - state->cold_init = 1; return 0; } diff --git a/drivers/media/dvb-frontends/cx24120.h b/drivers/media/dvb-frontends/cx24120.h index 076d2ddb5dde..e5748aaa8418 100644 --- a/drivers/media/dvb-frontends/cx24120.h +++ b/drivers/media/dvb-frontends/cx24120.h @@ -37,6 +37,9 @@ struct cx24120_config { int (*request_firmware)(struct dvb_frontend *fe, const struct firmware **fw, char *name); + + /* max bytes I2C provider can write at once */ + u16 i2c_wr_max; }; #if IS_REACHABLE(CONFIG_DVB_CX24120) -- 2.34.1