Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     VES1820  - Single Chip Cable Channel Receiver driver module
0004 
0005     Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
0006 
0007 */
0008 
0009 #include <linux/delay.h>
0010 #include <linux/errno.h>
0011 #include <linux/init.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/string.h>
0015 #include <linux/slab.h>
0016 #include <asm/div64.h>
0017 
0018 #include <media/dvb_frontend.h>
0019 #include "ves1820.h"
0020 
0021 
0022 
0023 struct ves1820_state {
0024     struct i2c_adapter* i2c;
0025     /* configuration settings */
0026     const struct ves1820_config* config;
0027     struct dvb_frontend frontend;
0028 
0029     /* private demodulator data */
0030     u8 reg0;
0031     u8 pwm;
0032 };
0033 
0034 
0035 static int verbose;
0036 
0037 static u8 ves1820_inittab[] = {
0038     0x69, 0x6A, 0x93, 0x1A, 0x12, 0x46, 0x26, 0x1A,
0039     0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
0040     0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
0041     0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0042     0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0043     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0044     0x00, 0x00, 0x00, 0x00, 0x40
0045 };
0046 
0047 static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
0048 {
0049     u8 buf[] = { 0x00, reg, data };
0050     struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 };
0051     int ret;
0052 
0053     ret = i2c_transfer(state->i2c, &msg, 1);
0054 
0055     if (ret != 1)
0056         printk("ves1820: %s(): writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
0057                __func__, reg, data, ret);
0058 
0059     return (ret != 1) ? -EREMOTEIO : 0;
0060 }
0061 
0062 static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
0063 {
0064     u8 b0[] = { 0x00, reg };
0065     u8 b1[] = { 0 };
0066     struct i2c_msg msg[] = {
0067         {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2},
0068         {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
0069     };
0070     int ret;
0071 
0072     ret = i2c_transfer(state->i2c, msg, 2);
0073 
0074     if (ret != 2)
0075         printk("ves1820: %s(): readreg error (reg == 0x%02x, ret == %i)\n",
0076                __func__, reg, ret);
0077 
0078     return b1[0];
0079 }
0080 
0081 static int ves1820_setup_reg0(struct ves1820_state *state,
0082                   u8 reg0, enum fe_spectral_inversion inversion)
0083 {
0084     reg0 |= state->reg0 & 0x62;
0085 
0086     if (INVERSION_ON == inversion) {
0087         if (!state->config->invert) reg0 |= 0x20;
0088         else reg0 &= ~0x20;
0089     } else if (INVERSION_OFF == inversion) {
0090         if (!state->config->invert) reg0 &= ~0x20;
0091         else reg0 |= 0x20;
0092     }
0093 
0094     ves1820_writereg(state, 0x00, reg0 & 0xfe);
0095     ves1820_writereg(state, 0x00, reg0 | 0x01);
0096 
0097     state->reg0 = reg0;
0098 
0099     return 0;
0100 }
0101 
0102 static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
0103 {
0104     s32 BDR;
0105     s32 BDRI;
0106     s16 SFIL = 0;
0107     u16 NDEC = 0;
0108     u32 ratio;
0109     u32 fin;
0110     u32 tmp;
0111     u64 fptmp;
0112     u64 fpxin;
0113 
0114     if (symbolrate > state->config->xin / 2)
0115         symbolrate = state->config->xin / 2;
0116 
0117     if (symbolrate < 500000)
0118         symbolrate = 500000;
0119 
0120     if (symbolrate < state->config->xin / 16)
0121         NDEC = 1;
0122     if (symbolrate < state->config->xin / 32)
0123         NDEC = 2;
0124     if (symbolrate < state->config->xin / 64)
0125         NDEC = 3;
0126 
0127     /* yeuch! */
0128     fpxin = state->config->xin * 10ULL;
0129     fptmp = fpxin; do_div(fptmp, 123);
0130     if (symbolrate < fptmp)
0131         SFIL = 1;
0132     fptmp = fpxin; do_div(fptmp, 160);
0133     if (symbolrate < fptmp)
0134         SFIL = 0;
0135     fptmp = fpxin; do_div(fptmp, 246);
0136     if (symbolrate < fptmp)
0137         SFIL = 1;
0138     fptmp = fpxin; do_div(fptmp, 320);
0139     if (symbolrate < fptmp)
0140         SFIL = 0;
0141     fptmp = fpxin; do_div(fptmp, 492);
0142     if (symbolrate < fptmp)
0143         SFIL = 1;
0144     fptmp = fpxin; do_div(fptmp, 640);
0145     if (symbolrate < fptmp)
0146         SFIL = 0;
0147     fptmp = fpxin; do_div(fptmp, 984);
0148     if (symbolrate < fptmp)
0149         SFIL = 1;
0150 
0151     fin = state->config->xin >> 4;
0152     symbolrate <<= NDEC;
0153     ratio = (symbolrate << 4) / fin;
0154     tmp = ((symbolrate << 4) % fin) << 8;
0155     ratio = (ratio << 8) + tmp / fin;
0156     tmp = (tmp % fin) << 8;
0157     ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, fin);
0158 
0159     BDR = ratio;
0160     BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2;
0161 
0162     if (BDRI > 0xFF)
0163         BDRI = 0xFF;
0164 
0165     SFIL = (SFIL << 4) | ves1820_inittab[0x0E];
0166 
0167     NDEC = (NDEC << 6) | ves1820_inittab[0x03];
0168 
0169     ves1820_writereg(state, 0x03, NDEC);
0170     ves1820_writereg(state, 0x0a, BDR & 0xff);
0171     ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff);
0172     ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f);
0173 
0174     ves1820_writereg(state, 0x0d, BDRI);
0175     ves1820_writereg(state, 0x0e, SFIL);
0176 
0177     return 0;
0178 }
0179 
0180 static int ves1820_init(struct dvb_frontend* fe)
0181 {
0182     struct ves1820_state* state = fe->demodulator_priv;
0183     int i;
0184 
0185     ves1820_writereg(state, 0, 0);
0186 
0187     for (i = 0; i < sizeof(ves1820_inittab); i++)
0188         ves1820_writereg(state, i, ves1820_inittab[i]);
0189     if (state->config->selagc)
0190         ves1820_writereg(state, 2, ves1820_inittab[2] | 0x08);
0191 
0192     ves1820_writereg(state, 0x34, state->pwm);
0193 
0194     return 0;
0195 }
0196 
0197 static int ves1820_set_parameters(struct dvb_frontend *fe)
0198 {
0199     struct dtv_frontend_properties *p = &fe->dtv_property_cache;
0200     struct ves1820_state* state = fe->demodulator_priv;
0201     static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
0202     static const u8 reg0x01[] = { 140, 140, 106, 100, 92 };
0203     static const u8 reg0x05[] = { 135, 100, 70, 54, 38 };
0204     static const u8 reg0x08[] = { 162, 116, 67, 52, 35 };
0205     static const u8 reg0x09[] = { 145, 150, 106, 126, 107 };
0206     int real_qam = p->modulation - QAM_16;
0207 
0208     if (real_qam < 0 || real_qam > 4)
0209         return -EINVAL;
0210 
0211     if (fe->ops.tuner_ops.set_params) {
0212         fe->ops.tuner_ops.set_params(fe);
0213         if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
0214     }
0215 
0216     ves1820_set_symbolrate(state, p->symbol_rate);
0217     ves1820_writereg(state, 0x34, state->pwm);
0218 
0219     ves1820_writereg(state, 0x01, reg0x01[real_qam]);
0220     ves1820_writereg(state, 0x05, reg0x05[real_qam]);
0221     ves1820_writereg(state, 0x08, reg0x08[real_qam]);
0222     ves1820_writereg(state, 0x09, reg0x09[real_qam]);
0223 
0224     ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion);
0225     ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0));
0226     return 0;
0227 }
0228 
0229 static int ves1820_read_status(struct dvb_frontend *fe,
0230                    enum fe_status *status)
0231 {
0232     struct ves1820_state* state = fe->demodulator_priv;
0233     int sync;
0234 
0235     *status = 0;
0236     sync = ves1820_readreg(state, 0x11);
0237 
0238     if (sync & 1)
0239         *status |= FE_HAS_SIGNAL;
0240 
0241     if (sync & 2)
0242         *status |= FE_HAS_CARRIER;
0243 
0244     if (sync & 2)   /* XXX FIXME! */
0245         *status |= FE_HAS_VITERBI;
0246 
0247     if (sync & 4)
0248         *status |= FE_HAS_SYNC;
0249 
0250     if (sync & 8)
0251         *status |= FE_HAS_LOCK;
0252 
0253     return 0;
0254 }
0255 
0256 static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber)
0257 {
0258     struct ves1820_state* state = fe->demodulator_priv;
0259 
0260     u32 _ber = ves1820_readreg(state, 0x14) |
0261             (ves1820_readreg(state, 0x15) << 8) |
0262             ((ves1820_readreg(state, 0x16) & 0x0f) << 16);
0263     *ber = 10 * _ber;
0264 
0265     return 0;
0266 }
0267 
0268 static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength)
0269 {
0270     struct ves1820_state* state = fe->demodulator_priv;
0271 
0272     u8 gain = ves1820_readreg(state, 0x17);
0273     *strength = (gain << 8) | gain;
0274 
0275     return 0;
0276 }
0277 
0278 static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr)
0279 {
0280     struct ves1820_state* state = fe->demodulator_priv;
0281 
0282     u8 quality = ~ves1820_readreg(state, 0x18);
0283     *snr = (quality << 8) | quality;
0284 
0285     return 0;
0286 }
0287 
0288 static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
0289 {
0290     struct ves1820_state* state = fe->demodulator_priv;
0291 
0292     *ucblocks = ves1820_readreg(state, 0x13) & 0x7f;
0293     if (*ucblocks == 0x7f)
0294         *ucblocks = 0xffffffff;
0295 
0296     /* reset uncorrected block counter */
0297     ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
0298     ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
0299 
0300     return 0;
0301 }
0302 
0303 static int ves1820_get_frontend(struct dvb_frontend *fe,
0304                 struct dtv_frontend_properties *p)
0305 {
0306     struct ves1820_state* state = fe->demodulator_priv;
0307     int sync;
0308     s8 afc = 0;
0309 
0310     sync = ves1820_readreg(state, 0x11);
0311     afc = ves1820_readreg(state, 0x19);
0312     if (verbose) {
0313         /* AFC only valid when carrier has been recovered */
0314         printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
0315             "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->symbol_rate * afc) >> 10);
0316     }
0317 
0318     if (!state->config->invert) {
0319         p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF;
0320     } else {
0321         p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF;
0322     }
0323 
0324     p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
0325 
0326     p->fec_inner = FEC_NONE;
0327 
0328     p->frequency = ((p->frequency + 31250) / 62500) * 62500;
0329     if (sync & 2)
0330         p->frequency -= ((s32) p->symbol_rate * afc) >> 10;
0331 
0332     return 0;
0333 }
0334 
0335 static int ves1820_sleep(struct dvb_frontend* fe)
0336 {
0337     struct ves1820_state* state = fe->demodulator_priv;
0338 
0339     ves1820_writereg(state, 0x1b, 0x02);    /* pdown ADC */
0340     ves1820_writereg(state, 0x00, 0x80);    /* standby */
0341 
0342     return 0;
0343 }
0344 
0345 static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
0346 {
0347 
0348     fesettings->min_delay_ms = 200;
0349     fesettings->step_size = 0;
0350     fesettings->max_drift = 0;
0351     return 0;
0352 }
0353 
0354 static void ves1820_release(struct dvb_frontend* fe)
0355 {
0356     struct ves1820_state* state = fe->demodulator_priv;
0357     kfree(state);
0358 }
0359 
0360 static const struct dvb_frontend_ops ves1820_ops;
0361 
0362 struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
0363                     struct i2c_adapter* i2c,
0364                     u8 pwm)
0365 {
0366     struct ves1820_state* state = NULL;
0367 
0368     /* allocate memory for the internal state */
0369     state = kzalloc(sizeof(struct ves1820_state), GFP_KERNEL);
0370     if (state == NULL)
0371         goto error;
0372 
0373     /* setup the state */
0374     state->reg0 = ves1820_inittab[0];
0375     state->config = config;
0376     state->i2c = i2c;
0377     state->pwm = pwm;
0378 
0379     /* check if the demod is there */
0380     if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70)
0381         goto error;
0382 
0383     if (verbose)
0384         printk("ves1820: pwm=0x%02x\n", state->pwm);
0385 
0386     /* create dvb_frontend */
0387     memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
0388     state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64;      /* SACLK/64 == (XIN/2)/64 */
0389     state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4;       /* SACLK/4 */
0390     state->frontend.demodulator_priv = state;
0391 
0392     return &state->frontend;
0393 
0394 error:
0395     kfree(state);
0396     return NULL;
0397 }
0398 
0399 static const struct dvb_frontend_ops ves1820_ops = {
0400     .delsys = { SYS_DVBC_ANNEX_A },
0401     .info = {
0402         .name = "VLSI VES1820 DVB-C",
0403         .frequency_min_hz =  47 * MHz,
0404         .frequency_max_hz = 862 * MHz,
0405         .frequency_stepsize_hz = 62500,
0406         .caps = FE_CAN_QAM_16 |
0407             FE_CAN_QAM_32 |
0408             FE_CAN_QAM_64 |
0409             FE_CAN_QAM_128 |
0410             FE_CAN_QAM_256 |
0411             FE_CAN_FEC_AUTO
0412     },
0413 
0414     .release = ves1820_release,
0415 
0416     .init = ves1820_init,
0417     .sleep = ves1820_sleep,
0418 
0419     .set_frontend = ves1820_set_parameters,
0420     .get_frontend = ves1820_get_frontend,
0421     .get_tune_settings = ves1820_get_tune_settings,
0422 
0423     .read_status = ves1820_read_status,
0424     .read_ber = ves1820_read_ber,
0425     .read_signal_strength = ves1820_read_signal_strength,
0426     .read_snr = ves1820_read_snr,
0427     .read_ucblocks = ves1820_read_ucblocks,
0428 };
0429 
0430 module_param(verbose, int, 0644);
0431 MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
0432 
0433 MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver");
0434 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
0435 MODULE_LICENSE("GPL");
0436 
0437 EXPORT_SYMBOL(ves1820_attach);