Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
0004  *
0005  *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/delay.h>
0010 #include <linux/dvb/frontend.h>
0011 #include <linux/i2c.h>
0012 #include <linux/slab.h>
0013 
0014 #include <media/dvb_frontend.h>
0015 
0016 #include "mc44s803.h"
0017 #include "mc44s803_priv.h"
0018 
0019 #define mc_printk(level, format, arg...)    \
0020     printk(level "mc44s803: " format , ## arg)
0021 
0022 /* Writes a single register */
0023 static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val)
0024 {
0025     u8 buf[3];
0026     struct i2c_msg msg = {
0027         .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3
0028     };
0029 
0030     buf[0] = (val & 0xff0000) >> 16;
0031     buf[1] = (val & 0xff00) >> 8;
0032     buf[2] = (val & 0xff);
0033 
0034     if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
0035         mc_printk(KERN_WARNING, "I2C write failed\n");
0036         return -EREMOTEIO;
0037     }
0038     return 0;
0039 }
0040 
0041 /* Reads a single register */
0042 static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val)
0043 {
0044     u32 wval;
0045     u8 buf[3];
0046     int ret;
0047     struct i2c_msg msg[] = {
0048         { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
0049           .buf = buf, .len = 3 },
0050     };
0051 
0052     wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) |
0053            MC44S803_REG_SM(reg, MC44S803_D);
0054 
0055     ret = mc44s803_writereg(priv, wval);
0056     if (ret)
0057         return ret;
0058 
0059     if (i2c_transfer(priv->i2c, msg, 1) != 1) {
0060         mc_printk(KERN_WARNING, "I2C read failed\n");
0061         return -EREMOTEIO;
0062     }
0063 
0064     *val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
0065 
0066     return 0;
0067 }
0068 
0069 static void mc44s803_release(struct dvb_frontend *fe)
0070 {
0071     struct mc44s803_priv *priv = fe->tuner_priv;
0072 
0073     fe->tuner_priv = NULL;
0074     kfree(priv);
0075 }
0076 
0077 static int mc44s803_init(struct dvb_frontend *fe)
0078 {
0079     struct mc44s803_priv *priv = fe->tuner_priv;
0080     u32 val;
0081     int err;
0082 
0083     if (fe->ops.i2c_gate_ctrl)
0084         fe->ops.i2c_gate_ctrl(fe, 1);
0085 
0086 /* Reset chip */
0087     val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) |
0088           MC44S803_REG_SM(1, MC44S803_RS);
0089 
0090     err = mc44s803_writereg(priv, val);
0091     if (err)
0092         goto exit;
0093 
0094     val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR);
0095 
0096     err = mc44s803_writereg(priv, val);
0097     if (err)
0098         goto exit;
0099 
0100 /* Power Up and Start Osc */
0101 
0102     val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
0103           MC44S803_REG_SM(0xC0, MC44S803_REFOSC) |
0104           MC44S803_REG_SM(1, MC44S803_OSCSEL);
0105 
0106     err = mc44s803_writereg(priv, val);
0107     if (err)
0108         goto exit;
0109 
0110     val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) |
0111           MC44S803_REG_SM(0x200, MC44S803_POWER);
0112 
0113     err = mc44s803_writereg(priv, val);
0114     if (err)
0115         goto exit;
0116 
0117     msleep(10);
0118 
0119     val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
0120           MC44S803_REG_SM(0x40, MC44S803_REFOSC) |
0121           MC44S803_REG_SM(1, MC44S803_OSCSEL);
0122 
0123     err = mc44s803_writereg(priv, val);
0124     if (err)
0125         goto exit;
0126 
0127     msleep(20);
0128 
0129 /* Setup Mixer */
0130 
0131     val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) |
0132           MC44S803_REG_SM(1, MC44S803_TRI_STATE) |
0133           MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES);
0134 
0135     err = mc44s803_writereg(priv, val);
0136     if (err)
0137         goto exit;
0138 
0139 /* Setup Cirquit Adjust */
0140 
0141     val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
0142           MC44S803_REG_SM(1, MC44S803_G1) |
0143           MC44S803_REG_SM(1, MC44S803_G3) |
0144           MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
0145           MC44S803_REG_SM(1, MC44S803_G6) |
0146           MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
0147           MC44S803_REG_SM(0x3, MC44S803_LP) |
0148           MC44S803_REG_SM(1, MC44S803_CLRF) |
0149           MC44S803_REG_SM(1, MC44S803_CLIF);
0150 
0151     err = mc44s803_writereg(priv, val);
0152     if (err)
0153         goto exit;
0154 
0155     val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
0156           MC44S803_REG_SM(1, MC44S803_G1) |
0157           MC44S803_REG_SM(1, MC44S803_G3) |
0158           MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
0159           MC44S803_REG_SM(1, MC44S803_G6) |
0160           MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
0161           MC44S803_REG_SM(0x3, MC44S803_LP);
0162 
0163     err = mc44s803_writereg(priv, val);
0164     if (err)
0165         goto exit;
0166 
0167 /* Setup Digtune */
0168 
0169     val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
0170           MC44S803_REG_SM(3, MC44S803_XOD);
0171 
0172     err = mc44s803_writereg(priv, val);
0173     if (err)
0174         goto exit;
0175 
0176 /* Setup AGC */
0177 
0178     val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) |
0179           MC44S803_REG_SM(1, MC44S803_AT1) |
0180           MC44S803_REG_SM(1, MC44S803_AT2) |
0181           MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) |
0182           MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) |
0183           MC44S803_REG_SM(1, MC44S803_LNA0);
0184 
0185     err = mc44s803_writereg(priv, val);
0186     if (err)
0187         goto exit;
0188 
0189     if (fe->ops.i2c_gate_ctrl)
0190         fe->ops.i2c_gate_ctrl(fe, 0);
0191     return 0;
0192 
0193 exit:
0194     if (fe->ops.i2c_gate_ctrl)
0195         fe->ops.i2c_gate_ctrl(fe, 0);
0196 
0197     mc_printk(KERN_WARNING, "I/O Error\n");
0198     return err;
0199 }
0200 
0201 static int mc44s803_set_params(struct dvb_frontend *fe)
0202 {
0203     struct mc44s803_priv *priv = fe->tuner_priv;
0204     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0205     u32 r1, r2, n1, n2, lo1, lo2, freq, val;
0206     int err;
0207 
0208     priv->frequency = c->frequency;
0209 
0210     r1 = MC44S803_OSC / 1000000;
0211     r2 = MC44S803_OSC /  100000;
0212 
0213     n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000;
0214     freq = MC44S803_OSC / r1 * n1;
0215     lo1 = ((60 * n1) + (r1 / 2)) / r1;
0216     freq = freq - c->frequency;
0217 
0218     n2 = (freq - MC44S803_IF2 + 50000) / 100000;
0219     lo2 = ((60 * n2) + (r2 / 2)) / r2;
0220 
0221     if (fe->ops.i2c_gate_ctrl)
0222         fe->ops.i2c_gate_ctrl(fe, 1);
0223 
0224     val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) |
0225           MC44S803_REG_SM(r1-1, MC44S803_R1) |
0226           MC44S803_REG_SM(r2-1, MC44S803_R2) |
0227           MC44S803_REG_SM(1, MC44S803_REFBUF_EN);
0228 
0229     err = mc44s803_writereg(priv, val);
0230     if (err)
0231         goto exit;
0232 
0233     val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) |
0234           MC44S803_REG_SM(n1-2, MC44S803_LO1);
0235 
0236     err = mc44s803_writereg(priv, val);
0237     if (err)
0238         goto exit;
0239 
0240     val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) |
0241           MC44S803_REG_SM(n2-2, MC44S803_LO2);
0242 
0243     err = mc44s803_writereg(priv, val);
0244     if (err)
0245         goto exit;
0246 
0247     val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
0248           MC44S803_REG_SM(1, MC44S803_DA) |
0249           MC44S803_REG_SM(lo1, MC44S803_LO_REF) |
0250           MC44S803_REG_SM(1, MC44S803_AT);
0251 
0252     err = mc44s803_writereg(priv, val);
0253     if (err)
0254         goto exit;
0255 
0256     val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
0257           MC44S803_REG_SM(2, MC44S803_DA) |
0258           MC44S803_REG_SM(lo2, MC44S803_LO_REF) |
0259           MC44S803_REG_SM(1, MC44S803_AT);
0260 
0261     err = mc44s803_writereg(priv, val);
0262     if (err)
0263         goto exit;
0264 
0265     if (fe->ops.i2c_gate_ctrl)
0266         fe->ops.i2c_gate_ctrl(fe, 0);
0267 
0268     return 0;
0269 
0270 exit:
0271     if (fe->ops.i2c_gate_ctrl)
0272         fe->ops.i2c_gate_ctrl(fe, 0);
0273 
0274     mc_printk(KERN_WARNING, "I/O Error\n");
0275     return err;
0276 }
0277 
0278 static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency)
0279 {
0280     struct mc44s803_priv *priv = fe->tuner_priv;
0281     *frequency = priv->frequency;
0282     return 0;
0283 }
0284 
0285 static int mc44s803_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
0286 {
0287     *frequency = MC44S803_IF2; /* 36.125 MHz */
0288     return 0;
0289 }
0290 
0291 static const struct dvb_tuner_ops mc44s803_tuner_ops = {
0292     .info = {
0293         .name              = "Freescale MC44S803",
0294         .frequency_min_hz  =   48 * MHz,
0295         .frequency_max_hz  = 1000 * MHz,
0296         .frequency_step_hz =  100 * kHz,
0297     },
0298 
0299     .release       = mc44s803_release,
0300     .init          = mc44s803_init,
0301     .set_params    = mc44s803_set_params,
0302     .get_frequency = mc44s803_get_frequency,
0303     .get_if_frequency = mc44s803_get_if_frequency,
0304 };
0305 
0306 /* This functions tries to identify a MC44S803 tuner by reading the ID
0307    register. This is hasty. */
0308 struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
0309      struct i2c_adapter *i2c, struct mc44s803_config *cfg)
0310 {
0311     struct mc44s803_priv *priv;
0312     u32 reg;
0313     u8 id;
0314     int ret;
0315 
0316     reg = 0;
0317 
0318     priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL);
0319     if (priv == NULL)
0320         return NULL;
0321 
0322     priv->cfg = cfg;
0323     priv->i2c = i2c;
0324     priv->fe  = fe;
0325 
0326     if (fe->ops.i2c_gate_ctrl)
0327         fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
0328 
0329     ret = mc44s803_readreg(priv, MC44S803_REG_ID, &reg);
0330     if (ret)
0331         goto error;
0332 
0333     id = MC44S803_REG_MS(reg, MC44S803_ID);
0334 
0335     if (id != 0x14) {
0336         mc_printk(KERN_ERR, "unsupported ID (%x should be 0x14)\n",
0337               id);
0338         goto error;
0339     }
0340 
0341     mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id);
0342     memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops,
0343            sizeof(struct dvb_tuner_ops));
0344 
0345     fe->tuner_priv = priv;
0346 
0347     if (fe->ops.i2c_gate_ctrl)
0348         fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
0349 
0350     return fe;
0351 
0352 error:
0353     if (fe->ops.i2c_gate_ctrl)
0354         fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
0355 
0356     kfree(priv);
0357     return NULL;
0358 }
0359 EXPORT_SYMBOL(mc44s803_attach);
0360 
0361 MODULE_AUTHOR("Jochen Friedrich");
0362 MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver");
0363 MODULE_LICENSE("GPL");