Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] qm1d1c0042: add driver for Sharp QM1D1C0042 ISDB-S tuner

This patch adds driver for qm1d1c0042 tuner chips.
It is used as an ISDB-S tuner in earthsoft pt3 cards.

Signed-off-by: Akihiro Tsukada <tskd08@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

authored by

Akihiro Tsukada and committed by
Mauro Carvalho Chehab
7608f575 aff0c42a

+490
+7
drivers/media/tuners/Kconfig
··· 267 267 default m if !MEDIA_SUBDRV_AUTOSELECT 268 268 help 269 269 MaxLinear MxL301RF OFDM tuner driver. 270 + 271 + config MEDIA_TUNER_QM1D1C0042 272 + tristate "Sharp QM1D1C0042 tuner" 273 + depends on MEDIA_SUPPORT && I2C 274 + default m if !MEDIA_SUBDRV_AUTOSELECT 275 + help 276 + Sharp QM1D1C0042 trellis coded 8PSK tuner driver. 270 277 endmenu
+1
drivers/media/tuners/Makefile
··· 40 40 obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o 41 41 obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o 42 42 obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o 43 + obj-$(CONFIG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o 43 44 44 45 ccflags-y += -I$(srctree)/drivers/media/dvb-core 45 46 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+445
drivers/media/tuners/qm1d1c0042.c
··· 1 + /* 2 + * Sharp QM1D1C0042 8PSK tuner driver 3 + * 4 + * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License as 8 + * published by the Free Software Foundation version 2. 9 + * 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 + 17 + /* 18 + * NOTICE: 19 + * As the disclosed information on the chip is very limited, 20 + * this driver lacks some features, including chip config like IF freq. 21 + * It assumes that users of this driver (such as a PCI bridge of 22 + * DTV receiver cards) know the relevant info and 23 + * configure the chip via I2C if necessary. 24 + * 25 + * Currently, PT3 driver is the only one that uses this driver, 26 + * and contains init/config code in its firmware. 27 + * Thus some part of the code might be dependent on PT3 specific config. 28 + */ 29 + 30 + #include <linux/kernel.h> 31 + #include "qm1d1c0042.h" 32 + 33 + #define QM1D1C0042_NUM_REGS 0x20 34 + 35 + static const u8 reg_initval[QM1D1C0042_NUM_REGS] = { 36 + 0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33, 37 + 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 38 + 0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86, 39 + 0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00 40 + }; 41 + 42 + static const struct qm1d1c0042_config default_cfg = { 43 + .xtal_freq = 16000, 44 + .lpf = 1, 45 + .fast_srch = 0, 46 + .lpf_wait = 20, 47 + .fast_srch_wait = 4, 48 + .normal_srch_wait = 15, 49 + }; 50 + 51 + struct qm1d1c0042_state { 52 + struct qm1d1c0042_config cfg; 53 + struct i2c_client *i2c; 54 + u8 regs[QM1D1C0042_NUM_REGS]; 55 + }; 56 + 57 + static struct qm1d1c0042_state *cfg_to_state(struct qm1d1c0042_config *c) 58 + { 59 + return container_of(c, struct qm1d1c0042_state, cfg); 60 + } 61 + 62 + static int reg_write(struct qm1d1c0042_state *state, u8 reg, u8 val) 63 + { 64 + u8 wbuf[2] = { reg, val }; 65 + int ret; 66 + 67 + ret = i2c_master_send(state->i2c, wbuf, sizeof(wbuf)); 68 + if (ret >= 0 && ret < sizeof(wbuf)) 69 + ret = -EIO; 70 + return (ret == sizeof(wbuf)) ? 0 : ret; 71 + } 72 + 73 + static int reg_read(struct qm1d1c0042_state *state, u8 reg, u8 *val) 74 + { 75 + struct i2c_msg msgs[2] = { 76 + { 77 + .addr = state->i2c->addr, 78 + .flags = 0, 79 + .buf = &reg, 80 + .len = 1, 81 + }, 82 + { 83 + .addr = state->i2c->addr, 84 + .flags = I2C_M_RD, 85 + .buf = val, 86 + .len = 1, 87 + }, 88 + }; 89 + int ret; 90 + 91 + ret = i2c_transfer(state->i2c->adapter, msgs, ARRAY_SIZE(msgs)); 92 + if (ret >= 0 && ret < ARRAY_SIZE(msgs)) 93 + ret = -EIO; 94 + return (ret == ARRAY_SIZE(msgs)) ? 0 : ret; 95 + } 96 + 97 + 98 + static int qm1d1c0042_set_srch_mode(struct qm1d1c0042_state *state, bool fast) 99 + { 100 + if (fast) 101 + state->regs[0x03] |= 0x01; /* set fast search mode */ 102 + else 103 + state->regs[0x03] &= ~0x01 & 0xff; 104 + 105 + return reg_write(state, 0x03, state->regs[0x03]); 106 + } 107 + 108 + static int qm1d1c0042_wakeup(struct qm1d1c0042_state *state) 109 + { 110 + int ret; 111 + 112 + state->regs[0x01] |= 1 << 3; /* BB_Reg_enable */ 113 + state->regs[0x01] &= (~(1 << 0)) & 0xff; /* NORMAL (wake-up) */ 114 + state->regs[0x05] &= (~(1 << 3)) & 0xff; /* pfd_rst NORMAL */ 115 + ret = reg_write(state, 0x01, state->regs[0x01]); 116 + if (ret == 0) 117 + ret = reg_write(state, 0x05, state->regs[0x05]); 118 + 119 + if (ret < 0) 120 + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", 121 + __func__, state->cfg.fe->dvb->num, state->cfg.fe->id); 122 + return ret; 123 + } 124 + 125 + /* tuner_ops */ 126 + 127 + static int qm1d1c0042_set_config(struct dvb_frontend *fe, void *priv_cfg) 128 + { 129 + struct qm1d1c0042_state *state; 130 + struct qm1d1c0042_config *cfg; 131 + 132 + state = fe->tuner_priv; 133 + cfg = priv_cfg; 134 + 135 + if (cfg->fe) 136 + state->cfg.fe = cfg->fe; 137 + 138 + if (cfg->xtal_freq != QM1D1C0042_CFG_XTAL_DFLT) 139 + dev_warn(&state->i2c->dev, 140 + "(%s) changing xtal_freq not supported. ", __func__); 141 + state->cfg.xtal_freq = default_cfg.xtal_freq; 142 + 143 + state->cfg.lpf = cfg->lpf; 144 + state->cfg.fast_srch = cfg->fast_srch; 145 + 146 + if (cfg->lpf_wait != QM1D1C0042_CFG_WAIT_DFLT) 147 + state->cfg.lpf_wait = cfg->lpf_wait; 148 + else 149 + state->cfg.lpf_wait = default_cfg.lpf_wait; 150 + 151 + if (cfg->fast_srch_wait != QM1D1C0042_CFG_WAIT_DFLT) 152 + state->cfg.fast_srch_wait = cfg->fast_srch_wait; 153 + else 154 + state->cfg.fast_srch_wait = default_cfg.fast_srch_wait; 155 + 156 + if (cfg->normal_srch_wait != QM1D1C0042_CFG_WAIT_DFLT) 157 + state->cfg.normal_srch_wait = cfg->normal_srch_wait; 158 + else 159 + state->cfg.normal_srch_wait = default_cfg.normal_srch_wait; 160 + return 0; 161 + } 162 + 163 + /* divisor, vco_band parameters */ 164 + /* {maxfreq, param1(band?), param2(div?) */ 165 + static const u32 conv_table[9][3] = { 166 + { 2151000, 1, 7 }, 167 + { 1950000, 1, 6 }, 168 + { 1800000, 1, 5 }, 169 + { 1600000, 1, 4 }, 170 + { 1450000, 1, 3 }, 171 + { 1250000, 1, 2 }, 172 + { 1200000, 0, 7 }, 173 + { 975000, 0, 6 }, 174 + { 950000, 0, 0 } 175 + }; 176 + 177 + static int qm1d1c0042_set_params(struct dvb_frontend *fe) 178 + { 179 + struct qm1d1c0042_state *state; 180 + u32 freq; 181 + int i, ret; 182 + u8 val, mask; 183 + u32 a, sd; 184 + s32 b; 185 + 186 + state = fe->tuner_priv; 187 + freq = fe->dtv_property_cache.frequency; 188 + 189 + state->regs[0x08] &= 0xf0; 190 + state->regs[0x08] |= 0x09; 191 + 192 + state->regs[0x13] &= 0x9f; 193 + state->regs[0x13] |= 0x20; 194 + 195 + /* div2/vco_band */ 196 + val = state->regs[0x02] & 0x0f; 197 + for (i = 0; i < 8; i++) 198 + if (freq < conv_table[i][0] && freq >= conv_table[i + 1][0]) { 199 + val |= conv_table[i][1] << 7; 200 + val |= conv_table[i][2] << 4; 201 + break; 202 + } 203 + ret = reg_write(state, 0x02, val); 204 + if (ret < 0) 205 + return ret; 206 + 207 + a = (freq + state->cfg.xtal_freq / 2) / state->cfg.xtal_freq; 208 + 209 + state->regs[0x06] &= 0x40; 210 + state->regs[0x06] |= (a - 12) / 4; 211 + ret = reg_write(state, 0x06, state->regs[0x06]); 212 + if (ret < 0) 213 + return ret; 214 + 215 + state->regs[0x07] &= 0xf0; 216 + state->regs[0x07] |= (a - 4 * ((a - 12) / 4 + 1) - 5) & 0x0f; 217 + ret = reg_write(state, 0x07, state->regs[0x07]); 218 + if (ret < 0) 219 + return ret; 220 + 221 + /* LPF */ 222 + val = state->regs[0x08]; 223 + if (state->cfg.lpf) { 224 + /* LPF_CLK, LPF_FC */ 225 + val &= 0xf0; 226 + val |= 0x02; 227 + } 228 + ret = reg_write(state, 0x08, val); 229 + if (ret < 0) 230 + return ret; 231 + 232 + /* 233 + * b = (freq / state->cfg.xtal_freq - a) << 20; 234 + * sd = b (b >= 0) 235 + * 1<<22 + b (b < 0) 236 + */ 237 + b = (((s64) freq) << 20) / state->cfg.xtal_freq - (((s64) a) << 20); 238 + if (b >= 0) 239 + sd = b; 240 + else 241 + sd = (1 << 22) + b; 242 + 243 + state->regs[0x09] &= 0xc0; 244 + state->regs[0x09] |= (sd >> 16) & 0x3f; 245 + state->regs[0x0a] = (sd >> 8) & 0xff; 246 + state->regs[0x0b] = sd & 0xff; 247 + ret = reg_write(state, 0x09, state->regs[0x09]); 248 + if (ret == 0) 249 + ret = reg_write(state, 0x0a, state->regs[0x0a]); 250 + if (ret == 0) 251 + ret = reg_write(state, 0x0b, state->regs[0x0b]); 252 + if (ret != 0) 253 + return ret; 254 + 255 + if (!state->cfg.lpf) { 256 + /* CSEL_Offset */ 257 + ret = reg_write(state, 0x13, state->regs[0x13]); 258 + if (ret < 0) 259 + return ret; 260 + } 261 + 262 + /* VCO_TM, LPF_TM */ 263 + mask = state->cfg.lpf ? 0x3f : 0x7f; 264 + val = state->regs[0x0c] & mask; 265 + ret = reg_write(state, 0x0c, val); 266 + if (ret < 0) 267 + return ret; 268 + usleep_range(2000, 3000); 269 + val = state->regs[0x0c] | ~mask; 270 + ret = reg_write(state, 0x0c, val); 271 + if (ret < 0) 272 + return ret; 273 + 274 + if (state->cfg.lpf) 275 + msleep(state->cfg.lpf_wait); 276 + else if (state->regs[0x03] & 0x01) 277 + msleep(state->cfg.fast_srch_wait); 278 + else 279 + msleep(state->cfg.normal_srch_wait); 280 + 281 + if (state->cfg.lpf) { 282 + /* LPF_FC */ 283 + ret = reg_write(state, 0x08, 0x09); 284 + if (ret < 0) 285 + return ret; 286 + 287 + /* CSEL_Offset */ 288 + ret = reg_write(state, 0x13, state->regs[0x13]); 289 + if (ret < 0) 290 + return ret; 291 + } 292 + return 0; 293 + } 294 + 295 + static int qm1d1c0042_sleep(struct dvb_frontend *fe) 296 + { 297 + struct qm1d1c0042_state *state; 298 + int ret; 299 + 300 + state = fe->tuner_priv; 301 + state->regs[0x01] &= (~(1 << 3)) & 0xff; /* BB_Reg_disable */ 302 + state->regs[0x01] |= 1 << 0; /* STDBY */ 303 + state->regs[0x05] |= 1 << 3; /* pfd_rst STANDBY */ 304 + ret = reg_write(state, 0x05, state->regs[0x05]); 305 + if (ret == 0) 306 + ret = reg_write(state, 0x01, state->regs[0x01]); 307 + if (ret < 0) 308 + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", 309 + __func__, fe->dvb->num, fe->id); 310 + return ret; 311 + } 312 + 313 + static int qm1d1c0042_init(struct dvb_frontend *fe) 314 + { 315 + struct qm1d1c0042_state *state; 316 + u8 val; 317 + int i, ret; 318 + 319 + state = fe->tuner_priv; 320 + memcpy(state->regs, reg_initval, sizeof(reg_initval)); 321 + 322 + reg_write(state, 0x01, 0x0c); 323 + reg_write(state, 0x01, 0x0c); 324 + 325 + ret = reg_write(state, 0x01, 0x0c); /* soft reset on */ 326 + if (ret < 0) 327 + goto failed; 328 + usleep_range(2000, 3000); 329 + 330 + val = state->regs[0x01] | 0x10; 331 + ret = reg_write(state, 0x01, val); /* soft reset off */ 332 + if (ret < 0) 333 + goto failed; 334 + 335 + /* check ID */ 336 + ret = reg_read(state, 0x00, &val); 337 + if (ret < 0 || val != 0x48) 338 + goto failed; 339 + usleep_range(2000, 3000); 340 + 341 + state->regs[0x0c] |= 0x40; 342 + ret = reg_write(state, 0x0c, state->regs[0x0c]); 343 + if (ret < 0) 344 + goto failed; 345 + msleep(state->cfg.lpf_wait); 346 + 347 + /* set all writable registers */ 348 + for (i = 1; i <= 0x0c ; i++) { 349 + ret = reg_write(state, i, state->regs[i]); 350 + if (ret < 0) 351 + goto failed; 352 + } 353 + for (i = 0x11; i < QM1D1C0042_NUM_REGS; i++) { 354 + ret = reg_write(state, i, state->regs[i]); 355 + if (ret < 0) 356 + goto failed; 357 + } 358 + 359 + ret = qm1d1c0042_wakeup(state); 360 + if (ret < 0) 361 + goto failed; 362 + 363 + ret = qm1d1c0042_set_srch_mode(state, state->cfg.fast_srch); 364 + if (ret < 0) 365 + goto failed; 366 + 367 + return ret; 368 + 369 + failed: 370 + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", 371 + __func__, fe->dvb->num, fe->id); 372 + return ret; 373 + } 374 + 375 + /* I2C driver functions */ 376 + 377 + static const struct dvb_tuner_ops qm1d1c0042_ops = { 378 + .info = { 379 + .name = "Sharp QM1D1C0042", 380 + 381 + .frequency_min = 950000, 382 + .frequency_max = 2150000, 383 + }, 384 + 385 + .init = qm1d1c0042_init, 386 + .sleep = qm1d1c0042_sleep, 387 + .set_config = qm1d1c0042_set_config, 388 + .set_params = qm1d1c0042_set_params, 389 + }; 390 + 391 + 392 + static int qm1d1c0042_probe(struct i2c_client *client, 393 + const struct i2c_device_id *id) 394 + { 395 + struct qm1d1c0042_state *state; 396 + struct qm1d1c0042_config *cfg; 397 + struct dvb_frontend *fe; 398 + 399 + state = kzalloc(sizeof(*state), GFP_KERNEL); 400 + if (!state) 401 + return -ENOMEM; 402 + state->i2c = client; 403 + 404 + cfg = client->dev.platform_data; 405 + fe = cfg->fe; 406 + fe->tuner_priv = state; 407 + qm1d1c0042_set_config(fe, cfg); 408 + memcpy(&fe->ops.tuner_ops, &qm1d1c0042_ops, sizeof(qm1d1c0042_ops)); 409 + 410 + i2c_set_clientdata(client, &state->cfg); 411 + dev_info(&client->dev, "Sharp QM1D1C0042 attached.\n"); 412 + return 0; 413 + } 414 + 415 + static int qm1d1c0042_remove(struct i2c_client *client) 416 + { 417 + struct qm1d1c0042_state *state; 418 + 419 + state = cfg_to_state(i2c_get_clientdata(client)); 420 + state->cfg.fe->tuner_priv = NULL; 421 + kfree(state); 422 + return 0; 423 + } 424 + 425 + 426 + static const struct i2c_device_id qm1d1c0042_id[] = { 427 + {"qm1d1c0042", 0}, 428 + {} 429 + }; 430 + MODULE_DEVICE_TABLE(i2c, qm1d1c0042_id); 431 + 432 + static struct i2c_driver qm1d1c0042_driver = { 433 + .driver = { 434 + .name = "qm1d1c0042", 435 + }, 436 + .probe = qm1d1c0042_probe, 437 + .remove = qm1d1c0042_remove, 438 + .id_table = qm1d1c0042_id, 439 + }; 440 + 441 + module_i2c_driver(qm1d1c0042_driver); 442 + 443 + MODULE_DESCRIPTION("Sharp QM1D1C0042 tuner"); 444 + MODULE_AUTHOR("Akihiro TSUKADA"); 445 + MODULE_LICENSE("GPL");
+37
drivers/media/tuners/qm1d1c0042.h
··· 1 + /* 2 + * Sharp QM1D1C0042 8PSK tuner driver 3 + * 4 + * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License as 8 + * published by the Free Software Foundation version 2. 9 + * 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 + 17 + #ifndef QM1D1C0042_H 18 + #define QM1D1C0042_H 19 + 20 + #include "dvb_frontend.h" 21 + 22 + 23 + struct qm1d1c0042_config { 24 + struct dvb_frontend *fe; 25 + 26 + u32 xtal_freq; /* [kHz] */ /* currently ignored */ 27 + bool lpf; /* enable LPF */ 28 + bool fast_srch; /* enable fast search mode, no LPF */ 29 + u32 lpf_wait; /* wait in tuning with LPF enabled. [ms] */ 30 + u32 fast_srch_wait; /* with fast-search mode, no LPF. [ms] */ 31 + u32 normal_srch_wait; /* with no LPF/fast-search mode. [ms] */ 32 + }; 33 + /* special values indicating to use the default in qm1d1c0042_config */ 34 + #define QM1D1C0042_CFG_XTAL_DFLT 0 35 + #define QM1D1C0042_CFG_WAIT_DFLT 0 36 + 37 + #endif /* QM1D1C0042_H */