diff options
author | Patrick Boettcher <patrick.boettcher@posteo.de> | 2015-04-28 01:47:42 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-05-18 15:32:35 -0400 |
commit | f7a77ebf08536da5cafd4494855001be74176efb (patch) | |
tree | 224a3cc3a1dab1f80e194f8087de1b04010f1c18 | |
parent | c5fb0f5f545cdf90c451ea7c9a6fb98ae4c64e49 (diff) |
[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 <patrick.boettcher@posteo.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
-rw-r--r-- | drivers/media/common/b2c2/flexcop-fe-tuner.c | 1 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/cx24120.c | 38 | ||||
-rw-r--r-- | 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 = { | |||
630 | .xtal_khz = 10111, | 630 | .xtal_khz = 10111, |
631 | .initial_mpeg_config = { 0xa1, 0x76, 0x07 }, | 631 | .initial_mpeg_config = { 0xa1, 0x76, 0x07 }, |
632 | .request_firmware = flexcop_fe_request_firmware, | 632 | .request_firmware = flexcop_fe_request_firmware, |
633 | .i2c_wr_max = 4, | ||
633 | }; | 634 | }; |
634 | 635 | ||
635 | static int skystarS2_rev33_attach(struct flexcop_device *fc, | 636 | 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) | |||
209 | } | 209 | } |
210 | 210 | ||
211 | 211 | ||
212 | /* Write multiple registers */ | 212 | /* Write multiple registers in chunks of i2c_wr_max-sized buffers */ |
213 | static int cx24120_writeregN(struct cx24120_state *state, | 213 | static int cx24120_writeregN(struct cx24120_state *state, |
214 | u8 reg, const u8 *values, u16 len, u8 incr) | 214 | u8 reg, const u8 *values, u16 len, u8 incr) |
215 | { | 215 | { |
216 | int ret; | 216 | int ret; |
217 | u8 buf[5]; /* maximum 4 data bytes at once - flexcop limitation | 217 | u16 max = state->config->i2c_wr_max > 0 ? |
218 | (very limited i2c-interface this one) */ | 218 | state->config->i2c_wr_max : |
219 | len; | ||
219 | 220 | ||
220 | struct i2c_msg msg = { | 221 | struct i2c_msg msg = { |
221 | .addr = state->config->i2c_addr, | 222 | .addr = state->config->i2c_addr, |
222 | .flags = 0, | 223 | .flags = 0, |
223 | .buf = buf, | 224 | }; |
224 | .len = len }; | 225 | |
226 | msg.buf = kmalloc(max + 1, GFP_KERNEL); | ||
227 | if (msg.buf == NULL) | ||
228 | return -ENOMEM; | ||
225 | 229 | ||
226 | while (len) { | 230 | while (len) { |
227 | buf[0] = reg; | 231 | msg.buf[0] = reg; |
228 | msg.len = len > 4 ? 4 : len; | 232 | msg.len = len > max ? max : len; |
229 | memcpy(&buf[1], values, msg.len); | 233 | memcpy(&msg.buf[1], values, msg.len); |
230 | 234 | ||
231 | len -= msg.len; /* data length revers counter */ | 235 | len -= msg.len; /* data length revers counter */ |
232 | values += msg.len; /* incr data pointer */ | 236 | values += msg.len; /* incr data pointer */ |
233 | 237 | ||
234 | if (incr) | 238 | if (incr) |
235 | reg += msg.len; | 239 | reg += msg.len; |
236 | msg.len++; /* don't forget the addr byte */ | 240 | msg.len++; /* don't forget the addr byte */ |
237 | 241 | ||
238 | ret = i2c_transfer(state->i2c, &msg, 1); | 242 | ret = i2c_transfer(state->i2c, &msg, 1); |
239 | if (ret != 1) { | 243 | if (ret != 1) { |
240 | err("i2c_write error(err == %i, 0x%02x)\n", ret, reg); | 244 | err("i2c_write error(err == %i, 0x%02x)\n", ret, reg); |
241 | return ret; | 245 | goto out; |
242 | } | 246 | } |
243 | 247 | ||
244 | dev_dbg(&state->i2c->dev, | 248 | dev_dbg(&state->i2c->dev, |
245 | "%s: reg=0x%02x; data=0x%02x,0x%02x,0x%02x,0x%02x\n", | 249 | "%s: reg=0x%02x; data=0x%02x,0x%02x,0x%02x,0x%02x\n", |
246 | __func__, reg, | 250 | __func__, reg, |
247 | buf[1], buf[2], buf[3], buf[4]); | 251 | msg.buf[1], msg.buf[2], msg.buf[3], msg.buf[4]); |
248 | |||
249 | } | 252 | } |
250 | 253 | ||
251 | return 0; | 254 | ret = 0; |
255 | |||
256 | out: | ||
257 | kfree(msg.buf); | ||
258 | return ret; | ||
252 | } | 259 | } |
253 | 260 | ||
254 | 261 | ||
@@ -1434,7 +1441,6 @@ int cx24120_init(struct dvb_frontend *fe) | |||
1434 | } | 1441 | } |
1435 | info("FW version %i.%i.%i.%i\n", vers[0], vers[1], vers[2], vers[3]); | 1442 | info("FW version %i.%i.%i.%i\n", vers[0], vers[1], vers[2], vers[3]); |
1436 | 1443 | ||
1437 | |||
1438 | state->cold_init = 1; | 1444 | state->cold_init = 1; |
1439 | return 0; | 1445 | return 0; |
1440 | } | 1446 | } |
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 { | |||
37 | 37 | ||
38 | int (*request_firmware)(struct dvb_frontend *fe, | 38 | int (*request_firmware)(struct dvb_frontend *fe, |
39 | const struct firmware **fw, char *name); | 39 | const struct firmware **fw, char *name); |
40 | |||
41 | /* max bytes I2C provider can write at once */ | ||
42 | u16 i2c_wr_max; | ||
40 | }; | 43 | }; |
41 | 44 | ||
42 | #if IS_REACHABLE(CONFIG_DVB_CX24120) | 45 | #if IS_REACHABLE(CONFIG_DVB_CX24120) |