Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * NXP TDA18212HN silicon tuner driver
0004  *
0005  * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
0006  */
0007 
0008 #include "tda18212.h"
0009 #include <linux/regmap.h>
0010 
0011 struct tda18212_dev {
0012     struct tda18212_config cfg;
0013     struct i2c_client *client;
0014     struct regmap *regmap;
0015 
0016     u32 if_frequency;
0017 };
0018 
0019 static int tda18212_set_params(struct dvb_frontend *fe)
0020 {
0021     struct tda18212_dev *dev = fe->tuner_priv;
0022     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0023     int ret, i;
0024     u32 if_khz;
0025     u8 buf[9];
0026     #define DVBT_6   0
0027     #define DVBT_7   1
0028     #define DVBT_8   2
0029     #define DVBT2_6  3
0030     #define DVBT2_7  4
0031     #define DVBT2_8  5
0032     #define DVBC_6   6
0033     #define DVBC_8   7
0034     #define ATSC_VSB 8
0035     #define ATSC_QAM 9
0036     static const u8 bw_params[][3] = {
0037              /* reg:   0f    13    23 */
0038         [DVBT_6]  = { 0xb3, 0x20, 0x03 },
0039         [DVBT_7]  = { 0xb3, 0x31, 0x01 },
0040         [DVBT_8]  = { 0xb3, 0x22, 0x01 },
0041         [DVBT2_6] = { 0xbc, 0x20, 0x03 },
0042         [DVBT2_7] = { 0xbc, 0x72, 0x03 },
0043         [DVBT2_8] = { 0xbc, 0x22, 0x01 },
0044         [DVBC_6]  = { 0x92, 0x50, 0x03 },
0045         [DVBC_8]  = { 0x92, 0x53, 0x03 },
0046         [ATSC_VSB] = { 0x7d, 0x20, 0x63 },
0047         [ATSC_QAM] = { 0x7d, 0x20, 0x63 },
0048     };
0049 
0050     dev_dbg(&dev->client->dev,
0051             "delivery_system=%d frequency=%d bandwidth_hz=%d\n",
0052             c->delivery_system, c->frequency,
0053             c->bandwidth_hz);
0054 
0055     if (fe->ops.i2c_gate_ctrl)
0056         fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
0057 
0058     switch (c->delivery_system) {
0059     case SYS_ATSC:
0060         if_khz = dev->cfg.if_atsc_vsb;
0061         i = ATSC_VSB;
0062         break;
0063     case SYS_DVBC_ANNEX_B:
0064         if_khz = dev->cfg.if_atsc_qam;
0065         i = ATSC_QAM;
0066         break;
0067     case SYS_DVBT:
0068         switch (c->bandwidth_hz) {
0069         case 6000000:
0070             if_khz = dev->cfg.if_dvbt_6;
0071             i = DVBT_6;
0072             break;
0073         case 7000000:
0074             if_khz = dev->cfg.if_dvbt_7;
0075             i = DVBT_7;
0076             break;
0077         case 8000000:
0078             if_khz = dev->cfg.if_dvbt_8;
0079             i = DVBT_8;
0080             break;
0081         default:
0082             ret = -EINVAL;
0083             goto error;
0084         }
0085         break;
0086     case SYS_DVBT2:
0087         switch (c->bandwidth_hz) {
0088         case 6000000:
0089             if_khz = dev->cfg.if_dvbt2_6;
0090             i = DVBT2_6;
0091             break;
0092         case 7000000:
0093             if_khz = dev->cfg.if_dvbt2_7;
0094             i = DVBT2_7;
0095             break;
0096         case 8000000:
0097             if_khz = dev->cfg.if_dvbt2_8;
0098             i = DVBT2_8;
0099             break;
0100         default:
0101             ret = -EINVAL;
0102             goto error;
0103         }
0104         break;
0105     case SYS_DVBC_ANNEX_A:
0106     case SYS_DVBC_ANNEX_C:
0107         if_khz = dev->cfg.if_dvbc;
0108         i = DVBC_8;
0109         break;
0110     default:
0111         ret = -EINVAL;
0112         goto error;
0113     }
0114 
0115     ret = regmap_write(dev->regmap, 0x23, bw_params[i][2]);
0116     if (ret)
0117         goto error;
0118 
0119     ret = regmap_write(dev->regmap, 0x06, 0x00);
0120     if (ret)
0121         goto error;
0122 
0123     ret = regmap_write(dev->regmap, 0x0f, bw_params[i][0]);
0124     if (ret)
0125         goto error;
0126 
0127     buf[0] = 0x02;
0128     buf[1] = bw_params[i][1];
0129     buf[2] = 0x03; /* default value */
0130     buf[3] = DIV_ROUND_CLOSEST(if_khz, 50);
0131     buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
0132     buf[5] = ((c->frequency / 1000) >>  8) & 0xff;
0133     buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
0134     buf[7] = 0xc1;
0135     buf[8] = 0x01;
0136     ret = regmap_bulk_write(dev->regmap, 0x12, buf, sizeof(buf));
0137     if (ret)
0138         goto error;
0139 
0140     /* actual IF rounded as it is on register */
0141     dev->if_frequency = buf[3] * 50 * 1000;
0142 
0143 exit:
0144     if (fe->ops.i2c_gate_ctrl)
0145         fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
0146 
0147     return ret;
0148 
0149 error:
0150     dev_dbg(&dev->client->dev, "failed=%d\n", ret);
0151     goto exit;
0152 }
0153 
0154 static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
0155 {
0156     struct tda18212_dev *dev = fe->tuner_priv;
0157 
0158     *frequency = dev->if_frequency;
0159 
0160     return 0;
0161 }
0162 
0163 static const struct dvb_tuner_ops tda18212_tuner_ops = {
0164     .info = {
0165         .name              = "NXP TDA18212",
0166 
0167         .frequency_min_hz  =  48 * MHz,
0168         .frequency_max_hz  = 864 * MHz,
0169         .frequency_step_hz =   1 * kHz,
0170     },
0171 
0172     .set_params    = tda18212_set_params,
0173     .get_if_frequency = tda18212_get_if_frequency,
0174 };
0175 
0176 static int tda18212_probe(struct i2c_client *client,
0177         const struct i2c_device_id *id)
0178 {
0179     struct tda18212_config *cfg = client->dev.platform_data;
0180     struct dvb_frontend *fe = cfg->fe;
0181     struct tda18212_dev *dev;
0182     int ret;
0183     unsigned int chip_id;
0184     char *version;
0185     static const struct regmap_config regmap_config = {
0186         .reg_bits = 8,
0187         .val_bits = 8,
0188     };
0189 
0190     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0191     if (dev == NULL) {
0192         ret = -ENOMEM;
0193         dev_err(&client->dev, "kzalloc() failed\n");
0194         goto err;
0195     }
0196 
0197     memcpy(&dev->cfg, cfg, sizeof(struct tda18212_config));
0198     dev->client = client;
0199     dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
0200     if (IS_ERR(dev->regmap)) {
0201         ret = PTR_ERR(dev->regmap);
0202         goto err;
0203     }
0204 
0205     /* check if the tuner is there */
0206     if (fe->ops.i2c_gate_ctrl)
0207         fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
0208 
0209     ret = regmap_read(dev->regmap, 0x00, &chip_id);
0210     dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id);
0211 
0212     if (fe->ops.i2c_gate_ctrl)
0213         fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
0214 
0215     if (ret)
0216         goto err;
0217 
0218     switch (chip_id) {
0219     case 0xc7:
0220         version = "M"; /* master */
0221         break;
0222     case 0x47:
0223         version = "S"; /* slave */
0224         break;
0225     default:
0226         ret = -ENODEV;
0227         goto err;
0228     }
0229 
0230     dev_info(&dev->client->dev,
0231             "NXP TDA18212HN/%s successfully identified\n", version);
0232 
0233     fe->tuner_priv = dev;
0234     memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
0235             sizeof(struct dvb_tuner_ops));
0236     i2c_set_clientdata(client, dev);
0237 
0238     return 0;
0239 err:
0240     dev_dbg(&client->dev, "failed=%d\n", ret);
0241     kfree(dev);
0242     return ret;
0243 }
0244 
0245 static int tda18212_remove(struct i2c_client *client)
0246 {
0247     struct tda18212_dev *dev = i2c_get_clientdata(client);
0248     struct dvb_frontend *fe = dev->cfg.fe;
0249 
0250     dev_dbg(&client->dev, "\n");
0251 
0252     memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
0253     fe->tuner_priv = NULL;
0254     kfree(dev);
0255 
0256     return 0;
0257 }
0258 
0259 static const struct i2c_device_id tda18212_id[] = {
0260     {"tda18212", 0},
0261     {}
0262 };
0263 MODULE_DEVICE_TABLE(i2c, tda18212_id);
0264 
0265 static struct i2c_driver tda18212_driver = {
0266     .driver = {
0267         .name   = "tda18212",
0268     },
0269     .probe      = tda18212_probe,
0270     .remove     = tda18212_remove,
0271     .id_table   = tda18212_id,
0272 };
0273 
0274 module_i2c_driver(tda18212_driver);
0275 
0276 MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
0277 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
0278 MODULE_LICENSE("GPL");