1 /* 2 * NXP TDA18212HN silicon tuner driver 3 * 4 * Copyright (C) 2011 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 along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #include "tda18212.h" 22 23 /* Max transfer size done by I2C transfer functions */ 24 #define MAX_XFER_SIZE 64 25 26 struct tda18212_priv { 27 struct tda18212_config *cfg; 28 struct i2c_adapter *i2c; 29 30 u32 if_frequency; 31 }; 32 33 /* write multiple registers */ 34 static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, 35 int len) 36 { 37 int ret; 38 u8 buf[MAX_XFER_SIZE]; 39 struct i2c_msg msg[1] = { 40 { 41 .addr = priv->cfg->i2c_address, 42 .flags = 0, 43 .len = 1 + len, 44 .buf = buf, 45 } 46 }; 47 48 if (1 + len > sizeof(buf)) { 49 dev_warn(&priv->i2c->dev, 50 "%s: i2c wr reg=%04x: len=%d is too big!\n", 51 KBUILD_MODNAME, reg, len); 52 return -EINVAL; 53 } 54 55 buf[0] = reg; 56 memcpy(&buf[1], val, len); 57 58 ret = i2c_transfer(priv->i2c, msg, 1); 59 if (ret == 1) { 60 ret = 0; 61 } else { 62 dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ 63 "len=%d\n", KBUILD_MODNAME, ret, reg, len); 64 ret = -EREMOTEIO; 65 } 66 return ret; 67 } 68 69 /* read multiple registers */ 70 static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, 71 int len) 72 { 73 int ret; 74 u8 buf[MAX_XFER_SIZE]; 75 struct i2c_msg msg[2] = { 76 { 77 .addr = priv->cfg->i2c_address, 78 .flags = 0, 79 .len = 1, 80 .buf = ®, 81 }, { 82 .addr = priv->cfg->i2c_address, 83 .flags = I2C_M_RD, 84 .len = len, 85 .buf = buf, 86 } 87 }; 88 89 if (len > sizeof(buf)) { 90 dev_warn(&priv->i2c->dev, 91 "%s: i2c rd reg=%04x: len=%d is too big!\n", 92 KBUILD_MODNAME, reg, len); 93 return -EINVAL; 94 } 95 96 ret = i2c_transfer(priv->i2c, msg, 2); 97 if (ret == 2) { 98 memcpy(val, buf, len); 99 ret = 0; 100 } else { 101 dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ 102 "len=%d\n", KBUILD_MODNAME, ret, reg, len); 103 ret = -EREMOTEIO; 104 } 105 106 return ret; 107 } 108 109 /* write single register */ 110 static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val) 111 { 112 return tda18212_wr_regs(priv, reg, &val, 1); 113 } 114 115 /* read single register */ 116 static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val) 117 { 118 return tda18212_rd_regs(priv, reg, val, 1); 119 } 120 121 #if 0 /* keep, useful when developing driver */ 122 static void tda18212_dump_regs(struct tda18212_priv *priv) 123 { 124 int i; 125 u8 buf[256]; 126 127 #define TDA18212_RD_LEN 32 128 for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN) 129 tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN); 130 131 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf, 132 sizeof(buf), true); 133 134 return; 135 } 136 #endif 137 138 static int tda18212_set_params(struct dvb_frontend *fe) 139 { 140 struct tda18212_priv *priv = fe->tuner_priv; 141 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 142 int ret, i; 143 u32 if_khz; 144 u8 buf[9]; 145 #define DVBT_6 0 146 #define DVBT_7 1 147 #define DVBT_8 2 148 #define DVBT2_6 3 149 #define DVBT2_7 4 150 #define DVBT2_8 5 151 #define DVBC_6 6 152 #define DVBC_8 7 153 #define ATSC_VSB 8 154 #define ATSC_QAM 9 155 static const u8 bw_params[][3] = { 156 /* reg: 0f 13 23 */ 157 [DVBT_6] = { 0xb3, 0x20, 0x03 }, 158 [DVBT_7] = { 0xb3, 0x31, 0x01 }, 159 [DVBT_8] = { 0xb3, 0x22, 0x01 }, 160 [DVBT2_6] = { 0xbc, 0x20, 0x03 }, 161 [DVBT2_7] = { 0xbc, 0x72, 0x03 }, 162 [DVBT2_8] = { 0xbc, 0x22, 0x01 }, 163 [DVBC_6] = { 0x92, 0x50, 0x03 }, 164 [DVBC_8] = { 0x92, 0x53, 0x03 }, 165 [ATSC_VSB] = { 0x7d, 0x20, 0x63 }, 166 [ATSC_QAM] = { 0x7d, 0x20, 0x63 }, 167 }; 168 169 dev_dbg(&priv->i2c->dev, 170 "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", 171 __func__, c->delivery_system, c->frequency, 172 c->bandwidth_hz); 173 174 if (fe->ops.i2c_gate_ctrl) 175 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 176 177 switch (c->delivery_system) { 178 case SYS_ATSC: 179 if_khz = priv->cfg->if_atsc_vsb; 180 i = ATSC_VSB; 181 break; 182 case SYS_DVBC_ANNEX_B: 183 if_khz = priv->cfg->if_atsc_qam; 184 i = ATSC_QAM; 185 break; 186 case SYS_DVBT: 187 switch (c->bandwidth_hz) { 188 case 6000000: 189 if_khz = priv->cfg->if_dvbt_6; 190 i = DVBT_6; 191 break; 192 case 7000000: 193 if_khz = priv->cfg->if_dvbt_7; 194 i = DVBT_7; 195 break; 196 case 8000000: 197 if_khz = priv->cfg->if_dvbt_8; 198 i = DVBT_8; 199 break; 200 default: 201 ret = -EINVAL; 202 goto error; 203 } 204 break; 205 case SYS_DVBT2: 206 switch (c->bandwidth_hz) { 207 case 6000000: 208 if_khz = priv->cfg->if_dvbt2_6; 209 i = DVBT2_6; 210 break; 211 case 7000000: 212 if_khz = priv->cfg->if_dvbt2_7; 213 i = DVBT2_7; 214 break; 215 case 8000000: 216 if_khz = priv->cfg->if_dvbt2_8; 217 i = DVBT2_8; 218 break; 219 default: 220 ret = -EINVAL; 221 goto error; 222 } 223 break; 224 case SYS_DVBC_ANNEX_A: 225 case SYS_DVBC_ANNEX_C: 226 if_khz = priv->cfg->if_dvbc; 227 i = DVBC_8; 228 break; 229 default: 230 ret = -EINVAL; 231 goto error; 232 } 233 234 ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]); 235 if (ret) 236 goto error; 237 238 ret = tda18212_wr_reg(priv, 0x06, 0x00); 239 if (ret) 240 goto error; 241 242 ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]); 243 if (ret) 244 goto error; 245 246 buf[0] = 0x02; 247 buf[1] = bw_params[i][1]; 248 buf[2] = 0x03; /* default value */ 249 buf[3] = DIV_ROUND_CLOSEST(if_khz, 50); 250 buf[4] = ((c->frequency / 1000) >> 16) & 0xff; 251 buf[5] = ((c->frequency / 1000) >> 8) & 0xff; 252 buf[6] = ((c->frequency / 1000) >> 0) & 0xff; 253 buf[7] = 0xc1; 254 buf[8] = 0x01; 255 ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf)); 256 if (ret) 257 goto error; 258 259 /* actual IF rounded as it is on register */ 260 priv->if_frequency = buf[3] * 50 * 1000; 261 262 exit: 263 if (fe->ops.i2c_gate_ctrl) 264 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 265 266 return ret; 267 268 error: 269 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); 270 goto exit; 271 } 272 273 static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 274 { 275 struct tda18212_priv *priv = fe->tuner_priv; 276 277 *frequency = priv->if_frequency; 278 279 return 0; 280 } 281 282 static int tda18212_release(struct dvb_frontend *fe) 283 { 284 kfree(fe->tuner_priv); 285 fe->tuner_priv = NULL; 286 return 0; 287 } 288 289 static const struct dvb_tuner_ops tda18212_tuner_ops = { 290 .info = { 291 .name = "NXP TDA18212", 292 293 .frequency_min = 48000000, 294 .frequency_max = 864000000, 295 .frequency_step = 1000, 296 }, 297 298 .release = tda18212_release, 299 300 .set_params = tda18212_set_params, 301 .get_if_frequency = tda18212_get_if_frequency, 302 }; 303 304 struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, 305 struct i2c_adapter *i2c, struct tda18212_config *cfg) 306 { 307 struct tda18212_priv *priv = NULL; 308 int ret; 309 u8 val; 310 311 priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL); 312 if (priv == NULL) 313 return NULL; 314 315 priv->cfg = cfg; 316 priv->i2c = i2c; 317 fe->tuner_priv = priv; 318 319 if (fe->ops.i2c_gate_ctrl) 320 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 321 322 /* check if the tuner is there */ 323 ret = tda18212_rd_reg(priv, 0x00, &val); 324 325 if (fe->ops.i2c_gate_ctrl) 326 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 327 328 if (!ret) 329 dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val); 330 if (ret || val != 0xc7) { 331 kfree(priv); 332 return NULL; 333 } 334 335 dev_info(&priv->i2c->dev, 336 "%s: NXP TDA18212HN successfully identified\n", 337 KBUILD_MODNAME); 338 339 memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, 340 sizeof(struct dvb_tuner_ops)); 341 342 return fe; 343 } 344 EXPORT_SYMBOL(tda18212_attach); 345 346 MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver"); 347 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 348 MODULE_LICENSE("GPL"); 349