linux/drivers/media/common/tuners/tda18218.c
<<
>>
Prefs
   1/*
   2 * NXP TDA18218HN silicon tuner 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
  17 *    along with this program; if not, write to the Free Software
  18 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19 */
  20
  21#include "tda18218.h"
  22#include "tda18218_priv.h"
  23
  24static int debug;
  25module_param(debug, int, 0644);
  26MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
  27
  28/* write multiple registers */
  29static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
  30{
  31        int ret = 0;
  32        u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
  33        struct i2c_msg msg[1] = {
  34                {
  35                        .addr = priv->cfg->i2c_address,
  36                        .flags = 0,
  37                        .buf = buf,
  38                }
  39        };
  40
  41        msg_len_max = priv->cfg->i2c_wr_max - 1;
  42        quotient = len / msg_len_max;
  43        remainder = len % msg_len_max;
  44        msg_len = msg_len_max;
  45        for (i = 0; (i <= quotient && remainder); i++) {
  46                if (i == quotient)  /* set len of the last msg */
  47                        msg_len = remainder;
  48
  49                msg[0].len = msg_len + 1;
  50                buf[0] = reg + i * msg_len_max;
  51                memcpy(&buf[1], &val[i * msg_len_max], msg_len);
  52
  53                ret = i2c_transfer(priv->i2c, msg, 1);
  54                if (ret != 1)
  55                        break;
  56        }
  57
  58        if (ret == 1) {
  59                ret = 0;
  60        } else {
  61                warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
  62                ret = -EREMOTEIO;
  63        }
  64
  65        return ret;
  66}
  67
  68/* read multiple registers */
  69static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
  70{
  71        int ret;
  72        u8 buf[reg+len]; /* we must start read always from reg 0x00 */
  73        struct i2c_msg msg[2] = {
  74                {
  75                        .addr = priv->cfg->i2c_address,
  76                        .flags = 0,
  77                        .len = 1,
  78                        .buf = "\x00",
  79                }, {
  80                        .addr = priv->cfg->i2c_address,
  81                        .flags = I2C_M_RD,
  82                        .len = sizeof(buf),
  83                        .buf = buf,
  84                }
  85        };
  86
  87        ret = i2c_transfer(priv->i2c, msg, 2);
  88        if (ret == 2) {
  89                memcpy(val, &buf[reg], len);
  90                ret = 0;
  91        } else {
  92                warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
  93                ret = -EREMOTEIO;
  94        }
  95
  96        return ret;
  97}
  98
  99/* write single register */
 100static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
 101{
 102        return tda18218_wr_regs(priv, reg, &val, 1);
 103}
 104
 105/* read single register */
 106
 107static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
 108{
 109        return tda18218_rd_regs(priv, reg, val, 1);
 110}
 111
 112static int tda18218_set_params(struct dvb_frontend *fe)
 113{
 114        struct tda18218_priv *priv = fe->tuner_priv;
 115        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 116        u32 bw = c->bandwidth_hz;
 117        int ret;
 118        u8 buf[3], i, BP_Filter, LP_Fc;
 119        u32 LO_Frac;
 120        /* TODO: find out correct AGC algorithm */
 121        u8 agc[][2] = {
 122                { R20_AGC11, 0x60 },
 123                { R23_AGC21, 0x02 },
 124                { R20_AGC11, 0xa0 },
 125                { R23_AGC21, 0x09 },
 126                { R20_AGC11, 0xe0 },
 127                { R23_AGC21, 0x0c },
 128                { R20_AGC11, 0x40 },
 129                { R23_AGC21, 0x01 },
 130                { R20_AGC11, 0x80 },
 131                { R23_AGC21, 0x08 },
 132                { R20_AGC11, 0xc0 },
 133                { R23_AGC21, 0x0b },
 134                { R24_AGC22, 0x1c },
 135                { R24_AGC22, 0x0c },
 136        };
 137
 138        if (fe->ops.i2c_gate_ctrl)
 139                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 140
 141        /* low-pass filter cut-off frequency */
 142        if (bw <= 6000000) {
 143                LP_Fc = 0;
 144                priv->if_frequency = 3000000;
 145        } else if (bw <= 7000000) {
 146                LP_Fc = 1;
 147                priv->if_frequency = 3500000;
 148        } else {
 149                LP_Fc = 2;
 150                priv->if_frequency = 4000000;
 151        }
 152
 153        LO_Frac = c->frequency + priv->if_frequency;
 154
 155        /* band-pass filter */
 156        if (LO_Frac < 188000000)
 157                BP_Filter = 3;
 158        else if (LO_Frac < 253000000)
 159                BP_Filter = 4;
 160        else if (LO_Frac < 343000000)
 161                BP_Filter = 5;
 162        else
 163                BP_Filter = 6;
 164
 165        buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
 166        buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
 167        buf[2] = priv->regs[R1C_AGC2B];
 168        ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
 169        if (ret)
 170                goto error;
 171
 172        buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
 173        buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
 174        buf[2] = (LO_Frac / 1000) << 4 |
 175                (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
 176        ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
 177        if (ret)
 178                goto error;
 179
 180        buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
 181        ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
 182        if (ret)
 183                goto error;
 184
 185        buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
 186        ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
 187        if (ret)
 188                goto error;
 189
 190        /* trigger AGC */
 191        for (i = 0; i < ARRAY_SIZE(agc); i++) {
 192                ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
 193                if (ret)
 194                        goto error;
 195        }
 196
 197error:
 198        if (fe->ops.i2c_gate_ctrl)
 199                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 200
 201        if (ret)
 202                dbg("%s: failed ret:%d", __func__, ret);
 203
 204        return ret;
 205}
 206
 207static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 208{
 209        struct tda18218_priv *priv = fe->tuner_priv;
 210        *frequency = priv->if_frequency;
 211        dbg("%s: if=%d", __func__, *frequency);
 212        return 0;
 213}
 214
 215static int tda18218_sleep(struct dvb_frontend *fe)
 216{
 217        struct tda18218_priv *priv = fe->tuner_priv;
 218        int ret;
 219
 220        if (fe->ops.i2c_gate_ctrl)
 221                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 222
 223        /* standby */
 224        ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
 225
 226        if (fe->ops.i2c_gate_ctrl)
 227                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 228
 229        if (ret)
 230                dbg("%s: failed ret:%d", __func__, ret);
 231
 232        return ret;
 233}
 234
 235static int tda18218_init(struct dvb_frontend *fe)
 236{
 237        struct tda18218_priv *priv = fe->tuner_priv;
 238        int ret;
 239
 240        /* TODO: calibrations */
 241
 242        if (fe->ops.i2c_gate_ctrl)
 243                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 244
 245        ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
 246
 247        if (fe->ops.i2c_gate_ctrl)
 248                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 249
 250        if (ret)
 251                dbg("%s: failed ret:%d", __func__, ret);
 252
 253        return ret;
 254}
 255
 256static int tda18218_release(struct dvb_frontend *fe)
 257{
 258        kfree(fe->tuner_priv);
 259        fe->tuner_priv = NULL;
 260        return 0;
 261}
 262
 263static const struct dvb_tuner_ops tda18218_tuner_ops = {
 264        .info = {
 265                .name           = "NXP TDA18218",
 266
 267                .frequency_min  = 174000000,
 268                .frequency_max  = 864000000,
 269                .frequency_step =      1000,
 270        },
 271
 272        .release       = tda18218_release,
 273        .init          = tda18218_init,
 274        .sleep         = tda18218_sleep,
 275
 276        .set_params    = tda18218_set_params,
 277
 278        .get_if_frequency = tda18218_get_if_frequency,
 279};
 280
 281struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
 282        struct i2c_adapter *i2c, struct tda18218_config *cfg)
 283{
 284        struct tda18218_priv *priv = NULL;
 285        u8 val;
 286        int ret;
 287        /* chip default registers values */
 288        static u8 def_regs[] = {
 289                0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
 290                0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
 291                0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
 292                0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
 293                0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
 294                0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
 295        };
 296
 297        priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
 298        if (priv == NULL)
 299                return NULL;
 300
 301        priv->cfg = cfg;
 302        priv->i2c = i2c;
 303        fe->tuner_priv = priv;
 304
 305        if (fe->ops.i2c_gate_ctrl)
 306                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 307
 308        /* check if the tuner is there */
 309        ret = tda18218_rd_reg(priv, R00_ID, &val);
 310        dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
 311        if (ret || val != def_regs[R00_ID]) {
 312                kfree(priv);
 313                return NULL;
 314        }
 315
 316        info("NXP TDA18218HN successfully identified.");
 317
 318        memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
 319                sizeof(struct dvb_tuner_ops));
 320        memcpy(priv->regs, def_regs, sizeof(def_regs));
 321
 322        /* loop-through enabled chip default register values */
 323        if (priv->cfg->loop_through) {
 324                priv->regs[R17_PD1] = 0xb0;
 325                priv->regs[R18_PD2] = 0x59;
 326        }
 327
 328        /* standby */
 329        ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
 330        if (ret)
 331                dbg("%s: failed ret:%d", __func__, ret);
 332
 333        if (fe->ops.i2c_gate_ctrl)
 334                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 335
 336        return fe;
 337}
 338EXPORT_SYMBOL(tda18218_attach);
 339
 340MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
 341MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 342MODULE_LICENSE("GPL");
 343