1/* 2 * Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator 3 * ATBM8830, ATBM8831 4 * 5 * Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22#include <asm/div64.h> 23#include "dvb_frontend.h" 24 25#include "atbm8830.h" 26#include "atbm8830_priv.h" 27 28#define dprintk(args...) \ 29 do { \ 30 if (debug) \ 31 printk(KERN_DEBUG "atbm8830: " args); \ 32 } while (0) 33 34static int debug; 35 36module_param(debug, int, 0644); 37MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 38 39static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data) 40{ 41 int ret = 0; 42 u8 dev_addr; 43 u8 buf1[] = { reg >> 8, reg & 0xFF }; 44 u8 buf2[] = { data }; 45 struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 }; 46 struct i2c_msg msg2 = { .flags = 0, .buf = buf2, .len = 1 }; 47 48 dev_addr = priv->config->demod_address; 49 msg1.addr = dev_addr; 50 msg2.addr = dev_addr; 51 52 if (debug >= 2) 53 printk(KERN_DEBUG "%s: reg=0x%04X, data=0x%02X\n", 54 __func__, reg, data); 55 56 ret = i2c_transfer(priv->i2c, &msg1, 1); 57 if (ret != 1) 58 return -EIO; 59 60 ret = i2c_transfer(priv->i2c, &msg2, 1); 61 return (ret != 1) ? -EIO : 0; 62} 63 64static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data) 65{ 66 int ret; 67 u8 dev_addr; 68 69 u8 buf1[] = { reg >> 8, reg & 0xFF }; 70 u8 buf2[] = { 0 }; 71 struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 }; 72 struct i2c_msg msg2 = { .flags = I2C_M_RD, .buf = buf2, .len = 1 }; 73 74 dev_addr = priv->config->demod_address; 75 msg1.addr = dev_addr; 76 msg2.addr = dev_addr; 77 78 ret = i2c_transfer(priv->i2c, &msg1, 1); 79 if (ret != 1) { 80 dprintk(KERN_DEBUG "%s: error reg=0x%04x, ret=%i\n", 81 __func__, reg, ret); 82 return -EIO; 83 } 84 85 ret = i2c_transfer(priv->i2c, &msg2, 1); 86 if (ret != 1) 87 return -EIO; 88 89 *p_data = buf2[0]; 90 if (debug >= 2) 91 printk(KERN_DEBUG "%s: reg=0x%04X, data=0x%02X\n", 92 __func__, reg, buf2[0]); 93 94 return 0; 95} 96 97/* Lock register latch so that multi-register read is atomic */ 98static inline int atbm8830_reglatch_lock(struct atbm_state *priv, int lock) 99{ 100 return atbm8830_write_reg(priv, REG_READ_LATCH, lock ? 1 : 0); 101} 102 103static int set_osc_freq(struct atbm_state *priv, u32 freq /*in kHz*/) 104{ 105 u32 val; 106 u64 t; 107 108 /* 0x100000 * freq / 30.4MHz */ 109 t = (u64)0x100000 * freq; 110 do_div(t, 30400); 111 val = t; 112 113 atbm8830_write_reg(priv, REG_OSC_CLK, val); 114 atbm8830_write_reg(priv, REG_OSC_CLK + 1, val >> 8); 115 atbm8830_write_reg(priv, REG_OSC_CLK + 2, val >> 16); 116 117 return 0; 118} 119 120static int set_if_freq(struct atbm_state *priv, u32 freq /*in kHz*/) 121{ 122 123 u32 fs = priv->config->osc_clk_freq; 124 u64 t; 125 u32 val; 126 u8 dat; 127 128 if (freq != 0) { 129 /* 2 * PI * (freq - fs) / fs * (2 ^ 22) */ 130 t = (u64) 2 * 31416 * (freq - fs); 131 t <<= 22; 132 do_div(t, fs); 133 do_div(t, 1000); 134 val = t; 135 136 atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 1); 137 atbm8830_write_reg(priv, REG_IF_FREQ, val); 138 atbm8830_write_reg(priv, REG_IF_FREQ+1, val >> 8); 139 atbm8830_write_reg(priv, REG_IF_FREQ+2, val >> 16); 140 141 atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat); 142 dat &= 0xFC; 143 atbm8830_write_reg(priv, REG_ADC_CONFIG, dat); 144 } else { 145 /* Zero IF */ 146 atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 0); 147 148 atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat); 149 dat &= 0xFC; 150 dat |= 0x02; 151 atbm8830_write_reg(priv, REG_ADC_CONFIG, dat); 152 153 if (priv->config->zif_swap_iq) 154 atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x03); 155 else 156 atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x01); 157 } 158 159 return 0; 160} 161 162static int is_locked(struct atbm_state *priv, u8 *locked) 163{ 164 u8 status; 165 166 atbm8830_read_reg(priv, REG_LOCK_STATUS, &status); 167 168 if (locked != NULL) 169 *locked = (status == 1); 170 return 0; 171} 172 173static int set_agc_config(struct atbm_state *priv, 174 u8 min, u8 max, u8 hold_loop) 175{ 176 /* no effect if both min and max are zero */ 177 if (!min && !max) 178 return 0; 179 180 atbm8830_write_reg(priv, REG_AGC_MIN, min); 181 atbm8830_write_reg(priv, REG_AGC_MAX, max); 182 atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop); 183 184 return 0; 185} 186 187static int set_static_channel_mode(struct atbm_state *priv) 188{ 189 int i; 190 191 for (i = 0; i < 5; i++) 192 atbm8830_write_reg(priv, 0x099B + i, 0x08); 193 194 atbm8830_write_reg(priv, 0x095B, 0x7F); 195 atbm8830_write_reg(priv, 0x09CB, 0x01); 196 atbm8830_write_reg(priv, 0x09CC, 0x7F); 197 atbm8830_write_reg(priv, 0x09CD, 0x7F); 198 atbm8830_write_reg(priv, 0x0E01, 0x20); 199 200 /* For single carrier */ 201 atbm8830_write_reg(priv, 0x0B03, 0x0A); 202 atbm8830_write_reg(priv, 0x0935, 0x10); 203 atbm8830_write_reg(priv, 0x0936, 0x08); 204 atbm8830_write_reg(priv, 0x093E, 0x08); 205 atbm8830_write_reg(priv, 0x096E, 0x06); 206 207 /* frame_count_max0 */ 208 atbm8830_write_reg(priv, 0x0B09, 0x00); 209 /* frame_count_max1 */ 210 atbm8830_write_reg(priv, 0x0B0A, 0x08); 211 212 return 0; 213} 214 215static int set_ts_config(struct atbm_state *priv) 216{ 217 const struct atbm8830_config *cfg = priv->config; 218 219 /*Set parallel/serial ts mode*/ 220 atbm8830_write_reg(priv, REG_TS_SERIAL, cfg->serial_ts ? 1 : 0); 221 atbm8830_write_reg(priv, REG_TS_CLK_MODE, cfg->serial_ts ? 1 : 0); 222 /*Set ts sampling edge*/ 223 atbm8830_write_reg(priv, REG_TS_SAMPLE_EDGE, 224 cfg->ts_sampling_edge ? 1 : 0); 225 /*Set ts clock freerun*/ 226 atbm8830_write_reg(priv, REG_TS_CLK_FREERUN, 227 cfg->ts_clk_gated ? 0 : 1); 228 229 return 0; 230} 231 232static int atbm8830_init(struct dvb_frontend *fe) 233{ 234 struct atbm_state *priv = fe->demodulator_priv; 235 const struct atbm8830_config *cfg = priv->config; 236 237 /*Set oscillator frequency*/ 238 set_osc_freq(priv, cfg->osc_clk_freq); 239 240 /*Set IF frequency*/ 241 set_if_freq(priv, cfg->if_freq); 242 243 /*Set AGC Config*/ 244 set_agc_config(priv, cfg->agc_min, cfg->agc_max, 245 cfg->agc_hold_loop); 246 247 /*Set static channel mode*/ 248 set_static_channel_mode(priv); 249 250 set_ts_config(priv); 251 /*Turn off DSP reset*/ 252 atbm8830_write_reg(priv, 0x000A, 0); 253 254 /*SW version test*/ 255 atbm8830_write_reg(priv, 0x020C, 11); 256 257 /* Run */ 258 atbm8830_write_reg(priv, REG_DEMOD_RUN, 1); 259 260 return 0; 261} 262 263 264static void atbm8830_release(struct dvb_frontend *fe) 265{ 266 struct atbm_state *state = fe->demodulator_priv; 267 dprintk("%s\n", __func__); 268 269 kfree(state); 270} 271 272static int atbm8830_set_fe(struct dvb_frontend *fe, 273 struct dvb_frontend_parameters *fe_params) 274{ 275 struct atbm_state *priv = fe->demodulator_priv; 276 int i; 277 u8 locked = 0; 278 dprintk("%s\n", __func__); 279 280 /* set frequency */ 281 if (fe->ops.tuner_ops.set_params) { 282 if (fe->ops.i2c_gate_ctrl) 283 fe->ops.i2c_gate_ctrl(fe, 1); 284 fe->ops.tuner_ops.set_params(fe, fe_params); 285 if (fe->ops.i2c_gate_ctrl) 286 fe->ops.i2c_gate_ctrl(fe, 0); 287 } 288 289 /* start auto lock */ 290 for (i = 0; i < 10; i++) { 291 mdelay(100); 292 dprintk("Try %d\n", i); 293 is_locked(priv, &locked); 294 if (locked != 0) { 295 dprintk("ATBM8830 locked!\n"); 296 break; 297 } 298 } 299 300 return 0; 301} 302 303static int atbm8830_get_fe(struct dvb_frontend *fe, 304 struct dvb_frontend_parameters *fe_params) 305{ 306 dprintk("%s\n", __func__); 307 308 /* TODO: get real readings from device */ 309 /* inversion status */ 310 fe_params->inversion = INVERSION_OFF; 311 312 /* bandwidth */ 313 fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; 314 315 fe_params->u.ofdm.code_rate_HP = FEC_AUTO; 316 fe_params->u.ofdm.code_rate_LP = FEC_AUTO; 317 318 fe_params->u.ofdm.constellation = QAM_AUTO; 319 320 /* transmission mode */ 321 fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; 322 323 /* guard interval */ 324 fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; 325 326 /* hierarchy */ 327 fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; 328 329 return 0; 330} 331 332static int atbm8830_get_tune_settings(struct dvb_frontend *fe, 333 struct dvb_frontend_tune_settings *fesettings) 334{ 335 fesettings->min_delay_ms = 0; 336 fesettings->step_size = 0; 337 fesettings->max_drift = 0; 338 return 0; 339} 340 341static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status) 342{ 343 struct atbm_state *priv = fe->demodulator_priv; 344 u8 locked = 0; 345 u8 agc_locked = 0; 346 347 dprintk("%s\n", __func__); 348 *fe_status = 0; 349 350 is_locked(priv, &locked); 351 if (locked) { 352 *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | 353 FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; 354 } 355 dprintk("%s: fe_status=0x%x\n", __func__, *fe_status); 356 357 atbm8830_read_reg(priv, REG_AGC_LOCK, &agc_locked); 358 dprintk("AGC Lock: %d\n", agc_locked); 359 360 return 0; 361} 362 363static int atbm8830_read_ber(struct dvb_frontend *fe, u32 *ber) 364{ 365 struct atbm_state *priv = fe->demodulator_priv; 366 u32 frame_err; 367 u8 t; 368 369 dprintk("%s\n", __func__); 370 371 atbm8830_reglatch_lock(priv, 1); 372 373 atbm8830_read_reg(priv, REG_FRAME_ERR_CNT + 1, &t); 374 frame_err = t & 0x7F; 375 frame_err <<= 8; 376 atbm8830_read_reg(priv, REG_FRAME_ERR_CNT, &t); 377 frame_err |= t; 378 379 atbm8830_reglatch_lock(priv, 0); 380 381 *ber = frame_err * 100 / 32767; 382 383 dprintk("%s: ber=0x%x\n", __func__, *ber); 384 return 0; 385} 386 387static int atbm8830_read_signal_strength(struct dvb_frontend *fe, u16 *signal) 388{ 389 struct atbm_state *priv = fe->demodulator_priv; 390 u32 pwm; 391 u8 t; 392 393 dprintk("%s\n", __func__); 394 atbm8830_reglatch_lock(priv, 1); 395 396 atbm8830_read_reg(priv, REG_AGC_PWM_VAL + 1, &t); 397 pwm = t & 0x03; 398 pwm <<= 8; 399 atbm8830_read_reg(priv, REG_AGC_PWM_VAL, &t); 400 pwm |= t; 401 402 atbm8830_reglatch_lock(priv, 0); 403 404 dprintk("AGC PWM = 0x%02X\n", pwm); 405 pwm = 0x400 - pwm; 406 407 *signal = pwm * 0x10000 / 0x400; 408 409 return 0; 410} 411 412static int atbm8830_read_snr(struct dvb_frontend *fe, u16 *snr) 413{ 414 dprintk("%s\n", __func__); 415 *snr = 0; 416 return 0; 417} 418 419static int atbm8830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 420{ 421 dprintk("%s\n", __func__); 422 *ucblocks = 0; 423 return 0; 424} 425 426static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 427{ 428 struct atbm_state *priv = fe->demodulator_priv; 429 430 return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0); 431} 432 433static struct dvb_frontend_ops atbm8830_ops = { 434 .info = { 435 .name = "AltoBeam ATBM8830/8831 DMB-TH", 436 .type = FE_OFDM, 437 .frequency_min = 474000000, 438 .frequency_max = 858000000, 439 .frequency_stepsize = 10000, 440 .caps = 441 FE_CAN_FEC_AUTO | 442 FE_CAN_QAM_AUTO | 443 FE_CAN_TRANSMISSION_MODE_AUTO | 444 FE_CAN_GUARD_INTERVAL_AUTO 445 }, 446 447 .release = atbm8830_release, 448 449 .init = atbm8830_init, 450 .sleep = NULL, 451 .write = NULL, 452 .i2c_gate_ctrl = atbm8830_i2c_gate_ctrl, 453 454 .set_frontend = atbm8830_set_fe, 455 .get_frontend = atbm8830_get_fe, 456 .get_tune_settings = atbm8830_get_tune_settings, 457 458 .read_status = atbm8830_read_status, 459 .read_ber = atbm8830_read_ber, 460 .read_signal_strength = atbm8830_read_signal_strength, 461 .read_snr = atbm8830_read_snr, 462 .read_ucblocks = atbm8830_read_ucblocks, 463}; 464 465struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config, 466 struct i2c_adapter *i2c) 467{ 468 struct atbm_state *priv = NULL; 469 u8 data = 0; 470 471 dprintk("%s()\n", __func__); 472 473 if (config == NULL || i2c == NULL) 474 return NULL; 475 476 priv = kzalloc(sizeof(struct atbm_state), GFP_KERNEL); 477 if (priv == NULL) 478 goto error_out; 479 480 priv->config = config; 481 priv->i2c = i2c; 482 483 /* check if the demod is there */ 484 if (atbm8830_read_reg(priv, REG_CHIP_ID, &data) != 0) { 485 dprintk("%s atbm8830/8831 not found at i2c addr 0x%02X\n", 486 __func__, priv->config->demod_address); 487 goto error_out; 488 } 489 dprintk("atbm8830 chip id: 0x%02X\n", data); 490 491 memcpy(&priv->frontend.ops, &atbm8830_ops, 492 sizeof(struct dvb_frontend_ops)); 493 priv->frontend.demodulator_priv = priv; 494 495 atbm8830_init(&priv->frontend); 496 497 atbm8830_i2c_gate_ctrl(&priv->frontend, 1); 498 499 return &priv->frontend; 500 501error_out: 502 dprintk("%s() error_out\n", __func__); 503 kfree(priv); 504 return NULL; 505 506} 507EXPORT_SYMBOL(atbm8830_attach); 508 509MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver"); 510MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>"); 511MODULE_LICENSE("GPL"); 512