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 "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_state(struct dvb_frontend *fe, 70 enum tuner_param param, 71 struct tuner_state *tstate) 72 { 73 struct tda665x_state *state = fe->tuner_priv; 74 int err = 0; 75 76 switch (param) { 77 case DVBFE_TUNER_FREQUENCY: 78 tstate->frequency = state->frequency; 79 break; 80 case DVBFE_TUNER_BANDWIDTH: 81 break; 82 default: 83 printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param); 84 err = -EINVAL; 85 break; 86 } 87 88 return err; 89 } 90 91 static int tda665x_get_status(struct dvb_frontend *fe, u32 *status) 92 { 93 struct tda665x_state *state = fe->tuner_priv; 94 u8 result = 0; 95 int err = 0; 96 97 *status = 0; 98 99 err = tda665x_read(state, &result); 100 if (err < 0) 101 goto exit; 102 103 if ((result >> 6) & 0x01) { 104 printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__); 105 *status = 1; 106 } 107 108 return err; 109 exit: 110 printk(KERN_ERR "%s: I/O Error\n", __func__); 111 return err; 112 } 113 114 static int tda665x_set_state(struct dvb_frontend *fe, 115 enum tuner_param param, 116 struct tuner_state *tstate) 117 { 118 struct tda665x_state *state = fe->tuner_priv; 119 const struct tda665x_config *config = state->config; 120 u32 frequency, status = 0; 121 u8 buf[4]; 122 int err = 0; 123 124 if (param & DVBFE_TUNER_FREQUENCY) { 125 126 frequency = tstate->frequency; 127 if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) { 128 printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency); 129 return -EINVAL; 130 } 131 132 frequency += config->frequency_offst; 133 frequency *= config->ref_multiplier; 134 frequency += config->ref_divider >> 1; 135 frequency /= config->ref_divider; 136 137 buf[0] = (u8) ((frequency & 0x7f00) >> 8); 138 buf[1] = (u8) (frequency & 0x00ff) >> 0; 139 buf[2] = 0x80 | 0x40 | 0x02; 140 buf[3] = 0x00; 141 142 /* restore frequency */ 143 frequency = tstate->frequency; 144 145 if (frequency < 153000000) { 146 /* VHF-L */ 147 buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */ 148 if (frequency < 68000000) 149 buf[3] |= 0x40; /* 83uA */ 150 if (frequency < 1040000000) 151 buf[3] |= 0x60; /* 122uA */ 152 if (frequency < 1250000000) 153 buf[3] |= 0x80; /* 163uA */ 154 else 155 buf[3] |= 0xa0; /* 254uA */ 156 } else if (frequency < 438000000) { 157 /* VHF-H */ 158 buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */ 159 if (frequency < 230000000) 160 buf[3] |= 0x40; 161 if (frequency < 300000000) 162 buf[3] |= 0x60; 163 else 164 buf[3] |= 0x80; 165 } else { 166 /* UHF */ 167 buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */ 168 if (frequency < 470000000) 169 buf[3] |= 0x60; 170 if (frequency < 526000000) 171 buf[3] |= 0x80; 172 else 173 buf[3] |= 0xa0; 174 } 175 176 /* Set params */ 177 err = tda665x_write(state, buf, 5); 178 if (err < 0) 179 goto exit; 180 181 /* sleep for some time */ 182 printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__); 183 msleep(20); 184 /* check status */ 185 err = tda665x_get_status(fe, &status); 186 if (err < 0) 187 goto exit; 188 189 if (status == 1) { 190 printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status); 191 state->frequency = frequency; /* cache successful state */ 192 } else { 193 printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status); 194 } 195 } else { 196 printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param); 197 return -EINVAL; 198 } 199 200 return 0; 201 exit: 202 printk(KERN_ERR "%s: I/O Error\n", __func__); 203 return err; 204 } 205 206 static int tda665x_release(struct dvb_frontend *fe) 207 { 208 struct tda665x_state *state = fe->tuner_priv; 209 210 fe->tuner_priv = NULL; 211 kfree(state); 212 return 0; 213 } 214 215 static struct dvb_tuner_ops tda665x_ops = { 216 217 .set_state = tda665x_set_state, 218 .get_state = tda665x_get_state, 219 .get_status = tda665x_get_status, 220 .release = tda665x_release 221 }; 222 223 struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, 224 const struct tda665x_config *config, 225 struct i2c_adapter *i2c) 226 { 227 struct tda665x_state *state = NULL; 228 struct dvb_tuner_info *info; 229 230 state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL); 231 if (!state) 232 return NULL; 233 234 state->config = config; 235 state->i2c = i2c; 236 state->fe = fe; 237 fe->tuner_priv = state; 238 fe->ops.tuner_ops = tda665x_ops; 239 info = &fe->ops.tuner_ops.info; 240 241 memcpy(info->name, config->name, sizeof(config->name)); 242 info->frequency_min = config->frequency_min; 243 info->frequency_max = config->frequency_max; 244 info->frequency_step = config->frequency_offst; 245 246 printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name); 247 248 return fe; 249 } 250 EXPORT_SYMBOL(tda665x_attach); 251 252 MODULE_DESCRIPTION("TDA665x driver"); 253 MODULE_AUTHOR("Manu Abraham"); 254 MODULE_LICENSE("GPL"); 255