linux/drivers/media/tuners/tda18212.c
<<
>>
Prefs
   1/*
   2 * NXP TDA18212HN silicon tuner driver
   3 *
   4 * Copyright (C) 2011 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#include "tda18212.h"
  22#include <linux/regmap.h>
  23
  24struct tda18212_dev {
  25        struct tda18212_config cfg;
  26        struct i2c_client *client;
  27        struct regmap *regmap;
  28
  29        u32 if_frequency;
  30};
  31
  32static int tda18212_set_params(struct dvb_frontend *fe)
  33{
  34        struct tda18212_dev *dev = fe->tuner_priv;
  35        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
  36        int ret, i;
  37        u32 if_khz;
  38        u8 buf[9];
  39        #define DVBT_6   0
  40        #define DVBT_7   1
  41        #define DVBT_8   2
  42        #define DVBT2_6  3
  43        #define DVBT2_7  4
  44        #define DVBT2_8  5
  45        #define DVBC_6   6
  46        #define DVBC_8   7
  47        #define ATSC_VSB 8
  48        #define ATSC_QAM 9
  49        static const u8 bw_params[][3] = {
  50                     /* reg:   0f    13    23 */
  51                [DVBT_6]  = { 0xb3, 0x20, 0x03 },
  52                [DVBT_7]  = { 0xb3, 0x31, 0x01 },
  53                [DVBT_8]  = { 0xb3, 0x22, 0x01 },
  54                [DVBT2_6] = { 0xbc, 0x20, 0x03 },
  55                [DVBT2_7] = { 0xbc, 0x72, 0x03 },
  56                [DVBT2_8] = { 0xbc, 0x22, 0x01 },
  57                [DVBC_6]  = { 0x92, 0x50, 0x03 },
  58                [DVBC_8]  = { 0x92, 0x53, 0x03 },
  59                [ATSC_VSB] = { 0x7d, 0x20, 0x63 },
  60                [ATSC_QAM] = { 0x7d, 0x20, 0x63 },
  61        };
  62
  63        dev_dbg(&dev->client->dev,
  64                        "delivery_system=%d frequency=%d bandwidth_hz=%d\n",
  65                        c->delivery_system, c->frequency,
  66                        c->bandwidth_hz);
  67
  68        if (fe->ops.i2c_gate_ctrl)
  69                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
  70
  71        switch (c->delivery_system) {
  72        case SYS_ATSC:
  73                if_khz = dev->cfg.if_atsc_vsb;
  74                i = ATSC_VSB;
  75                break;
  76        case SYS_DVBC_ANNEX_B:
  77                if_khz = dev->cfg.if_atsc_qam;
  78                i = ATSC_QAM;
  79                break;
  80        case SYS_DVBT:
  81                switch (c->bandwidth_hz) {
  82                case 6000000:
  83                        if_khz = dev->cfg.if_dvbt_6;
  84                        i = DVBT_6;
  85                        break;
  86                case 7000000:
  87                        if_khz = dev->cfg.if_dvbt_7;
  88                        i = DVBT_7;
  89                        break;
  90                case 8000000:
  91                        if_khz = dev->cfg.if_dvbt_8;
  92                        i = DVBT_8;
  93                        break;
  94                default:
  95                        ret = -EINVAL;
  96                        goto error;
  97                }
  98                break;
  99        case SYS_DVBT2:
 100                switch (c->bandwidth_hz) {
 101                case 6000000:
 102                        if_khz = dev->cfg.if_dvbt2_6;
 103                        i = DVBT2_6;
 104                        break;
 105                case 7000000:
 106                        if_khz = dev->cfg.if_dvbt2_7;
 107                        i = DVBT2_7;
 108                        break;
 109                case 8000000:
 110                        if_khz = dev->cfg.if_dvbt2_8;
 111                        i = DVBT2_8;
 112                        break;
 113                default:
 114                        ret = -EINVAL;
 115                        goto error;
 116                }
 117                break;
 118        case SYS_DVBC_ANNEX_A:
 119        case SYS_DVBC_ANNEX_C:
 120                if_khz = dev->cfg.if_dvbc;
 121                i = DVBC_8;
 122                break;
 123        default:
 124                ret = -EINVAL;
 125                goto error;
 126        }
 127
 128        ret = regmap_write(dev->regmap, 0x23, bw_params[i][2]);
 129        if (ret)
 130                goto error;
 131
 132        ret = regmap_write(dev->regmap, 0x06, 0x00);
 133        if (ret)
 134                goto error;
 135
 136        ret = regmap_write(dev->regmap, 0x0f, bw_params[i][0]);
 137        if (ret)
 138                goto error;
 139
 140        buf[0] = 0x02;
 141        buf[1] = bw_params[i][1];
 142        buf[2] = 0x03; /* default value */
 143        buf[3] = DIV_ROUND_CLOSEST(if_khz, 50);
 144        buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
 145        buf[5] = ((c->frequency / 1000) >>  8) & 0xff;
 146        buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
 147        buf[7] = 0xc1;
 148        buf[8] = 0x01;
 149        ret = regmap_bulk_write(dev->regmap, 0x12, buf, sizeof(buf));
 150        if (ret)
 151                goto error;
 152
 153        /* actual IF rounded as it is on register */
 154        dev->if_frequency = buf[3] * 50 * 1000;
 155
 156exit:
 157        if (fe->ops.i2c_gate_ctrl)
 158                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 159
 160        return ret;
 161
 162error:
 163        dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 164        goto exit;
 165}
 166
 167static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 168{
 169        struct tda18212_dev *dev = fe->tuner_priv;
 170
 171        *frequency = dev->if_frequency;
 172
 173        return 0;
 174}
 175
 176static const struct dvb_tuner_ops tda18212_tuner_ops = {
 177        .info = {
 178                .name           = "NXP TDA18212",
 179
 180                .frequency_min  =  48000000,
 181                .frequency_max  = 864000000,
 182                .frequency_step =      1000,
 183        },
 184
 185        .set_params    = tda18212_set_params,
 186        .get_if_frequency = tda18212_get_if_frequency,
 187};
 188
 189static int tda18212_probe(struct i2c_client *client,
 190                const struct i2c_device_id *id)
 191{
 192        struct tda18212_config *cfg = client->dev.platform_data;
 193        struct dvb_frontend *fe = cfg->fe;
 194        struct tda18212_dev *dev;
 195        int ret;
 196        unsigned int chip_id;
 197        char *version;
 198        static const struct regmap_config regmap_config = {
 199                .reg_bits = 8,
 200                .val_bits = 8,
 201        };
 202
 203        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 204        if (dev == NULL) {
 205                ret = -ENOMEM;
 206                dev_err(&client->dev, "kzalloc() failed\n");
 207                goto err;
 208        }
 209
 210        memcpy(&dev->cfg, cfg, sizeof(struct tda18212_config));
 211        dev->client = client;
 212        dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
 213        if (IS_ERR(dev->regmap)) {
 214                ret = PTR_ERR(dev->regmap);
 215                goto err;
 216        }
 217
 218        /* check if the tuner is there */
 219        if (fe->ops.i2c_gate_ctrl)
 220                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 221
 222        ret = regmap_read(dev->regmap, 0x00, &chip_id);
 223        dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id);
 224
 225        if (fe->ops.i2c_gate_ctrl)
 226                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 227
 228        if (ret)
 229                goto err;
 230
 231        switch (chip_id) {
 232        case 0xc7:
 233                version = "M"; /* master */
 234                break;
 235        case 0x47:
 236                version = "S"; /* slave */
 237                break;
 238        default:
 239                ret = -ENODEV;
 240                goto err;
 241        }
 242
 243        dev_info(&dev->client->dev,
 244                        "NXP TDA18212HN/%s successfully identified\n", version);
 245
 246        fe->tuner_priv = dev;
 247        memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
 248                        sizeof(struct dvb_tuner_ops));
 249        i2c_set_clientdata(client, dev);
 250
 251        return 0;
 252err:
 253        dev_dbg(&client->dev, "failed=%d\n", ret);
 254        kfree(dev);
 255        return ret;
 256}
 257
 258static int tda18212_remove(struct i2c_client *client)
 259{
 260        struct tda18212_dev *dev = i2c_get_clientdata(client);
 261        struct dvb_frontend *fe = dev->cfg.fe;
 262
 263        dev_dbg(&client->dev, "\n");
 264
 265        memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
 266        fe->tuner_priv = NULL;
 267        kfree(dev);
 268
 269        return 0;
 270}
 271
 272static const struct i2c_device_id tda18212_id[] = {
 273        {"tda18212", 0},
 274        {}
 275};
 276MODULE_DEVICE_TABLE(i2c, tda18212_id);
 277
 278static struct i2c_driver tda18212_driver = {
 279        .driver = {
 280                .name   = "tda18212",
 281        },
 282        .probe          = tda18212_probe,
 283        .remove         = tda18212_remove,
 284        .id_table       = tda18212_id,
 285};
 286
 287module_i2c_driver(tda18212_driver);
 288
 289MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
 290MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 291MODULE_LICENSE("GPL");
 292