diff options
author | Patrick Boettcher <pb@linuxtv.org> | 2008-03-29 19:49:57 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:07:56 -0400 |
commit | 6394cf53abc0b3a2db9e8b947ef5c77b16861ec8 (patch) | |
tree | 6d442ab2e89d17ef963ee840ba50440e225f30cb /drivers/media/dvb/b2c2 | |
parent | 0b5afdd2ea5f52d260d1e42d43fb0fa09ec0da2f (diff) |
V4L/DVB (7469): Preparation for supporting new devices, cleanup and saneness
To prepare the support for new device to the flexcop-family some preparation and cleanups was done + some saneness:
- created an i2c-adapter for each i2c-port available. Easier usage for devices with several device on different i2c-busses
- initialize i2c before doing the eeprom read
- changed the way to attach the different frontends, easier to read now
- enabled support for i2c-devices having no register address (1-byte access)
Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb/b2c2')
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-common.h | 17 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-eeprom.c | 9 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 111 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-i2c.c | 180 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-usb.c | 17 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop.c | 10 |
6 files changed, 221 insertions, 123 deletions
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h index 5a6c4fe249e7..8ce06336e76f 100644 --- a/drivers/media/dvb/b2c2/flexcop-common.h +++ b/drivers/media/dvb/b2c2/flexcop-common.h | |||
@@ -44,6 +44,14 @@ struct flexcop_dma { | |||
44 | u32 size; /* size of each address in bytes */ | 44 | u32 size; /* size of each address in bytes */ |
45 | }; | 45 | }; |
46 | 46 | ||
47 | struct flexcop_i2c_adapter { | ||
48 | struct flexcop_device *fc; | ||
49 | struct i2c_adapter i2c_adap; | ||
50 | |||
51 | u8 no_base_addr; | ||
52 | flexcop_i2c_port_t port; | ||
53 | }; | ||
54 | |||
47 | /* Control structure for data definitions that are common to | 55 | /* Control structure for data definitions that are common to |
48 | * the B2C2-based PCI and USB devices. | 56 | * the B2C2-based PCI and USB devices. |
49 | */ | 57 | */ |
@@ -72,7 +80,7 @@ struct flexcop_device { | |||
72 | struct dmx_frontend mem_frontend; | 80 | struct dmx_frontend mem_frontend; |
73 | int (*fe_sleep) (struct dvb_frontend *); | 81 | int (*fe_sleep) (struct dvb_frontend *); |
74 | 82 | ||
75 | struct i2c_adapter i2c_adap; | 83 | struct flexcop_i2c_adapter fc_i2c_adap[3]; |
76 | struct mutex i2c_mutex; | 84 | struct mutex i2c_mutex; |
77 | struct module *owner; | 85 | struct module *owner; |
78 | 86 | ||
@@ -87,7 +95,8 @@ struct flexcop_device { | |||
87 | int (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value); | 95 | int (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value); |
88 | 96 | ||
89 | 97 | ||
90 | int (*i2c_request) (struct flexcop_device*, flexcop_access_op_t, flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); | 98 | int (*i2c_request) (struct flexcop_i2c_adapter*, |
99 | flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); | ||
91 | int (*stream_control) (struct flexcop_device*, int); | 100 | int (*stream_control) (struct flexcop_device*, int); |
92 | 101 | ||
93 | int (*get_mac_addr) (struct flexcop_device *fc, int extended); | 102 | int (*get_mac_addr) (struct flexcop_device *fc, int extended); |
@@ -128,8 +137,8 @@ int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended); | |||
128 | * one. We have it in flexcop-i2c.c, because it is going via the actual | 137 | * one. We have it in flexcop-i2c.c, because it is going via the actual |
129 | * I2C-channel of the flexcop. | 138 | * I2C-channel of the flexcop. |
130 | */ | 139 | */ |
131 | int flexcop_i2c_request(struct flexcop_device*, flexcop_access_op_t, | 140 | int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t, |
132 | flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); | 141 | u8 chipaddr, u8 addr, u8 *buf, u16 len); |
133 | 142 | ||
134 | /* from flexcop-sram.c */ | 143 | /* from flexcop-sram.c */ |
135 | int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target); | 144 | int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target); |
diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c index bbcf070a178d..8a8ae8a3e6ba 100644 --- a/drivers/media/dvb/b2c2/flexcop-eeprom.c +++ b/drivers/media/dvb/b2c2/flexcop-eeprom.c | |||
@@ -114,15 +114,18 @@ static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t | |||
114 | { | 114 | { |
115 | int i,ret = 0; | 115 | int i,ret = 0; |
116 | u8 chipaddr = 0x50 | ((addr >> 8) & 3); | 116 | u8 chipaddr = 0x50 | ((addr >> 8) & 3); |
117 | for (i = 0; i < retries; i++) | 117 | for (i = 0; i < retries; i++) { |
118 | if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0) | 118 | ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr, |
119 | addr & 0xff, buf, len); | ||
120 | if (ret == 0) | ||
119 | break; | 121 | break; |
122 | } | ||
120 | return ret; | 123 | return ret; |
121 | } | 124 | } |
122 | 125 | ||
123 | static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries) | 126 | static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries) |
124 | { | 127 | { |
125 | int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries); | 128 | int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries); |
126 | if (ret == 0) | 129 | if (ret == 0) |
127 | if (calc_lrc(buf, len - 1) != buf[len - 1]) | 130 | if (calc_lrc(buf, len - 1) != buf[len - 1]) |
128 | ret = -EINVAL; | 131 | ret = -EINVAL; |
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 441ffdf0d9c9..46d6f5d8cd1c 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c | |||
@@ -183,13 +183,13 @@ static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dv | |||
183 | buf[2] = 0x84; /* 0xC4 */ | 183 | buf[2] = 0x84; /* 0xC4 */ |
184 | buf[3] = 0x08; | 184 | buf[3] = 0x08; |
185 | 185 | ||
186 | if (params->frequency < 1500000) buf[3] |= 0x10; | 186 | if (params->frequency < 1500000) |
187 | buf[3] |= 0x10; | ||
187 | 188 | ||
188 | if (fe->ops.i2c_gate_ctrl) | 189 | if (fe->ops.i2c_gate_ctrl) |
189 | fe->ops.i2c_gate_ctrl(fe, 1); | 190 | fe->ops.i2c_gate_ctrl(fe, 1); |
190 | if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) { | 191 | if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1) |
191 | return -EIO; | 192 | return -EIO; |
192 | } | ||
193 | return 0; | 193 | return 0; |
194 | } | 194 | } |
195 | 195 | ||
@@ -340,7 +340,7 @@ static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, | |||
340 | 340 | ||
341 | if (fe->ops.i2c_gate_ctrl) | 341 | if (fe->ops.i2c_gate_ctrl) |
342 | fe->ops.i2c_gate_ctrl(fe, 1); | 342 | fe->ops.i2c_gate_ctrl(fe, 1); |
343 | if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) | 343 | if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1) |
344 | return -EIO; | 344 | return -EIO; |
345 | return 0; | 345 | return 0; |
346 | } | 346 | } |
@@ -389,10 +389,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe, | |||
389 | if (fe->ops.i2c_gate_ctrl) | 389 | if (fe->ops.i2c_gate_ctrl) |
390 | fe->ops.i2c_gate_ctrl(fe, 0); | 390 | fe->ops.i2c_gate_ctrl(fe, 0); |
391 | deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]); | 391 | deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]); |
392 | ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_TUNER, 0x61, buf[0], &buf[1], 3); | 392 | ret = fc->i2c_request(&fc->fc_i2c_adap[2], |
393 | FC_WRITE, 0x61, buf[0], &buf[1], 3); | ||
393 | deb_tuner("tuner write returned: %d\n",ret); | 394 | deb_tuner("tuner write returned: %d\n",ret); |
394 | 395 | ||
395 | return 0; | 396 | return ret; |
396 | } | 397 | } |
397 | 398 | ||
398 | static u8 alps_tdee4_stv0297_inittab[] = { | 399 | static u8 alps_tdee4_stv0297_inittab[] = { |
@@ -479,53 +480,67 @@ static struct stv0297_config alps_tdee4_stv0297_config = { | |||
479 | int flexcop_frontend_init(struct flexcop_device *fc) | 480 | int flexcop_frontend_init(struct flexcop_device *fc) |
480 | { | 481 | { |
481 | struct dvb_frontend_ops *ops; | 482 | struct dvb_frontend_ops *ops; |
483 | struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap; | ||
482 | 484 | ||
483 | /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ | 485 | /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ |
484 | if ((fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) { | 486 | fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); |
487 | if (fc->fe != NULL) { | ||
485 | ops = &fc->fe->ops; | 488 | ops = &fc->fe->ops; |
486 | 489 | ||
487 | ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params; | 490 | ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params; |
488 | 491 | ||
489 | ops->set_voltage = flexcop_set_voltage; | 492 | ops->set_voltage = flexcop_set_voltage; |
490 | 493 | ||
491 | fc->fe_sleep = ops->sleep; | 494 | fc->fe_sleep = ops->sleep; |
492 | ops->sleep = flexcop_sleep; | 495 | ops->sleep = flexcop_sleep; |
496 | |||
497 | fc->dev_type = FC_SKY; | ||
498 | goto fe_found; | ||
499 | } | ||
493 | 500 | ||
494 | fc->dev_type = FC_SKY; | ||
495 | info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address); | ||
496 | } else | ||
497 | /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */ | 501 | /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */ |
498 | if ((fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) { | 502 | fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); |
499 | fc->dev_type = FC_AIR_DVB; | 503 | if (fc->fe != NULL) { |
504 | fc->dev_type = FC_AIR_DVB; | ||
500 | fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs; | 505 | fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs; |
501 | info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address); | 506 | goto fe_found; |
502 | } else | 507 | } |
508 | |||
503 | /* try the air atsc 2nd generation (nxt2002) */ | 509 | /* try the air atsc 2nd generation (nxt2002) */ |
504 | if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) { | 510 | fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); |
505 | fc->dev_type = FC_AIR_ATSC2; | 511 | if (fc->fe != NULL) { |
512 | fc->dev_type = FC_AIR_ATSC2; | ||
506 | dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV); | 513 | dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV); |
507 | info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address); | 514 | goto fe_found; |
508 | } else | 515 | } |
509 | /* try the air atsc 3nd generation (lgdt3303) */ | 516 | |
510 | if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) { | 517 | fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); |
511 | fc->dev_type = FC_AIR_ATSC3; | 518 | if (fc->fe != NULL) { |
512 | dvb_attach(simple_tuner_attach, fc->fe, | 519 | fc->dev_type = FC_AIR_ATSC3; |
513 | &fc->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF); | 520 | dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, |
514 | info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address); | 521 | TUNER_LG_TDVS_H06XF); |
515 | } else | 522 | goto fe_found; |
523 | } | ||
524 | |||
516 | /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ | 525 | /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ |
517 | if ((fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) { | 526 | fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); |
518 | fc->dev_type = FC_AIR_ATSC1; | 527 | if (fc->fe != NULL) { |
519 | info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address); | 528 | fc->dev_type = FC_AIR_ATSC1; |
520 | } else | 529 | goto fe_found; |
530 | } | ||
531 | |||
521 | /* try the cable dvb (stv0297) */ | 532 | /* try the cable dvb (stv0297) */ |
522 | if ((fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) { | 533 | fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); |
523 | fc->dev_type = FC_CABLE; | 534 | if (fc->fe != NULL) { |
535 | fc->dev_type = FC_CABLE; | ||
524 | fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params; | 536 | fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params; |
525 | info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address); | 537 | goto fe_found; |
526 | } else | 538 | } |
539 | |||
527 | /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ | 540 | /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ |
528 | if ((fc->fe = dvb_attach(vp310_mt312_attach, &skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) { | 541 | fc->fe = dvb_attach(vp310_mt312_attach, |
542 | &skystar23_samsung_tbdu18132_config, i2c); | ||
543 | if (fc->fe != NULL) { | ||
529 | ops = &fc->fe->ops; | 544 | ops = &fc->fe->ops; |
530 | 545 | ||
531 | ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params; | 546 | ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params; |
@@ -539,19 +554,21 @@ int flexcop_frontend_init(struct flexcop_device *fc) | |||
539 | ops->sleep = flexcop_sleep; | 554 | ops->sleep = flexcop_sleep; |
540 | 555 | ||
541 | fc->dev_type = FC_SKY_OLD; | 556 | fc->dev_type = FC_SKY_OLD; |
542 | info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address); | 557 | goto fe_found; |
543 | } | 558 | } |
544 | 559 | ||
545 | if (fc->fe == NULL) { | 560 | err("no frontend driver found for this B2C2/FlexCop adapter"); |
546 | err("no frontend driver found for this B2C2/FlexCop adapter"); | 561 | return -ENODEV; |
547 | return -ENODEV; | 562 | |
548 | } else { | 563 | fe_found: |
549 | if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { | 564 | info("found '%s' .", fc->fe->ops.info.name); |
550 | err("frontend registration failed!"); | 565 | if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { |
551 | dvb_frontend_detach(fc->fe); | 566 | err("frontend registration failed!"); |
552 | fc->fe = NULL; | 567 | ops = &fc->fe->ops; |
553 | return -EINVAL; | 568 | if (ops->release != NULL) |
554 | } | 569 | ops->release(fc->fe); |
570 | fc->fe = NULL; | ||
571 | return -EINVAL; | ||
555 | } | 572 | } |
556 | fc->init_state |= FC_STATE_FE_INIT; | 573 | fc->init_state |= FC_STATE_FE_INIT; |
557 | return 0; | 574 | return 0; |
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index 6bf858a436c9..55973eaf3711 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c | |||
@@ -9,6 +9,8 @@ | |||
9 | 9 | ||
10 | #define FC_MAX_I2C_RETRIES 100000 | 10 | #define FC_MAX_I2C_RETRIES 100000 |
11 | 11 | ||
12 | /* #define DUMP_I2C_MESSAGES */ | ||
13 | |||
12 | static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100) | 14 | static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100) |
13 | { | 15 | { |
14 | int i; | 16 | int i; |
@@ -38,30 +40,25 @@ static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r | |||
38 | return -EREMOTEIO; | 40 | return -EREMOTEIO; |
39 | } | 41 | } |
40 | 42 | ||
41 | static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf) | 43 | static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c, |
44 | flexcop_ibi_value r100, u8 *buf) | ||
42 | { | 45 | { |
43 | flexcop_ibi_value r104; | 46 | flexcop_ibi_value r104; |
44 | int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */ | 47 | int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */ |
45 | ret; | 48 | ret; |
46 | 49 | ||
47 | if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) { | 50 | r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; |
48 | /* The Cablestar needs a different kind of i2c-transfer (does not | 51 | ret = flexcop_i2c_operation(i2c->fc, &r100); |
49 | * support "Repeat Start"): | 52 | if (ret != 0) { |
50 | * wait for the ACK failure, | 53 | deb_i2c("read failed. %d\n", ret); |
51 | * and do a subsequent read with the Bit 30 enabled | 54 | return ret; |
52 | */ | ||
53 | r100.tw_sm_c_100.no_base_addr_ack_error = 1; | ||
54 | if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) { | ||
55 | deb_i2c("no_base_addr read failed. %d\n",ret); | ||
56 | return ret; | ||
57 | } | ||
58 | } | 55 | } |
59 | 56 | ||
60 | buf[0] = r100.tw_sm_c_100.data1_reg; | 57 | buf[0] = r100.tw_sm_c_100.data1_reg; |
61 | 58 | ||
62 | if (len > 0) { | 59 | if (len > 0) { |
63 | r104 = fc->read_ibi_reg(fc,tw_sm_c_104); | 60 | r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104); |
64 | deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw); | 61 | deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw); |
65 | 62 | ||
66 | /* there is at least one more byte, otherwise we wouldn't be here */ | 63 | /* there is at least one more byte, otherwise we wouldn't be here */ |
67 | buf[1] = r104.tw_sm_c_104.data2_reg; | 64 | buf[1] = r104.tw_sm_c_104.data2_reg; |
@@ -85,17 +82,22 @@ static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100, | |||
85 | r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0; | 82 | r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0; |
86 | r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0; | 83 | r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0; |
87 | 84 | ||
88 | deb_i2c("write: r100: %08x, r104: %08x\n",r100.raw,r104.raw); | 85 | deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw); |
89 | 86 | ||
90 | /* write the additional i2c data before doing the actual i2c operation */ | 87 | /* write the additional i2c data before doing the actual i2c operation */ |
91 | fc->write_ibi_reg(fc,tw_sm_c_104,r104); | 88 | fc->write_ibi_reg(fc, tw_sm_c_104, r104); |
92 | return flexcop_i2c_operation(fc,&r100); | 89 | return flexcop_i2c_operation(fc, &r100); |
93 | } | 90 | } |
94 | 91 | ||
95 | int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | 92 | int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, |
96 | flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) | 93 | flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) |
97 | { | 94 | { |
98 | int ret; | 95 | int ret; |
96 | |||
97 | #ifdef DUMP_I2C_MESSAGES | ||
98 | int i; | ||
99 | #endif | ||
100 | |||
99 | u16 bytes_to_transfer; | 101 | u16 bytes_to_transfer; |
100 | flexcop_ibi_value r100; | 102 | flexcop_ibi_value r100; |
101 | 103 | ||
@@ -103,7 +105,25 @@ int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | |||
103 | r100.raw = 0; | 105 | r100.raw = 0; |
104 | r100.tw_sm_c_100.chipaddr = chipaddr; | 106 | r100.tw_sm_c_100.chipaddr = chipaddr; |
105 | r100.tw_sm_c_100.twoWS_rw = op; | 107 | r100.tw_sm_c_100.twoWS_rw = op; |
106 | r100.tw_sm_c_100.twoWS_port_reg = port; | 108 | r100.tw_sm_c_100.twoWS_port_reg = i2c->port; |
109 | |||
110 | #ifdef DUMP_I2C_MESSAGES | ||
111 | printk(KERN_DEBUG "%d ", i2c->port); | ||
112 | if (op == FC_READ) | ||
113 | printk("rd("); | ||
114 | else | ||
115 | printk("wr("); | ||
116 | |||
117 | printk("%02x): %02x ", chipaddr, addr); | ||
118 | #endif | ||
119 | |||
120 | /* in that case addr is the only value -> | ||
121 | * we write it twice as baseaddr and val0 | ||
122 | * BBTI is doing it like that for ISL6421 at least */ | ||
123 | if (i2c->no_base_addr && len == 0 && op == FC_WRITE) { | ||
124 | buf = &addr; | ||
125 | len = 1; | ||
126 | } | ||
107 | 127 | ||
108 | while (len != 0) { | 128 | while (len != 0) { |
109 | bytes_to_transfer = len > 4 ? 4 : len; | 129 | bytes_to_transfer = len > 4 ? 4 : len; |
@@ -112,9 +132,14 @@ int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | |||
112 | r100.tw_sm_c_100.baseaddr = addr; | 132 | r100.tw_sm_c_100.baseaddr = addr; |
113 | 133 | ||
114 | if (op == FC_READ) | 134 | if (op == FC_READ) |
115 | ret = flexcop_i2c_read4(fc, r100, buf); | 135 | ret = flexcop_i2c_read4(i2c, r100, buf); |
116 | else | 136 | else |
117 | ret = flexcop_i2c_write4(fc,r100, buf); | 137 | ret = flexcop_i2c_write4(i2c->fc, r100, buf); |
138 | |||
139 | #ifdef DUMP_I2C_MESSAGES | ||
140 | for (i = 0; i < bytes_to_transfer; i++) | ||
141 | printk("%02x ", buf[i]); | ||
142 | #endif | ||
118 | 143 | ||
119 | if (ret < 0) | 144 | if (ret < 0) |
120 | return ret; | 145 | return ret; |
@@ -122,7 +147,11 @@ int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | |||
122 | buf += bytes_to_transfer; | 147 | buf += bytes_to_transfer; |
123 | addr += bytes_to_transfer; | 148 | addr += bytes_to_transfer; |
124 | len -= bytes_to_transfer; | 149 | len -= bytes_to_transfer; |
125 | }; | 150 | } |
151 | |||
152 | #ifdef DUMP_I2C_MESSAGES | ||
153 | printk("\n"); | ||
154 | #endif | ||
126 | 155 | ||
127 | return 0; | 156 | return 0; |
128 | } | 157 | } |
@@ -132,7 +161,7 @@ EXPORT_SYMBOL(flexcop_i2c_request); | |||
132 | /* master xfer callback for demodulator */ | 161 | /* master xfer callback for demodulator */ |
133 | static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) | 162 | static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) |
134 | { | 163 | { |
135 | struct flexcop_device *fc = i2c_get_adapdata(i2c_adap); | 164 | struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap); |
136 | int i, ret = 0; | 165 | int i, ret = 0; |
137 | 166 | ||
138 | /* Some drivers use 1 byte or 0 byte reads as probes, which this | 167 | /* Some drivers use 1 byte or 0 byte reads as probes, which this |
@@ -142,34 +171,29 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs | |||
142 | if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1) | 171 | if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1) |
143 | return 1; | 172 | return 1; |
144 | 173 | ||
145 | if (mutex_lock_interruptible(&fc->i2c_mutex)) | 174 | if (mutex_lock_interruptible(&i2c->fc->i2c_mutex)) |
146 | return -ERESTARTSYS; | 175 | return -ERESTARTSYS; |
147 | 176 | ||
148 | /* reading */ | 177 | for (i = 0; i < num; i++) { |
149 | if (num == 2 && | 178 | /* reading */ |
150 | msgs[0].flags == 0 && | 179 | if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) { |
151 | msgs[1].flags == I2C_M_RD && | 180 | ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr, |
152 | msgs[0].buf != NULL && | 181 | msgs[i].buf[0], msgs[i+1].buf, msgs[i+1].len); |
153 | msgs[1].buf != NULL) { | 182 | i++; /* skip the following message */ |
154 | 183 | } else /* writing */ | |
155 | ret = fc->i2c_request(fc, FC_READ, FC_I2C_PORT_DEMOD, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len); | 184 | ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr, |
156 | 185 | msgs[i].buf[0], &msgs[i].buf[1], | |
157 | } else for (i = 0; i < num; i++) { /* writing command */ | 186 | msgs[i].len - 1); |
158 | if (msgs[i].flags != 0 || msgs[i].buf == NULL || msgs[i].len < 2) { | 187 | if (ret < 0) { |
159 | ret = -EINVAL; | 188 | err("i2c master_xfer failed"); |
160 | break; | 189 | break; |
161 | } | 190 | } |
162 | |||
163 | ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_DEMOD, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1); | ||
164 | } | 191 | } |
165 | 192 | ||
166 | if (ret < 0) | 193 | mutex_unlock(&i2c->fc->i2c_mutex); |
167 | err("i2c master_xfer failed"); | ||
168 | else | ||
169 | ret = num; | ||
170 | |||
171 | mutex_unlock(&fc->i2c_mutex); | ||
172 | 194 | ||
195 | if (ret == 0) | ||
196 | ret = num; | ||
173 | return ret; | 197 | return ret; |
174 | } | 198 | } |
175 | 199 | ||
@@ -189,28 +213,68 @@ int flexcop_i2c_init(struct flexcop_device *fc) | |||
189 | 213 | ||
190 | mutex_init(&fc->i2c_mutex); | 214 | mutex_init(&fc->i2c_mutex); |
191 | 215 | ||
192 | memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter)); | 216 | fc->fc_i2c_adap[0].fc = fc; |
193 | strncpy(fc->i2c_adap.name, "B2C2 FlexCop device", | 217 | fc->fc_i2c_adap[1].fc = fc; |
194 | sizeof(fc->i2c_adap.name)); | 218 | fc->fc_i2c_adap[2].fc = fc; |
195 | 219 | ||
196 | i2c_set_adapdata(&fc->i2c_adap,fc); | 220 | fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD; |
221 | fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM; | ||
222 | fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER; | ||
223 | |||
224 | strncpy(fc->fc_i2c_adap[0].i2c_adap.name, | ||
225 | "B2C2 FlexCop I2C to demod", I2C_NAME_SIZE); | ||
226 | strncpy(fc->fc_i2c_adap[1].i2c_adap.name, | ||
227 | "B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE); | ||
228 | strncpy(fc->fc_i2c_adap[2].i2c_adap.name, | ||
229 | "B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE); | ||
230 | |||
231 | i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]); | ||
232 | i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]); | ||
233 | i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]); | ||
234 | |||
235 | fc->fc_i2c_adap[0].i2c_adap.class = | ||
236 | fc->fc_i2c_adap[1].i2c_adap.class = | ||
237 | fc->fc_i2c_adap[2].i2c_adap.class = I2C_CLASS_TV_DIGITAL; | ||
238 | fc->fc_i2c_adap[0].i2c_adap.algo = | ||
239 | fc->fc_i2c_adap[1].i2c_adap.algo = | ||
240 | fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo; | ||
241 | fc->fc_i2c_adap[0].i2c_adap.algo_data = | ||
242 | fc->fc_i2c_adap[1].i2c_adap.algo_data = | ||
243 | fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL; | ||
244 | fc->fc_i2c_adap[0].i2c_adap.dev.parent = | ||
245 | fc->fc_i2c_adap[1].i2c_adap.dev.parent = | ||
246 | fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev; | ||
247 | |||
248 | ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap); | ||
249 | if (ret < 0) | ||
250 | return ret; | ||
197 | 251 | ||
198 | fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL; | 252 | ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap); |
199 | fc->i2c_adap.algo = &flexcop_algo; | 253 | if (ret < 0) |
200 | fc->i2c_adap.algo_data = NULL; | 254 | goto adap_1_failed; |
201 | fc->i2c_adap.dev.parent = fc->dev; | ||
202 | 255 | ||
203 | if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0) | 256 | ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap); |
204 | return ret; | 257 | if (ret < 0) |
258 | goto adap_2_failed; | ||
205 | 259 | ||
206 | fc->init_state |= FC_STATE_I2C_INIT; | 260 | fc->init_state |= FC_STATE_I2C_INIT; |
207 | return 0; | 261 | return 0; |
262 | |||
263 | adap_2_failed: | ||
264 | i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); | ||
265 | adap_1_failed: | ||
266 | i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); | ||
267 | |||
268 | return ret; | ||
208 | } | 269 | } |
209 | 270 | ||
210 | void flexcop_i2c_exit(struct flexcop_device *fc) | 271 | void flexcop_i2c_exit(struct flexcop_device *fc) |
211 | { | 272 | { |
212 | if (fc->init_state & FC_STATE_I2C_INIT) | 273 | if (fc->init_state & FC_STATE_I2C_INIT) { |
213 | i2c_del_adapter(&fc->i2c_adap); | 274 | i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap); |
275 | i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); | ||
276 | i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); | ||
277 | } | ||
214 | 278 | ||
215 | fc->init_state &= ~FC_STATE_I2C_INIT; | 279 | fc->init_state &= ~FC_STATE_I2C_INIT; |
216 | } | 280 | } |
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c index 87fb75f0d1cf..449fb5c3d0b1 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ b/drivers/media/dvb/b2c2/flexcop-usb.c | |||
@@ -211,10 +211,11 @@ static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set, | |||
211 | #endif | 211 | #endif |
212 | 212 | ||
213 | /* usb i2c stuff */ | 213 | /* usb i2c stuff */ |
214 | static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb, | 214 | static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c, |
215 | flexcop_usb_request_t req, flexcop_usb_i2c_function_t func, | 215 | flexcop_usb_request_t req, flexcop_usb_i2c_function_t func, |
216 | flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u8 buflen) | 216 | u8 chipaddr, u8 addr, u8 *buf, u8 buflen) |
217 | { | 217 | { |
218 | struct flexcop_usb *fc_usb = i2c->fc->bus_specific; | ||
218 | u16 wValue, wIndex; | 219 | u16 wValue, wIndex; |
219 | int nWaitTime,pipe,len; | 220 | int nWaitTime,pipe,len; |
220 | // u8 dwRequestType; | 221 | // u8 dwRequestType; |
@@ -242,7 +243,7 @@ static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb, | |||
242 | deb_info("unsupported function for i2c_req %x\n",func); | 243 | deb_info("unsupported function for i2c_req %x\n",func); |
243 | return -EINVAL; | 244 | return -EINVAL; |
244 | } | 245 | } |
245 | wValue = (func << 8 ) | (port << 4); | 246 | wValue = (func << 8) | (i2c->port << 4); |
246 | wIndex = (chipaddr << 8 ) | addr; | 247 | wIndex = (chipaddr << 8 ) | addr; |
247 | 248 | ||
248 | deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req, | 249 | deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req, |
@@ -274,13 +275,15 @@ static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_regi | |||
274 | return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0); | 275 | return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0); |
275 | } | 276 | } |
276 | 277 | ||
277 | static int flexcop_usb_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | 278 | static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c, |
278 | flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) | 279 | flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) |
279 | { | 280 | { |
280 | if (op == FC_READ) | 281 | if (op == FC_READ) |
281 | return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_READ,port,chipaddr,addr,buf,len); | 282 | return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST, |
283 | USB_FUNC_I2C_READ, chipaddr, addr, buf, len); | ||
282 | else | 284 | else |
283 | return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_WRITE,port,chipaddr,addr,buf,len); | 285 | return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST, |
286 | USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len); | ||
284 | } | 287 | } |
285 | 288 | ||
286 | static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, int buffer_length) | 289 | static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, int buffer_length) |
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 2ddafd071c97..205146c24129 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c | |||
@@ -257,6 +257,12 @@ int flexcop_device_initialize(struct flexcop_device *fc) | |||
257 | if ((ret = flexcop_dvb_init(fc))) | 257 | if ((ret = flexcop_dvb_init(fc))) |
258 | goto error; | 258 | goto error; |
259 | 259 | ||
260 | /* i2c has to be done before doing EEProm stuff - | ||
261 | * because the EEProm is accessed via i2c */ | ||
262 | ret = flexcop_i2c_init(fc); | ||
263 | if (ret) | ||
264 | goto error; | ||
265 | |||
260 | /* do the MAC address reading after initializing the dvb_adapter */ | 266 | /* do the MAC address reading after initializing the dvb_adapter */ |
261 | if (fc->get_mac_addr(fc, 0) == 0) { | 267 | if (fc->get_mac_addr(fc, 0) == 0) { |
262 | u8 *b = fc->dvb_adapter.proposed_mac; | 268 | u8 *b = fc->dvb_adapter.proposed_mac; |
@@ -266,10 +272,6 @@ int flexcop_device_initialize(struct flexcop_device *fc) | |||
266 | } else | 272 | } else |
267 | warn("reading of MAC address failed.\n"); | 273 | warn("reading of MAC address failed.\n"); |
268 | 274 | ||
269 | |||
270 | if ((ret = flexcop_i2c_init(fc))) | ||
271 | goto error; | ||
272 | |||
273 | if ((ret = flexcop_frontend_init(fc))) | 275 | if ((ret = flexcop_frontend_init(fc))) |
274 | goto error; | 276 | goto error; |
275 | 277 | ||