tda665x.c (5392B)
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 16struct 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 25static 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; 36exit: 37 printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err); 38 return err; 39} 40 41static 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; 52exit: 53 printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err); 54 return err; 55} 56 57static 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 66static 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; 84exit: 85 printk(KERN_ERR "%s: I/O Error\n", __func__); 86 return err; 87} 88 89static 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; 174exit: 175 printk(KERN_ERR "%s: I/O Error\n", __func__); 176 return err; 177} 178 179static 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 188static 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 196static 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 203struct 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} 230EXPORT_SYMBOL(tda665x_attach); 231 232MODULE_DESCRIPTION("TDA665x driver"); 233MODULE_AUTHOR("Manu Abraham"); 234MODULE_LICENSE("GPL");