/drivers/media/common/tuners/tda18218.c
C | 334 lines | 245 code | 56 blank | 33 comment | 42 complexity | 377b2ac4e2aef737bbe49e47dbde8190 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
1/* 2 * NXP TDA18218HN silicon tuner driver 3 * 4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21#include "tda18218.h" 22#include "tda18218_priv.h" 23 24static int debug; 25module_param(debug, int, 0644); 26MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); 27 28/* write multiple registers */ 29static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) 30{ 31 int ret = 0; 32 u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max; 33 struct i2c_msg msg[1] = { 34 { 35 .addr = priv->cfg->i2c_address, 36 .flags = 0, 37 .buf = buf, 38 } 39 }; 40 41 msg_len_max = priv->cfg->i2c_wr_max - 1; 42 quotient = len / msg_len_max; 43 remainder = len % msg_len_max; 44 msg_len = msg_len_max; 45 for (i = 0; (i <= quotient && remainder); i++) { 46 if (i == quotient) /* set len of the last msg */ 47 msg_len = remainder; 48 49 msg[0].len = msg_len + 1; 50 buf[0] = reg + i * msg_len_max; 51 memcpy(&buf[1], &val[i * msg_len_max], msg_len); 52 53 ret = i2c_transfer(priv->i2c, msg, 1); 54 if (ret != 1) 55 break; 56 } 57 58 if (ret == 1) { 59 ret = 0; 60 } else { 61 warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); 62 ret = -EREMOTEIO; 63 } 64 65 return ret; 66} 67 68/* read multiple registers */ 69static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) 70{ 71 int ret; 72 u8 buf[reg+len]; /* we must start read always from reg 0x00 */ 73 struct i2c_msg msg[2] = { 74 { 75 .addr = priv->cfg->i2c_address, 76 .flags = 0, 77 .len = 1, 78 .buf = "\x00", 79 }, { 80 .addr = priv->cfg->i2c_address, 81 .flags = I2C_M_RD, 82 .len = sizeof(buf), 83 .buf = buf, 84 } 85 }; 86 87 ret = i2c_transfer(priv->i2c, msg, 2); 88 if (ret == 2) { 89 memcpy(val, &buf[reg], len); 90 ret = 0; 91 } else { 92 warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); 93 ret = -EREMOTEIO; 94 } 95 96 return ret; 97} 98 99/* write single register */ 100static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val) 101{ 102 return tda18218_wr_regs(priv, reg, &val, 1); 103} 104 105/* read single register */ 106 107static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val) 108{ 109 return tda18218_rd_regs(priv, reg, val, 1); 110} 111 112static int tda18218_set_params(struct dvb_frontend *fe, 113 struct dvb_frontend_parameters *params) 114{ 115 struct tda18218_priv *priv = fe->tuner_priv; 116 int ret; 117 u8 buf[3], i, BP_Filter, LP_Fc; 118 u32 LO_Frac; 119 /* TODO: find out correct AGC algorithm */ 120 u8 agc[][2] = { 121 { R20_AGC11, 0x60 }, 122 { R23_AGC21, 0x02 }, 123 { R20_AGC11, 0xa0 }, 124 { R23_AGC21, 0x09 }, 125 { R20_AGC11, 0xe0 }, 126 { R23_AGC21, 0x0c }, 127 { R20_AGC11, 0x40 }, 128 { R23_AGC21, 0x01 }, 129 { R20_AGC11, 0x80 }, 130 { R23_AGC21, 0x08 }, 131 { R20_AGC11, 0xc0 }, 132 { R23_AGC21, 0x0b }, 133 { R24_AGC22, 0x1c }, 134 { R24_AGC22, 0x0c }, 135 }; 136 137 if (fe->ops.i2c_gate_ctrl) 138 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 139 140 /* low-pass filter cut-off frequency */ 141 switch (params->u.ofdm.bandwidth) { 142 case BANDWIDTH_6_MHZ: 143 LP_Fc = 0; 144 LO_Frac = params->frequency + 4000000; 145 break; 146 case BANDWIDTH_7_MHZ: 147 LP_Fc = 1; 148 LO_Frac = params->frequency + 3500000; 149 break; 150 case BANDWIDTH_8_MHZ: 151 default: 152 LP_Fc = 2; 153 LO_Frac = params->frequency + 4000000; 154 break; 155 } 156 157 /* band-pass filter */ 158 if (LO_Frac < 188000000) 159 BP_Filter = 3; 160 else if (LO_Frac < 253000000) 161 BP_Filter = 4; 162 else if (LO_Frac < 343000000) 163 BP_Filter = 5; 164 else 165 BP_Filter = 6; 166 167 buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */ 168 buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */ 169 buf[2] = priv->regs[R1C_AGC2B]; 170 ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3); 171 if (ret) 172 goto error; 173 174 buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */ 175 buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */ 176 buf[2] = (LO_Frac / 1000) << 4 | 177 (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */ 178 ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3); 179 if (ret) 180 goto error; 181 182 buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */ 183 ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); 184 if (ret) 185 goto error; 186 187 buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */ 188 ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); 189 if (ret) 190 goto error; 191 192 /* trigger AGC */ 193 for (i = 0; i < ARRAY_SIZE(agc); i++) { 194 ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]); 195 if (ret) 196 goto error; 197 } 198 199error: 200 if (fe->ops.i2c_gate_ctrl) 201 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 202 203 if (ret) 204 dbg("%s: failed ret:%d", __func__, ret); 205 206 return ret; 207} 208 209static int tda18218_sleep(struct dvb_frontend *fe) 210{ 211 struct tda18218_priv *priv = fe->tuner_priv; 212 int ret; 213 214 if (fe->ops.i2c_gate_ctrl) 215 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 216 217 /* standby */ 218 ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); 219 220 if (fe->ops.i2c_gate_ctrl) 221 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 222 223 if (ret) 224 dbg("%s: failed ret:%d", __func__, ret); 225 226 return ret; 227} 228 229static int tda18218_init(struct dvb_frontend *fe) 230{ 231 struct tda18218_priv *priv = fe->tuner_priv; 232 int ret; 233 234 /* TODO: calibrations */ 235 236 if (fe->ops.i2c_gate_ctrl) 237 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 238 239 ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS); 240 241 if (fe->ops.i2c_gate_ctrl) 242 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 243 244 if (ret) 245 dbg("%s: failed ret:%d", __func__, ret); 246 247 return ret; 248} 249 250static int tda18218_release(struct dvb_frontend *fe) 251{ 252 kfree(fe->tuner_priv); 253 fe->tuner_priv = NULL; 254 return 0; 255} 256 257static const struct dvb_tuner_ops tda18218_tuner_ops = { 258 .info = { 259 .name = "NXP TDA18218", 260 261 .frequency_min = 174000000, 262 .frequency_max = 864000000, 263 .frequency_step = 1000, 264 }, 265 266 .release = tda18218_release, 267 .init = tda18218_init, 268 .sleep = tda18218_sleep, 269 270 .set_params = tda18218_set_params, 271}; 272 273struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, 274 struct i2c_adapter *i2c, struct tda18218_config *cfg) 275{ 276 struct tda18218_priv *priv = NULL; 277 u8 val; 278 int ret; 279 /* chip default registers values */ 280 static u8 def_regs[] = { 281 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40, 282 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00, 283 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01, 284 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9, 285 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00, 286 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6 287 }; 288 289 priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL); 290 if (priv == NULL) 291 return NULL; 292 293 priv->cfg = cfg; 294 priv->i2c = i2c; 295 fe->tuner_priv = priv; 296 297 if (fe->ops.i2c_gate_ctrl) 298 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 299 300 /* check if the tuner is there */ 301 ret = tda18218_rd_reg(priv, R00_ID, &val); 302 dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); 303 if (ret || val != def_regs[R00_ID]) { 304 kfree(priv); 305 return NULL; 306 } 307 308 info("NXP TDA18218HN successfully identified."); 309 310 memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops, 311 sizeof(struct dvb_tuner_ops)); 312 memcpy(priv->regs, def_regs, sizeof(def_regs)); 313 314 /* loop-through enabled chip default register values */ 315 if (priv->cfg->loop_through) { 316 priv->regs[R17_PD1] = 0xb0; 317 priv->regs[R18_PD2] = 0x59; 318 } 319 320 /* standby */ 321 ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); 322 if (ret) 323 dbg("%s: failed ret:%d", __func__, ret); 324 325 if (fe->ops.i2c_gate_ctrl) 326 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 327 328 return fe; 329} 330EXPORT_SYMBOL(tda18218_attach); 331 332MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver"); 333MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 334MODULE_LICENSE("GPL");