1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner |
4 | * |
5 | * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org> |
6 | */ |
7 | |
8 | #include <linux/i2c.h> |
9 | #include <linux/types.h> |
10 | #include <linux/videodev2.h> |
11 | #include "tuner-i2c.h" |
12 | #include "mxl5007t.h" |
13 | |
14 | static DEFINE_MUTEX(mxl5007t_list_mutex); |
15 | static LIST_HEAD(hybrid_tuner_instance_list); |
16 | |
17 | static int mxl5007t_debug; |
18 | module_param_named(debug, mxl5007t_debug, int, 0644); |
19 | MODULE_PARM_DESC(debug, "set debug level" ); |
20 | |
21 | /* ------------------------------------------------------------------------- */ |
22 | |
23 | #define mxl_printk(kern, fmt, arg...) \ |
24 | printk(kern "%s: " fmt "\n", __func__, ##arg) |
25 | |
26 | #define mxl_err(fmt, arg...) \ |
27 | mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) |
28 | |
29 | #define mxl_warn(fmt, arg...) \ |
30 | mxl_printk(KERN_WARNING, fmt, ##arg) |
31 | |
32 | #define mxl_info(fmt, arg...) \ |
33 | mxl_printk(KERN_INFO, fmt, ##arg) |
34 | |
35 | #define mxl_debug(fmt, arg...) \ |
36 | ({ \ |
37 | if (mxl5007t_debug) \ |
38 | mxl_printk(KERN_DEBUG, fmt, ##arg); \ |
39 | }) |
40 | |
41 | #define mxl_fail(ret) \ |
42 | ({ \ |
43 | int __ret; \ |
44 | __ret = (ret < 0); \ |
45 | if (__ret) \ |
46 | mxl_printk(KERN_ERR, "error %d on line %d", \ |
47 | ret, __LINE__); \ |
48 | __ret; \ |
49 | }) |
50 | |
51 | /* ------------------------------------------------------------------------- */ |
52 | |
53 | enum mxl5007t_mode { |
54 | MxL_MODE_ISDBT = 0, |
55 | MxL_MODE_DVBT = 1, |
56 | MxL_MODE_ATSC = 2, |
57 | MxL_MODE_CABLE = 0x10, |
58 | }; |
59 | |
60 | enum mxl5007t_chip_version { |
61 | MxL_UNKNOWN_ID = 0x00, |
62 | MxL_5007_V1_F1 = 0x11, |
63 | MxL_5007_V1_F2 = 0x12, |
64 | MxL_5007_V4 = 0x14, |
65 | MxL_5007_V2_100_F1 = 0x21, |
66 | MxL_5007_V2_100_F2 = 0x22, |
67 | MxL_5007_V2_200_F1 = 0x23, |
68 | MxL_5007_V2_200_F2 = 0x24, |
69 | }; |
70 | |
71 | struct reg_pair_t { |
72 | u8 reg; |
73 | u8 val; |
74 | }; |
75 | |
76 | /* ------------------------------------------------------------------------- */ |
77 | |
78 | static struct reg_pair_t init_tab[] = { |
79 | { 0x02, 0x06 }, |
80 | { 0x03, 0x48 }, |
81 | { 0x05, 0x04 }, |
82 | { 0x06, 0x10 }, |
83 | { 0x2e, 0x15 }, /* OVERRIDE */ |
84 | { 0x30, 0x10 }, /* OVERRIDE */ |
85 | { 0x45, 0x58 }, /* OVERRIDE */ |
86 | { 0x48, 0x19 }, /* OVERRIDE */ |
87 | { 0x52, 0x03 }, /* OVERRIDE */ |
88 | { 0x53, 0x44 }, /* OVERRIDE */ |
89 | { 0x6a, 0x4b }, /* OVERRIDE */ |
90 | { 0x76, 0x00 }, /* OVERRIDE */ |
91 | { 0x78, 0x18 }, /* OVERRIDE */ |
92 | { 0x7a, 0x17 }, /* OVERRIDE */ |
93 | { 0x85, 0x06 }, /* OVERRIDE */ |
94 | { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ |
95 | { 0, 0 } |
96 | }; |
97 | |
98 | static struct reg_pair_t init_tab_cable[] = { |
99 | { 0x02, 0x06 }, |
100 | { 0x03, 0x48 }, |
101 | { 0x05, 0x04 }, |
102 | { 0x06, 0x10 }, |
103 | { 0x09, 0x3f }, |
104 | { 0x0a, 0x3f }, |
105 | { 0x0b, 0x3f }, |
106 | { 0x2e, 0x15 }, /* OVERRIDE */ |
107 | { 0x30, 0x10 }, /* OVERRIDE */ |
108 | { 0x45, 0x58 }, /* OVERRIDE */ |
109 | { 0x48, 0x19 }, /* OVERRIDE */ |
110 | { 0x52, 0x03 }, /* OVERRIDE */ |
111 | { 0x53, 0x44 }, /* OVERRIDE */ |
112 | { 0x6a, 0x4b }, /* OVERRIDE */ |
113 | { 0x76, 0x00 }, /* OVERRIDE */ |
114 | { 0x78, 0x18 }, /* OVERRIDE */ |
115 | { 0x7a, 0x17 }, /* OVERRIDE */ |
116 | { 0x85, 0x06 }, /* OVERRIDE */ |
117 | { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ |
118 | { 0, 0 } |
119 | }; |
120 | |
121 | /* ------------------------------------------------------------------------- */ |
122 | |
123 | static struct reg_pair_t reg_pair_rftune[] = { |
124 | { 0x0f, 0x00 }, /* abort tune */ |
125 | { 0x0c, 0x15 }, |
126 | { 0x0d, 0x40 }, |
127 | { 0x0e, 0x0e }, |
128 | { 0x1f, 0x87 }, /* OVERRIDE */ |
129 | { 0x20, 0x1f }, /* OVERRIDE */ |
130 | { 0x21, 0x87 }, /* OVERRIDE */ |
131 | { 0x22, 0x1f }, /* OVERRIDE */ |
132 | { 0x80, 0x01 }, /* freq dependent */ |
133 | { 0x0f, 0x01 }, /* start tune */ |
134 | { 0, 0 } |
135 | }; |
136 | |
137 | /* ------------------------------------------------------------------------- */ |
138 | |
139 | struct mxl5007t_state { |
140 | struct list_head hybrid_tuner_instance_list; |
141 | struct tuner_i2c_props i2c_props; |
142 | |
143 | struct mutex lock; |
144 | |
145 | struct mxl5007t_config *config; |
146 | |
147 | enum mxl5007t_chip_version chip_id; |
148 | |
149 | struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; |
150 | struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; |
151 | struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; |
152 | |
153 | enum mxl5007t_if_freq if_freq; |
154 | |
155 | u32 frequency; |
156 | u32 bandwidth; |
157 | }; |
158 | |
159 | /* ------------------------------------------------------------------------- */ |
160 | |
161 | /* called by _init and _rftun to manipulate the register arrays */ |
162 | |
163 | static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) |
164 | { |
165 | unsigned int i = 0; |
166 | |
167 | while (reg_pair[i].reg || reg_pair[i].val) { |
168 | if (reg_pair[i].reg == reg) { |
169 | reg_pair[i].val &= ~mask; |
170 | reg_pair[i].val |= val; |
171 | } |
172 | i++; |
173 | |
174 | } |
175 | } |
176 | |
177 | static void copy_reg_bits(struct reg_pair_t *reg_pair1, |
178 | struct reg_pair_t *reg_pair2) |
179 | { |
180 | unsigned int i, j; |
181 | |
182 | i = j = 0; |
183 | |
184 | while (reg_pair1[i].reg || reg_pair1[i].val) { |
185 | while (reg_pair2[j].reg || reg_pair2[j].val) { |
186 | if (reg_pair1[i].reg != reg_pair2[j].reg) { |
187 | j++; |
188 | continue; |
189 | } |
190 | reg_pair2[j].val = reg_pair1[i].val; |
191 | break; |
192 | } |
193 | i++; |
194 | } |
195 | } |
196 | |
197 | /* ------------------------------------------------------------------------- */ |
198 | |
199 | static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, |
200 | enum mxl5007t_mode mode, |
201 | s32 if_diff_out_level) |
202 | { |
203 | switch (mode) { |
204 | case MxL_MODE_ATSC: |
205 | set_reg_bits(reg_pair: state->tab_init, reg: 0x06, mask: 0x1f, val: 0x12); |
206 | break; |
207 | case MxL_MODE_DVBT: |
208 | set_reg_bits(reg_pair: state->tab_init, reg: 0x06, mask: 0x1f, val: 0x11); |
209 | break; |
210 | case MxL_MODE_ISDBT: |
211 | set_reg_bits(reg_pair: state->tab_init, reg: 0x06, mask: 0x1f, val: 0x10); |
212 | break; |
213 | case MxL_MODE_CABLE: |
214 | set_reg_bits(reg_pair: state->tab_init_cable, reg: 0x09, mask: 0xff, val: 0xc1); |
215 | set_reg_bits(reg_pair: state->tab_init_cable, reg: 0x0a, mask: 0xff, |
216 | val: 8 - if_diff_out_level); |
217 | set_reg_bits(reg_pair: state->tab_init_cable, reg: 0x0b, mask: 0xff, val: 0x17); |
218 | break; |
219 | default: |
220 | mxl_fail(-EINVAL); |
221 | } |
222 | } |
223 | |
224 | static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, |
225 | enum mxl5007t_if_freq if_freq, |
226 | int invert_if) |
227 | { |
228 | u8 val; |
229 | |
230 | switch (if_freq) { |
231 | case MxL_IF_4_MHZ: |
232 | val = 0x00; |
233 | break; |
234 | case MxL_IF_4_5_MHZ: |
235 | val = 0x02; |
236 | break; |
237 | case MxL_IF_4_57_MHZ: |
238 | val = 0x03; |
239 | break; |
240 | case MxL_IF_5_MHZ: |
241 | val = 0x04; |
242 | break; |
243 | case MxL_IF_5_38_MHZ: |
244 | val = 0x05; |
245 | break; |
246 | case MxL_IF_6_MHZ: |
247 | val = 0x06; |
248 | break; |
249 | case MxL_IF_6_28_MHZ: |
250 | val = 0x07; |
251 | break; |
252 | case MxL_IF_9_1915_MHZ: |
253 | val = 0x08; |
254 | break; |
255 | case MxL_IF_35_25_MHZ: |
256 | val = 0x09; |
257 | break; |
258 | case MxL_IF_36_15_MHZ: |
259 | val = 0x0a; |
260 | break; |
261 | case MxL_IF_44_MHZ: |
262 | val = 0x0b; |
263 | break; |
264 | default: |
265 | mxl_fail(-EINVAL); |
266 | return; |
267 | } |
268 | set_reg_bits(reg_pair: state->tab_init, reg: 0x02, mask: 0x0f, val); |
269 | |
270 | /* set inverted IF or normal IF */ |
271 | set_reg_bits(reg_pair: state->tab_init, reg: 0x02, mask: 0x10, val: invert_if ? 0x10 : 0x00); |
272 | |
273 | state->if_freq = if_freq; |
274 | } |
275 | |
276 | static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, |
277 | enum mxl5007t_xtal_freq xtal_freq) |
278 | { |
279 | switch (xtal_freq) { |
280 | case MxL_XTAL_16_MHZ: |
281 | /* select xtal freq & ref freq */ |
282 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0x00); |
283 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x00); |
284 | break; |
285 | case MxL_XTAL_20_MHZ: |
286 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0x10); |
287 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x01); |
288 | break; |
289 | case MxL_XTAL_20_25_MHZ: |
290 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0x20); |
291 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x02); |
292 | break; |
293 | case MxL_XTAL_20_48_MHZ: |
294 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0x30); |
295 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x03); |
296 | break; |
297 | case MxL_XTAL_24_MHZ: |
298 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0x40); |
299 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x04); |
300 | break; |
301 | case MxL_XTAL_25_MHZ: |
302 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0x50); |
303 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x05); |
304 | break; |
305 | case MxL_XTAL_25_14_MHZ: |
306 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0x60); |
307 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x06); |
308 | break; |
309 | case MxL_XTAL_27_MHZ: |
310 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0x70); |
311 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x07); |
312 | break; |
313 | case MxL_XTAL_28_8_MHZ: |
314 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0x80); |
315 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x08); |
316 | break; |
317 | case MxL_XTAL_32_MHZ: |
318 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0x90); |
319 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x09); |
320 | break; |
321 | case MxL_XTAL_40_MHZ: |
322 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0xa0); |
323 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x0a); |
324 | break; |
325 | case MxL_XTAL_44_MHZ: |
326 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0xb0); |
327 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x0b); |
328 | break; |
329 | case MxL_XTAL_48_MHZ: |
330 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0xc0); |
331 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x0c); |
332 | break; |
333 | case MxL_XTAL_49_3811_MHZ: |
334 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0xf0, val: 0xd0); |
335 | set_reg_bits(reg_pair: state->tab_init, reg: 0x05, mask: 0x0f, val: 0x0d); |
336 | break; |
337 | default: |
338 | mxl_fail(-EINVAL); |
339 | return; |
340 | } |
341 | } |
342 | |
343 | static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, |
344 | enum mxl5007t_mode mode) |
345 | { |
346 | struct mxl5007t_config *cfg = state->config; |
347 | |
348 | memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); |
349 | memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); |
350 | |
351 | mxl5007t_set_mode_bits(state, mode, if_diff_out_level: cfg->if_diff_out_level); |
352 | mxl5007t_set_if_freq_bits(state, if_freq: cfg->if_freq_hz, invert_if: cfg->invert_if); |
353 | mxl5007t_set_xtal_freq_bits(state, xtal_freq: cfg->xtal_freq_hz); |
354 | |
355 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0x08, val: cfg->clk_out_enable << 3); |
356 | set_reg_bits(reg_pair: state->tab_init, reg: 0x03, mask: 0x07, val: cfg->clk_out_amp); |
357 | |
358 | if (mode >= MxL_MODE_CABLE) { |
359 | copy_reg_bits(reg_pair1: state->tab_init, reg_pair2: state->tab_init_cable); |
360 | return state->tab_init_cable; |
361 | } else |
362 | return state->tab_init; |
363 | } |
364 | |
365 | /* ------------------------------------------------------------------------- */ |
366 | |
367 | enum mxl5007t_bw_mhz { |
368 | MxL_BW_6MHz = 6, |
369 | MxL_BW_7MHz = 7, |
370 | MxL_BW_8MHz = 8, |
371 | }; |
372 | |
373 | static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, |
374 | enum mxl5007t_bw_mhz bw) |
375 | { |
376 | u8 val; |
377 | |
378 | switch (bw) { |
379 | case MxL_BW_6MHz: |
380 | val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, |
381 | * and DIG_MODEINDEX_CSF */ |
382 | break; |
383 | case MxL_BW_7MHz: |
384 | val = 0x2a; |
385 | break; |
386 | case MxL_BW_8MHz: |
387 | val = 0x3f; |
388 | break; |
389 | default: |
390 | mxl_fail(-EINVAL); |
391 | return; |
392 | } |
393 | set_reg_bits(reg_pair: state->tab_rftune, reg: 0x0c, mask: 0x3f, val); |
394 | } |
395 | |
396 | static struct |
397 | reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, |
398 | u32 rf_freq, enum mxl5007t_bw_mhz bw) |
399 | { |
400 | u32 dig_rf_freq = 0; |
401 | u32 temp; |
402 | u32 frac_divider = 1000000; |
403 | unsigned int i; |
404 | |
405 | memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); |
406 | |
407 | mxl5007t_set_bw_bits(state, bw); |
408 | |
409 | /* Convert RF frequency into 16 bits => |
410 | * 10 bit integer (MHz) + 6 bit fraction */ |
411 | dig_rf_freq = rf_freq / MHz; |
412 | |
413 | temp = rf_freq % MHz; |
414 | |
415 | for (i = 0; i < 6; i++) { |
416 | dig_rf_freq <<= 1; |
417 | frac_divider /= 2; |
418 | if (temp > frac_divider) { |
419 | temp -= frac_divider; |
420 | dig_rf_freq++; |
421 | } |
422 | } |
423 | |
424 | /* add to have shift center point by 7.8124 kHz */ |
425 | if (temp > 7812) |
426 | dig_rf_freq++; |
427 | |
428 | set_reg_bits(reg_pair: state->tab_rftune, reg: 0x0d, mask: 0xff, val: (u8) dig_rf_freq); |
429 | set_reg_bits(reg_pair: state->tab_rftune, reg: 0x0e, mask: 0xff, val: (u8) (dig_rf_freq >> 8)); |
430 | |
431 | if (rf_freq >= 333000000) |
432 | set_reg_bits(reg_pair: state->tab_rftune, reg: 0x80, mask: 0x40, val: 0x40); |
433 | |
434 | return state->tab_rftune; |
435 | } |
436 | |
437 | /* ------------------------------------------------------------------------- */ |
438 | |
439 | static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) |
440 | { |
441 | u8 buf[] = { reg, val }; |
442 | struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, |
443 | .buf = buf, .len = 2 }; |
444 | int ret; |
445 | |
446 | ret = i2c_transfer(adap: state->i2c_props.adap, msgs: &msg, num: 1); |
447 | if (ret != 1) { |
448 | mxl_err("failed!" ); |
449 | return -EREMOTEIO; |
450 | } |
451 | return 0; |
452 | } |
453 | |
454 | static int mxl5007t_write_regs(struct mxl5007t_state *state, |
455 | struct reg_pair_t *reg_pair) |
456 | { |
457 | unsigned int i = 0; |
458 | int ret = 0; |
459 | |
460 | while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { |
461 | ret = mxl5007t_write_reg(state, |
462 | reg: reg_pair[i].reg, val: reg_pair[i].val); |
463 | i++; |
464 | } |
465 | return ret; |
466 | } |
467 | |
468 | static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) |
469 | { |
470 | u8 buf[2] = { 0xfb, reg }; |
471 | struct i2c_msg msg[] = { |
472 | { .addr = state->i2c_props.addr, .flags = 0, |
473 | .buf = buf, .len = 2 }, |
474 | { .addr = state->i2c_props.addr, .flags = I2C_M_RD, |
475 | .buf = val, .len = 1 }, |
476 | }; |
477 | int ret; |
478 | |
479 | ret = i2c_transfer(adap: state->i2c_props.adap, msgs: msg, num: 2); |
480 | if (ret != 2) { |
481 | mxl_err("failed!" ); |
482 | return -EREMOTEIO; |
483 | } |
484 | return 0; |
485 | } |
486 | |
487 | static int mxl5007t_soft_reset(struct mxl5007t_state *state) |
488 | { |
489 | u8 d = 0xff; |
490 | struct i2c_msg msg = { |
491 | .addr = state->i2c_props.addr, .flags = 0, |
492 | .buf = &d, .len = 1 |
493 | }; |
494 | int ret = i2c_transfer(adap: state->i2c_props.adap, msgs: &msg, num: 1); |
495 | |
496 | if (ret != 1) { |
497 | mxl_err("failed!" ); |
498 | return -EREMOTEIO; |
499 | } |
500 | return 0; |
501 | } |
502 | |
503 | static int mxl5007t_tuner_init(struct mxl5007t_state *state, |
504 | enum mxl5007t_mode mode) |
505 | { |
506 | struct reg_pair_t *init_regs; |
507 | int ret; |
508 | |
509 | /* calculate initialization reg array */ |
510 | init_regs = mxl5007t_calc_init_regs(state, mode); |
511 | |
512 | ret = mxl5007t_write_regs(state, reg_pair: init_regs); |
513 | if (mxl_fail(ret)) |
514 | goto fail; |
515 | mdelay(1); |
516 | fail: |
517 | return ret; |
518 | } |
519 | |
520 | static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, |
521 | enum mxl5007t_bw_mhz bw) |
522 | { |
523 | struct reg_pair_t *rf_tune_regs; |
524 | int ret; |
525 | |
526 | /* calculate channel change reg array */ |
527 | rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq: rf_freq_hz, bw); |
528 | |
529 | ret = mxl5007t_write_regs(state, reg_pair: rf_tune_regs); |
530 | if (mxl_fail(ret)) |
531 | goto fail; |
532 | msleep(msecs: 3); |
533 | fail: |
534 | return ret; |
535 | } |
536 | |
537 | /* ------------------------------------------------------------------------- */ |
538 | |
539 | static int mxl5007t_synth_lock_status(struct mxl5007t_state *state, |
540 | int *rf_locked, int *ref_locked) |
541 | { |
542 | u8 d; |
543 | int ret; |
544 | |
545 | *rf_locked = 0; |
546 | *ref_locked = 0; |
547 | |
548 | ret = mxl5007t_read_reg(state, reg: 0xd8, val: &d); |
549 | if (mxl_fail(ret)) |
550 | goto fail; |
551 | |
552 | if ((d & 0x0c) == 0x0c) |
553 | *rf_locked = 1; |
554 | |
555 | if ((d & 0x03) == 0x03) |
556 | *ref_locked = 1; |
557 | fail: |
558 | return ret; |
559 | } |
560 | |
561 | /* ------------------------------------------------------------------------- */ |
562 | |
563 | static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) |
564 | { |
565 | struct mxl5007t_state *state = fe->tuner_priv; |
566 | int rf_locked, ref_locked, ret; |
567 | |
568 | *status = 0; |
569 | |
570 | if (fe->ops.i2c_gate_ctrl) |
571 | fe->ops.i2c_gate_ctrl(fe, 1); |
572 | |
573 | ret = mxl5007t_synth_lock_status(state, rf_locked: &rf_locked, ref_locked: &ref_locked); |
574 | if (mxl_fail(ret)) |
575 | goto fail; |
576 | mxl_debug("%s%s" , rf_locked ? "rf locked " : "" , |
577 | ref_locked ? "ref locked" : "" ); |
578 | |
579 | if ((rf_locked) || (ref_locked)) |
580 | *status |= TUNER_STATUS_LOCKED; |
581 | fail: |
582 | if (fe->ops.i2c_gate_ctrl) |
583 | fe->ops.i2c_gate_ctrl(fe, 0); |
584 | |
585 | return ret; |
586 | } |
587 | |
588 | /* ------------------------------------------------------------------------- */ |
589 | |
590 | static int mxl5007t_set_params(struct dvb_frontend *fe) |
591 | { |
592 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
593 | u32 delsys = c->delivery_system; |
594 | struct mxl5007t_state *state = fe->tuner_priv; |
595 | enum mxl5007t_bw_mhz bw; |
596 | enum mxl5007t_mode mode; |
597 | int ret; |
598 | u32 freq = c->frequency; |
599 | |
600 | switch (delsys) { |
601 | case SYS_ATSC: |
602 | mode = MxL_MODE_ATSC; |
603 | bw = MxL_BW_6MHz; |
604 | break; |
605 | case SYS_DVBC_ANNEX_B: |
606 | mode = MxL_MODE_CABLE; |
607 | bw = MxL_BW_6MHz; |
608 | break; |
609 | case SYS_DVBT: |
610 | case SYS_DVBT2: |
611 | mode = MxL_MODE_DVBT; |
612 | switch (c->bandwidth_hz) { |
613 | case 6000000: |
614 | bw = MxL_BW_6MHz; |
615 | break; |
616 | case 7000000: |
617 | bw = MxL_BW_7MHz; |
618 | break; |
619 | case 8000000: |
620 | bw = MxL_BW_8MHz; |
621 | break; |
622 | default: |
623 | return -EINVAL; |
624 | } |
625 | break; |
626 | default: |
627 | mxl_err("modulation type not supported!" ); |
628 | return -EINVAL; |
629 | } |
630 | |
631 | if (fe->ops.i2c_gate_ctrl) |
632 | fe->ops.i2c_gate_ctrl(fe, 1); |
633 | |
634 | mutex_lock(&state->lock); |
635 | |
636 | ret = mxl5007t_tuner_init(state, mode); |
637 | if (mxl_fail(ret)) |
638 | goto fail; |
639 | |
640 | ret = mxl5007t_tuner_rf_tune(state, rf_freq_hz: freq, bw); |
641 | if (mxl_fail(ret)) |
642 | goto fail; |
643 | |
644 | state->frequency = freq; |
645 | state->bandwidth = c->bandwidth_hz; |
646 | fail: |
647 | mutex_unlock(lock: &state->lock); |
648 | |
649 | if (fe->ops.i2c_gate_ctrl) |
650 | fe->ops.i2c_gate_ctrl(fe, 0); |
651 | |
652 | return ret; |
653 | } |
654 | |
655 | /* ------------------------------------------------------------------------- */ |
656 | |
657 | static int mxl5007t_init(struct dvb_frontend *fe) |
658 | { |
659 | struct mxl5007t_state *state = fe->tuner_priv; |
660 | int ret; |
661 | |
662 | if (fe->ops.i2c_gate_ctrl) |
663 | fe->ops.i2c_gate_ctrl(fe, 1); |
664 | |
665 | /* wake from standby */ |
666 | ret = mxl5007t_write_reg(state, reg: 0x01, val: 0x01); |
667 | mxl_fail(ret); |
668 | |
669 | if (fe->ops.i2c_gate_ctrl) |
670 | fe->ops.i2c_gate_ctrl(fe, 0); |
671 | |
672 | return ret; |
673 | } |
674 | |
675 | static int mxl5007t_sleep(struct dvb_frontend *fe) |
676 | { |
677 | struct mxl5007t_state *state = fe->tuner_priv; |
678 | int ret; |
679 | |
680 | if (fe->ops.i2c_gate_ctrl) |
681 | fe->ops.i2c_gate_ctrl(fe, 1); |
682 | |
683 | /* enter standby mode */ |
684 | ret = mxl5007t_write_reg(state, reg: 0x01, val: 0x00); |
685 | mxl_fail(ret); |
686 | ret = mxl5007t_write_reg(state, reg: 0x0f, val: 0x00); |
687 | mxl_fail(ret); |
688 | |
689 | if (fe->ops.i2c_gate_ctrl) |
690 | fe->ops.i2c_gate_ctrl(fe, 0); |
691 | |
692 | return ret; |
693 | } |
694 | |
695 | /* ------------------------------------------------------------------------- */ |
696 | |
697 | static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) |
698 | { |
699 | struct mxl5007t_state *state = fe->tuner_priv; |
700 | *frequency = state->frequency; |
701 | return 0; |
702 | } |
703 | |
704 | static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) |
705 | { |
706 | struct mxl5007t_state *state = fe->tuner_priv; |
707 | *bandwidth = state->bandwidth; |
708 | return 0; |
709 | } |
710 | |
711 | static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) |
712 | { |
713 | struct mxl5007t_state *state = fe->tuner_priv; |
714 | |
715 | *frequency = 0; |
716 | |
717 | switch (state->if_freq) { |
718 | case MxL_IF_4_MHZ: |
719 | *frequency = 4000000; |
720 | break; |
721 | case MxL_IF_4_5_MHZ: |
722 | *frequency = 4500000; |
723 | break; |
724 | case MxL_IF_4_57_MHZ: |
725 | *frequency = 4570000; |
726 | break; |
727 | case MxL_IF_5_MHZ: |
728 | *frequency = 5000000; |
729 | break; |
730 | case MxL_IF_5_38_MHZ: |
731 | *frequency = 5380000; |
732 | break; |
733 | case MxL_IF_6_MHZ: |
734 | *frequency = 6000000; |
735 | break; |
736 | case MxL_IF_6_28_MHZ: |
737 | *frequency = 6280000; |
738 | break; |
739 | case MxL_IF_9_1915_MHZ: |
740 | *frequency = 9191500; |
741 | break; |
742 | case MxL_IF_35_25_MHZ: |
743 | *frequency = 35250000; |
744 | break; |
745 | case MxL_IF_36_15_MHZ: |
746 | *frequency = 36150000; |
747 | break; |
748 | case MxL_IF_44_MHZ: |
749 | *frequency = 44000000; |
750 | break; |
751 | } |
752 | return 0; |
753 | } |
754 | |
755 | static void mxl5007t_release(struct dvb_frontend *fe) |
756 | { |
757 | struct mxl5007t_state *state = fe->tuner_priv; |
758 | |
759 | mutex_lock(&mxl5007t_list_mutex); |
760 | |
761 | if (state) |
762 | hybrid_tuner_release_state(state); |
763 | |
764 | mutex_unlock(lock: &mxl5007t_list_mutex); |
765 | |
766 | fe->tuner_priv = NULL; |
767 | } |
768 | |
769 | /* ------------------------------------------------------------------------- */ |
770 | |
771 | static const struct dvb_tuner_ops mxl5007t_tuner_ops = { |
772 | .info = { |
773 | .name = "MaxLinear MxL5007T" , |
774 | }, |
775 | .init = mxl5007t_init, |
776 | .sleep = mxl5007t_sleep, |
777 | .set_params = mxl5007t_set_params, |
778 | .get_status = mxl5007t_get_status, |
779 | .get_frequency = mxl5007t_get_frequency, |
780 | .get_bandwidth = mxl5007t_get_bandwidth, |
781 | .release = mxl5007t_release, |
782 | .get_if_frequency = mxl5007t_get_if_frequency, |
783 | }; |
784 | |
785 | static int mxl5007t_get_chip_id(struct mxl5007t_state *state) |
786 | { |
787 | char *name; |
788 | int ret; |
789 | u8 id; |
790 | |
791 | ret = mxl5007t_read_reg(state, reg: 0xd9, val: &id); |
792 | if (mxl_fail(ret)) |
793 | goto fail; |
794 | |
795 | switch (id) { |
796 | case MxL_5007_V1_F1: |
797 | name = "MxL5007.v1.f1" ; |
798 | break; |
799 | case MxL_5007_V1_F2: |
800 | name = "MxL5007.v1.f2" ; |
801 | break; |
802 | case MxL_5007_V2_100_F1: |
803 | name = "MxL5007.v2.100.f1" ; |
804 | break; |
805 | case MxL_5007_V2_100_F2: |
806 | name = "MxL5007.v2.100.f2" ; |
807 | break; |
808 | case MxL_5007_V2_200_F1: |
809 | name = "MxL5007.v2.200.f1" ; |
810 | break; |
811 | case MxL_5007_V2_200_F2: |
812 | name = "MxL5007.v2.200.f2" ; |
813 | break; |
814 | case MxL_5007_V4: |
815 | name = "MxL5007T.v4" ; |
816 | break; |
817 | default: |
818 | name = "MxL5007T" ; |
819 | printk(KERN_WARNING "%s: unknown rev (%02x)\n" , __func__, id); |
820 | id = MxL_UNKNOWN_ID; |
821 | } |
822 | state->chip_id = id; |
823 | mxl_info("%s detected @ %d-%04x" , name, |
824 | i2c_adapter_id(state->i2c_props.adap), |
825 | state->i2c_props.addr); |
826 | return 0; |
827 | fail: |
828 | mxl_warn("unable to identify device @ %d-%04x" , |
829 | i2c_adapter_id(state->i2c_props.adap), |
830 | state->i2c_props.addr); |
831 | |
832 | state->chip_id = MxL_UNKNOWN_ID; |
833 | return ret; |
834 | } |
835 | |
836 | struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, |
837 | struct i2c_adapter *i2c, u8 addr, |
838 | struct mxl5007t_config *cfg) |
839 | { |
840 | struct mxl5007t_state *state = NULL; |
841 | int instance, ret; |
842 | |
843 | mutex_lock(&mxl5007t_list_mutex); |
844 | instance = hybrid_tuner_request_state(struct mxl5007t_state, state, |
845 | hybrid_tuner_instance_list, |
846 | i2c, addr, "mxl5007t" ); |
847 | switch (instance) { |
848 | case 0: |
849 | goto fail; |
850 | case 1: |
851 | /* new tuner instance */ |
852 | state->config = cfg; |
853 | |
854 | mutex_init(&state->lock); |
855 | |
856 | if (fe->ops.i2c_gate_ctrl) |
857 | fe->ops.i2c_gate_ctrl(fe, 1); |
858 | |
859 | ret = mxl5007t_get_chip_id(state); |
860 | |
861 | if (fe->ops.i2c_gate_ctrl) |
862 | fe->ops.i2c_gate_ctrl(fe, 0); |
863 | |
864 | /* check return value of mxl5007t_get_chip_id */ |
865 | if (mxl_fail(ret)) |
866 | goto fail; |
867 | break; |
868 | default: |
869 | /* existing tuner instance */ |
870 | break; |
871 | } |
872 | |
873 | if (fe->ops.i2c_gate_ctrl) |
874 | fe->ops.i2c_gate_ctrl(fe, 1); |
875 | |
876 | ret = mxl5007t_soft_reset(state); |
877 | |
878 | if (fe->ops.i2c_gate_ctrl) |
879 | fe->ops.i2c_gate_ctrl(fe, 0); |
880 | |
881 | if (mxl_fail(ret)) |
882 | goto fail; |
883 | |
884 | if (fe->ops.i2c_gate_ctrl) |
885 | fe->ops.i2c_gate_ctrl(fe, 1); |
886 | |
887 | ret = mxl5007t_write_reg(state, reg: 0x04, |
888 | val: state->config->loop_thru_enable); |
889 | |
890 | if (fe->ops.i2c_gate_ctrl) |
891 | fe->ops.i2c_gate_ctrl(fe, 0); |
892 | |
893 | if (mxl_fail(ret)) |
894 | goto fail; |
895 | |
896 | fe->tuner_priv = state; |
897 | |
898 | mutex_unlock(lock: &mxl5007t_list_mutex); |
899 | |
900 | memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, |
901 | sizeof(struct dvb_tuner_ops)); |
902 | |
903 | return fe; |
904 | fail: |
905 | mutex_unlock(lock: &mxl5007t_list_mutex); |
906 | |
907 | mxl5007t_release(fe); |
908 | return NULL; |
909 | } |
910 | EXPORT_SYMBOL_GPL(mxl5007t_attach); |
911 | MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver" ); |
912 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>" ); |
913 | MODULE_LICENSE("GPL" ); |
914 | MODULE_VERSION("0.2" ); |
915 | |