linux/drivers/media/tuners/mc44s803.c
<<
>>
Prefs
   1/*
   2 *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
   3 *
   4 *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
   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 *
  15 *  GNU General Public License for more details.
  16 *
  17 *  You should have received a copy of the GNU General Public License
  18 *  along with this program; if not, write to the Free Software
  19 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
  20 */
  21
  22#include <linux/module.h>
  23#include <linux/delay.h>
  24#include <linux/dvb/frontend.h>
  25#include <linux/i2c.h>
  26#include <linux/slab.h>
  27
  28#include "dvb_frontend.h"
  29
  30#include "mc44s803.h"
  31#include "mc44s803_priv.h"
  32
  33#define mc_printk(level, format, arg...)        \
  34        printk(level "mc44s803: " format , ## arg)
  35
  36/* Writes a single register */
  37static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val)
  38{
  39        u8 buf[3];
  40        struct i2c_msg msg = {
  41                .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3
  42        };
  43
  44        buf[0] = (val & 0xff0000) >> 16;
  45        buf[1] = (val & 0xff00) >> 8;
  46        buf[2] = (val & 0xff);
  47
  48        if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
  49                mc_printk(KERN_WARNING, "I2C write failed\n");
  50                return -EREMOTEIO;
  51        }
  52        return 0;
  53}
  54
  55/* Reads a single register */
  56static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val)
  57{
  58        u32 wval;
  59        u8 buf[3];
  60        int ret;
  61        struct i2c_msg msg[] = {
  62                { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
  63                  .buf = buf, .len = 3 },
  64        };
  65
  66        wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) |
  67               MC44S803_REG_SM(reg, MC44S803_D);
  68
  69        ret = mc44s803_writereg(priv, wval);
  70        if (ret)
  71                return ret;
  72
  73        if (i2c_transfer(priv->i2c, msg, 1) != 1) {
  74                mc_printk(KERN_WARNING, "I2C read failed\n");
  75                return -EREMOTEIO;
  76        }
  77
  78        *val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
  79
  80        return 0;
  81}
  82
  83static int mc44s803_release(struct dvb_frontend *fe)
  84{
  85        struct mc44s803_priv *priv = fe->tuner_priv;
  86
  87        fe->tuner_priv = NULL;
  88        kfree(priv);
  89
  90        return 0;
  91}
  92
  93static int mc44s803_init(struct dvb_frontend *fe)
  94{
  95        struct mc44s803_priv *priv = fe->tuner_priv;
  96        u32 val;
  97        int err;
  98
  99        if (fe->ops.i2c_gate_ctrl)
 100                fe->ops.i2c_gate_ctrl(fe, 1);
 101
 102/* Reset chip */
 103        val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) |
 104              MC44S803_REG_SM(1, MC44S803_RS);
 105
 106        err = mc44s803_writereg(priv, val);
 107        if (err)
 108                goto exit;
 109
 110        val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR);
 111
 112        err = mc44s803_writereg(priv, val);
 113        if (err)
 114                goto exit;
 115
 116/* Power Up and Start Osc */
 117
 118        val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
 119              MC44S803_REG_SM(0xC0, MC44S803_REFOSC) |
 120              MC44S803_REG_SM(1, MC44S803_OSCSEL);
 121
 122        err = mc44s803_writereg(priv, val);
 123        if (err)
 124                goto exit;
 125
 126        val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) |
 127              MC44S803_REG_SM(0x200, MC44S803_POWER);
 128
 129        err = mc44s803_writereg(priv, val);
 130        if (err)
 131                goto exit;
 132
 133        msleep(10);
 134
 135        val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
 136              MC44S803_REG_SM(0x40, MC44S803_REFOSC) |
 137              MC44S803_REG_SM(1, MC44S803_OSCSEL);
 138
 139        err = mc44s803_writereg(priv, val);
 140        if (err)
 141                goto exit;
 142
 143        msleep(20);
 144
 145/* Setup Mixer */
 146
 147        val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) |
 148              MC44S803_REG_SM(1, MC44S803_TRI_STATE) |
 149              MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES);
 150
 151        err = mc44s803_writereg(priv, val);
 152        if (err)
 153                goto exit;
 154
 155/* Setup Cirquit Adjust */
 156
 157        val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
 158              MC44S803_REG_SM(1, MC44S803_G1) |
 159              MC44S803_REG_SM(1, MC44S803_G3) |
 160              MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
 161              MC44S803_REG_SM(1, MC44S803_G6) |
 162              MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
 163              MC44S803_REG_SM(0x3, MC44S803_LP) |
 164              MC44S803_REG_SM(1, MC44S803_CLRF) |
 165              MC44S803_REG_SM(1, MC44S803_CLIF);
 166
 167        err = mc44s803_writereg(priv, val);
 168        if (err)
 169                goto exit;
 170
 171        val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
 172              MC44S803_REG_SM(1, MC44S803_G1) |
 173              MC44S803_REG_SM(1, MC44S803_G3) |
 174              MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
 175              MC44S803_REG_SM(1, MC44S803_G6) |
 176              MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
 177              MC44S803_REG_SM(0x3, MC44S803_LP);
 178
 179        err = mc44s803_writereg(priv, val);
 180        if (err)
 181                goto exit;
 182
 183/* Setup Digtune */
 184
 185        val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
 186              MC44S803_REG_SM(3, MC44S803_XOD);
 187
 188        err = mc44s803_writereg(priv, val);
 189        if (err)
 190                goto exit;
 191
 192/* Setup AGC */
 193
 194        val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) |
 195              MC44S803_REG_SM(1, MC44S803_AT1) |
 196              MC44S803_REG_SM(1, MC44S803_AT2) |
 197              MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) |
 198              MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) |
 199              MC44S803_REG_SM(1, MC44S803_LNA0);
 200
 201        err = mc44s803_writereg(priv, val);
 202        if (err)
 203                goto exit;
 204
 205        if (fe->ops.i2c_gate_ctrl)
 206                fe->ops.i2c_gate_ctrl(fe, 0);
 207        return 0;
 208
 209exit:
 210        if (fe->ops.i2c_gate_ctrl)
 211                fe->ops.i2c_gate_ctrl(fe, 0);
 212
 213        mc_printk(KERN_WARNING, "I/O Error\n");
 214        return err;
 215}
 216
 217static int mc44s803_set_params(struct dvb_frontend *fe)
 218{
 219        struct mc44s803_priv *priv = fe->tuner_priv;
 220        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 221        u32 r1, r2, n1, n2, lo1, lo2, freq, val;
 222        int err;
 223
 224        priv->frequency = c->frequency;
 225
 226        r1 = MC44S803_OSC / 1000000;
 227        r2 = MC44S803_OSC /  100000;
 228
 229        n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000;
 230        freq = MC44S803_OSC / r1 * n1;
 231        lo1 = ((60 * n1) + (r1 / 2)) / r1;
 232        freq = freq - c->frequency;
 233
 234        n2 = (freq - MC44S803_IF2 + 50000) / 100000;
 235        lo2 = ((60 * n2) + (r2 / 2)) / r2;
 236
 237        if (fe->ops.i2c_gate_ctrl)
 238                fe->ops.i2c_gate_ctrl(fe, 1);
 239
 240        val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) |
 241              MC44S803_REG_SM(r1-1, MC44S803_R1) |
 242              MC44S803_REG_SM(r2-1, MC44S803_R2) |
 243              MC44S803_REG_SM(1, MC44S803_REFBUF_EN);
 244
 245        err = mc44s803_writereg(priv, val);
 246        if (err)
 247                goto exit;
 248
 249        val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) |
 250              MC44S803_REG_SM(n1-2, MC44S803_LO1);
 251
 252        err = mc44s803_writereg(priv, val);
 253        if (err)
 254                goto exit;
 255
 256        val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) |
 257              MC44S803_REG_SM(n2-2, MC44S803_LO2);
 258
 259        err = mc44s803_writereg(priv, val);
 260        if (err)
 261                goto exit;
 262
 263        val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
 264              MC44S803_REG_SM(1, MC44S803_DA) |
 265              MC44S803_REG_SM(lo1, MC44S803_LO_REF) |
 266              MC44S803_REG_SM(1, MC44S803_AT);
 267
 268        err = mc44s803_writereg(priv, val);
 269        if (err)
 270                goto exit;
 271
 272        val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
 273              MC44S803_REG_SM(2, MC44S803_DA) |
 274              MC44S803_REG_SM(lo2, MC44S803_LO_REF) |
 275              MC44S803_REG_SM(1, MC44S803_AT);
 276
 277        err = mc44s803_writereg(priv, val);
 278        if (err)
 279                goto exit;
 280
 281        if (fe->ops.i2c_gate_ctrl)
 282                fe->ops.i2c_gate_ctrl(fe, 0);
 283
 284        return 0;
 285
 286exit:
 287        if (fe->ops.i2c_gate_ctrl)
 288                fe->ops.i2c_gate_ctrl(fe, 0);
 289
 290        mc_printk(KERN_WARNING, "I/O Error\n");
 291        return err;
 292}
 293
 294static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 295{
 296        struct mc44s803_priv *priv = fe->tuner_priv;
 297        *frequency = priv->frequency;
 298        return 0;
 299}
 300
 301static int mc44s803_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 302{
 303        *frequency = MC44S803_IF2; /* 36.125 MHz */
 304        return 0;
 305}
 306
 307static const struct dvb_tuner_ops mc44s803_tuner_ops = {
 308        .info = {
 309                .name           = "Freescale MC44S803",
 310                .frequency_min  =   48000000,
 311                .frequency_max  = 1000000000,
 312                .frequency_step =     100000,
 313        },
 314
 315        .release       = mc44s803_release,
 316        .init          = mc44s803_init,
 317        .set_params    = mc44s803_set_params,
 318        .get_frequency = mc44s803_get_frequency,
 319        .get_if_frequency = mc44s803_get_if_frequency,
 320};
 321
 322/* This functions tries to identify a MC44S803 tuner by reading the ID
 323   register. This is hasty. */
 324struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
 325         struct i2c_adapter *i2c, struct mc44s803_config *cfg)
 326{
 327        struct mc44s803_priv *priv;
 328        u32 reg;
 329        u8 id;
 330        int ret;
 331
 332        reg = 0;
 333
 334        priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL);
 335        if (priv == NULL)
 336                return NULL;
 337
 338        priv->cfg = cfg;
 339        priv->i2c = i2c;
 340        priv->fe  = fe;
 341
 342        if (fe->ops.i2c_gate_ctrl)
 343                fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
 344
 345        ret = mc44s803_readreg(priv, MC44S803_REG_ID, &reg);
 346        if (ret)
 347                goto error;
 348
 349        id = MC44S803_REG_MS(reg, MC44S803_ID);
 350
 351        if (id != 0x14) {
 352                mc_printk(KERN_ERR, "unsupported ID "
 353                       "(%x should be 0x14)\n", id);
 354                goto error;
 355        }
 356
 357        mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id);
 358        memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops,
 359               sizeof(struct dvb_tuner_ops));
 360
 361        fe->tuner_priv = priv;
 362
 363        if (fe->ops.i2c_gate_ctrl)
 364                fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
 365
 366        return fe;
 367
 368error:
 369        if (fe->ops.i2c_gate_ctrl)
 370                fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
 371
 372        kfree(priv);
 373        return NULL;
 374}
 375EXPORT_SYMBOL(mc44s803_attach);
 376
 377MODULE_AUTHOR("Jochen Friedrich");
 378MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver");
 379MODULE_LICENSE("GPL");
 380