Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Sony CXD2820R demodulator driver
0004  *
0005  * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
0006  */
0007 
0008 
0009 #include "cxd2820r_priv.h"
0010 
0011 int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
0012 {
0013     struct cxd2820r_priv *priv = fe->demodulator_priv;
0014     struct i2c_client *client = priv->client[0];
0015     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0016     int ret;
0017     unsigned int utmp;
0018     u8 buf[2];
0019     u32 if_frequency;
0020     struct reg_val_mask tab[] = {
0021         { 0x00080, 0x01, 0xff },
0022         { 0x00081, 0x05, 0xff },
0023         { 0x00085, 0x07, 0xff },
0024         { 0x00088, 0x01, 0xff },
0025 
0026         { 0x00082, 0x20, 0x60 },
0027         { 0x1016a, 0x48, 0xff },
0028         { 0x100a5, 0x00, 0x01 },
0029         { 0x10020, 0x06, 0x07 },
0030         { 0x10059, 0x50, 0xff },
0031         { 0x10087, 0x0c, 0x3c },
0032         { 0x1008b, 0x07, 0xff },
0033         { 0x1001f, priv->if_agc_polarity << 7, 0x80 },
0034         { 0x10070, priv->ts_mode, 0xff },
0035         { 0x10071, !priv->ts_clk_inv << 4, 0x10 },
0036     };
0037 
0038     dev_dbg(&client->dev,
0039         "delivery_system=%d modulation=%d frequency=%u symbol_rate=%u inversion=%d\n",
0040         c->delivery_system, c->modulation, c->frequency,
0041         c->symbol_rate, c->inversion);
0042 
0043     /* program tuner */
0044     if (fe->ops.tuner_ops.set_params)
0045         fe->ops.tuner_ops.set_params(fe);
0046 
0047     if (priv->delivery_system !=  SYS_DVBC_ANNEX_A) {
0048         ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab));
0049         if (ret)
0050             goto error;
0051     }
0052 
0053     priv->delivery_system = SYS_DVBC_ANNEX_A;
0054     priv->ber_running = false; /* tune stops BER counter */
0055 
0056     /* program IF frequency */
0057     if (fe->ops.tuner_ops.get_if_frequency) {
0058         ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
0059         if (ret)
0060             goto error;
0061         dev_dbg(&client->dev, "if_frequency=%u\n", if_frequency);
0062     } else {
0063         ret = -EINVAL;
0064         goto error;
0065     }
0066 
0067     utmp = 0x4000 - DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x4000, CXD2820R_CLK);
0068     buf[0] = (utmp >> 8) & 0xff;
0069     buf[1] = (utmp >> 0) & 0xff;
0070     ret = regmap_bulk_write(priv->regmap[1], 0x0042, buf, 2);
0071     if (ret)
0072         goto error;
0073 
0074     ret = regmap_write(priv->regmap[0], 0x00ff, 0x08);
0075     if (ret)
0076         goto error;
0077 
0078     ret = regmap_write(priv->regmap[0], 0x00fe, 0x01);
0079     if (ret)
0080         goto error;
0081 
0082     return ret;
0083 error:
0084     dev_dbg(&client->dev, "failed=%d\n", ret);
0085     return ret;
0086 }
0087 
0088 int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
0089                 struct dtv_frontend_properties *c)
0090 {
0091     struct cxd2820r_priv *priv = fe->demodulator_priv;
0092     struct i2c_client *client = priv->client[0];
0093     int ret;
0094     unsigned int utmp;
0095     u8 buf[2];
0096 
0097     dev_dbg(&client->dev, "\n");
0098 
0099     ret = regmap_bulk_read(priv->regmap[1], 0x001a, buf, 2);
0100     if (ret)
0101         goto error;
0102 
0103     c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]);
0104 
0105     ret = regmap_read(priv->regmap[1], 0x0019, &utmp);
0106     if (ret)
0107         goto error;
0108 
0109     switch ((utmp >> 0) & 0x07) {
0110     case 0:
0111         c->modulation = QAM_16;
0112         break;
0113     case 1:
0114         c->modulation = QAM_32;
0115         break;
0116     case 2:
0117         c->modulation = QAM_64;
0118         break;
0119     case 3:
0120         c->modulation = QAM_128;
0121         break;
0122     case 4:
0123         c->modulation = QAM_256;
0124         break;
0125     }
0126 
0127     switch ((utmp >> 7) & 0x01) {
0128     case 0:
0129         c->inversion = INVERSION_OFF;
0130         break;
0131     case 1:
0132         c->inversion = INVERSION_ON;
0133         break;
0134     }
0135 
0136     return ret;
0137 error:
0138     dev_dbg(&client->dev, "failed=%d\n", ret);
0139     return ret;
0140 }
0141 
0142 int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status)
0143 {
0144     struct cxd2820r_priv *priv = fe->demodulator_priv;
0145     struct i2c_client *client = priv->client[0];
0146     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0147     int ret;
0148     unsigned int utmp, utmp1, utmp2;
0149     u8 buf[3];
0150 
0151     /* Lock detection */
0152     ret = regmap_bulk_read(priv->regmap[1], 0x0088, &buf[0], 1);
0153     if (ret)
0154         goto error;
0155     ret = regmap_bulk_read(priv->regmap[1], 0x0073, &buf[1], 1);
0156     if (ret)
0157         goto error;
0158 
0159     utmp1 = (buf[0] >> 0) & 0x01;
0160     utmp2 = (buf[1] >> 3) & 0x01;
0161 
0162     if (utmp1 == 1 && utmp2 == 1) {
0163         *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
0164               FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
0165     } else if (utmp1 == 1 || utmp2 == 1) {
0166         *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
0167               FE_HAS_VITERBI | FE_HAS_SYNC;
0168     } else {
0169         *status = 0;
0170     }
0171 
0172     dev_dbg(&client->dev, "status=%02x raw=%*ph sync=%u ts=%u\n",
0173         *status, 2, buf, utmp1, utmp2);
0174 
0175     /* Signal strength */
0176     if (*status & FE_HAS_SIGNAL) {
0177         unsigned int strength;
0178 
0179         ret = regmap_bulk_read(priv->regmap[1], 0x0049, buf, 2);
0180         if (ret)
0181             goto error;
0182 
0183         utmp = buf[0] << 8 | buf[1] << 0;
0184         utmp = 511 - sign_extend32(utmp, 9);
0185         /* Scale value to 0x0000-0xffff */
0186         strength = utmp << 6 | utmp >> 4;
0187 
0188         c->strength.len = 1;
0189         c->strength.stat[0].scale = FE_SCALE_RELATIVE;
0190         c->strength.stat[0].uvalue = strength;
0191     } else {
0192         c->strength.len = 1;
0193         c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
0194     }
0195 
0196     /* CNR */
0197     if (*status & FE_HAS_VITERBI) {
0198         unsigned int cnr, const_a, const_b;
0199 
0200         ret = regmap_read(priv->regmap[1], 0x0019, &utmp);
0201         if (ret)
0202             goto error;
0203 
0204         if (((utmp >> 0) & 0x03) % 2) {
0205             const_a = 8750;
0206             const_b = 650;
0207         } else {
0208             const_a = 9500;
0209             const_b = 760;
0210         }
0211 
0212         ret = regmap_read(priv->regmap[1], 0x004d, &utmp);
0213         if (ret)
0214             goto error;
0215 
0216         #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */
0217         if (utmp)
0218             cnr = div_u64((u64)(intlog2(const_b) - intlog2(utmp))
0219                       * const_a, CXD2820R_LOG2_E_24);
0220         else
0221             cnr = 0;
0222 
0223         c->cnr.len = 1;
0224         c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
0225         c->cnr.stat[0].svalue = cnr;
0226     } else {
0227         c->cnr.len = 1;
0228         c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
0229     }
0230 
0231     /* BER */
0232     if (*status & FE_HAS_SYNC) {
0233         unsigned int post_bit_error;
0234         bool start_ber;
0235 
0236         if (priv->ber_running) {
0237             ret = regmap_bulk_read(priv->regmap[1], 0x0076, buf, 3);
0238             if (ret)
0239                 goto error;
0240 
0241             if ((buf[2] >> 7) & 0x01) {
0242                 post_bit_error = buf[2] << 16 | buf[1] << 8 |
0243                          buf[0] << 0;
0244                 post_bit_error &= 0x0fffff;
0245                 start_ber = true;
0246             } else {
0247                 post_bit_error = 0;
0248                 start_ber = false;
0249             }
0250         } else {
0251             post_bit_error = 0;
0252             start_ber = true;
0253         }
0254 
0255         if (start_ber) {
0256             ret = regmap_write(priv->regmap[1], 0x0079, 0x01);
0257             if (ret)
0258                 goto error;
0259             priv->ber_running = true;
0260         }
0261 
0262         priv->post_bit_error += post_bit_error;
0263 
0264         c->post_bit_error.len = 1;
0265         c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
0266         c->post_bit_error.stat[0].uvalue = priv->post_bit_error;
0267     } else {
0268         c->post_bit_error.len = 1;
0269         c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
0270     }
0271 
0272     return ret;
0273 error:
0274     dev_dbg(&client->dev, "failed=%d\n", ret);
0275     return ret;
0276 }
0277 
0278 int cxd2820r_init_c(struct dvb_frontend *fe)
0279 {
0280     struct cxd2820r_priv *priv = fe->demodulator_priv;
0281     struct i2c_client *client = priv->client[0];
0282     int ret;
0283 
0284     dev_dbg(&client->dev, "\n");
0285 
0286     ret = regmap_write(priv->regmap[0], 0x0085, 0x07);
0287     if (ret)
0288         goto error;
0289 
0290     return ret;
0291 error:
0292     dev_dbg(&client->dev, "failed=%d\n", ret);
0293     return ret;
0294 }
0295 
0296 int cxd2820r_sleep_c(struct dvb_frontend *fe)
0297 {
0298     struct cxd2820r_priv *priv = fe->demodulator_priv;
0299     struct i2c_client *client = priv->client[0];
0300     int ret;
0301     static const struct reg_val_mask tab[] = {
0302         { 0x000ff, 0x1f, 0xff },
0303         { 0x00085, 0x00, 0xff },
0304         { 0x00088, 0x01, 0xff },
0305         { 0x00081, 0x00, 0xff },
0306         { 0x00080, 0x00, 0xff },
0307     };
0308 
0309     dev_dbg(&client->dev, "\n");
0310 
0311     priv->delivery_system = SYS_UNDEFINED;
0312 
0313     ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab));
0314     if (ret)
0315         goto error;
0316 
0317     return ret;
0318 error:
0319     dev_dbg(&client->dev, "failed=%d\n", ret);
0320     return ret;
0321 }
0322 
0323 int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
0324     struct dvb_frontend_tune_settings *s)
0325 {
0326     s->min_delay_ms = 500;
0327     s->step_size = 0; /* no zigzag */
0328     s->max_drift = 0;
0329 
0330     return 0;
0331 }