root/drivers/media/dvb-frontends/ves1820.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ves1820_writereg
  2. ves1820_readreg
  3. ves1820_setup_reg0
  4. ves1820_set_symbolrate
  5. ves1820_init
  6. ves1820_set_parameters
  7. ves1820_read_status
  8. ves1820_read_ber
  9. ves1820_read_signal_strength
  10. ves1820_read_snr
  11. ves1820_read_ucblocks
  12. ves1820_get_frontend
  13. ves1820_sleep
  14. ves1820_get_tune_settings
  15. ves1820_release
  16. ves1820_attach

   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 
  23 struct 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 
  35 static int verbose;
  36 
  37 static 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 
  47 static 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 
  62 static 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 
  81 static 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 
 102 static 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 
 180 static 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 
 197 static 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 
 229 static 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 
 256 static 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 
 268 static 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 
 278 static 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 
 288 static 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 
 303 static 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 
 335 static 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 
 345 static 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 
 354 static void ves1820_release(struct dvb_frontend* fe)
 355 {
 356         struct ves1820_state* state = fe->demodulator_priv;
 357         kfree(state);
 358 }
 359 
 360 static const struct dvb_frontend_ops ves1820_ops;
 361 
 362 struct 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 
 394 error:
 395         kfree(state);
 396         return NULL;
 397 }
 398 
 399 static 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 
 430 module_param(verbose, int, 0644);
 431 MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
 432 
 433 MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver");
 434 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
 435 MODULE_LICENSE("GPL");
 436 
 437 EXPORT_SYMBOL(ves1820_attach);

/* [<][>][^][v][top][bottom][index][help] */