root/drivers/media/tuners/mc44s803.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mc44s803_writereg
  2. mc44s803_readreg
  3. mc44s803_release
  4. mc44s803_init
  5. mc44s803_set_params
  6. mc44s803_get_frequency
  7. mc44s803_get_if_frequency
  8. mc44s803_attach

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

/* [<][>][^][v][top][bottom][index][help] */