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