root/drivers/media/dvb-frontends/tda665x.c

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

DEFINITIONS

This source file includes following definitions.
  1. tda665x_read
  2. tda665x_write
  3. tda665x_get_frequency
  4. tda665x_get_status
  5. tda665x_set_frequency
  6. tda665x_set_params
  7. tda665x_release
  8. tda665x_attach

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3         TDA665x tuner driver
   4         Copyright (C) Manu Abraham (abraham.manu@gmail.com)
   5 
   6 */
   7 
   8 #include <linux/init.h>
   9 #include <linux/kernel.h>
  10 #include <linux/module.h>
  11 #include <linux/slab.h>
  12 
  13 #include <media/dvb_frontend.h>
  14 #include "tda665x.h"
  15 
  16 struct tda665x_state {
  17         struct dvb_frontend             *fe;
  18         struct i2c_adapter              *i2c;
  19         const struct tda665x_config     *config;
  20 
  21         u32 frequency;
  22         u32 bandwidth;
  23 };
  24 
  25 static int tda665x_read(struct tda665x_state *state, u8 *buf)
  26 {
  27         const struct tda665x_config *config = state->config;
  28         int err = 0;
  29         struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 };
  30 
  31         err = i2c_transfer(state->i2c, &msg, 1);
  32         if (err != 1)
  33                 goto exit;
  34 
  35         return err;
  36 exit:
  37         printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
  38         return err;
  39 }
  40 
  41 static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length)
  42 {
  43         const struct tda665x_config *config = state->config;
  44         int err = 0;
  45         struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length };
  46 
  47         err = i2c_transfer(state->i2c, &msg, 1);
  48         if (err != 1)
  49                 goto exit;
  50 
  51         return err;
  52 exit:
  53         printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
  54         return err;
  55 }
  56 
  57 static int tda665x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
  58 {
  59         struct tda665x_state *state = fe->tuner_priv;
  60 
  61         *frequency = state->frequency;
  62 
  63         return 0;
  64 }
  65 
  66 static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
  67 {
  68         struct tda665x_state *state = fe->tuner_priv;
  69         u8 result = 0;
  70         int err = 0;
  71 
  72         *status = 0;
  73 
  74         err = tda665x_read(state, &result);
  75         if (err < 0)
  76                 goto exit;
  77 
  78         if ((result >> 6) & 0x01) {
  79                 printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__);
  80                 *status = 1;
  81         }
  82 
  83         return err;
  84 exit:
  85         printk(KERN_ERR "%s: I/O Error\n", __func__);
  86         return err;
  87 }
  88 
  89 static int tda665x_set_frequency(struct dvb_frontend *fe,
  90                                  u32 new_frequency)
  91 {
  92         struct tda665x_state *state = fe->tuner_priv;
  93         const struct tda665x_config *config = state->config;
  94         u32 frequency, status = 0;
  95         u8 buf[4];
  96         int err = 0;
  97 
  98         if ((new_frequency < config->frequency_max)
  99             || (new_frequency > config->frequency_min)) {
 100                 printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n",
 101                        __func__, new_frequency);
 102                 return -EINVAL;
 103         }
 104 
 105         frequency = new_frequency;
 106 
 107         frequency += config->frequency_offst;
 108         frequency *= config->ref_multiplier;
 109         frequency += config->ref_divider >> 1;
 110         frequency /= config->ref_divider;
 111 
 112         buf[0] = (u8) ((frequency & 0x7f00) >> 8);
 113         buf[1] = (u8) (frequency & 0x00ff) >> 0;
 114         buf[2] = 0x80 | 0x40 | 0x02;
 115         buf[3] = 0x00;
 116 
 117         /* restore frequency */
 118         frequency = new_frequency;
 119 
 120         if (frequency < 153000000) {
 121                 /* VHF-L */
 122                 buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
 123                 if (frequency < 68000000)
 124                         buf[3] |= 0x40; /* 83uA */
 125                 if (frequency < 1040000000)
 126                         buf[3] |= 0x60; /* 122uA */
 127                 if (frequency < 1250000000)
 128                         buf[3] |= 0x80; /* 163uA */
 129                 else
 130                         buf[3] |= 0xa0; /* 254uA */
 131         } else if (frequency < 438000000) {
 132                 /* VHF-H */
 133                 buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
 134                 if (frequency < 230000000)
 135                         buf[3] |= 0x40;
 136                 if (frequency < 300000000)
 137                         buf[3] |= 0x60;
 138                 else
 139                         buf[3] |= 0x80;
 140         } else {
 141                 /* UHF */
 142                 buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
 143                 if (frequency < 470000000)
 144                         buf[3] |= 0x60;
 145                 if (frequency < 526000000)
 146                         buf[3] |= 0x80;
 147                 else
 148                         buf[3] |= 0xa0;
 149         }
 150 
 151         /* Set params */
 152         err = tda665x_write(state, buf, 5);
 153         if (err < 0)
 154                 goto exit;
 155 
 156         /* sleep for some time */
 157         printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
 158         msleep(20);
 159         /* check status */
 160         err = tda665x_get_status(fe, &status);
 161         if (err < 0)
 162                 goto exit;
 163 
 164         if (status == 1) {
 165                 printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n",
 166                        __func__, status);
 167                 state->frequency = frequency; /* cache successful state */
 168         } else {
 169                 printk(KERN_ERR "%s: No Phase lock: status=%d\n",
 170                        __func__, status);
 171         }
 172 
 173         return 0;
 174 exit:
 175         printk(KERN_ERR "%s: I/O Error\n", __func__);
 176         return err;
 177 }
 178 
 179 static int tda665x_set_params(struct dvb_frontend *fe)
 180 {
 181         struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 182 
 183         tda665x_set_frequency(fe, c->frequency);
 184 
 185         return 0;
 186 }
 187 
 188 static void tda665x_release(struct dvb_frontend *fe)
 189 {
 190         struct tda665x_state *state = fe->tuner_priv;
 191 
 192         fe->tuner_priv = NULL;
 193         kfree(state);
 194 }
 195 
 196 static const struct dvb_tuner_ops tda665x_ops = {
 197         .get_status     = tda665x_get_status,
 198         .set_params     = tda665x_set_params,
 199         .get_frequency  = tda665x_get_frequency,
 200         .release        = tda665x_release
 201 };
 202 
 203 struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
 204                                     const struct tda665x_config *config,
 205                                     struct i2c_adapter *i2c)
 206 {
 207         struct tda665x_state *state = NULL;
 208         struct dvb_tuner_info *info;
 209 
 210         state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL);
 211         if (!state)
 212                 return NULL;
 213 
 214         state->config           = config;
 215         state->i2c              = i2c;
 216         state->fe               = fe;
 217         fe->tuner_priv          = state;
 218         fe->ops.tuner_ops       = tda665x_ops;
 219         info                     = &fe->ops.tuner_ops.info;
 220 
 221         memcpy(info->name, config->name, sizeof(config->name));
 222         info->frequency_min_hz  = config->frequency_min;
 223         info->frequency_max_hz  = config->frequency_max;
 224         info->frequency_step_hz = config->frequency_offst;
 225 
 226         printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name);
 227 
 228         return fe;
 229 }
 230 EXPORT_SYMBOL(tda665x_attach);
 231 
 232 MODULE_DESCRIPTION("TDA665x driver");
 233 MODULE_AUTHOR("Manu Abraham");
 234 MODULE_LICENSE("GPL");

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