1/* 2 * mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner 3 * 4 * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21#include "mxl111sf-tuner.h" 22#include "mxl111sf-phy.h" 23#include "mxl111sf-reg.h" 24 25/* debug */ 26static int mxl111sf_tuner_debug; 27module_param_named(debug, mxl111sf_tuner_debug, int, 0644); 28MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); 29 30#define mxl_dbg(fmt, arg...) \ 31 if (mxl111sf_tuner_debug) \ 32 mxl_printk(KERN_DEBUG, fmt, ##arg) 33 34/* ------------------------------------------------------------------------ */ 35 36struct mxl111sf_tuner_state { 37 struct mxl111sf_state *mxl_state; 38 39 struct mxl111sf_tuner_config *cfg; 40 41 enum mxl_if_freq if_freq; 42 43 u32 frequency; 44 u32 bandwidth; 45}; 46 47static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state, 48 u8 addr, u8 *data) 49{ 50 return (state->cfg->read_reg) ? 51 state->cfg->read_reg(state->mxl_state, addr, data) : 52 -EINVAL; 53} 54 55static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state, 56 u8 addr, u8 data) 57{ 58 return (state->cfg->write_reg) ? 59 state->cfg->write_reg(state->mxl_state, addr, data) : 60 -EINVAL; 61} 62 63static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state, 64 struct mxl111sf_reg_ctrl_info *ctrl_reg_info) 65{ 66 return (state->cfg->program_regs) ? 67 state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : 68 -EINVAL; 69} 70 71static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state, 72 int onoff) 73{ 74 return (state->cfg->top_master_ctrl) ? 75 state->cfg->top_master_ctrl(state->mxl_state, onoff) : 76 -EINVAL; 77} 78 79/* ------------------------------------------------------------------------ */ 80 81static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = { 82 {0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3, 83 DIG_MODEINDEX, _A, _CSF, */ 84 {0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */ 85 {0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */ 86 {0, 0, 0} 87}; 88 89/* ------------------------------------------------------------------------ */ 90 91static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq, 92 u8 bw) 93{ 94 u8 filt_bw; 95 96 /* set channel bandwidth */ 97 switch (bw) { 98 case 0: /* ATSC */ 99 filt_bw = 25; 100 break; 101 case 1: /* QAM */ 102 filt_bw = 69; 103 break; 104 case 6: 105 filt_bw = 21; 106 break; 107 case 7: 108 filt_bw = 42; 109 break; 110 case 8: 111 filt_bw = 63; 112 break; 113 default: 114 err("%s: invalid bandwidth setting!", __func__); 115 return NULL; 116 } 117 118 /* calculate RF channel */ 119 freq /= 1000000; 120 121 freq *= 64; 122#if 0 123 /* do round */ 124 freq += 0.5; 125#endif 126 /* set bandwidth */ 127 mxl_phy_tune_rf[0].data = filt_bw; 128 129 /* set RF */ 130 mxl_phy_tune_rf[1].data = (freq & 0xff); 131 mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff; 132 133 /* start tune */ 134 return mxl_phy_tune_rf; 135} 136 137static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state) 138{ 139 int ret; 140 u8 ctrl; 141#if 0 142 u16 iffcw; 143 u32 if_freq; 144#endif 145 mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)", 146 state->cfg->invert_spectrum, state->cfg->if_freq); 147 148 /* set IF polarity */ 149 ctrl = state->cfg->invert_spectrum; 150 151 ctrl |= state->cfg->if_freq; 152 153 ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl); 154 if (mxl_fail(ret)) 155 goto fail; 156 157#if 0 158 if_freq /= 1000000; 159 160 /* do round */ 161 if_freq += 0.5; 162 163 if (MXL_IF_LO == state->cfg->if_freq) { 164 ctrl = 0x08; 165 iffcw = (u16)(if_freq / (108 * 4096)); 166 } else if (MXL_IF_HI == state->cfg->if_freq) { 167 ctrl = 0x08; 168 iffcw = (u16)(if_freq / (216 * 4096)); 169 } else { 170 ctrl = 0; 171 iffcw = 0; 172 } 173 174 ctrl |= (iffcw >> 8); 175#endif 176 ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl); 177 if (mxl_fail(ret)) 178 goto fail; 179 180 ctrl &= 0xf0; 181 ctrl |= 0x90; 182 183 ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl); 184 if (mxl_fail(ret)) 185 goto fail; 186 187#if 0 188 ctrl = iffcw & 0x00ff; 189#endif 190 ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl); 191 if (mxl_fail(ret)) 192 goto fail; 193 194 state->if_freq = state->cfg->if_freq; 195fail: 196 return ret; 197} 198 199static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw) 200{ 201 struct mxl111sf_tuner_state *state = fe->tuner_priv; 202 static struct mxl111sf_reg_ctrl_info *reg_ctrl_array; 203 int ret; 204 u8 mxl_mode; 205 206 mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw); 207 208 /* stop tune */ 209 ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0); 210 if (mxl_fail(ret)) 211 goto fail; 212 213 /* check device mode */ 214 ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode); 215 if (mxl_fail(ret)) 216 goto fail; 217 218 /* Fill out registers for channel tune */ 219 reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw); 220 if (!reg_ctrl_array) 221 return -EINVAL; 222 223 ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array); 224 if (mxl_fail(ret)) 225 goto fail; 226 227 if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) { 228 /* IF tuner mode only */ 229 mxl1x1sf_tuner_top_master_ctrl(state, 0); 230 mxl1x1sf_tuner_top_master_ctrl(state, 1); 231 mxl1x1sf_tuner_set_if_output_freq(state); 232 } 233 234 ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1); 235 if (mxl_fail(ret)) 236 goto fail; 237 238 if (state->cfg->ant_hunt) 239 state->cfg->ant_hunt(fe); 240fail: 241 return ret; 242} 243 244static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state, 245 int *rf_synth_lock, 246 int *ref_synth_lock) 247{ 248 int ret; 249 u8 data; 250 251 *rf_synth_lock = 0; 252 *ref_synth_lock = 0; 253 254 ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data); 255 if (mxl_fail(ret)) 256 goto fail; 257 258 *ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0; 259 *rf_synth_lock = ((data & 0x0c) == 0x0c) ? 1 : 0; 260fail: 261 return ret; 262} 263 264#if 0 265static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state, 266 int onoff) 267{ 268 return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG, 269 onoff ? 1 : 0); 270} 271#endif 272 273/* ------------------------------------------------------------------------ */ 274 275static int mxl111sf_tuner_set_params(struct dvb_frontend *fe) 276{ 277 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 278 u32 delsys = c->delivery_system; 279 struct mxl111sf_tuner_state *state = fe->tuner_priv; 280 int ret; 281 u8 bw; 282 283 mxl_dbg("()"); 284 285 switch (delsys) { 286 case SYS_ATSC: 287 bw = 0; /* ATSC */ 288 break; 289 case SYS_DVBC_ANNEX_B: 290 bw = 1; /* US CABLE */ 291 break; 292 case SYS_DVBT: 293 switch (c->bandwidth_hz) { 294 case 6000000: 295 bw = 6; 296 break; 297 case 7000000: 298 bw = 7; 299 break; 300 case 8000000: 301 bw = 8; 302 break; 303 default: 304 err("%s: bandwidth not set!", __func__); 305 return -EINVAL; 306 } 307 break; 308 default: 309 err("%s: modulation type not supported!", __func__); 310 return -EINVAL; 311 } 312 ret = mxl1x1sf_tune_rf(fe, c->frequency, bw); 313 if (mxl_fail(ret)) 314 goto fail; 315 316 state->frequency = c->frequency; 317 state->bandwidth = c->bandwidth_hz; 318fail: 319 return ret; 320} 321 322/* ------------------------------------------------------------------------ */ 323 324#if 0 325static int mxl111sf_tuner_init(struct dvb_frontend *fe) 326{ 327 struct mxl111sf_tuner_state *state = fe->tuner_priv; 328 int ret; 329 330 /* wake from standby handled by usb driver */ 331 332 return ret; 333} 334 335static int mxl111sf_tuner_sleep(struct dvb_frontend *fe) 336{ 337 struct mxl111sf_tuner_state *state = fe->tuner_priv; 338 int ret; 339 340 /* enter standby mode handled by usb driver */ 341 342 return ret; 343} 344#endif 345 346/* ------------------------------------------------------------------------ */ 347 348static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status) 349{ 350 struct mxl111sf_tuner_state *state = fe->tuner_priv; 351 int rf_locked, ref_locked, ret; 352 353 *status = 0; 354 355 ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked); 356 if (mxl_fail(ret)) 357 goto fail; 358 mxl_info("%s%s", rf_locked ? "rf locked " : "", 359 ref_locked ? "ref locked" : ""); 360 361 if ((rf_locked) || (ref_locked)) 362 *status |= TUNER_STATUS_LOCKED; 363fail: 364 return ret; 365} 366 367static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength) 368{ 369 struct mxl111sf_tuner_state *state = fe->tuner_priv; 370 u8 val1, val2; 371 int ret; 372 373 *strength = 0; 374 375 ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02); 376 if (mxl_fail(ret)) 377 goto fail; 378 ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1); 379 if (mxl_fail(ret)) 380 goto fail; 381 ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2); 382 if (mxl_fail(ret)) 383 goto fail; 384 385 *strength = val1 | ((val2 & 0x07) << 8); 386fail: 387 ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00); 388 mxl_fail(ret); 389 390 return ret; 391} 392 393/* ------------------------------------------------------------------------ */ 394 395static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency) 396{ 397 struct mxl111sf_tuner_state *state = fe->tuner_priv; 398 *frequency = state->frequency; 399 return 0; 400} 401 402static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) 403{ 404 struct mxl111sf_tuner_state *state = fe->tuner_priv; 405 *bandwidth = state->bandwidth; 406 return 0; 407} 408 409static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe, 410 u32 *frequency) 411{ 412 struct mxl111sf_tuner_state *state = fe->tuner_priv; 413 414 *frequency = 0; 415 416 switch (state->if_freq) { 417 case MXL_IF_4_0: /* 4.0 MHz */ 418 *frequency = 4000000; 419 break; 420 case MXL_IF_4_5: /* 4.5 MHz */ 421 *frequency = 4500000; 422 break; 423 case MXL_IF_4_57: /* 4.57 MHz */ 424 *frequency = 4570000; 425 break; 426 case MXL_IF_5_0: /* 5.0 MHz */ 427 *frequency = 5000000; 428 break; 429 case MXL_IF_5_38: /* 5.38 MHz */ 430 *frequency = 5380000; 431 break; 432 case MXL_IF_6_0: /* 6.0 MHz */ 433 *frequency = 6000000; 434 break; 435 case MXL_IF_6_28: /* 6.28 MHz */ 436 *frequency = 6280000; 437 break; 438 case MXL_IF_7_2: /* 7.2 MHz */ 439 *frequency = 7200000; 440 break; 441 case MXL_IF_35_25: /* 35.25 MHz */ 442 *frequency = 35250000; 443 break; 444 case MXL_IF_36: /* 36 MHz */ 445 *frequency = 36000000; 446 break; 447 case MXL_IF_36_15: /* 36.15 MHz */ 448 *frequency = 36150000; 449 break; 450 case MXL_IF_44: /* 44 MHz */ 451 *frequency = 44000000; 452 break; 453 } 454 return 0; 455} 456 457static int mxl111sf_tuner_release(struct dvb_frontend *fe) 458{ 459 struct mxl111sf_tuner_state *state = fe->tuner_priv; 460 mxl_dbg("()"); 461 kfree(state); 462 fe->tuner_priv = NULL; 463 return 0; 464} 465 466/* ------------------------------------------------------------------------- */ 467 468static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { 469 .info = { 470 .name = "MaxLinear MxL111SF", 471#if 0 472 .frequency_min = , 473 .frequency_max = , 474 .frequency_step = , 475#endif 476 }, 477#if 0 478 .init = mxl111sf_tuner_init, 479 .sleep = mxl111sf_tuner_sleep, 480#endif 481 .set_params = mxl111sf_tuner_set_params, 482 .get_status = mxl111sf_tuner_get_status, 483 .get_rf_strength = mxl111sf_get_rf_strength, 484 .get_frequency = mxl111sf_tuner_get_frequency, 485 .get_bandwidth = mxl111sf_tuner_get_bandwidth, 486 .get_if_frequency = mxl111sf_tuner_get_if_frequency, 487 .release = mxl111sf_tuner_release, 488}; 489 490struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, 491 struct mxl111sf_state *mxl_state, 492 struct mxl111sf_tuner_config *cfg) 493{ 494 struct mxl111sf_tuner_state *state = NULL; 495 496 mxl_dbg("()"); 497 498 state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL); 499 if (state == NULL) 500 return NULL; 501 502 state->mxl_state = mxl_state; 503 state->cfg = cfg; 504 505 memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops, 506 sizeof(struct dvb_tuner_ops)); 507 508 fe->tuner_priv = state; 509 return fe; 510} 511EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach); 512 513MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver"); 514MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>"); 515MODULE_LICENSE("GPL"); 516MODULE_VERSION("0.1"); 517 518/* 519 * Overrides for Emacs so that we follow Linus's tabbing style. 520 * --------------------------------------------------------------------------- 521 * Local variables: 522 * c-basic-offset: 8 523 * End: 524 */ 525