linux/drivers/media/dvb-frontends/cxd2820r_c.c
<<
>>
Prefs
   1/*
   2 * Sony CXD2820R demodulator driver
   3 *
   4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
   5 *
   6 *    This program is free software; you can redistribute it and/or modify
   7 *    it under the terms of the GNU General Public License as published by
   8 *    the Free Software Foundation; either version 2 of the License, or
   9 *    (at your option) any later version.
  10 *
  11 *    This program is distributed in the hope that it will be useful,
  12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *    GNU General Public License for more details.
  15 *
  16 *    You should have received a copy of the GNU General Public License along
  17 *    with this program; if not, write to the Free Software Foundation, Inc.,
  18 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19 */
  20
  21
  22#include "cxd2820r_priv.h"
  23
  24int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
  25{
  26        struct cxd2820r_priv *priv = fe->demodulator_priv;
  27        struct i2c_client *client = priv->client[0];
  28        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
  29        int ret;
  30        unsigned int utmp;
  31        u8 buf[2];
  32        u32 if_frequency;
  33        struct reg_val_mask tab[] = {
  34                { 0x00080, 0x01, 0xff },
  35                { 0x00081, 0x05, 0xff },
  36                { 0x00085, 0x07, 0xff },
  37                { 0x00088, 0x01, 0xff },
  38
  39                { 0x00082, 0x20, 0x60 },
  40                { 0x1016a, 0x48, 0xff },
  41                { 0x100a5, 0x00, 0x01 },
  42                { 0x10020, 0x06, 0x07 },
  43                { 0x10059, 0x50, 0xff },
  44                { 0x10087, 0x0c, 0x3c },
  45                { 0x1008b, 0x07, 0xff },
  46                { 0x1001f, priv->if_agc_polarity << 7, 0x80 },
  47                { 0x10070, priv->ts_mode, 0xff },
  48                { 0x10071, !priv->ts_clk_inv << 4, 0x10 },
  49        };
  50
  51        dev_dbg(&client->dev,
  52                "delivery_system=%d modulation=%d frequency=%u symbol_rate=%u inversion=%d\n",
  53                c->delivery_system, c->modulation, c->frequency,
  54                c->symbol_rate, c->inversion);
  55
  56        /* program tuner */
  57        if (fe->ops.tuner_ops.set_params)
  58                fe->ops.tuner_ops.set_params(fe);
  59
  60        if (priv->delivery_system !=  SYS_DVBC_ANNEX_A) {
  61                ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab));
  62                if (ret)
  63                        goto error;
  64        }
  65
  66        priv->delivery_system = SYS_DVBC_ANNEX_A;
  67        priv->ber_running = false; /* tune stops BER counter */
  68
  69        /* program IF frequency */
  70        if (fe->ops.tuner_ops.get_if_frequency) {
  71                ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
  72                if (ret)
  73                        goto error;
  74                dev_dbg(&client->dev, "if_frequency=%u\n", if_frequency);
  75        } else {
  76                ret = -EINVAL;
  77                goto error;
  78        }
  79
  80        utmp = 0x4000 - DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x4000, CXD2820R_CLK);
  81        buf[0] = (utmp >> 8) & 0xff;
  82        buf[1] = (utmp >> 0) & 0xff;
  83        ret = regmap_bulk_write(priv->regmap[1], 0x0042, buf, 2);
  84        if (ret)
  85                goto error;
  86
  87        ret = regmap_write(priv->regmap[0], 0x00ff, 0x08);
  88        if (ret)
  89                goto error;
  90
  91        ret = regmap_write(priv->regmap[0], 0x00fe, 0x01);
  92        if (ret)
  93                goto error;
  94
  95        return ret;
  96error:
  97        dev_dbg(&client->dev, "failed=%d\n", ret);
  98        return ret;
  99}
 100
 101int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
 102                            struct dtv_frontend_properties *c)
 103{
 104        struct cxd2820r_priv *priv = fe->demodulator_priv;
 105        struct i2c_client *client = priv->client[0];
 106        int ret;
 107        unsigned int utmp;
 108        u8 buf[2];
 109
 110        dev_dbg(&client->dev, "\n");
 111
 112        ret = regmap_bulk_read(priv->regmap[1], 0x001a, buf, 2);
 113        if (ret)
 114                goto error;
 115
 116        c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]);
 117
 118        ret = regmap_read(priv->regmap[1], 0x0019, &utmp);
 119        if (ret)
 120                goto error;
 121
 122        switch ((utmp >> 0) & 0x07) {
 123        case 0:
 124                c->modulation = QAM_16;
 125                break;
 126        case 1:
 127                c->modulation = QAM_32;
 128                break;
 129        case 2:
 130                c->modulation = QAM_64;
 131                break;
 132        case 3:
 133                c->modulation = QAM_128;
 134                break;
 135        case 4:
 136                c->modulation = QAM_256;
 137                break;
 138        }
 139
 140        switch ((utmp >> 7) & 0x01) {
 141        case 0:
 142                c->inversion = INVERSION_OFF;
 143                break;
 144        case 1:
 145                c->inversion = INVERSION_ON;
 146                break;
 147        }
 148
 149        return ret;
 150error:
 151        dev_dbg(&client->dev, "failed=%d\n", ret);
 152        return ret;
 153}
 154
 155int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status)
 156{
 157        struct cxd2820r_priv *priv = fe->demodulator_priv;
 158        struct i2c_client *client = priv->client[0];
 159        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 160        int ret;
 161        unsigned int utmp, utmp1, utmp2;
 162        u8 buf[3];
 163
 164        /* Lock detection */
 165        ret = regmap_bulk_read(priv->regmap[1], 0x0088, &buf[0], 1);
 166        if (ret)
 167                goto error;
 168        ret = regmap_bulk_read(priv->regmap[1], 0x0073, &buf[1], 1);
 169        if (ret)
 170                goto error;
 171
 172        utmp1 = (buf[0] >> 0) & 0x01;
 173        utmp2 = (buf[1] >> 3) & 0x01;
 174
 175        if (utmp1 == 1 && utmp2 == 1) {
 176                *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
 177                          FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 178        } else if (utmp1 == 1 || utmp2 == 1) {
 179                *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
 180                          FE_HAS_VITERBI | FE_HAS_SYNC;
 181        } else {
 182                *status = 0;
 183        }
 184
 185        dev_dbg(&client->dev, "status=%02x raw=%*ph sync=%u ts=%u\n",
 186                *status, 2, buf, utmp1, utmp2);
 187
 188        /* Signal strength */
 189        if (*status & FE_HAS_SIGNAL) {
 190                unsigned int strength;
 191
 192                ret = regmap_bulk_read(priv->regmap[1], 0x0049, buf, 2);
 193                if (ret)
 194                        goto error;
 195
 196                utmp = buf[0] << 8 | buf[1] << 0;
 197                utmp = 511 - sign_extend32(utmp, 9);
 198                /* Scale value to 0x0000-0xffff */
 199                strength = utmp << 6 | utmp >> 4;
 200
 201                c->strength.len = 1;
 202                c->strength.stat[0].scale = FE_SCALE_RELATIVE;
 203                c->strength.stat[0].uvalue = strength;
 204        } else {
 205                c->strength.len = 1;
 206                c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 207        }
 208
 209        /* CNR */
 210        if (*status & FE_HAS_VITERBI) {
 211                unsigned int cnr, const_a, const_b;
 212
 213                ret = regmap_read(priv->regmap[1], 0x0019, &utmp);
 214                if (ret)
 215                        goto error;
 216
 217                if (((utmp >> 0) & 0x03) % 2) {
 218                        const_a = 8750;
 219                        const_b = 650;
 220                } else {
 221                        const_a = 9500;
 222                        const_b = 760;
 223                }
 224
 225                ret = regmap_read(priv->regmap[1], 0x004d, &utmp);
 226                if (ret)
 227                        goto error;
 228
 229                #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */
 230                if (utmp)
 231                        cnr = div_u64((u64)(intlog2(const_b) - intlog2(utmp))
 232                                      * const_a, CXD2820R_LOG2_E_24);
 233                else
 234                        cnr = 0;
 235
 236                c->cnr.len = 1;
 237                c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
 238                c->cnr.stat[0].svalue = cnr;
 239        } else {
 240                c->cnr.len = 1;
 241                c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 242        }
 243
 244        /* BER */
 245        if (*status & FE_HAS_SYNC) {
 246                unsigned int post_bit_error;
 247                bool start_ber;
 248
 249                if (priv->ber_running) {
 250                        ret = regmap_bulk_read(priv->regmap[1], 0x0076, buf, 3);
 251                        if (ret)
 252                                goto error;
 253
 254                        if ((buf[2] >> 7) & 0x01) {
 255                                post_bit_error = buf[2] << 16 | buf[1] << 8 |
 256                                                 buf[0] << 0;
 257                                post_bit_error &= 0x0fffff;
 258                                start_ber = true;
 259                        } else {
 260                                post_bit_error = 0;
 261                                start_ber = false;
 262                        }
 263                } else {
 264                        post_bit_error = 0;
 265                        start_ber = true;
 266                }
 267
 268                if (start_ber) {
 269                        ret = regmap_write(priv->regmap[1], 0x0079, 0x01);
 270                        if (ret)
 271                                goto error;
 272                        priv->ber_running = true;
 273                }
 274
 275                priv->post_bit_error += post_bit_error;
 276
 277                c->post_bit_error.len = 1;
 278                c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
 279                c->post_bit_error.stat[0].uvalue = priv->post_bit_error;
 280        } else {
 281                c->post_bit_error.len = 1;
 282                c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 283        }
 284
 285        return ret;
 286error:
 287        dev_dbg(&client->dev, "failed=%d\n", ret);
 288        return ret;
 289}
 290
 291int cxd2820r_init_c(struct dvb_frontend *fe)
 292{
 293        struct cxd2820r_priv *priv = fe->demodulator_priv;
 294        struct i2c_client *client = priv->client[0];
 295        int ret;
 296
 297        dev_dbg(&client->dev, "\n");
 298
 299        ret = regmap_write(priv->regmap[0], 0x0085, 0x07);
 300        if (ret)
 301                goto error;
 302
 303        return ret;
 304error:
 305        dev_dbg(&client->dev, "failed=%d\n", ret);
 306        return ret;
 307}
 308
 309int cxd2820r_sleep_c(struct dvb_frontend *fe)
 310{
 311        struct cxd2820r_priv *priv = fe->demodulator_priv;
 312        struct i2c_client *client = priv->client[0];
 313        int ret;
 314        struct reg_val_mask tab[] = {
 315                { 0x000ff, 0x1f, 0xff },
 316                { 0x00085, 0x00, 0xff },
 317                { 0x00088, 0x01, 0xff },
 318                { 0x00081, 0x00, 0xff },
 319                { 0x00080, 0x00, 0xff },
 320        };
 321
 322        dev_dbg(&client->dev, "\n");
 323
 324        priv->delivery_system = SYS_UNDEFINED;
 325
 326        ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab));
 327        if (ret)
 328                goto error;
 329
 330        return ret;
 331error:
 332        dev_dbg(&client->dev, "failed=%d\n", ret);
 333        return ret;
 334}
 335
 336int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
 337        struct dvb_frontend_tune_settings *s)
 338{
 339        s->min_delay_ms = 500;
 340        s->step_size = 0; /* no zigzag */
 341        s->max_drift = 0;
 342
 343        return 0;
 344}
 345