linux/drivers/media/dvb-frontends/cxd2820r_t.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Sony CXD2820R demodulator driver
   4 *
   5 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
   6 */
   7
   8
   9#include "cxd2820r_priv.h"
  10
  11int cxd2820r_set_frontend_t(struct dvb_frontend *fe)
  12{
  13        struct cxd2820r_priv *priv = fe->demodulator_priv;
  14        struct i2c_client *client = priv->client[0];
  15        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
  16        int ret, bw_i;
  17        unsigned int utmp;
  18        u32 if_frequency;
  19        u8 buf[3], bw_param;
  20        u8 bw_params1[][5] = {
  21                { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
  22                { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
  23                { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
  24        };
  25        u8 bw_params2[][2] = {
  26                { 0x1f, 0xdc }, /* 6 MHz */
  27                { 0x12, 0xf8 }, /* 7 MHz */
  28                { 0x01, 0xe0 }, /* 8 MHz */
  29        };
  30        struct reg_val_mask tab[] = {
  31                { 0x00080, 0x00, 0xff },
  32                { 0x00081, 0x03, 0xff },
  33                { 0x00085, 0x07, 0xff },
  34                { 0x00088, 0x01, 0xff },
  35
  36                { 0x00070, priv->ts_mode, 0xff },
  37                { 0x00071, !priv->ts_clk_inv << 4, 0x10 },
  38                { 0x000cb, priv->if_agc_polarity << 6, 0x40 },
  39                { 0x000a5, 0x00, 0x01 },
  40                { 0x00082, 0x20, 0x60 },
  41                { 0x000c2, 0xc3, 0xff },
  42                { 0x0016a, 0x50, 0xff },
  43                { 0x00427, 0x41, 0xff },
  44        };
  45
  46        dev_dbg(&client->dev,
  47                "delivery_system=%d modulation=%d frequency=%u bandwidth_hz=%u inversion=%d\n",
  48                c->delivery_system, c->modulation, c->frequency,
  49                c->bandwidth_hz, c->inversion);
  50
  51        switch (c->bandwidth_hz) {
  52        case 6000000:
  53                bw_i = 0;
  54                bw_param = 2;
  55                break;
  56        case 7000000:
  57                bw_i = 1;
  58                bw_param = 1;
  59                break;
  60        case 8000000:
  61                bw_i = 2;
  62                bw_param = 0;
  63                break;
  64        default:
  65                return -EINVAL;
  66        }
  67
  68        /* program tuner */
  69        if (fe->ops.tuner_ops.set_params)
  70                fe->ops.tuner_ops.set_params(fe);
  71
  72        if (priv->delivery_system != SYS_DVBT) {
  73                ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab));
  74                if (ret)
  75                        goto error;
  76        }
  77
  78        priv->delivery_system = SYS_DVBT;
  79        priv->ber_running = false; /* tune stops BER counter */
  80
  81        /* program IF frequency */
  82        if (fe->ops.tuner_ops.get_if_frequency) {
  83                ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
  84                if (ret)
  85                        goto error;
  86                dev_dbg(&client->dev, "if_frequency=%u\n", if_frequency);
  87        } else {
  88                ret = -EINVAL;
  89                goto error;
  90        }
  91
  92        utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x1000000, CXD2820R_CLK);
  93        buf[0] = (utmp >> 16) & 0xff;
  94        buf[1] = (utmp >>  8) & 0xff;
  95        buf[2] = (utmp >>  0) & 0xff;
  96        ret = regmap_bulk_write(priv->regmap[0], 0x00b6, buf, 3);
  97        if (ret)
  98                goto error;
  99
 100        ret = regmap_bulk_write(priv->regmap[0], 0x009f, bw_params1[bw_i], 5);
 101        if (ret)
 102                goto error;
 103
 104        ret = regmap_update_bits(priv->regmap[0], 0x00d7, 0xc0, bw_param << 6);
 105        if (ret)
 106                goto error;
 107
 108        ret = regmap_bulk_write(priv->regmap[0], 0x00d9, bw_params2[bw_i], 2);
 109        if (ret)
 110                goto error;
 111
 112        ret = regmap_write(priv->regmap[0], 0x00ff, 0x08);
 113        if (ret)
 114                goto error;
 115
 116        ret = regmap_write(priv->regmap[0], 0x00fe, 0x01);
 117        if (ret)
 118                goto error;
 119
 120        return ret;
 121error:
 122        dev_dbg(&client->dev, "failed=%d\n", ret);
 123        return ret;
 124}
 125
 126int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
 127                            struct dtv_frontend_properties *c)
 128{
 129        struct cxd2820r_priv *priv = fe->demodulator_priv;
 130        struct i2c_client *client = priv->client[0];
 131        int ret;
 132        unsigned int utmp;
 133        u8 buf[2];
 134
 135        dev_dbg(&client->dev, "\n");
 136
 137        ret = regmap_bulk_read(priv->regmap[0], 0x002f, buf, sizeof(buf));
 138        if (ret)
 139                goto error;
 140
 141        switch ((buf[0] >> 6) & 0x03) {
 142        case 0:
 143                c->modulation = QPSK;
 144                break;
 145        case 1:
 146                c->modulation = QAM_16;
 147                break;
 148        case 2:
 149                c->modulation = QAM_64;
 150                break;
 151        }
 152
 153        switch ((buf[1] >> 1) & 0x03) {
 154        case 0:
 155                c->transmission_mode = TRANSMISSION_MODE_2K;
 156                break;
 157        case 1:
 158                c->transmission_mode = TRANSMISSION_MODE_8K;
 159                break;
 160        }
 161
 162        switch ((buf[1] >> 3) & 0x03) {
 163        case 0:
 164                c->guard_interval = GUARD_INTERVAL_1_32;
 165                break;
 166        case 1:
 167                c->guard_interval = GUARD_INTERVAL_1_16;
 168                break;
 169        case 2:
 170                c->guard_interval = GUARD_INTERVAL_1_8;
 171                break;
 172        case 3:
 173                c->guard_interval = GUARD_INTERVAL_1_4;
 174                break;
 175        }
 176
 177        switch ((buf[0] >> 3) & 0x07) {
 178        case 0:
 179                c->hierarchy = HIERARCHY_NONE;
 180                break;
 181        case 1:
 182                c->hierarchy = HIERARCHY_1;
 183                break;
 184        case 2:
 185                c->hierarchy = HIERARCHY_2;
 186                break;
 187        case 3:
 188                c->hierarchy = HIERARCHY_4;
 189                break;
 190        }
 191
 192        switch ((buf[0] >> 0) & 0x07) {
 193        case 0:
 194                c->code_rate_HP = FEC_1_2;
 195                break;
 196        case 1:
 197                c->code_rate_HP = FEC_2_3;
 198                break;
 199        case 2:
 200                c->code_rate_HP = FEC_3_4;
 201                break;
 202        case 3:
 203                c->code_rate_HP = FEC_5_6;
 204                break;
 205        case 4:
 206                c->code_rate_HP = FEC_7_8;
 207                break;
 208        }
 209
 210        switch ((buf[1] >> 5) & 0x07) {
 211        case 0:
 212                c->code_rate_LP = FEC_1_2;
 213                break;
 214        case 1:
 215                c->code_rate_LP = FEC_2_3;
 216                break;
 217        case 2:
 218                c->code_rate_LP = FEC_3_4;
 219                break;
 220        case 3:
 221                c->code_rate_LP = FEC_5_6;
 222                break;
 223        case 4:
 224                c->code_rate_LP = FEC_7_8;
 225                break;
 226        }
 227
 228        ret = regmap_read(priv->regmap[0], 0x07c6, &utmp);
 229        if (ret)
 230                goto error;
 231
 232        switch ((utmp >> 0) & 0x01) {
 233        case 0:
 234                c->inversion = INVERSION_OFF;
 235                break;
 236        case 1:
 237                c->inversion = INVERSION_ON;
 238                break;
 239        }
 240
 241        return ret;
 242error:
 243        dev_dbg(&client->dev, "failed=%d\n", ret);
 244        return ret;
 245}
 246
 247int cxd2820r_read_status_t(struct dvb_frontend *fe, enum fe_status *status)
 248{
 249        struct cxd2820r_priv *priv = fe->demodulator_priv;
 250        struct i2c_client *client = priv->client[0];
 251        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 252        int ret;
 253        unsigned int utmp, utmp1, utmp2;
 254        u8 buf[3];
 255
 256        /* Lock detection */
 257        ret = regmap_bulk_read(priv->regmap[0], 0x0010, &buf[0], 1);
 258        if (ret)
 259                goto error;
 260        ret = regmap_bulk_read(priv->regmap[0], 0x0073, &buf[1], 1);
 261        if (ret)
 262                goto error;
 263
 264        utmp1 = (buf[0] >> 0) & 0x07;
 265        utmp2 = (buf[1] >> 3) & 0x01;
 266
 267        if (utmp1 == 6 && utmp2 == 1) {
 268                *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
 269                          FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 270        } else if (utmp1 == 6 || utmp2 == 1) {
 271                *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
 272                          FE_HAS_VITERBI | FE_HAS_SYNC;
 273        } else {
 274                *status = 0;
 275        }
 276
 277        dev_dbg(&client->dev, "status=%02x raw=%*ph sync=%u ts=%u\n",
 278                *status, 2, buf, utmp1, utmp2);
 279
 280        /* Signal strength */
 281        if (*status & FE_HAS_SIGNAL) {
 282                unsigned int strength;
 283
 284                ret = regmap_bulk_read(priv->regmap[0], 0x0026, buf, 2);
 285                if (ret)
 286                        goto error;
 287
 288                utmp = buf[0] << 8 | buf[1] << 0;
 289                utmp = ~utmp & 0x0fff;
 290                /* Scale value to 0x0000-0xffff */
 291                strength = utmp << 4 | utmp >> 8;
 292
 293                c->strength.len = 1;
 294                c->strength.stat[0].scale = FE_SCALE_RELATIVE;
 295                c->strength.stat[0].uvalue = strength;
 296        } else {
 297                c->strength.len = 1;
 298                c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 299        }
 300
 301        /* CNR */
 302        if (*status & FE_HAS_VITERBI) {
 303                unsigned int cnr;
 304
 305                ret = regmap_bulk_read(priv->regmap[0], 0x002c, buf, 2);
 306                if (ret)
 307                        goto error;
 308
 309                utmp = buf[0] << 8 | buf[1] << 0;
 310                if (utmp)
 311                        cnr = div_u64((u64)(intlog10(utmp)
 312                                      - intlog10(32000 - utmp) + 55532585)
 313                                      * 10000, (1 << 24));
 314                else
 315                        cnr = 0;
 316
 317                c->cnr.len = 1;
 318                c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
 319                c->cnr.stat[0].svalue = cnr;
 320        } else {
 321                c->cnr.len = 1;
 322                c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 323        }
 324
 325        /* BER */
 326        if (*status & FE_HAS_SYNC) {
 327                unsigned int post_bit_error;
 328                bool start_ber;
 329
 330                if (priv->ber_running) {
 331                        ret = regmap_bulk_read(priv->regmap[0], 0x0076, buf, 3);
 332                        if (ret)
 333                                goto error;
 334
 335                        if ((buf[2] >> 7) & 0x01) {
 336                                post_bit_error = buf[2] << 16 | buf[1] << 8 |
 337                                                 buf[0] << 0;
 338                                post_bit_error &= 0x0fffff;
 339                                start_ber = true;
 340                        } else {
 341                                post_bit_error = 0;
 342                                start_ber = false;
 343                        }
 344                } else {
 345                        post_bit_error = 0;
 346                        start_ber = true;
 347                }
 348
 349                if (start_ber) {
 350                        ret = regmap_write(priv->regmap[0], 0x0079, 0x01);
 351                        if (ret)
 352                                goto error;
 353                        priv->ber_running = true;
 354                }
 355
 356                priv->post_bit_error += post_bit_error;
 357
 358                c->post_bit_error.len = 1;
 359                c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
 360                c->post_bit_error.stat[0].uvalue = priv->post_bit_error;
 361        } else {
 362                c->post_bit_error.len = 1;
 363                c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 364        }
 365
 366        return ret;
 367error:
 368        dev_dbg(&client->dev, "failed=%d\n", ret);
 369        return ret;
 370}
 371
 372int cxd2820r_init_t(struct dvb_frontend *fe)
 373{
 374        struct cxd2820r_priv *priv = fe->demodulator_priv;
 375        struct i2c_client *client = priv->client[0];
 376        int ret;
 377
 378        dev_dbg(&client->dev, "\n");
 379
 380        ret = regmap_write(priv->regmap[0], 0x0085, 0x07);
 381        if (ret)
 382                goto error;
 383
 384        return ret;
 385error:
 386        dev_dbg(&client->dev, "failed=%d\n", ret);
 387        return ret;
 388}
 389
 390int cxd2820r_sleep_t(struct dvb_frontend *fe)
 391{
 392        struct cxd2820r_priv *priv = fe->demodulator_priv;
 393        struct i2c_client *client = priv->client[0];
 394        int ret;
 395        struct reg_val_mask tab[] = {
 396                { 0x000ff, 0x1f, 0xff },
 397                { 0x00085, 0x00, 0xff },
 398                { 0x00088, 0x01, 0xff },
 399                { 0x00081, 0x00, 0xff },
 400                { 0x00080, 0x00, 0xff },
 401        };
 402
 403        dev_dbg(&client->dev, "\n");
 404
 405        priv->delivery_system = SYS_UNDEFINED;
 406
 407        ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab));
 408        if (ret)
 409                goto error;
 410
 411        return ret;
 412error:
 413        dev_dbg(&client->dev, "failed=%d\n", ret);
 414        return ret;
 415}
 416
 417int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
 418        struct dvb_frontend_tune_settings *s)
 419{
 420        s->min_delay_ms = 500;
 421        s->step_size = fe->ops.info.frequency_stepsize_hz * 2;
 422        s->max_drift = (fe->ops.info.frequency_stepsize_hz * 2) + 1;
 423
 424        return 0;
 425}
 426