ves1820.c (10876B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 VES1820 - Single Chip Cable Channel Receiver driver module 4 5 Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> 6 7*/ 8 9#include <linux/delay.h> 10#include <linux/errno.h> 11#include <linux/init.h> 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/string.h> 15#include <linux/slab.h> 16#include <asm/div64.h> 17 18#include <media/dvb_frontend.h> 19#include "ves1820.h" 20 21 22 23struct ves1820_state { 24 struct i2c_adapter* i2c; 25 /* configuration settings */ 26 const struct ves1820_config* config; 27 struct dvb_frontend frontend; 28 29 /* private demodulator data */ 30 u8 reg0; 31 u8 pwm; 32}; 33 34 35static int verbose; 36 37static u8 ves1820_inittab[] = { 38 0x69, 0x6A, 0x93, 0x1A, 0x12, 0x46, 0x26, 0x1A, 39 0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20, 40 0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 41 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 42 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 0x00, 0x00, 0x00, 0x00, 0x40 45}; 46 47static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) 48{ 49 u8 buf[] = { 0x00, reg, data }; 50 struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 }; 51 int ret; 52 53 ret = i2c_transfer(state->i2c, &msg, 1); 54 55 if (ret != 1) 56 printk("ves1820: %s(): writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", 57 __func__, reg, data, ret); 58 59 return (ret != 1) ? -EREMOTEIO : 0; 60} 61 62static u8 ves1820_readreg(struct ves1820_state *state, u8 reg) 63{ 64 u8 b0[] = { 0x00, reg }; 65 u8 b1[] = { 0 }; 66 struct i2c_msg msg[] = { 67 {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2}, 68 {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} 69 }; 70 int ret; 71 72 ret = i2c_transfer(state->i2c, msg, 2); 73 74 if (ret != 2) 75 printk("ves1820: %s(): readreg error (reg == 0x%02x, ret == %i)\n", 76 __func__, reg, ret); 77 78 return b1[0]; 79} 80 81static int ves1820_setup_reg0(struct ves1820_state *state, 82 u8 reg0, enum fe_spectral_inversion inversion) 83{ 84 reg0 |= state->reg0 & 0x62; 85 86 if (INVERSION_ON == inversion) { 87 if (!state->config->invert) reg0 |= 0x20; 88 else reg0 &= ~0x20; 89 } else if (INVERSION_OFF == inversion) { 90 if (!state->config->invert) reg0 &= ~0x20; 91 else reg0 |= 0x20; 92 } 93 94 ves1820_writereg(state, 0x00, reg0 & 0xfe); 95 ves1820_writereg(state, 0x00, reg0 | 0x01); 96 97 state->reg0 = reg0; 98 99 return 0; 100} 101 102static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate) 103{ 104 s32 BDR; 105 s32 BDRI; 106 s16 SFIL = 0; 107 u16 NDEC = 0; 108 u32 ratio; 109 u32 fin; 110 u32 tmp; 111 u64 fptmp; 112 u64 fpxin; 113 114 if (symbolrate > state->config->xin / 2) 115 symbolrate = state->config->xin / 2; 116 117 if (symbolrate < 500000) 118 symbolrate = 500000; 119 120 if (symbolrate < state->config->xin / 16) 121 NDEC = 1; 122 if (symbolrate < state->config->xin / 32) 123 NDEC = 2; 124 if (symbolrate < state->config->xin / 64) 125 NDEC = 3; 126 127 /* yeuch! */ 128 fpxin = state->config->xin * 10ULL; 129 fptmp = fpxin; do_div(fptmp, 123); 130 if (symbolrate < fptmp) 131 SFIL = 1; 132 fptmp = fpxin; do_div(fptmp, 160); 133 if (symbolrate < fptmp) 134 SFIL = 0; 135 fptmp = fpxin; do_div(fptmp, 246); 136 if (symbolrate < fptmp) 137 SFIL = 1; 138 fptmp = fpxin; do_div(fptmp, 320); 139 if (symbolrate < fptmp) 140 SFIL = 0; 141 fptmp = fpxin; do_div(fptmp, 492); 142 if (symbolrate < fptmp) 143 SFIL = 1; 144 fptmp = fpxin; do_div(fptmp, 640); 145 if (symbolrate < fptmp) 146 SFIL = 0; 147 fptmp = fpxin; do_div(fptmp, 984); 148 if (symbolrate < fptmp) 149 SFIL = 1; 150 151 fin = state->config->xin >> 4; 152 symbolrate <<= NDEC; 153 ratio = (symbolrate << 4) / fin; 154 tmp = ((symbolrate << 4) % fin) << 8; 155 ratio = (ratio << 8) + tmp / fin; 156 tmp = (tmp % fin) << 8; 157 ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, fin); 158 159 BDR = ratio; 160 BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2; 161 162 if (BDRI > 0xFF) 163 BDRI = 0xFF; 164 165 SFIL = (SFIL << 4) | ves1820_inittab[0x0E]; 166 167 NDEC = (NDEC << 6) | ves1820_inittab[0x03]; 168 169 ves1820_writereg(state, 0x03, NDEC); 170 ves1820_writereg(state, 0x0a, BDR & 0xff); 171 ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff); 172 ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f); 173 174 ves1820_writereg(state, 0x0d, BDRI); 175 ves1820_writereg(state, 0x0e, SFIL); 176 177 return 0; 178} 179 180static int ves1820_init(struct dvb_frontend* fe) 181{ 182 struct ves1820_state* state = fe->demodulator_priv; 183 int i; 184 185 ves1820_writereg(state, 0, 0); 186 187 for (i = 0; i < sizeof(ves1820_inittab); i++) 188 ves1820_writereg(state, i, ves1820_inittab[i]); 189 if (state->config->selagc) 190 ves1820_writereg(state, 2, ves1820_inittab[2] | 0x08); 191 192 ves1820_writereg(state, 0x34, state->pwm); 193 194 return 0; 195} 196 197static int ves1820_set_parameters(struct dvb_frontend *fe) 198{ 199 struct dtv_frontend_properties *p = &fe->dtv_property_cache; 200 struct ves1820_state* state = fe->demodulator_priv; 201 static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 }; 202 static const u8 reg0x01[] = { 140, 140, 106, 100, 92 }; 203 static const u8 reg0x05[] = { 135, 100, 70, 54, 38 }; 204 static const u8 reg0x08[] = { 162, 116, 67, 52, 35 }; 205 static const u8 reg0x09[] = { 145, 150, 106, 126, 107 }; 206 int real_qam = p->modulation - QAM_16; 207 208 if (real_qam < 0 || real_qam > 4) 209 return -EINVAL; 210 211 if (fe->ops.tuner_ops.set_params) { 212 fe->ops.tuner_ops.set_params(fe); 213 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 214 } 215 216 ves1820_set_symbolrate(state, p->symbol_rate); 217 ves1820_writereg(state, 0x34, state->pwm); 218 219 ves1820_writereg(state, 0x01, reg0x01[real_qam]); 220 ves1820_writereg(state, 0x05, reg0x05[real_qam]); 221 ves1820_writereg(state, 0x08, reg0x08[real_qam]); 222 ves1820_writereg(state, 0x09, reg0x09[real_qam]); 223 224 ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion); 225 ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0)); 226 return 0; 227} 228 229static int ves1820_read_status(struct dvb_frontend *fe, 230 enum fe_status *status) 231{ 232 struct ves1820_state* state = fe->demodulator_priv; 233 int sync; 234 235 *status = 0; 236 sync = ves1820_readreg(state, 0x11); 237 238 if (sync & 1) 239 *status |= FE_HAS_SIGNAL; 240 241 if (sync & 2) 242 *status |= FE_HAS_CARRIER; 243 244 if (sync & 2) /* XXX FIXME! */ 245 *status |= FE_HAS_VITERBI; 246 247 if (sync & 4) 248 *status |= FE_HAS_SYNC; 249 250 if (sync & 8) 251 *status |= FE_HAS_LOCK; 252 253 return 0; 254} 255 256static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber) 257{ 258 struct ves1820_state* state = fe->demodulator_priv; 259 260 u32 _ber = ves1820_readreg(state, 0x14) | 261 (ves1820_readreg(state, 0x15) << 8) | 262 ((ves1820_readreg(state, 0x16) & 0x0f) << 16); 263 *ber = 10 * _ber; 264 265 return 0; 266} 267 268static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength) 269{ 270 struct ves1820_state* state = fe->demodulator_priv; 271 272 u8 gain = ves1820_readreg(state, 0x17); 273 *strength = (gain << 8) | gain; 274 275 return 0; 276} 277 278static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr) 279{ 280 struct ves1820_state* state = fe->demodulator_priv; 281 282 u8 quality = ~ves1820_readreg(state, 0x18); 283 *snr = (quality << 8) | quality; 284 285 return 0; 286} 287 288static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) 289{ 290 struct ves1820_state* state = fe->demodulator_priv; 291 292 *ucblocks = ves1820_readreg(state, 0x13) & 0x7f; 293 if (*ucblocks == 0x7f) 294 *ucblocks = 0xffffffff; 295 296 /* reset uncorrected block counter */ 297 ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf); 298 ves1820_writereg(state, 0x10, ves1820_inittab[0x10]); 299 300 return 0; 301} 302 303static int ves1820_get_frontend(struct dvb_frontend *fe, 304 struct dtv_frontend_properties *p) 305{ 306 struct ves1820_state* state = fe->demodulator_priv; 307 int sync; 308 s8 afc = 0; 309 310 sync = ves1820_readreg(state, 0x11); 311 afc = ves1820_readreg(state, 0x19); 312 if (verbose) { 313 /* AFC only valid when carrier has been recovered */ 314 printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" : 315 "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->symbol_rate * afc) >> 10); 316 } 317 318 if (!state->config->invert) { 319 p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF; 320 } else { 321 p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF; 322 } 323 324 p->modulation = ((state->reg0 >> 2) & 7) + QAM_16; 325 326 p->fec_inner = FEC_NONE; 327 328 p->frequency = ((p->frequency + 31250) / 62500) * 62500; 329 if (sync & 2) 330 p->frequency -= ((s32) p->symbol_rate * afc) >> 10; 331 332 return 0; 333} 334 335static int ves1820_sleep(struct dvb_frontend* fe) 336{ 337 struct ves1820_state* state = fe->demodulator_priv; 338 339 ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */ 340 ves1820_writereg(state, 0x00, 0x80); /* standby */ 341 342 return 0; 343} 344 345static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) 346{ 347 348 fesettings->min_delay_ms = 200; 349 fesettings->step_size = 0; 350 fesettings->max_drift = 0; 351 return 0; 352} 353 354static void ves1820_release(struct dvb_frontend* fe) 355{ 356 struct ves1820_state* state = fe->demodulator_priv; 357 kfree(state); 358} 359 360static const struct dvb_frontend_ops ves1820_ops; 361 362struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, 363 struct i2c_adapter* i2c, 364 u8 pwm) 365{ 366 struct ves1820_state* state = NULL; 367 368 /* allocate memory for the internal state */ 369 state = kzalloc(sizeof(struct ves1820_state), GFP_KERNEL); 370 if (state == NULL) 371 goto error; 372 373 /* setup the state */ 374 state->reg0 = ves1820_inittab[0]; 375 state->config = config; 376 state->i2c = i2c; 377 state->pwm = pwm; 378 379 /* check if the demod is there */ 380 if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70) 381 goto error; 382 383 if (verbose) 384 printk("ves1820: pwm=0x%02x\n", state->pwm); 385 386 /* create dvb_frontend */ 387 memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops)); 388 state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */ 389 state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */ 390 state->frontend.demodulator_priv = state; 391 392 return &state->frontend; 393 394error: 395 kfree(state); 396 return NULL; 397} 398 399static const struct dvb_frontend_ops ves1820_ops = { 400 .delsys = { SYS_DVBC_ANNEX_A }, 401 .info = { 402 .name = "VLSI VES1820 DVB-C", 403 .frequency_min_hz = 47 * MHz, 404 .frequency_max_hz = 862 * MHz, 405 .frequency_stepsize_hz = 62500, 406 .caps = FE_CAN_QAM_16 | 407 FE_CAN_QAM_32 | 408 FE_CAN_QAM_64 | 409 FE_CAN_QAM_128 | 410 FE_CAN_QAM_256 | 411 FE_CAN_FEC_AUTO 412 }, 413 414 .release = ves1820_release, 415 416 .init = ves1820_init, 417 .sleep = ves1820_sleep, 418 419 .set_frontend = ves1820_set_parameters, 420 .get_frontend = ves1820_get_frontend, 421 .get_tune_settings = ves1820_get_tune_settings, 422 423 .read_status = ves1820_read_status, 424 .read_ber = ves1820_read_ber, 425 .read_signal_strength = ves1820_read_signal_strength, 426 .read_snr = ves1820_read_snr, 427 .read_ucblocks = ves1820_read_ucblocks, 428}; 429 430module_param(verbose, int, 0644); 431MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting"); 432 433MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver"); 434MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); 435MODULE_LICENSE("GPL"); 436 437EXPORT_SYMBOL(ves1820_attach);