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

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

DEFINITIONS

This source file includes following definitions.
  1. tda8261_read
  2. tda8261_write
  3. tda8261_get_status
  4. tda8261_get_frequency
  5. tda8261_set_params
  6. tda8261_release
  7. tda8261_attach

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3         TDA8261 8PSK/QPSK tuner driver
   4         Copyright (C) Manu Abraham (abraham.manu@gmail.com)
   5 
   6 */
   7 
   8 
   9 #include <linux/init.h>
  10 #include <linux/kernel.h>
  11 #include <linux/module.h>
  12 #include <linux/slab.h>
  13 
  14 #include <media/dvb_frontend.h>
  15 #include "tda8261.h"
  16 
  17 struct tda8261_state {
  18         struct dvb_frontend             *fe;
  19         struct i2c_adapter              *i2c;
  20         const struct tda8261_config     *config;
  21 
  22         /* state cache */
  23         u32 frequency;
  24         u32 bandwidth;
  25 };
  26 
  27 static int tda8261_read(struct tda8261_state *state, u8 *buf)
  28 {
  29         const struct tda8261_config *config = state->config;
  30         int err = 0;
  31         struct i2c_msg msg = { .addr    = config->addr, .flags = I2C_M_RD,.buf = buf,  .len = 1 };
  32 
  33         if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
  34                 pr_err("%s: read error, err=%d\n", __func__, err);
  35 
  36         return err;
  37 }
  38 
  39 static int tda8261_write(struct tda8261_state *state, u8 *buf)
  40 {
  41         const struct tda8261_config *config = state->config;
  42         int err = 0;
  43         struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = 4 };
  44 
  45         if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
  46                 pr_err("%s: write error, err=%d\n", __func__, err);
  47 
  48         return err;
  49 }
  50 
  51 static int tda8261_get_status(struct dvb_frontend *fe, u32 *status)
  52 {
  53         struct tda8261_state *state = fe->tuner_priv;
  54         u8 result = 0;
  55         int err = 0;
  56 
  57         *status = 0;
  58 
  59         if ((err = tda8261_read(state, &result)) < 0) {
  60                 pr_err("%s: I/O Error\n", __func__);
  61                 return err;
  62         }
  63         if ((result >> 6) & 0x01) {
  64                 pr_debug("%s: Tuner Phase Locked\n", __func__);
  65                 *status = 1;
  66         }
  67 
  68         return err;
  69 }
  70 
  71 static const u32 div_tab[] = { 2000, 1000,  500,  250,  125 }; /* kHz */
  72 static const u8  ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 };
  73 
  74 static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
  75 {
  76         struct tda8261_state *state = fe->tuner_priv;
  77 
  78         *frequency = state->frequency;
  79 
  80         return 0;
  81 }
  82 
  83 static int tda8261_set_params(struct dvb_frontend *fe)
  84 {
  85         struct dtv_frontend_properties *c = &fe->dtv_property_cache;
  86         struct tda8261_state *state = fe->tuner_priv;
  87         const struct tda8261_config *config = state->config;
  88         u32 frequency, N, status = 0;
  89         u8 buf[4];
  90         int err = 0;
  91 
  92         /*
  93          * N = Max VCO Frequency / Channel Spacing
  94          * Max VCO Frequency = VCO frequency + (channel spacing - 1)
  95          * (to account for half channel spacing on either side)
  96          */
  97         frequency = c->frequency;
  98         if ((frequency < 950000) || (frequency > 2150000)) {
  99                 pr_warn("%s: Frequency beyond limits, frequency=%d\n",
 100                         __func__, frequency);
 101                 return -EINVAL;
 102         }
 103         N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size];
 104         pr_debug("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n",
 105                 __func__, config->step_size, div_tab[config->step_size], N, N);
 106 
 107         buf[0] = (N >> 8) & 0xff;
 108         buf[1] = N & 0xff;
 109         buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1);
 110 
 111         if (frequency < 1450000)
 112                 buf[3] = 0x00;
 113         else if (frequency < 2000000)
 114                 buf[3] = 0x40;
 115         else if (frequency < 2150000)
 116                 buf[3] = 0x80;
 117 
 118         /* Set params */
 119         err = tda8261_write(state, buf);
 120         if (err < 0) {
 121                 pr_err("%s: I/O Error\n", __func__);
 122                 return err;
 123         }
 124         /* sleep for some time */
 125         pr_debug("%s: Waiting to Phase LOCK\n", __func__);
 126         msleep(20);
 127         /* check status */
 128         if ((err = tda8261_get_status(fe, &status)) < 0) {
 129                 pr_err("%s: I/O Error\n", __func__);
 130                 return err;
 131         }
 132         if (status == 1) {
 133                 pr_debug("%s: Tuner Phase locked: status=%d\n", __func__,
 134                          status);
 135                 state->frequency = frequency; /* cache successful state */
 136         } else {
 137                 pr_debug("%s: No Phase lock: status=%d\n", __func__, status);
 138         }
 139 
 140         return 0;
 141 }
 142 
 143 static void tda8261_release(struct dvb_frontend *fe)
 144 {
 145         struct tda8261_state *state = fe->tuner_priv;
 146 
 147         fe->tuner_priv = NULL;
 148         kfree(state);
 149 }
 150 
 151 static const struct dvb_tuner_ops tda8261_ops = {
 152 
 153         .info = {
 154                 .name              = "TDA8261",
 155                 .frequency_min_hz  =  950 * MHz,
 156                 .frequency_max_hz  = 2150 * MHz,
 157         },
 158 
 159         .set_params     = tda8261_set_params,
 160         .get_frequency  = tda8261_get_frequency,
 161         .get_status     = tda8261_get_status,
 162         .release        = tda8261_release
 163 };
 164 
 165 struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
 166                                     const struct tda8261_config *config,
 167                                     struct i2c_adapter *i2c)
 168 {
 169         struct tda8261_state *state = NULL;
 170 
 171         if ((state = kzalloc(sizeof (struct tda8261_state), GFP_KERNEL)) == NULL)
 172                 goto exit;
 173 
 174         state->config           = config;
 175         state->i2c              = i2c;
 176         state->fe               = fe;
 177         fe->tuner_priv          = state;
 178         fe->ops.tuner_ops       = tda8261_ops;
 179 
 180         fe->ops.tuner_ops.info.frequency_step_hz = div_tab[config->step_size] * kHz;
 181 
 182         pr_info("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__);
 183 
 184         return fe;
 185 
 186 exit:
 187         kfree(state);
 188         return NULL;
 189 }
 190 
 191 EXPORT_SYMBOL(tda8261_attach);
 192 
 193 MODULE_AUTHOR("Manu Abraham");
 194 MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
 195 MODULE_LICENSE("GPL");

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