aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/tuners/Kconfig7
-rw-r--r--drivers/media/tuners/Makefile1
-rw-r--r--drivers/media/tuners/m88ts2022.c664
-rw-r--r--drivers/media/tuners/m88ts2022.h72
-rw-r--r--drivers/media/tuners/m88ts2022_priv.h38
5 files changed, 782 insertions, 0 deletions
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index 15665debc572..ba2e365296cf 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -215,6 +215,13 @@ config MEDIA_TUNER_FC2580
215 help 215 help
216 FCI FC2580 silicon tuner driver. 216 FCI FC2580 silicon tuner driver.
217 217
218config MEDIA_TUNER_M88TS2022
219 tristate "Montage M88TS2022 silicon tuner"
220 depends on MEDIA_SUPPORT && I2C
221 default m if !MEDIA_SUBDRV_AUTOSELECT
222 help
223 Montage M88TS2022 silicon tuner driver.
224
218config MEDIA_TUNER_TUA9001 225config MEDIA_TUNER_TUA9001
219 tristate "Infineon TUA 9001 silicon tuner" 226 tristate "Infineon TUA 9001 silicon tuner"
220 depends on MEDIA_SUPPORT && I2C 227 depends on MEDIA_SUPPORT && I2C
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
index 308f108eadba..efe82a904b12 100644
--- a/drivers/media/tuners/Makefile
+++ b/drivers/media/tuners/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
31obj-$(CONFIG_MEDIA_TUNER_E4000) += e4000.o 31obj-$(CONFIG_MEDIA_TUNER_E4000) += e4000.o
32obj-$(CONFIG_MEDIA_TUNER_FC2580) += fc2580.o 32obj-$(CONFIG_MEDIA_TUNER_FC2580) += fc2580.o
33obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o 33obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
34obj-$(CONFIG_MEDIA_TUNER_M88TS2022) += m88ts2022.o
34obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o 35obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
35obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o 36obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
36obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o 37obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c
new file mode 100644
index 000000000000..0625e36d0a92
--- /dev/null
+++ b/drivers/media/tuners/m88ts2022.c
@@ -0,0 +1,664 @@
1/*
2 * Montage M88TS2022 silicon tuner driver
3 *
4 * Copyright (C) 2013 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 * Some calculations are taken from existing TS2020 driver.
21 */
22
23#include "m88ts2022_priv.h"
24
25/* write multiple registers */
26static int m88ts2022_wr_regs(struct m88ts2022_priv *priv,
27 u8 reg, const u8 *val, int len)
28{
29 int ret;
30 u8 buf[1 + len];
31 struct i2c_msg msg[1] = {
32 {
33 .addr = priv->cfg->i2c_addr,
34 .flags = 0,
35 .len = sizeof(buf),
36 .buf = buf,
37 }
38 };
39
40 buf[0] = reg;
41 memcpy(&buf[1], val, len);
42
43 ret = i2c_transfer(priv->i2c, msg, 1);
44 if (ret == 1) {
45 ret = 0;
46 } else {
47 dev_warn(&priv->i2c->dev,
48 "%s: i2c wr failed=%d reg=%02x len=%d\n",
49 KBUILD_MODNAME, ret, reg, len);
50 ret = -EREMOTEIO;
51 }
52
53 return ret;
54}
55
56/* read multiple registers */
57static int m88ts2022_rd_regs(struct m88ts2022_priv *priv, u8 reg,
58 u8 *val, int len)
59{
60 int ret;
61 u8 buf[len];
62 struct i2c_msg msg[2] = {
63 {
64 .addr = priv->cfg->i2c_addr,
65 .flags = 0,
66 .len = 1,
67 .buf = &reg,
68 }, {
69 .addr = priv->cfg->i2c_addr,
70 .flags = I2C_M_RD,
71 .len = sizeof(buf),
72 .buf = buf,
73 }
74 };
75
76 ret = i2c_transfer(priv->i2c, msg, 2);
77 if (ret == 2) {
78 memcpy(val, buf, len);
79 ret = 0;
80 } else {
81 dev_warn(&priv->i2c->dev,
82 "%s: i2c rd failed=%d reg=%02x len=%d\n",
83 KBUILD_MODNAME, ret, reg, len);
84 ret = -EREMOTEIO;
85 }
86
87 return ret;
88}
89
90/* write single register */
91static int m88ts2022_wr_reg(struct m88ts2022_priv *priv, u8 reg, u8 val)
92{
93 return m88ts2022_wr_regs(priv, reg, &val, 1);
94}
95
96/* read single register */
97static int m88ts2022_rd_reg(struct m88ts2022_priv *priv, u8 reg, u8 *val)
98{
99 return m88ts2022_rd_regs(priv, reg, val, 1);
100}
101
102/* write single register with mask */
103static int m88ts2022_wr_reg_mask(struct m88ts2022_priv *priv,
104 u8 reg, u8 val, u8 mask)
105{
106 int ret;
107 u8 u8tmp;
108
109 /* no need for read if whole reg is written */
110 if (mask != 0xff) {
111 ret = m88ts2022_rd_regs(priv, reg, &u8tmp, 1);
112 if (ret)
113 return ret;
114
115 val &= mask;
116 u8tmp &= ~mask;
117 val |= u8tmp;
118 }
119
120 return m88ts2022_wr_regs(priv, reg, &val, 1);
121}
122
123static int m88ts2022_cmd(struct dvb_frontend *fe,
124 int op, int sleep, u8 reg, u8 mask, u8 val, u8 *reg_val)
125{
126 struct m88ts2022_priv *priv = fe->tuner_priv;
127 int ret, i;
128 u8 u8tmp;
129 struct m88ts2022_reg_val reg_vals[] = {
130 {0x51, 0x1f - op},
131 {0x51, 0x1f},
132 {0x50, 0x00 + op},
133 {0x50, 0x00},
134 };
135
136 for (i = 0; i < 2; i++) {
137 dev_dbg(&priv->i2c->dev,
138 "%s: i=%d op=%02x reg=%02x mask=%02x val=%02x\n",
139 __func__, i, op, reg, mask, val);
140
141 for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
142 ret = m88ts2022_wr_reg(priv, reg_vals[i].reg,
143 reg_vals[i].val);
144 if (ret)
145 goto err;
146 }
147
148 usleep_range(sleep * 1000, sleep * 10000);
149
150 ret = m88ts2022_rd_reg(priv, reg, &u8tmp);
151 if (ret)
152 goto err;
153
154 if ((u8tmp & mask) != val)
155 break;
156 }
157
158 if (reg_val)
159 *reg_val = u8tmp;
160err:
161 return ret;
162}
163
164static int m88ts2022_set_params(struct dvb_frontend *fe)
165{
166 struct m88ts2022_priv *priv = fe->tuner_priv;
167 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
168 int ret = 0, div;
169 u8 buf[3], u8tmp, cap_code, lpf_mxdiv, div_max, div_min;
170 u16 N_reg, N, K;
171 u32 lpf_gm, lpf_coeff, gdiv28, frequency_khz, frequency_offset;
172 u32 freq_3db;
173 dev_dbg(&priv->i2c->dev,
174 "%s: frequency=%d symbol_rate=%d rolloff=%d\n",
175 __func__, c->frequency, c->symbol_rate, c->rolloff);
176
177 if (c->symbol_rate < 5000000)
178 frequency_offset = 3000000; /* 3 MHz */
179 else
180 frequency_offset = 0;
181
182 frequency_khz = c->frequency + (frequency_offset / 1000);
183
184 if (frequency_khz < 1103000) {
185 div = 2;
186 u8tmp = 0x1b;
187 } else {
188 div = 1;
189 u8tmp = 0x0b;
190 }
191
192 buf[0] = u8tmp;
193 buf[1] = 0x40;
194 ret = m88ts2022_wr_regs(priv, 0x10, buf, 2);
195 if (ret)
196 goto err;
197
198 K = DIV_ROUND_CLOSEST((priv->cfg->clock / 2), 1000000);
199 N = 1ul * frequency_khz * K * div * 2 / (priv->cfg->clock / 1000);
200 N += N % 2;
201
202 if (N < 4095)
203 N_reg = N - 1024;
204 else if (N < 6143)
205 N_reg = N + 1024;
206 else
207 N_reg = N + 3072;
208
209 buf[0] = (N_reg >> 8) & 0x3f;
210 buf[1] = (N_reg >> 0) & 0xff;
211 buf[2] = K - 8;
212 ret = m88ts2022_wr_regs(priv, 0x01, buf, 3);
213 if (ret)
214 goto err;
215
216 priv->frequency_khz = 1ul * N * (priv->cfg->clock / 1000) / K / div / 2;
217
218 dev_dbg(&priv->i2c->dev,
219 "%s: frequency=%d offset=%d K=%d N=%d div=%d\n",
220 __func__, priv->frequency_khz,
221 priv->frequency_khz - c->frequency, K, N, div);
222
223 ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL);
224 if (ret)
225 goto err;
226
227 ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp);
228 if (ret)
229 goto err;
230
231 u8tmp &= 0x7f;
232 if (u8tmp < 64) {
233 ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x80, 0x80);
234 if (ret)
235 goto err;
236
237 ret = m88ts2022_wr_reg(priv, 0x11, 0x6f);
238 if (ret)
239 goto err;
240
241 ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL);
242 if (ret)
243 goto err;
244 }
245
246 ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp);
247 if (ret)
248 goto err;
249
250 u8tmp &= 0x1f;
251 if (u8tmp > 19) {
252 ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x00, 0x02);
253 if (ret)
254 goto err;
255 }
256
257 ret = m88ts2022_cmd(fe, 0x08, 5, 0x3c, 0xff, 0x00, NULL);
258 if (ret)
259 goto err;
260
261 ret = m88ts2022_wr_reg(priv, 0x25, 0x00);
262 if (ret)
263 goto err;
264
265 ret = m88ts2022_wr_reg(priv, 0x27, 0x70);
266 if (ret)
267 goto err;
268
269 ret = m88ts2022_wr_reg(priv, 0x41, 0x09);
270 if (ret)
271 goto err;
272
273 ret = m88ts2022_wr_reg(priv, 0x08, 0x0b);
274 if (ret)
275 goto err;
276
277 gdiv28 = DIV_ROUND_CLOSEST(priv->cfg->clock / 1000000 * 1694, 1000);
278
279 ret = m88ts2022_wr_reg(priv, 0x04, gdiv28);
280 if (ret)
281 goto err;
282
283 ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
284 if (ret)
285 goto err;
286
287 cap_code = u8tmp & 0x3f;
288
289 ret = m88ts2022_wr_reg(priv, 0x41, 0x0d);
290 if (ret)
291 goto err;
292
293 ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
294 if (ret)
295 goto err;
296
297 u8tmp &= 0x3f;
298 cap_code = (cap_code + u8tmp) / 2;
299 gdiv28 = gdiv28 * 207 / (cap_code * 2 + 151);
300 div_max = gdiv28 * 135 / 100;
301 div_min = gdiv28 * 78 / 100;
302 if (div_max > 63)
303 div_max = 63;
304
305 freq_3db = 1ul * c->symbol_rate * 135 / 200 + 2000000;
306 freq_3db += frequency_offset;
307 if (freq_3db < 7000000)
308 freq_3db = 7000000;
309 if (freq_3db > 40000000)
310 freq_3db = 40000000;
311
312 lpf_coeff = 3200;
313 lpf_gm = DIV_ROUND_CLOSEST(freq_3db * gdiv28, lpf_coeff *
314 (priv->cfg->clock / 1000));
315 if (lpf_gm > 23)
316 lpf_gm = 23;
317 if (lpf_gm < 1)
318 lpf_gm = 1;
319
320 lpf_mxdiv = DIV_ROUND_CLOSEST(lpf_gm * lpf_coeff *
321 (priv->cfg->clock / 1000), freq_3db);
322
323 if (lpf_mxdiv < div_min) {
324 lpf_gm++;
325 lpf_mxdiv = DIV_ROUND_CLOSEST(lpf_gm * lpf_coeff *
326 (priv->cfg->clock / 1000), freq_3db);
327 }
328
329 if (lpf_mxdiv > div_max)
330 lpf_mxdiv = div_max;
331
332 ret = m88ts2022_wr_reg(priv, 0x04, lpf_mxdiv);
333 if (ret)
334 goto err;
335
336 ret = m88ts2022_wr_reg(priv, 0x06, lpf_gm);
337 if (ret)
338 goto err;
339
340 ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
341 if (ret)
342 goto err;
343
344 cap_code = u8tmp & 0x3f;
345
346 ret = m88ts2022_wr_reg(priv, 0x41, 0x09);
347 if (ret)
348 goto err;
349
350 ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
351 if (ret)
352 goto err;
353
354 u8tmp &= 0x3f;
355 cap_code = (cap_code + u8tmp) / 2;
356
357 u8tmp = cap_code | 0x80;
358 ret = m88ts2022_wr_reg(priv, 0x25, u8tmp);
359 if (ret)
360 goto err;
361
362 ret = m88ts2022_wr_reg(priv, 0x27, 0x30);
363 if (ret)
364 goto err;
365
366 ret = m88ts2022_wr_reg(priv, 0x08, 0x09);
367 if (ret)
368 goto err;
369
370 ret = m88ts2022_cmd(fe, 0x01, 20, 0x21, 0xff, 0x00, NULL);
371 if (ret)
372 goto err;
373err:
374 if (ret)
375 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
376
377 return ret;
378}
379
380static int m88ts2022_init(struct dvb_frontend *fe)
381{
382 struct m88ts2022_priv *priv = fe->tuner_priv;
383 int ret, i;
384 u8 u8tmp;
385 static const struct m88ts2022_reg_val reg_vals[] = {
386 {0x7d, 0x9d},
387 {0x7c, 0x9a},
388 {0x7a, 0x76},
389 {0x3b, 0x01},
390 {0x63, 0x88},
391 {0x61, 0x85},
392 {0x22, 0x30},
393 {0x30, 0x40},
394 {0x20, 0x23},
395 {0x24, 0x02},
396 {0x12, 0xa0},
397 };
398 dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
399
400 ret = m88ts2022_wr_reg(priv, 0x00, 0x01);
401 if (ret)
402 goto err;
403
404 ret = m88ts2022_wr_reg(priv, 0x00, 0x03);
405 if (ret)
406 goto err;
407
408 switch (priv->cfg->clock_out) {
409 case M88TS2022_CLOCK_OUT_DISABLED:
410 u8tmp = 0x60;
411 break;
412 case M88TS2022_CLOCK_OUT_ENABLED:
413 u8tmp = 0x70;
414 ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg->clock_out_div);
415 if (ret)
416 goto err;
417 break;
418 case M88TS2022_CLOCK_OUT_ENABLED_XTALOUT:
419 u8tmp = 0x6c;
420 break;
421 default:
422 goto err;
423 }
424
425 ret = m88ts2022_wr_reg(priv, 0x42, u8tmp);
426 if (ret)
427 goto err;
428
429 if (priv->cfg->loop_through)
430 u8tmp = 0xec;
431 else
432 u8tmp = 0x6c;
433
434 ret = m88ts2022_wr_reg(priv, 0x62, u8tmp);
435 if (ret)
436 goto err;
437
438 for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
439 ret = m88ts2022_wr_reg(priv, reg_vals[i].reg, reg_vals[i].val);
440 if (ret)
441 goto err;
442 }
443err:
444 if (ret)
445 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
446 return ret;
447}
448
449static int m88ts2022_sleep(struct dvb_frontend *fe)
450{
451 struct m88ts2022_priv *priv = fe->tuner_priv;
452 int ret;
453 dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
454
455 ret = m88ts2022_wr_reg(priv, 0x00, 0x00);
456 if (ret)
457 goto err;
458err:
459 if (ret)
460 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
461 return ret;
462}
463
464static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency)
465{
466 struct m88ts2022_priv *priv = fe->tuner_priv;
467 dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
468
469 *frequency = priv->frequency_khz;
470 return 0;
471}
472
473static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
474{
475 struct m88ts2022_priv *priv = fe->tuner_priv;
476 dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
477
478 *frequency = 0; /* Zero-IF */
479 return 0;
480}
481
482static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
483{
484 struct m88ts2022_priv *priv = fe->tuner_priv;
485 u8 u8tmp, gain1, gain2, gain3;
486 u16 gain, u16tmp;
487 int ret;
488
489 ret = m88ts2022_rd_reg(priv, 0x3d, &u8tmp);
490 if (ret)
491 goto err;
492
493 gain1 = (u8tmp >> 0) & 0x1f;
494 if (gain1 > 15)
495 gain1 = 15;
496
497 ret = m88ts2022_rd_reg(priv, 0x21, &u8tmp);
498 if (ret)
499 goto err;
500
501 gain2 = (u8tmp >> 0) & 0x1f;
502 if (gain2 < 2)
503 gain2 = 2;
504 if (gain2 > 16)
505 gain2 = 16;
506
507 ret = m88ts2022_rd_reg(priv, 0x66, &u8tmp);
508 if (ret)
509 goto err;
510
511 gain3 = (u8tmp >> 3) & 0x07;
512 if (gain3 > 6)
513 gain3 = 6;
514
515 gain = gain1 * 265 + gain2 * 338 + gain3 * 285;
516
517 /* scale value to 0x0000-0xffff */
518 u16tmp = (0xffff - gain);
519 if (u16tmp < 59000)
520 u16tmp = 59000;
521 else if (u16tmp > 61500)
522 u16tmp = 61500;
523
524 *strength = (u16tmp - 59000) * 0xffff / (61500 - 59000);
525err:
526 if (ret)
527 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
528 return ret;
529}
530
531static int m88ts2022_release(struct dvb_frontend *fe)
532{
533 struct m88ts2022_priv *priv = fe->tuner_priv;
534 dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
535
536 kfree(fe->tuner_priv);
537 return 0;
538}
539
540static const struct dvb_tuner_ops m88ts2022_tuner_ops = {
541 .info = {
542 .name = "Montage M88TS2022",
543 .frequency_min = 950000,
544 .frequency_max = 2150000,
545 },
546
547 .release = m88ts2022_release,
548
549 .init = m88ts2022_init,
550 .sleep = m88ts2022_sleep,
551 .set_params = m88ts2022_set_params,
552
553 .get_frequency = m88ts2022_get_frequency,
554 .get_if_frequency = m88ts2022_get_if_frequency,
555 .get_rf_strength = m88ts2022_get_rf_strength,
556};
557
558struct dvb_frontend *m88ts2022_attach(struct dvb_frontend *fe,
559 struct i2c_adapter *i2c, const struct m88ts2022_config *cfg)
560{
561 struct m88ts2022_priv *priv;
562 int ret;
563 u8 chip_id, u8tmp;
564
565 priv = kzalloc(sizeof(struct m88ts2022_priv), GFP_KERNEL);
566 if (!priv) {
567 ret = -ENOMEM;
568 dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
569 goto err;
570 }
571
572 priv->cfg = cfg;
573 priv->i2c = i2c;
574 priv->fe = fe;
575
576 /* check if the tuner is there */
577 ret = m88ts2022_rd_reg(priv, 0x00, &u8tmp);
578 if (ret)
579 goto err;
580
581 if ((u8tmp & 0x03) == 0x00) {
582 ret = m88ts2022_wr_reg(priv, 0x00, 0x01);
583 if (ret < 0)
584 goto err;
585
586 usleep_range(2000, 50000);
587 }
588
589 ret = m88ts2022_wr_reg(priv, 0x00, 0x03);
590 if (ret)
591 goto err;
592
593 usleep_range(2000, 50000);
594
595 ret = m88ts2022_rd_reg(priv, 0x00, &chip_id);
596 if (ret)
597 goto err;
598
599 dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id);
600
601 switch (chip_id) {
602 case 0xc3:
603 case 0x83:
604 break;
605 default:
606 goto err;
607 }
608
609 switch (priv->cfg->clock_out) {
610 case M88TS2022_CLOCK_OUT_DISABLED:
611 u8tmp = 0x60;
612 break;
613 case M88TS2022_CLOCK_OUT_ENABLED:
614 u8tmp = 0x70;
615 ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg->clock_out_div);
616 if (ret)
617 goto err;
618 break;
619 case M88TS2022_CLOCK_OUT_ENABLED_XTALOUT:
620 u8tmp = 0x6c;
621 break;
622 default:
623 goto err;
624 }
625
626 ret = m88ts2022_wr_reg(priv, 0x42, u8tmp);
627 if (ret)
628 goto err;
629
630 if (priv->cfg->loop_through)
631 u8tmp = 0xec;
632 else
633 u8tmp = 0x6c;
634
635 ret = m88ts2022_wr_reg(priv, 0x62, u8tmp);
636 if (ret)
637 goto err;
638
639 /* sleep */
640 ret = m88ts2022_wr_reg(priv, 0x00, 0x00);
641 if (ret)
642 goto err;
643
644 dev_info(&priv->i2c->dev,
645 "%s: Montage M88TS2022 successfully identified\n",
646 KBUILD_MODNAME);
647
648 fe->tuner_priv = priv;
649 memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops,
650 sizeof(struct dvb_tuner_ops));
651err:
652 if (ret) {
653 dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
654 kfree(priv);
655 return NULL;
656 }
657
658 return fe;
659}
660EXPORT_SYMBOL(m88ts2022_attach);
661
662MODULE_DESCRIPTION("Montage M88TS2022 silicon tuner driver");
663MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
664MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/m88ts2022.h b/drivers/media/tuners/m88ts2022.h
new file mode 100644
index 000000000000..fa1112cad656
--- /dev/null
+++ b/drivers/media/tuners/m88ts2022.h
@@ -0,0 +1,72 @@
1/*
2 * Montage M88TS2022 silicon tuner driver
3 *
4 * Copyright (C) 2013 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#ifndef M88TS2022_H
22#define M88TS2022_H
23
24#include "dvb_frontend.h"
25
26struct m88ts2022_config {
27 /*
28 * I2C address
29 * 0x60, ...
30 */
31 u8 i2c_addr;
32
33 /*
34 * clock
35 * 16000000 - 32000000
36 */
37 u32 clock;
38
39 /*
40 * RF loop-through
41 */
42 u8 loop_through:1;
43
44 /*
45 * clock output
46 */
47#define M88TS2022_CLOCK_OUT_DISABLED 0
48#define M88TS2022_CLOCK_OUT_ENABLED 1
49#define M88TS2022_CLOCK_OUT_ENABLED_XTALOUT 2
50 u8 clock_out:2;
51
52 /*
53 * clock output divider
54 * 1 - 31
55 */
56 u8 clock_out_div:5;
57};
58
59#if defined(CONFIG_MEDIA_TUNER_M88TS2022) || \
60 (defined(CONFIG_MEDIA_TUNER_M88TS2022_MODULE) && defined(MODULE))
61extern struct dvb_frontend *m88ts2022_attach(struct dvb_frontend *fe,
62 struct i2c_adapter *i2c, const struct m88ts2022_config *cfg);
63#else
64static inline struct dvb_frontend *m88ts2022_attach(struct dvb_frontend *fe,
65 struct i2c_adapter *i2c, const struct m88ts2022_config *cfg)
66{
67 pr_warn("%s: driver disabled by Kconfig\n", __func__);
68 return NULL;
69}
70#endif
71
72#endif
diff --git a/drivers/media/tuners/m88ts2022_priv.h b/drivers/media/tuners/m88ts2022_priv.h
new file mode 100644
index 000000000000..190299a95ce9
--- /dev/null
+++ b/drivers/media/tuners/m88ts2022_priv.h
@@ -0,0 +1,38 @@
1/*
2 * Montage M88TS2022 silicon tuner driver
3 *
4 * Copyright (C) 2013 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#ifndef M88TS2022_PRIV_H
22#define M88TS2022_PRIV_H
23
24#include "m88ts2022.h"
25
26struct m88ts2022_priv {
27 const struct m88ts2022_config *cfg;
28 struct i2c_adapter *i2c;
29 struct dvb_frontend *fe;
30 u32 frequency_khz;
31};
32
33struct m88ts2022_reg_val {
34 u8 reg;
35 u8 val;
36};
37
38#endif