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