Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] dvb: flexcop: add BCM3510 ATSC frontend support for Air2PC card

Added support for the Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC
QAM64/256) demodulator used in the first generation of Air2PC ATSC
PCI-cards/USB-boxes made by B2C2.

Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Johannes Stezenbach <js@linuxtv.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Johannes Stezenbach and committed by
Linus Torvalds
55f51efd cc89c229

+1389 -14
+1
drivers/media/dvb/b2c2/Kconfig
··· 6 6 select DVB_MT312 7 7 select DVB_NXT2002 8 8 select DVB_STV0297 9 + select DVB_BCM3510 9 10 help 10 11 Support for the digital TV receiver chip made by B2C2 Inc. included in 11 12 Technisats PCI cards and USB boxes.
+18 -8
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
··· 10 10 #include "stv0299.h" 11 11 #include "mt352.h" 12 12 #include "nxt2002.h" 13 + #include "bcm3510.h" 13 14 #include "stv0297.h" 14 15 #include "mt312.h" 15 16 ··· 286 285 } 287 286 288 287 static struct mt352_config samsung_tdtc9251dh0_config = { 289 - 290 288 .demod_address = 0x0f, 291 - .demod_init = samsung_tdtc9251dh0_demod_init, 292 - .pll_set = samsung_tdtc9251dh0_pll_set, 289 + .demod_init = samsung_tdtc9251dh0_demod_init, 290 + .pll_set = samsung_tdtc9251dh0_pll_set, 293 291 }; 294 292 295 - static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) 293 + static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) 296 294 { 297 295 struct flexcop_device *fc = fe->dvb->priv; 298 296 return request_firmware(fw, name, fc->dev); 299 297 } 300 298 301 299 static struct nxt2002_config samsung_tbmv_config = { 302 - .demod_address = 0x0a, 303 - .request_firmware = nxt2002_request_firmware, 300 + .demod_address = 0x0a, 301 + .request_firmware = flexcop_fe_request_firmware, 302 + }; 303 + 304 + static struct bcm3510_config air2pc_atsc_first_gen_config = { 305 + .demod_address = 0x0f, 306 + .request_firmware = flexcop_fe_request_firmware, 304 307 }; 305 308 306 309 static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) ··· 359 354 fc->dev_type = FC_AIR_DVB; 360 355 info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address); 361 356 } else 362 - /* try the air atsc (nxt2002) */ 357 + /* try the air atsc 2nd generation (nxt2002) */ 363 358 if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) { 364 - fc->dev_type = FC_AIR_ATSC; 359 + fc->dev_type = FC_AIR_ATSC2; 365 360 info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address); 361 + } else 362 + /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ 363 + if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) { 364 + fc->dev_type = FC_AIR_ATSC1; 365 + info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address); 366 366 } else 367 367 /* try the cable dvb (stv0297) */ 368 368 if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) {
+6 -5
drivers/media/dvb/b2c2/flexcop-misc.c
··· 45 45 46 46 const char *flexcop_device_names[] = { 47 47 "Unkown device", 48 - "AirStar 2 DVB-T", 49 - "AirStar 2 ATSC", 50 - "SkyStar 2 DVB-S", 51 - "SkyStar 2 DVB-S (old version)", 52 - "CableStar 2 DVB-C", 48 + "Air2PC/AirStar 2 DVB-T", 49 + "Air2PC/AirStar 2 ATSC 1st generation", 50 + "Air2PC/AirStar 2 ATSC 2nd generation", 51 + "Sky2PC/SkyStar 2 DVB-S", 52 + "Sky2PC/SkyStar 2 DVB-S (old version)", 53 + "Cable2PC/CableStar 2 DVB-C", 53 54 }; 54 55 55 56 const char *flexcop_bus_names[] = {
+2 -1
drivers/media/dvb/b2c2/flexcop-reg.h
··· 21 21 typedef enum { 22 22 FC_UNK = 0, 23 23 FC_AIR_DVB, 24 - FC_AIR_ATSC, 24 + FC_AIR_ATSC1, 25 + FC_AIR_ATSC2, 25 26 FC_SKY, 26 27 FC_SKY_OLD, 27 28 FC_CABLE,
+8
drivers/media/dvb/frontends/Kconfig
··· 173 173 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want 174 174 to support this frontend. 175 175 176 + config DVB_BCM3510 177 + tristate "Broadcom BCM3510" 178 + depends on DVB_CORE 179 + select FW_LOADER 180 + help 181 + An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to 182 + support this frontend. 183 + 176 184 endmenu
+1
drivers/media/dvb/frontends/Makefile
··· 28 28 obj-$(CONFIG_DVB_NXT2002) += nxt2002.o 29 29 obj-$(CONFIG_DVB_OR51211) += or51211.o 30 30 obj-$(CONFIG_DVB_OR51132) += or51132.o 31 + obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
+853
drivers/media/dvb/frontends/bcm3510.c
··· 1 + /* 2 + * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) 3 + * 4 + * Copyright (C) 2001-5, B2C2 inc. 5 + * 6 + * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de> 7 + * 8 + * This driver is "hard-coded" to be used with the 1st generation of 9 + * Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming 10 + * (Panasonic CT10S) is located here, which is actually wrong. Unless there is 11 + * another device with a BCM3510, this is no problem. 12 + * 13 + * The driver works also with QAM64 DVB-C, but had an unreasonable high 14 + * UNC. (Tested with the Air2PC ATSC 1st generation) 15 + * 16 + * You'll need a firmware for this driver in order to get it running. It is 17 + * called "dvb-fe-bcm3510-01.fw". 18 + * 19 + * This program is free software; you can redistribute it and/or modify it 20 + * under the terms of the GNU General Public License as published by the Free 21 + * Software Foundation; either version 2 of the License, or (at your option) 22 + * any later version. 23 + * 24 + * This program is distributed in the hope that it will be useful, but WITHOUT 25 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 26 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 27 + * more details. 28 + * 29 + * You should have received a copy of the GNU General Public License along with 30 + * this program; if not, write to the Free Software Foundation, Inc., 675 Mass 31 + * Ave, Cambridge, MA 02139, USA. 32 + */ 33 + 34 + #include <linux/init.h> 35 + #include <linux/module.h> 36 + #include <linux/moduleparam.h> 37 + #include <linux/device.h> 38 + #include <linux/firmware.h> 39 + 40 + #include "dvb_frontend.h" 41 + #include "bcm3510.h" 42 + #include "bcm3510_priv.h" 43 + 44 + struct bcm3510_state { 45 + 46 + struct i2c_adapter* i2c; 47 + struct dvb_frontend_ops ops; 48 + const struct bcm3510_config* config; 49 + struct dvb_frontend frontend; 50 + 51 + /* demodulator private data */ 52 + struct semaphore hab_sem; 53 + u8 firmware_loaded:1; 54 + 55 + unsigned long next_status_check; 56 + unsigned long status_check_interval; 57 + struct bcm3510_hab_cmd_status1 status1; 58 + struct bcm3510_hab_cmd_status2 status2; 59 + }; 60 + 61 + static int debug; 62 + module_param(debug, int, 0644); 63 + MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c (|-able))."); 64 + 65 + #define dprintk(level,x...) if (level & debug) printk(x) 66 + #define dbufout(b,l,m) {\ 67 + int i; \ 68 + for (i = 0; i < l; i++) \ 69 + m("%02x ",b[i]); \ 70 + } 71 + #define deb_info(args...) dprintk(0x01,args) 72 + #define deb_i2c(args...) dprintk(0x02,args) 73 + #define deb_hab(args...) dprintk(0x04,args) 74 + 75 + /* transfer functions */ 76 + static int bcm3510_writebytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len) 77 + { 78 + u8 b[256]; 79 + int err; 80 + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = len + 1 }; 81 + 82 + b[0] = reg; 83 + memcpy(&b[1],buf,len); 84 + 85 + deb_i2c("i2c wr %02x: ",reg); 86 + dbufout(buf,len,deb_i2c); 87 + deb_i2c("\n"); 88 + 89 + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 90 + 91 + deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n", 92 + __FUNCTION__, state->config->demod_address, reg, err); 93 + return -EREMOTEIO; 94 + } 95 + 96 + return 0; 97 + } 98 + 99 + static int bcm3510_readbytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len) 100 + { 101 + struct i2c_msg msg[] = { 102 + { .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 }, 103 + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } 104 + }; 105 + int err; 106 + 107 + memset(buf,0,len); 108 + 109 + if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { 110 + deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n", 111 + __FUNCTION__, state->config->demod_address, reg, err); 112 + return -EREMOTEIO; 113 + } 114 + deb_i2c("i2c rd %02x: ",reg); 115 + dbufout(buf,len,deb_i2c); 116 + deb_i2c("\n"); 117 + 118 + return 0; 119 + } 120 + 121 + static int bcm3510_writeB(struct bcm3510_state *state, u8 reg, bcm3510_register_value v) 122 + { 123 + return bcm3510_writebytes(state,reg,&v.raw,1); 124 + } 125 + 126 + static int bcm3510_readB(struct bcm3510_state *state, u8 reg, bcm3510_register_value *v) 127 + { 128 + return bcm3510_readbytes(state,reg,&v->raw,1); 129 + } 130 + 131 + /* Host Access Buffer transfers */ 132 + static int bcm3510_hab_get_response(struct bcm3510_state *st, u8 *buf, int len) 133 + { 134 + bcm3510_register_value v; 135 + int ret,i; 136 + 137 + v.HABADR_a6.HABADR = 0; 138 + if ((ret = bcm3510_writeB(st,0xa6,v)) < 0) 139 + return ret; 140 + 141 + for (i = 0; i < len; i++) { 142 + if ((ret = bcm3510_readB(st,0xa7,&v)) < 0) 143 + return ret; 144 + buf[i] = v.HABDATA_a7; 145 + } 146 + return 0; 147 + } 148 + 149 + static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len) 150 + { 151 + bcm3510_register_value v,hab; 152 + int ret,i; 153 + unsigned long t; 154 + 155 + /* Check if any previous HAB request still needs to be serviced by the 156 + * Aquisition Processor before sending new request */ 157 + if ((ret = bcm3510_readB(st,0xa8,&v)) < 0) 158 + return ret; 159 + if (v.HABSTAT_a8.HABR) { 160 + deb_info("HAB is running already - clearing it.\n"); 161 + v.HABSTAT_a8.HABR = 0; 162 + bcm3510_writeB(st,0xa8,v); 163 + // return -EBUSY; 164 + } 165 + 166 + /* Send the start HAB Address (automatically incremented after write of 167 + * HABDATA) and write the HAB Data */ 168 + hab.HABADR_a6.HABADR = 0; 169 + if ((ret = bcm3510_writeB(st,0xa6,hab)) < 0) 170 + return ret; 171 + 172 + for (i = 0; i < len; i++) { 173 + hab.HABDATA_a7 = buf[i]; 174 + if ((ret = bcm3510_writeB(st,0xa7,hab)) < 0) 175 + return ret; 176 + } 177 + 178 + /* Set the HABR bit to indicate AP request in progress (LBHABR allows HABR to 179 + * be written) */ 180 + v.raw = 0; v.HABSTAT_a8.HABR = 1; v.HABSTAT_a8.LDHABR = 1; 181 + if ((ret = bcm3510_writeB(st,0xa8,v)) < 0) 182 + return ret; 183 + 184 + /* Polling method: Wait until the AP finishes processing the HAB request */ 185 + t = jiffies + 1*HZ; 186 + while (time_before(jiffies, t)) { 187 + deb_info("waiting for HAB to complete\n"); 188 + msleep(10); 189 + if ((ret = bcm3510_readB(st,0xa8,&v)) < 0) 190 + return ret; 191 + 192 + if (!v.HABSTAT_a8.HABR) 193 + return 0; 194 + } 195 + 196 + deb_info("send_request execution timed out.\n"); 197 + return -ETIMEDOUT; 198 + } 199 + 200 + static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen) 201 + { 202 + u8 ob[olen+2],ib[ilen+2]; 203 + int ret = 0; 204 + 205 + ob[0] = cmd; 206 + ob[1] = msgid; 207 + memcpy(&ob[2],obuf,olen); 208 + 209 + deb_hab("hab snd: "); 210 + dbufout(ob,olen+2,deb_hab); 211 + deb_hab("\n"); 212 + 213 + if (down_interruptible(&st->hab_sem) < 0) 214 + return -EAGAIN; 215 + 216 + if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 || 217 + (ret = bcm3510_hab_get_response(st, ib, ilen+2)) < 0) 218 + goto error; 219 + 220 + deb_hab("hab get: "); 221 + dbufout(ib,ilen+2,deb_hab); 222 + deb_hab("\n"); 223 + 224 + memcpy(ibuf,&ib[2],ilen); 225 + error: 226 + up(&st->hab_sem); 227 + return ret; 228 + } 229 + 230 + #if 0 231 + /* not needed, we use a semaphore to prevent HAB races */ 232 + static int bcm3510_is_ap_ready(struct bcm3510_state *st) 233 + { 234 + bcm3510_register_value ap,hab; 235 + int ret; 236 + 237 + if ((ret = bcm3510_readB(st,0xa8,&hab)) < 0 || 238 + (ret = bcm3510_readB(st,0xa2,&ap) < 0)) 239 + return ret; 240 + 241 + if (ap.APSTAT1_a2.RESET || ap.APSTAT1_a2.IDLE || ap.APSTAT1_a2.STOP || hab.HABSTAT_a8.HABR) { 242 + deb_info("AP is busy\n"); 243 + return -EBUSY; 244 + } 245 + 246 + return 0; 247 + } 248 + #endif 249 + 250 + static int bcm3510_bert_reset(struct bcm3510_state *st) 251 + { 252 + bcm3510_register_value b; 253 + int ret; 254 + 255 + if ((ret < bcm3510_readB(st,0xfa,&b)) < 0) 256 + return ret; 257 + 258 + b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b); 259 + b.BERCTL_fa.RESYNC = 1; bcm3510_writeB(st,0xfa,b); 260 + b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b); 261 + b.BERCTL_fa.CNTCTL = 1; b.BERCTL_fa.BITCNT = 1; bcm3510_writeB(st,0xfa,b); 262 + 263 + /* clear residual bit counter TODO */ 264 + return 0; 265 + } 266 + 267 + static int bcm3510_refresh_state(struct bcm3510_state *st) 268 + { 269 + if (time_after(jiffies,st->next_status_check)) { 270 + bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS1, NULL,0, (u8 *)&st->status1, sizeof(st->status1)); 271 + bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS2, NULL,0, (u8 *)&st->status2, sizeof(st->status2)); 272 + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; 273 + } 274 + return 0; 275 + } 276 + 277 + static int bcm3510_read_status(struct dvb_frontend *fe, fe_status_t *status) 278 + { 279 + struct bcm3510_state* st = fe->demodulator_priv; 280 + bcm3510_refresh_state(st); 281 + 282 + *status = 0; 283 + if (st->status1.STATUS1.RECEIVER_LOCK) 284 + *status |= FE_HAS_LOCK | FE_HAS_SYNC; 285 + 286 + if (st->status1.STATUS1.FEC_LOCK) 287 + *status |= FE_HAS_VITERBI; 288 + 289 + if (st->status1.STATUS1.OUT_PLL_LOCK) 290 + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; 291 + 292 + if (*status & FE_HAS_LOCK) 293 + st->status_check_interval = 1500; 294 + else /* more frequently checks if no lock has been achieved yet */ 295 + st->status_check_interval = 500; 296 + 297 + deb_info("real_status: %02x\n",*status); 298 + return 0; 299 + } 300 + 301 + static int bcm3510_read_ber(struct dvb_frontend* fe, u32* ber) 302 + { 303 + struct bcm3510_state* st = fe->demodulator_priv; 304 + bcm3510_refresh_state(st); 305 + 306 + *ber = (st->status2.LDBER0 << 16) | (st->status2.LDBER1 << 8) | st->status2.LDBER2; 307 + return 0; 308 + } 309 + 310 + static int bcm3510_read_unc(struct dvb_frontend* fe, u32* unc) 311 + { 312 + struct bcm3510_state* st = fe->demodulator_priv; 313 + bcm3510_refresh_state(st); 314 + *unc = (st->status2.LDUERC0 << 8) | st->status2.LDUERC1; 315 + return 0; 316 + } 317 + 318 + static int bcm3510_read_signal_strength(struct dvb_frontend* fe, u16* strength) 319 + { 320 + struct bcm3510_state* st = fe->demodulator_priv; 321 + s32 t; 322 + 323 + bcm3510_refresh_state(st); 324 + t = st->status2.SIGNAL; 325 + 326 + if (t > 190) 327 + t = 190; 328 + if (t < 90) 329 + t = 90; 330 + 331 + t -= 90; 332 + t = t * 0xff / 100; 333 + /* normalize if necessary */ 334 + *strength = (t << 8) | t; 335 + return 0; 336 + } 337 + 338 + static int bcm3510_read_snr(struct dvb_frontend* fe, u16* snr) 339 + { 340 + struct bcm3510_state* st = fe->demodulator_priv; 341 + bcm3510_refresh_state(st); 342 + 343 + *snr = st->status1.SNR_EST0*1000 + ((st->status1.SNR_EST1*1000) >> 8); 344 + return 0; 345 + } 346 + 347 + /* tuner frontend programming */ 348 + static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a) 349 + { 350 + struct bcm3510_hab_cmd_tune c; 351 + memset(&c,0,sizeof(struct bcm3510_hab_cmd_tune)); 352 + 353 + /* I2C Mode disabled, set 16 control / Data pairs */ 354 + c.length = 0x10; 355 + c.clock_width = 0; 356 + /* CS1, CS0, DATA, CLK bits control the tuner RF_AGC_SEL pin is set to 357 + * logic high (as Configuration) */ 358 + c.misc = 0x10; 359 + /* Set duration of the initial state of TUNCTL = 3.34 micro Sec */ 360 + c.TUNCTL_state = 0x40; 361 + 362 + /* PRESCALER DEVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */ 363 + c.ctl_dat[0].ctrl.size = BITS_8; 364 + c.ctl_dat[0].data = 0x80 | bc; 365 + 366 + /* Control DATA pin, 1stosc REFERENCE COUNTER REF_S10 to REF_S3 */ 367 + c.ctl_dat[1].ctrl.size = BITS_8; 368 + c.ctl_dat[1].data = 4; 369 + 370 + /* set CONTROL BIT 1 to 1, 1stosc REFERENCE COUNTER REF_S2 to REF_S1 */ 371 + c.ctl_dat[2].ctrl.size = BITS_3; 372 + c.ctl_dat[2].data = 0x20; 373 + 374 + /* control CS0 pin, pulse byte ? */ 375 + c.ctl_dat[3].ctrl.size = BITS_3; 376 + c.ctl_dat[3].ctrl.clk_off = 1; 377 + c.ctl_dat[3].ctrl.cs0 = 1; 378 + c.ctl_dat[3].data = 0x40; 379 + 380 + /* PGM_S18 to PGM_S11 */ 381 + c.ctl_dat[4].ctrl.size = BITS_8; 382 + c.ctl_dat[4].data = n >> 3; 383 + 384 + /* PGM_S10 to PGM_S8, SWL_S7 to SWL_S3 */ 385 + c.ctl_dat[5].ctrl.size = BITS_8; 386 + c.ctl_dat[5].data = ((n & 0x7) << 5) | (a >> 2); 387 + 388 + /* SWL_S2 and SWL_S1, set CONTROL BIT 2 to 0 */ 389 + c.ctl_dat[6].ctrl.size = BITS_3; 390 + c.ctl_dat[6].data = (a << 6) & 0xdf; 391 + 392 + /* control CS0 pin, pulse byte ? */ 393 + c.ctl_dat[7].ctrl.size = BITS_3; 394 + c.ctl_dat[7].ctrl.clk_off = 1; 395 + c.ctl_dat[7].ctrl.cs0 = 1; 396 + c.ctl_dat[7].data = 0x40; 397 + 398 + /* PRESCALER DEVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */ 399 + c.ctl_dat[8].ctrl.size = BITS_8; 400 + c.ctl_dat[8].data = 0x80; 401 + 402 + /* 2ndosc REFERENCE COUNTER REF_S10 to REF_S3 */ 403 + c.ctl_dat[9].ctrl.size = BITS_8; 404 + c.ctl_dat[9].data = 0x10; 405 + 406 + /* set CONTROL BIT 1 to 1, 2ndosc REFERENCE COUNTER REF_S2 to REF_S1 */ 407 + c.ctl_dat[10].ctrl.size = BITS_3; 408 + c.ctl_dat[10].data = 0x20; 409 + 410 + /* pulse byte */ 411 + c.ctl_dat[11].ctrl.size = BITS_3; 412 + c.ctl_dat[11].ctrl.clk_off = 1; 413 + c.ctl_dat[11].ctrl.cs1 = 1; 414 + c.ctl_dat[11].data = 0x40; 415 + 416 + /* PGM_S18 to PGM_S11 */ 417 + c.ctl_dat[12].ctrl.size = BITS_8; 418 + c.ctl_dat[12].data = 0x2a; 419 + 420 + /* PGM_S10 to PGM_S8 and SWL_S7 to SWL_S3 */ 421 + c.ctl_dat[13].ctrl.size = BITS_8; 422 + c.ctl_dat[13].data = 0x8e; 423 + 424 + /* SWL_S2 and SWL_S1 and set CONTROL BIT 2 to 0 */ 425 + c.ctl_dat[14].ctrl.size = BITS_3; 426 + c.ctl_dat[14].data = 0; 427 + 428 + /* Pulse Byte */ 429 + c.ctl_dat[15].ctrl.size = BITS_3; 430 + c.ctl_dat[15].ctrl.clk_off = 1; 431 + c.ctl_dat[15].ctrl.cs1 = 1; 432 + c.ctl_dat[15].data = 0x40; 433 + 434 + return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0); 435 + } 436 + 437 + static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq) 438 + { 439 + u8 bc,a; 440 + u16 n; 441 + s32 YIntercept,Tfvco1; 442 + 443 + freq /= 1000; 444 + 445 + deb_info("%dkHz:",freq); 446 + /* set Band Switch */ 447 + if (freq <= 168000) 448 + bc = 0x1c; 449 + else if (freq <= 378000) 450 + bc = 0x2c; 451 + else 452 + bc = 0x30; 453 + 454 + if (freq >= 470000) { 455 + freq -= 470001; 456 + YIntercept = 18805; 457 + } else if (freq >= 90000) { 458 + freq -= 90001; 459 + YIntercept = 15005; 460 + } else if (freq >= 76000){ 461 + freq -= 76001; 462 + YIntercept = 14865; 463 + } else { 464 + freq -= 54001; 465 + YIntercept = 14645; 466 + } 467 + 468 + Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10; 469 + 470 + n = Tfvco1 >> 6; 471 + a = Tfvco1 & 0x3f; 472 + 473 + deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a); 474 + if (n >= 16 && n <= 2047) 475 + return bcm3510_tuner_cmd(st,bc,n,a); 476 + 477 + return -EINVAL; 478 + } 479 + 480 + static int bcm3510_set_frontend(struct dvb_frontend* fe, 481 + struct dvb_frontend_parameters *p) 482 + { 483 + struct bcm3510_state* st = fe->demodulator_priv; 484 + struct bcm3510_hab_cmd_ext_acquire cmd; 485 + struct bcm3510_hab_cmd_bert_control bert; 486 + int ret; 487 + 488 + memset(&cmd,0,sizeof(cmd)); 489 + switch (p->u.vsb.modulation) { 490 + case QAM_256: 491 + cmd.ACQUIRE0.MODE = 0x1; 492 + cmd.ACQUIRE1.SYM_RATE = 0x1; 493 + cmd.ACQUIRE1.IF_FREQ = 0x1; 494 + break; 495 + case QAM_64: 496 + cmd.ACQUIRE0.MODE = 0x2; 497 + cmd.ACQUIRE1.SYM_RATE = 0x2; 498 + cmd.ACQUIRE1.IF_FREQ = 0x1; 499 + break; 500 + /* case QAM_256: 501 + cmd.ACQUIRE0.MODE = 0x3; 502 + break; 503 + case QAM_128: 504 + cmd.ACQUIRE0.MODE = 0x4; 505 + break; 506 + case QAM_64: 507 + cmd.ACQUIRE0.MODE = 0x5; 508 + break; 509 + case QAM_32: 510 + cmd.ACQUIRE0.MODE = 0x6; 511 + break; 512 + case QAM_16: 513 + cmd.ACQUIRE0.MODE = 0x7; 514 + break;*/ 515 + case VSB_8: 516 + cmd.ACQUIRE0.MODE = 0x8; 517 + cmd.ACQUIRE1.SYM_RATE = 0x0; 518 + cmd.ACQUIRE1.IF_FREQ = 0x0; 519 + break; 520 + case VSB_16: 521 + cmd.ACQUIRE0.MODE = 0x9; 522 + cmd.ACQUIRE1.SYM_RATE = 0x0; 523 + cmd.ACQUIRE1.IF_FREQ = 0x0; 524 + default: 525 + return -EINVAL; 526 + }; 527 + cmd.ACQUIRE0.OFFSET = 0; 528 + cmd.ACQUIRE0.NTSCSWEEP = 1; 529 + cmd.ACQUIRE0.FA = 1; 530 + cmd.ACQUIRE0.BW = 0; 531 + 532 + /* if (enableOffset) { 533 + cmd.IF_OFFSET0 = xx; 534 + cmd.IF_OFFSET1 = xx; 535 + 536 + cmd.SYM_OFFSET0 = xx; 537 + cmd.SYM_OFFSET1 = xx; 538 + if (enableNtscSweep) { 539 + cmd.NTSC_OFFSET0; 540 + cmd.NTSC_OFFSET1; 541 + } 542 + } */ 543 + bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0); 544 + 545 + /* doing it with different MSGIDs, data book and source differs */ 546 + bert.BE = 0; 547 + bert.unused = 0; 548 + bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0); 549 + bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0); 550 + 551 + bcm3510_bert_reset(st); 552 + 553 + if ((ret = bcm3510_set_freq(st,p->frequency)) < 0) 554 + return ret; 555 + 556 + memset(&st->status1,0,sizeof(st->status1)); 557 + memset(&st->status2,0,sizeof(st->status2)); 558 + st->status_check_interval = 500; 559 + 560 + /* Give the AP some time */ 561 + msleep(200); 562 + 563 + return 0; 564 + } 565 + 566 + static int bcm3510_sleep(struct dvb_frontend* fe) 567 + { 568 + return 0; 569 + } 570 + 571 + static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s) 572 + { 573 + s->min_delay_ms = 1000; 574 + s->step_size = 0; 575 + s->max_drift = 0; 576 + return 0; 577 + } 578 + 579 + static void bcm3510_release(struct dvb_frontend* fe) 580 + { 581 + struct bcm3510_state* state = fe->demodulator_priv; 582 + kfree(state); 583 + } 584 + 585 + /* firmware download: 586 + * firmware file is build up like this: 587 + * 16bit addr, 16bit length, 8byte of length 588 + */ 589 + #define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw" 590 + 591 + static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, u8 *b, u16 len) 592 + { 593 + int ret = 0,i; 594 + bcm3510_register_value vH, vL,vD; 595 + 596 + vH.MADRH_a9 = addr >> 8; 597 + vL.MADRL_aa = addr; 598 + if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret; 599 + if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret; 600 + 601 + for (i = 0; i < len; i++) { 602 + vD.MDATA_ab = b[i]; 603 + if ((ret = bcm3510_writeB(st,0xab,vD)) < 0) 604 + return ret; 605 + } 606 + 607 + return 0; 608 + } 609 + 610 + static int bcm3510_download_firmware(struct dvb_frontend* fe) 611 + { 612 + struct bcm3510_state* st = fe->demodulator_priv; 613 + const struct firmware *fw; 614 + u16 addr,len; 615 + u8 *b; 616 + int ret,i; 617 + 618 + deb_info("requesting firmware\n"); 619 + if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) { 620 + err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret); 621 + return ret; 622 + } 623 + deb_info("got firmware: %d\n",fw->size); 624 + 625 + b = fw->data; 626 + for (i = 0; i < fw->size;) { 627 + addr = le16_to_cpu( *( (u16 *)&b[i] ) ); 628 + len = le16_to_cpu( *( (u16 *)&b[i+2] ) ); 629 + deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size); 630 + if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) { 631 + err("firmware download failed: %d\n",ret); 632 + return ret; 633 + } 634 + i += 4 + len; 635 + } 636 + release_firmware(fw); 637 + deb_info("firmware download successfully completed\n"); 638 + return 0; 639 + } 640 + 641 + static int bcm3510_check_firmware_version(struct bcm3510_state *st) 642 + { 643 + struct bcm3510_hab_cmd_get_version_info ver; 644 + bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver)); 645 + 646 + deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n", 647 + ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version); 648 + 649 + if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION && 650 + ver.config_version == BCM3510_DEF_CONFIG_VERSION && 651 + ver.demod_version == BCM3510_DEF_DEMOD_VERSION) 652 + return 0; 653 + 654 + deb_info("version check failed\n"); 655 + return -ENODEV; 656 + } 657 + 658 + /* (un)resetting the AP */ 659 + static int bcm3510_reset(struct bcm3510_state *st) 660 + { 661 + int ret; 662 + unsigned long t; 663 + bcm3510_register_value v; 664 + 665 + bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1; 666 + if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) 667 + return ret; 668 + 669 + t = jiffies + 3*HZ; 670 + while (time_before(jiffies, t)) { 671 + msleep(10); 672 + if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) 673 + return ret; 674 + 675 + if (v.APSTAT1_a2.RESET) 676 + return 0; 677 + } 678 + deb_info("reset timed out\n"); 679 + return -ETIMEDOUT; 680 + } 681 + 682 + static int bcm3510_clear_reset(struct bcm3510_state *st) 683 + { 684 + bcm3510_register_value v; 685 + int ret; 686 + unsigned long t; 687 + 688 + v.raw = 0; 689 + if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) 690 + return ret; 691 + 692 + t = jiffies + 3*HZ; 693 + while (time_before(jiffies, t)) { 694 + msleep(10); 695 + if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) 696 + return ret; 697 + 698 + /* verify that reset is cleared */ 699 + if (!v.APSTAT1_a2.RESET) 700 + return 0; 701 + } 702 + deb_info("reset clear timed out\n"); 703 + return -ETIMEDOUT; 704 + } 705 + 706 + static int bcm3510_init_cold(struct bcm3510_state *st) 707 + { 708 + int ret; 709 + bcm3510_register_value v; 710 + 711 + /* read Acquisation Processor status register and check it is not in RUN mode */ 712 + if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) 713 + return ret; 714 + if (v.APSTAT1_a2.RUN) { 715 + deb_info("AP is already running - firmware already loaded.\n"); 716 + return 0; 717 + } 718 + 719 + deb_info("reset?\n"); 720 + if ((ret = bcm3510_reset(st)) < 0) 721 + return ret; 722 + 723 + deb_info("tristate?\n"); 724 + /* tri-state */ 725 + v.TSTCTL_2e.CTL = 0; 726 + if ((ret = bcm3510_writeB(st,0x2e,v)) < 0) 727 + return ret; 728 + 729 + deb_info("firmware?\n"); 730 + if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 || 731 + (ret = bcm3510_clear_reset(st)) < 0) 732 + return ret; 733 + 734 + /* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */ 735 + 736 + return 0; 737 + } 738 + 739 + static int bcm3510_init(struct dvb_frontend* fe) 740 + { 741 + struct bcm3510_state* st = fe->demodulator_priv; 742 + bcm3510_register_value j; 743 + struct bcm3510_hab_cmd_set_agc c; 744 + int ret; 745 + 746 + if ((ret = bcm3510_readB(st,0xca,&j)) < 0) 747 + return ret; 748 + 749 + deb_info("JDEC: %02x\n",j.raw); 750 + 751 + switch (j.JDEC_ca.JDEC) { 752 + case JDEC_WAIT_AT_RAM: 753 + deb_info("attempting to download firmware\n"); 754 + if ((ret = bcm3510_init_cold(st)) < 0) 755 + return ret; 756 + case JDEC_EEPROM_LOAD_WAIT: /* fall-through is wanted */ 757 + deb_info("firmware is loaded\n"); 758 + bcm3510_check_firmware_version(st); 759 + break; 760 + default: 761 + return -ENODEV; 762 + } 763 + 764 + memset(&c,0,1); 765 + c.SEL = 1; 766 + bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0); 767 + 768 + return 0; 769 + } 770 + 771 + 772 + static struct dvb_frontend_ops bcm3510_ops; 773 + 774 + struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config, 775 + struct i2c_adapter *i2c) 776 + { 777 + struct bcm3510_state* state = NULL; 778 + int ret; 779 + bcm3510_register_value v; 780 + 781 + /* allocate memory for the internal state */ 782 + state = kmalloc(sizeof(struct bcm3510_state), GFP_KERNEL); 783 + if (state == NULL) 784 + goto error; 785 + memset(state,0,sizeof(struct bcm3510_state)); 786 + 787 + /* setup the state */ 788 + 789 + state->config = config; 790 + state->i2c = i2c; 791 + memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops)); 792 + 793 + /* create dvb_frontend */ 794 + state->frontend.ops = &state->ops; 795 + state->frontend.demodulator_priv = state; 796 + 797 + sema_init(&state->hab_sem, 1); 798 + 799 + if ((ret = bcm3510_readB(state,0xe0,&v)) < 0) 800 + goto error; 801 + 802 + deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER); 803 + 804 + if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */ 805 + (v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0)) /* warm */ 806 + goto error; 807 + 808 + info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER); 809 + 810 + bcm3510_reset(state); 811 + 812 + return &state->frontend; 813 + 814 + error: 815 + kfree(state); 816 + return NULL; 817 + } 818 + EXPORT_SYMBOL(bcm3510_attach); 819 + 820 + static struct dvb_frontend_ops bcm3510_ops = { 821 + 822 + .info = { 823 + .name = "Broadcom BCM3510 VSB/QAM frontend", 824 + .type = FE_ATSC, 825 + .frequency_min = 54000000, 826 + .frequency_max = 803000000, 827 + /* stepsize is just a guess */ 828 + .frequency_stepsize = 0, 829 + .caps = 830 + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 831 + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 832 + FE_CAN_8VSB | FE_CAN_16VSB | 833 + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 834 + }, 835 + 836 + .release = bcm3510_release, 837 + 838 + .init = bcm3510_init, 839 + .sleep = bcm3510_sleep, 840 + 841 + .set_frontend = bcm3510_set_frontend, 842 + .get_tune_settings = bcm3510_get_tune_settings, 843 + 844 + .read_status = bcm3510_read_status, 845 + .read_ber = bcm3510_read_ber, 846 + .read_signal_strength = bcm3510_read_signal_strength, 847 + .read_snr = bcm3510_read_snr, 848 + .read_ucblocks = bcm3510_read_unc, 849 + }; 850 + 851 + MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver"); 852 + MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); 853 + MODULE_LICENSE("GPL");
+40
drivers/media/dvb/frontends/bcm3510.h
··· 1 + /* 2 + * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) 3 + * 4 + * Copyright (C) 2001-5, B2C2 inc. 5 + * 6 + * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2 of the License, or 11 + * (at your option) any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, write to the Free Software 20 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 + */ 22 + #ifndef BCM3510_H 23 + #define BCM3510_H 24 + 25 + #include <linux/dvb/frontend.h> 26 + #include <linux/firmware.h> 27 + 28 + struct bcm3510_config 29 + { 30 + /* the demodulator's i2c address */ 31 + u8 demod_address; 32 + 33 + /* request firmware for device */ 34 + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); 35 + }; 36 + 37 + extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config, 38 + struct i2c_adapter* i2c); 39 + 40 + #endif
+460
drivers/media/dvb/frontends/bcm3510_priv.h
··· 1 + /* 2 + * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) 3 + * 4 + * Copyright (C) 2001-5, B2C2 inc. 5 + * 6 + * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2 of the License, or 11 + * (at your option) any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, write to the Free Software 20 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 + */ 22 + #ifndef __BCM3510_PRIV_H__ 23 + #define __BCM3510_PRIV_H__ 24 + 25 + #define PACKED __attribute__((packed)) 26 + 27 + #undef err 28 + #define err(format, arg...) printk(KERN_ERR "bcm3510: " format "\n" , ## arg) 29 + #undef info 30 + #define info(format, arg...) printk(KERN_INFO "bcm3510: " format "\n" , ## arg) 31 + #undef warn 32 + #define warn(format, arg...) printk(KERN_WARNING "bcm3510: " format "\n" , ## arg) 33 + 34 + 35 + #define PANASONIC_FIRST_IF_BASE_IN_KHz 1407500 36 + #define BCM3510_SYMBOL_RATE 5381000 37 + 38 + typedef union { 39 + u8 raw; 40 + 41 + struct { 42 + u8 CTL :8; 43 + } TSTCTL_2e; 44 + 45 + u8 LDCERC_4e; 46 + u8 LDUERC_4f; 47 + u8 LD_BER0_65; 48 + u8 LD_BER1_66; 49 + u8 LD_BER2_67; 50 + u8 LD_BER3_68; 51 + 52 + struct { 53 + u8 RESET :1; 54 + u8 IDLE :1; 55 + u8 STOP :1; 56 + u8 HIRQ0 :1; 57 + u8 HIRQ1 :1; 58 + u8 na0 :1; 59 + u8 HABAV :1; 60 + u8 na1 :1; 61 + } HCTL1_a0; 62 + 63 + struct { 64 + u8 na0 :1; 65 + u8 IDLMSK :1; 66 + u8 STMSK :1; 67 + u8 I0MSK :1; 68 + u8 I1MSK :1; 69 + u8 na1 :1; 70 + u8 HABMSK :1; 71 + u8 na2 :1; 72 + } HCTLMSK_a1; 73 + 74 + struct { 75 + u8 RESET :1; 76 + u8 IDLE :1; 77 + u8 STOP :1; 78 + u8 RUN :1; 79 + u8 HABAV :1; 80 + u8 MEMAV :1; 81 + u8 ALDONE :1; 82 + u8 REIRQ :1; 83 + } APSTAT1_a2; 84 + 85 + struct { 86 + u8 RSTMSK :1; 87 + u8 IMSK :1; 88 + u8 SMSK :1; 89 + u8 RMSK :1; 90 + u8 HABMSK :1; 91 + u8 MAVMSK :1; 92 + u8 ALDMSK :1; 93 + u8 REMSK :1; 94 + } APMSK1_a3; 95 + 96 + u8 APSTAT2_a4; 97 + u8 APMSK2_a5; 98 + 99 + struct { 100 + u8 HABADR :7; 101 + u8 na :1; 102 + } HABADR_a6; 103 + 104 + u8 HABDATA_a7; 105 + 106 + struct { 107 + u8 HABR :1; 108 + u8 LDHABR :1; 109 + u8 APMSK :1; 110 + u8 HMSK :1; 111 + u8 LDMSK :1; 112 + u8 na :3; 113 + } HABSTAT_a8; 114 + 115 + u8 MADRH_a9; 116 + u8 MADRL_aa; 117 + u8 MDATA_ab; 118 + 119 + struct { 120 + #define JDEC_WAIT_AT_RAM 0x7 121 + #define JDEC_EEPROM_LOAD_WAIT 0x4 122 + u8 JDEC :3; 123 + u8 na :5; 124 + } JDEC_ca; 125 + 126 + struct { 127 + u8 REV :4; 128 + u8 LAYER :4; 129 + } REVID_e0; 130 + 131 + struct { 132 + u8 unk0 :1; 133 + u8 CNTCTL :1; 134 + u8 BITCNT :1; 135 + u8 unk1 :1; 136 + u8 RESYNC :1; 137 + u8 unk2 :3; 138 + } BERCTL_fa; 139 + 140 + struct { 141 + u8 CSEL0 :1; 142 + u8 CLKED0 :1; 143 + u8 CSEL1 :1; 144 + u8 CLKED1 :1; 145 + u8 CLKLEV :1; 146 + u8 SPIVAR :1; 147 + u8 na :2; 148 + } TUNSET_fc; 149 + 150 + struct { 151 + u8 CLK :1; 152 + u8 DATA :1; 153 + u8 CS0 :1; 154 + u8 CS1 :1; 155 + u8 AGCSEL :1; 156 + u8 na0 :1; 157 + u8 TUNSEL :1; 158 + u8 na1 :1; 159 + } TUNCTL_fd; 160 + 161 + u8 TUNSEL0_fe; 162 + u8 TUNSEL1_ff; 163 + 164 + } bcm3510_register_value; 165 + 166 + /* HAB commands */ 167 + 168 + /* version */ 169 + #define CMD_GET_VERSION_INFO 0x3D 170 + #define MSGID_GET_VERSION_INFO 0x15 171 + struct bcm3510_hab_cmd_get_version_info { 172 + u8 microcode_version; 173 + u8 script_version; 174 + u8 config_version; 175 + u8 demod_version; 176 + } PACKED; 177 + 178 + #define BCM3510_DEF_MICROCODE_VERSION 0x0E 179 + #define BCM3510_DEF_SCRIPT_VERSION 0x06 180 + #define BCM3510_DEF_CONFIG_VERSION 0x01 181 + #define BCM3510_DEF_DEMOD_VERSION 0xB1 182 + 183 + /* acquire */ 184 + #define CMD_ACQUIRE 0x38 185 + 186 + #define MSGID_EXT_TUNER_ACQUIRE 0x0A 187 + struct bcm3510_hab_cmd_ext_acquire { 188 + struct { 189 + u8 MODE :4; 190 + u8 BW :1; 191 + u8 FA :1; 192 + u8 NTSCSWEEP :1; 193 + u8 OFFSET :1; 194 + } PACKED ACQUIRE0; /* control_byte */ 195 + 196 + struct { 197 + u8 IF_FREQ :3; 198 + u8 zero0 :1; 199 + u8 SYM_RATE :3; 200 + u8 zero1 :1; 201 + } PACKED ACQUIRE1; /* sym_if */ 202 + 203 + u8 IF_OFFSET0; /* IF_Offset_10hz */ 204 + u8 IF_OFFSET1; 205 + u8 SYM_OFFSET0; /* SymbolRateOffset */ 206 + u8 SYM_OFFSET1; 207 + u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */ 208 + u8 NTSC_OFFSET1; 209 + } PACKED; 210 + 211 + #define MSGID_INT_TUNER_ACQUIRE 0x0B 212 + struct bcm3510_hab_cmd_int_acquire { 213 + struct { 214 + u8 MODE :4; 215 + u8 BW :1; 216 + u8 FA :1; 217 + u8 NTSCSWEEP :1; 218 + u8 OFFSET :1; 219 + } PACKED ACQUIRE0; /* control_byte */ 220 + 221 + struct { 222 + u8 IF_FREQ :3; 223 + u8 zero0 :1; 224 + u8 SYM_RATE :3; 225 + u8 zero1 :1; 226 + } PACKED ACQUIRE1; /* sym_if */ 227 + 228 + u8 TUNER_FREQ0; 229 + u8 TUNER_FREQ1; 230 + u8 TUNER_FREQ2; 231 + u8 TUNER_FREQ3; 232 + u8 IF_OFFSET0; /* IF_Offset_10hz */ 233 + u8 IF_OFFSET1; 234 + u8 SYM_OFFSET0; /* SymbolRateOffset */ 235 + u8 SYM_OFFSET1; 236 + u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */ 237 + u8 NTSC_OFFSET1; 238 + } PACKED; 239 + 240 + /* modes */ 241 + #define BCM3510_QAM16 = 0x01 242 + #define BCM3510_QAM32 = 0x02 243 + #define BCM3510_QAM64 = 0x03 244 + #define BCM3510_QAM128 = 0x04 245 + #define BCM3510_QAM256 = 0x05 246 + #define BCM3510_8VSB = 0x0B 247 + #define BCM3510_16VSB = 0x0D 248 + 249 + /* IF_FREQS */ 250 + #define BCM3510_IF_TERRESTRIAL 0x0 251 + #define BCM3510_IF_CABLE 0x1 252 + #define BCM3510_IF_USE_CMD 0x7 253 + 254 + /* SYM_RATE */ 255 + #define BCM3510_SR_8VSB 0x0 /* 5381119 s/sec */ 256 + #define BCM3510_SR_256QAM 0x1 /* 5360537 s/sec */ 257 + #define BCM3510_SR_16QAM 0x2 /* 5056971 s/sec */ 258 + #define BCM3510_SR_MISC 0x3 /* 5000000 s/sec */ 259 + #define BCM3510_SR_USE_CMD 0x7 260 + 261 + /* special symbol rate */ 262 + #define CMD_SET_VALUE_NOT_LISTED 0x2d 263 + #define MSGID_SET_SYMBOL_RATE_NOT_LISTED 0x0c 264 + struct bcm3510_hab_cmd_set_sr_not_listed { 265 + u8 HOST_SYM_RATE0; 266 + u8 HOST_SYM_RATE1; 267 + u8 HOST_SYM_RATE2; 268 + u8 HOST_SYM_RATE3; 269 + } PACKED; 270 + 271 + /* special IF */ 272 + #define MSGID_SET_IF_FREQ_NOT_LISTED 0x0d 273 + struct bcm3510_hab_cmd_set_if_freq_not_listed { 274 + u8 HOST_IF_FREQ0; 275 + u8 HOST_IF_FREQ1; 276 + u8 HOST_IF_FREQ2; 277 + u8 HOST_IF_FREQ3; 278 + } PACKED; 279 + 280 + /* auto reacquire */ 281 + #define CMD_AUTO_PARAM 0x2a 282 + #define MSGID_AUTO_REACQUIRE 0x0e 283 + struct bcm3510_hab_cmd_auto_reacquire { 284 + u8 ACQ :1; /* on/off*/ 285 + u8 unused :7; 286 + } PACKED; 287 + 288 + #define MSGID_SET_RF_AGC_SEL 0x12 289 + struct bcm3510_hab_cmd_set_agc { 290 + u8 LVL :1; 291 + u8 unused :6; 292 + u8 SEL :1; 293 + } PACKED; 294 + 295 + #define MSGID_SET_AUTO_INVERSION 0x14 296 + struct bcm3510_hab_cmd_auto_inversion { 297 + u8 AI :1; 298 + u8 unused :7; 299 + } PACKED; 300 + 301 + 302 + /* bert control */ 303 + #define CMD_STATE_CONTROL 0x12 304 + #define MSGID_BERT_CONTROL 0x0e 305 + #define MSGID_BERT_SET 0xfa 306 + struct bcm3510_hab_cmd_bert_control { 307 + u8 BE :1; 308 + u8 unused :7; 309 + } PACKED; 310 + 311 + #define MSGID_TRI_STATE 0x2e 312 + struct bcm3510_hab_cmd_tri_state { 313 + u8 RE :1; /* a/d ram port pins */ 314 + u8 PE :1; /* baud clock pin */ 315 + u8 AC :1; /* a/d clock pin */ 316 + u8 BE :1; /* baud clock pin */ 317 + u8 unused :4; 318 + } PACKED; 319 + 320 + 321 + /* tune */ 322 + #define CMD_TUNE 0x38 323 + #define MSGID_TUNE 0x16 324 + struct bcm3510_hab_cmd_tune_ctrl_data_pair { 325 + struct { 326 + #define BITS_8 0x07 327 + #define BITS_7 0x06 328 + #define BITS_6 0x05 329 + #define BITS_5 0x04 330 + #define BITS_4 0x03 331 + #define BITS_3 0x02 332 + #define BITS_2 0x01 333 + #define BITS_1 0x00 334 + u8 size :3; 335 + u8 unk :2; 336 + u8 clk_off :1; 337 + u8 cs0 :1; 338 + u8 cs1 :1; 339 + 340 + } PACKED ctrl; 341 + 342 + u8 data; 343 + } PACKED; 344 + 345 + struct bcm3510_hab_cmd_tune { 346 + u8 length; 347 + u8 clock_width; 348 + u8 misc; 349 + u8 TUNCTL_state; 350 + 351 + struct bcm3510_hab_cmd_tune_ctrl_data_pair ctl_dat[16]; 352 + } PACKED; 353 + 354 + #define CMD_STATUS 0x38 355 + #define MSGID_STATUS1 0x08 356 + struct bcm3510_hab_cmd_status1 { 357 + struct { 358 + u8 EQ_MODE :4; 359 + u8 reserved :2; 360 + u8 QRE :1; /* if QSE and the spectrum is inversed */ 361 + u8 QSE :1; /* automatic spectral inversion */ 362 + } PACKED STATUS0; 363 + 364 + struct { 365 + u8 RECEIVER_LOCK :1; 366 + u8 FEC_LOCK :1; 367 + u8 OUT_PLL_LOCK :1; 368 + u8 reserved :5; 369 + } PACKED STATUS1; 370 + 371 + struct { 372 + u8 reserved :2; 373 + u8 BW :1; 374 + u8 NTE :1; /* NTSC filter sweep enabled */ 375 + u8 AQI :1; /* currently acquiring */ 376 + u8 FA :1; /* fast acquisition */ 377 + u8 ARI :1; /* auto reacquire */ 378 + u8 TI :1; /* programming the tuner */ 379 + } PACKED STATUS2; 380 + u8 STATUS3; 381 + u8 SNR_EST0; 382 + u8 SNR_EST1; 383 + u8 TUNER_FREQ0; 384 + u8 TUNER_FREQ1; 385 + u8 TUNER_FREQ2; 386 + u8 TUNER_FREQ3; 387 + u8 SYM_RATE0; 388 + u8 SYM_RATE1; 389 + u8 SYM_RATE2; 390 + u8 SYM_RATE3; 391 + u8 SYM_OFFSET0; 392 + u8 SYM_OFFSET1; 393 + u8 SYM_ERROR0; 394 + u8 SYM_ERROR1; 395 + u8 IF_FREQ0; 396 + u8 IF_FREQ1; 397 + u8 IF_FREQ2; 398 + u8 IF_FREQ3; 399 + u8 IF_OFFSET0; 400 + u8 IF_OFFSET1; 401 + u8 IF_ERROR0; 402 + u8 IF_ERROR1; 403 + u8 NTSC_FILTER0; 404 + u8 NTSC_FILTER1; 405 + u8 NTSC_FILTER2; 406 + u8 NTSC_FILTER3; 407 + u8 NTSC_OFFSET0; 408 + u8 NTSC_OFFSET1; 409 + u8 NTSC_ERROR0; 410 + u8 NTSC_ERROR1; 411 + u8 INT_AGC_LEVEL0; 412 + u8 INT_AGC_LEVEL1; 413 + u8 EXT_AGC_LEVEL0; 414 + u8 EXT_AGC_LEVEL1; 415 + } PACKED; 416 + 417 + #define MSGID_STATUS2 0x14 418 + struct bcm3510_hab_cmd_status2 { 419 + struct { 420 + u8 EQ_MODE :4; 421 + u8 reserved :2; 422 + u8 QRE :1; 423 + u8 QSR :1; 424 + } PACKED STATUS0; 425 + struct { 426 + u8 RL :1; 427 + u8 FL :1; 428 + u8 OL :1; 429 + u8 reserved :5; 430 + } PACKED STATUS1; 431 + u8 SYMBOL_RATE0; 432 + u8 SYMBOL_RATE1; 433 + u8 SYMBOL_RATE2; 434 + u8 SYMBOL_RATE3; 435 + u8 LDCERC0; 436 + u8 LDCERC1; 437 + u8 LDCERC2; 438 + u8 LDCERC3; 439 + u8 LDUERC0; 440 + u8 LDUERC1; 441 + u8 LDUERC2; 442 + u8 LDUERC3; 443 + u8 LDBER0; 444 + u8 LDBER1; 445 + u8 LDBER2; 446 + u8 LDBER3; 447 + struct { 448 + u8 MODE_TYPE :4; /* acquire mode 0 */ 449 + u8 reservd :4; 450 + } MODE_TYPE; 451 + u8 SNR_EST0; 452 + u8 SNR_EST1; 453 + u8 SIGNAL; 454 + } PACKED; 455 + 456 + #define CMD_SET_RF_BW_NOT_LISTED 0x3f 457 + #define MSGID_SET_RF_BW_NOT_LISTED 0x11 458 + /* TODO */ 459 + 460 + #endif