Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     TDA665x tuner driver
0004     Copyright (C) Manu Abraham (abraham.manu@gmail.com)
0005 
0006 */
0007 
0008 #include <linux/init.h>
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/slab.h>
0012 
0013 #include <media/dvb_frontend.h>
0014 #include "tda665x.h"
0015 
0016 struct tda665x_state {
0017     struct dvb_frontend     *fe;
0018     struct i2c_adapter      *i2c;
0019     const struct tda665x_config *config;
0020 
0021     u32 frequency;
0022     u32 bandwidth;
0023 };
0024 
0025 static int tda665x_read(struct tda665x_state *state, u8 *buf)
0026 {
0027     const struct tda665x_config *config = state->config;
0028     int err = 0;
0029     struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 };
0030 
0031     err = i2c_transfer(state->i2c, &msg, 1);
0032     if (err != 1)
0033         goto exit;
0034 
0035     return err;
0036 exit:
0037     printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
0038     return err;
0039 }
0040 
0041 static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length)
0042 {
0043     const struct tda665x_config *config = state->config;
0044     int err = 0;
0045     struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length };
0046 
0047     err = i2c_transfer(state->i2c, &msg, 1);
0048     if (err != 1)
0049         goto exit;
0050 
0051     return err;
0052 exit:
0053     printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
0054     return err;
0055 }
0056 
0057 static int tda665x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
0058 {
0059     struct tda665x_state *state = fe->tuner_priv;
0060 
0061     *frequency = state->frequency;
0062 
0063     return 0;
0064 }
0065 
0066 static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
0067 {
0068     struct tda665x_state *state = fe->tuner_priv;
0069     u8 result = 0;
0070     int err = 0;
0071 
0072     *status = 0;
0073 
0074     err = tda665x_read(state, &result);
0075     if (err < 0)
0076         goto exit;
0077 
0078     if ((result >> 6) & 0x01) {
0079         printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__);
0080         *status = 1;
0081     }
0082 
0083     return err;
0084 exit:
0085     printk(KERN_ERR "%s: I/O Error\n", __func__);
0086     return err;
0087 }
0088 
0089 static int tda665x_set_frequency(struct dvb_frontend *fe,
0090                  u32 new_frequency)
0091 {
0092     struct tda665x_state *state = fe->tuner_priv;
0093     const struct tda665x_config *config = state->config;
0094     u32 frequency, status = 0;
0095     u8 buf[4];
0096     int err = 0;
0097 
0098     if ((new_frequency < config->frequency_max)
0099         || (new_frequency > config->frequency_min)) {
0100         printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n",
0101                __func__, new_frequency);
0102         return -EINVAL;
0103     }
0104 
0105     frequency = new_frequency;
0106 
0107     frequency += config->frequency_offst;
0108     frequency *= config->ref_multiplier;
0109     frequency += config->ref_divider >> 1;
0110     frequency /= config->ref_divider;
0111 
0112     buf[0] = (u8) ((frequency & 0x7f00) >> 8);
0113     buf[1] = (u8) (frequency & 0x00ff) >> 0;
0114     buf[2] = 0x80 | 0x40 | 0x02;
0115     buf[3] = 0x00;
0116 
0117     /* restore frequency */
0118     frequency = new_frequency;
0119 
0120     if (frequency < 153000000) {
0121         /* VHF-L */
0122         buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
0123         if (frequency < 68000000)
0124             buf[3] |= 0x40; /* 83uA */
0125         if (frequency < 1040000000)
0126             buf[3] |= 0x60; /* 122uA */
0127         if (frequency < 1250000000)
0128             buf[3] |= 0x80; /* 163uA */
0129         else
0130             buf[3] |= 0xa0; /* 254uA */
0131     } else if (frequency < 438000000) {
0132         /* VHF-H */
0133         buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
0134         if (frequency < 230000000)
0135             buf[3] |= 0x40;
0136         if (frequency < 300000000)
0137             buf[3] |= 0x60;
0138         else
0139             buf[3] |= 0x80;
0140     } else {
0141         /* UHF */
0142         buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
0143         if (frequency < 470000000)
0144             buf[3] |= 0x60;
0145         if (frequency < 526000000)
0146             buf[3] |= 0x80;
0147         else
0148             buf[3] |= 0xa0;
0149     }
0150 
0151     /* Set params */
0152     err = tda665x_write(state, buf, 5);
0153     if (err < 0)
0154         goto exit;
0155 
0156     /* sleep for some time */
0157     printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
0158     msleep(20);
0159     /* check status */
0160     err = tda665x_get_status(fe, &status);
0161     if (err < 0)
0162         goto exit;
0163 
0164     if (status == 1) {
0165         printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n",
0166                __func__, status);
0167         state->frequency = frequency; /* cache successful state */
0168     } else {
0169         printk(KERN_ERR "%s: No Phase lock: status=%d\n",
0170                __func__, status);
0171     }
0172 
0173     return 0;
0174 exit:
0175     printk(KERN_ERR "%s: I/O Error\n", __func__);
0176     return err;
0177 }
0178 
0179 static int tda665x_set_params(struct dvb_frontend *fe)
0180 {
0181     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0182 
0183     tda665x_set_frequency(fe, c->frequency);
0184 
0185     return 0;
0186 }
0187 
0188 static void tda665x_release(struct dvb_frontend *fe)
0189 {
0190     struct tda665x_state *state = fe->tuner_priv;
0191 
0192     fe->tuner_priv = NULL;
0193     kfree(state);
0194 }
0195 
0196 static const struct dvb_tuner_ops tda665x_ops = {
0197     .get_status = tda665x_get_status,
0198     .set_params = tda665x_set_params,
0199     .get_frequency  = tda665x_get_frequency,
0200     .release    = tda665x_release
0201 };
0202 
0203 struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
0204                     const struct tda665x_config *config,
0205                     struct i2c_adapter *i2c)
0206 {
0207     struct tda665x_state *state = NULL;
0208     struct dvb_tuner_info *info;
0209 
0210     state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL);
0211     if (!state)
0212         return NULL;
0213 
0214     state->config       = config;
0215     state->i2c      = i2c;
0216     state->fe       = fe;
0217     fe->tuner_priv      = state;
0218     fe->ops.tuner_ops   = tda665x_ops;
0219     info             = &fe->ops.tuner_ops.info;
0220 
0221     memcpy(info->name, config->name, sizeof(config->name));
0222     info->frequency_min_hz  = config->frequency_min;
0223     info->frequency_max_hz  = config->frequency_max;
0224     info->frequency_step_hz = config->frequency_offst;
0225 
0226     printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name);
0227 
0228     return fe;
0229 }
0230 EXPORT_SYMBOL(tda665x_attach);
0231 
0232 MODULE_DESCRIPTION("TDA665x driver");
0233 MODULE_AUTHOR("Manu Abraham");
0234 MODULE_LICENSE("GPL");