root/drivers/media/tuners/max2165.c

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

DEFINITIONS

This source file includes following definitions.
  1. max2165_write_reg
  2. max2165_read_reg
  3. max2165_mask_write_reg
  4. max2165_read_rom_table
  5. max2165_set_osc
  6. max2165_set_bandwidth
  7. fixpt_div32
  8. max2165_set_rf
  9. max2165_debug_status
  10. max2165_set_params
  11. max2165_get_frequency
  12. max2165_get_bandwidth
  13. max2165_get_status
  14. max2165_sleep
  15. max2165_init
  16. max2165_release
  17. max2165_attach

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Driver for Maxim MAX2165 silicon tuner
   4  *
   5  *  Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/moduleparam.h>
  10 #include <linux/videodev2.h>
  11 #include <linux/delay.h>
  12 #include <linux/dvb/frontend.h>
  13 #include <linux/i2c.h>
  14 #include <linux/slab.h>
  15 
  16 #include <media/dvb_frontend.h>
  17 
  18 #include "max2165.h"
  19 #include "max2165_priv.h"
  20 #include "tuner-i2c.h"
  21 
  22 #define dprintk(args...) \
  23         do { \
  24                 if (debug) \
  25                         printk(KERN_DEBUG "max2165: " args); \
  26         } while (0)
  27 
  28 static int debug;
  29 module_param(debug, int, 0644);
  30 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
  31 
  32 static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data)
  33 {
  34         int ret;
  35         u8 buf[] = { reg, data };
  36         struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
  37 
  38         msg.addr = priv->config->i2c_address;
  39 
  40         if (debug >= 2)
  41                 dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
  42 
  43         ret = i2c_transfer(priv->i2c, &msg, 1);
  44 
  45         if (ret != 1)
  46                 dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
  47                         __func__, reg, data, ret);
  48 
  49         return (ret != 1) ? -EIO : 0;
  50 }
  51 
  52 static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data)
  53 {
  54         int ret;
  55         u8 dev_addr = priv->config->i2c_address;
  56 
  57         u8 b0[] = { reg };
  58         u8 b1[] = { 0 };
  59         struct i2c_msg msg[] = {
  60                 { .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 },
  61                 { .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 },
  62         };
  63 
  64         ret = i2c_transfer(priv->i2c, msg, 2);
  65         if (ret != 2) {
  66                 dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
  67                 return -EIO;
  68         }
  69 
  70         *p_data = b1[0];
  71         if (debug >= 2)
  72                 dprintk("%s: reg=0x%02X, data=0x%02X\n",
  73                         __func__, reg, b1[0]);
  74         return 0;
  75 }
  76 
  77 static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg,
  78         u8 mask, u8 data)
  79 {
  80         int ret;
  81         u8 v;
  82 
  83         data &= mask;
  84         ret = max2165_read_reg(priv, reg, &v);
  85         if (ret != 0)
  86                 return ret;
  87         v &= ~mask;
  88         v |= data;
  89         ret = max2165_write_reg(priv, reg, v);
  90 
  91         return ret;
  92 }
  93 
  94 static int max2165_read_rom_table(struct max2165_priv *priv)
  95 {
  96         u8 dat[3];
  97         int i;
  98 
  99         for (i = 0; i < 3; i++) {
 100                 max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1);
 101                 max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]);
 102         }
 103 
 104         priv->tf_ntch_low_cfg = dat[0] >> 4;
 105         priv->tf_ntch_hi_cfg = dat[0] & 0x0F;
 106         priv->tf_balun_low_ref = dat[1] & 0x0F;
 107         priv->tf_balun_hi_ref = dat[1] >> 4;
 108         priv->bb_filter_7mhz_cfg = dat[2] & 0x0F;
 109         priv->bb_filter_8mhz_cfg = dat[2] >> 4;
 110 
 111         dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg);
 112         dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg);
 113         dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref);
 114         dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref);
 115         dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg);
 116         dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg);
 117 
 118         return 0;
 119 }
 120 
 121 static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/)
 122 {
 123         u8 v;
 124 
 125         v = (osc / 2);
 126         if (v == 2)
 127                 v = 0x7;
 128         else
 129                 v -= 8;
 130 
 131         max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v);
 132 
 133         return 0;
 134 }
 135 
 136 static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw)
 137 {
 138         u8 val;
 139 
 140         if (bw == 8000000)
 141                 val = priv->bb_filter_8mhz_cfg;
 142         else
 143                 val = priv->bb_filter_7mhz_cfg;
 144 
 145         max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4);
 146 
 147         return 0;
 148 }
 149 
 150 static int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction)
 151 {
 152         u32 remainder;
 153         u32 q, f = 0;
 154         int i;
 155 
 156         if (0 == divisor)
 157                 return -EINVAL;
 158 
 159         q = dividend / divisor;
 160         remainder = dividend - q * divisor;
 161 
 162         for (i = 0; i < 31; i++) {
 163                 remainder <<= 1;
 164                 if (remainder >= divisor) {
 165                         f += 1;
 166                         remainder -= divisor;
 167                 }
 168                 f <<= 1;
 169         }
 170 
 171         *quotient = q;
 172         *fraction = f;
 173 
 174         return 0;
 175 }
 176 
 177 static int max2165_set_rf(struct max2165_priv *priv, u32 freq)
 178 {
 179         u8 tf;
 180         u8 tf_ntch;
 181         u32 t;
 182         u32 quotient, fraction;
 183         int ret;
 184 
 185         /* Set PLL divider according to RF frequency */
 186         ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
 187                          &quotient, &fraction);
 188         if (ret != 0)
 189                 return ret;
 190 
 191         /* 20-bit fraction */
 192         fraction >>= 12;
 193 
 194         max2165_write_reg(priv, REG_NDIV_INT, quotient);
 195         max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16);
 196         max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8);
 197         max2165_write_reg(priv, REG_NDIV_FRAC0, fraction);
 198 
 199         /* Norch Filter */
 200         tf_ntch = (freq < 725000000) ?
 201                 priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg;
 202 
 203         /* Tracking filter balun */
 204         t = priv->tf_balun_low_ref;
 205         t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref)
 206                 * (freq / 1000 - 470000) / (780000 - 470000);
 207 
 208         tf = t;
 209         dprintk("tf = %X\n", tf);
 210         tf |= tf_ntch << 4;
 211 
 212         max2165_write_reg(priv, REG_TRACK_FILTER, tf);
 213 
 214         return 0;
 215 }
 216 
 217 static void max2165_debug_status(struct max2165_priv *priv)
 218 {
 219         u8 status, autotune;
 220         u8 auto_vco_success, auto_vco_active;
 221         u8 pll_locked;
 222         u8 dc_offset_low, dc_offset_hi;
 223         u8 signal_lv_over_threshold;
 224         u8 vco, vco_sub_band, adc;
 225 
 226         max2165_read_reg(priv, REG_STATUS, &status);
 227         max2165_read_reg(priv, REG_AUTOTUNE, &autotune);
 228 
 229         auto_vco_success = (status >> 6) & 0x01;
 230         auto_vco_active = (status >> 5) & 0x01;
 231         pll_locked = (status >> 4) & 0x01;
 232         dc_offset_low = (status >> 3) & 0x01;
 233         dc_offset_hi = (status >> 2) & 0x01;
 234         signal_lv_over_threshold = status & 0x01;
 235 
 236         vco = autotune >> 6;
 237         vco_sub_band = (autotune >> 3) & 0x7;
 238         adc = autotune & 0x7;
 239 
 240         dprintk("auto VCO active: %d, auto VCO success: %d\n",
 241                 auto_vco_active, auto_vco_success);
 242         dprintk("PLL locked: %d\n", pll_locked);
 243         dprintk("DC offset low: %d, DC offset high: %d\n",
 244                 dc_offset_low, dc_offset_hi);
 245         dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold);
 246         dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc);
 247 }
 248 
 249 static int max2165_set_params(struct dvb_frontend *fe)
 250 {
 251         struct max2165_priv *priv = fe->tuner_priv;
 252         struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 253         int ret;
 254 
 255         switch (c->bandwidth_hz) {
 256         case 7000000:
 257         case 8000000:
 258                 priv->frequency = c->frequency;
 259                 break;
 260         default:
 261                 printk(KERN_INFO "MAX2165: bandwidth %d Hz not supported.\n",
 262                        c->bandwidth_hz);
 263                 return -EINVAL;
 264         }
 265 
 266         dprintk("%s() frequency=%d\n", __func__, c->frequency);
 267 
 268         if (fe->ops.i2c_gate_ctrl)
 269                 fe->ops.i2c_gate_ctrl(fe, 1);
 270         max2165_set_bandwidth(priv, c->bandwidth_hz);
 271         ret = max2165_set_rf(priv, priv->frequency);
 272         mdelay(50);
 273         max2165_debug_status(priv);
 274         if (fe->ops.i2c_gate_ctrl)
 275                 fe->ops.i2c_gate_ctrl(fe, 0);
 276 
 277         if (ret != 0)
 278                 return -EREMOTEIO;
 279 
 280         return 0;
 281 }
 282 
 283 static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq)
 284 {
 285         struct max2165_priv *priv = fe->tuner_priv;
 286         dprintk("%s()\n", __func__);
 287         *freq = priv->frequency;
 288         return 0;
 289 }
 290 
 291 static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
 292 {
 293         struct max2165_priv *priv = fe->tuner_priv;
 294         dprintk("%s()\n", __func__);
 295 
 296         *bw = priv->bandwidth;
 297         return 0;
 298 }
 299 
 300 static int max2165_get_status(struct dvb_frontend *fe, u32 *status)
 301 {
 302         struct max2165_priv *priv = fe->tuner_priv;
 303         u16 lock_status = 0;
 304 
 305         dprintk("%s()\n", __func__);
 306 
 307         if (fe->ops.i2c_gate_ctrl)
 308                         fe->ops.i2c_gate_ctrl(fe, 1);
 309 
 310         max2165_debug_status(priv);
 311         *status = lock_status;
 312 
 313         if (fe->ops.i2c_gate_ctrl)
 314                         fe->ops.i2c_gate_ctrl(fe, 0);
 315 
 316         return 0;
 317 }
 318 
 319 static int max2165_sleep(struct dvb_frontend *fe)
 320 {
 321         dprintk("%s()\n", __func__);
 322         return 0;
 323 }
 324 
 325 static int max2165_init(struct dvb_frontend *fe)
 326 {
 327         struct max2165_priv *priv = fe->tuner_priv;
 328         dprintk("%s()\n", __func__);
 329 
 330         if (fe->ops.i2c_gate_ctrl)
 331                 fe->ops.i2c_gate_ctrl(fe, 1);
 332 
 333         /* Setup initial values */
 334         /* Fractional Mode on */
 335         max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18);
 336         /* LNA on */
 337         max2165_write_reg(priv, REG_LNA, 0x01);
 338         max2165_write_reg(priv, REG_PLL_CFG, 0x7A);
 339         max2165_write_reg(priv, REG_TEST, 0x08);
 340         max2165_write_reg(priv, REG_SHUTDOWN, 0x40);
 341         max2165_write_reg(priv, REG_VCO_CTRL, 0x84);
 342         max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3);
 343         max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75);
 344         max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00);
 345         max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00);
 346 
 347         max2165_set_osc(priv, priv->config->osc_clk);
 348 
 349         max2165_read_rom_table(priv);
 350 
 351         max2165_set_bandwidth(priv, 8000000);
 352 
 353         if (fe->ops.i2c_gate_ctrl)
 354                         fe->ops.i2c_gate_ctrl(fe, 0);
 355 
 356         return 0;
 357 }
 358 
 359 static void max2165_release(struct dvb_frontend *fe)
 360 {
 361         struct max2165_priv *priv = fe->tuner_priv;
 362         dprintk("%s()\n", __func__);
 363 
 364         kfree(priv);
 365         fe->tuner_priv = NULL;
 366 }
 367 
 368 static const struct dvb_tuner_ops max2165_tuner_ops = {
 369         .info = {
 370                 .name              = "Maxim MAX2165",
 371                 .frequency_min_hz  = 470 * MHz,
 372                 .frequency_max_hz  = 862 * MHz,
 373                 .frequency_step_hz =  50 * kHz,
 374         },
 375 
 376         .release           = max2165_release,
 377         .init              = max2165_init,
 378         .sleep             = max2165_sleep,
 379 
 380         .set_params        = max2165_set_params,
 381         .set_analog_params = NULL,
 382         .get_frequency     = max2165_get_frequency,
 383         .get_bandwidth     = max2165_get_bandwidth,
 384         .get_status        = max2165_get_status
 385 };
 386 
 387 struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
 388                                    struct i2c_adapter *i2c,
 389                                    struct max2165_config *cfg)
 390 {
 391         struct max2165_priv *priv = NULL;
 392 
 393         dprintk("%s(%d-%04x)\n", __func__,
 394                 i2c ? i2c_adapter_id(i2c) : -1,
 395                 cfg ? cfg->i2c_address : -1);
 396 
 397         priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL);
 398         if (priv == NULL)
 399                 return NULL;
 400 
 401         memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops,
 402                 sizeof(struct dvb_tuner_ops));
 403 
 404         priv->config = cfg;
 405         priv->i2c = i2c;
 406         fe->tuner_priv = priv;
 407 
 408         max2165_init(fe);
 409         max2165_debug_status(priv);
 410 
 411         return fe;
 412 }
 413 EXPORT_SYMBOL(max2165_attach);
 414 
 415 MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
 416 MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver");
 417 MODULE_LICENSE("GPL");

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