]>
Commit | Line | Data |
---|---|---|
88b38bef AP |
1 | /* |
2 | * ITE Tech IT9137 silicon tuner driver | |
3 | * | |
4 | * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) | |
5 | * IT9137 Copyright (C) ITE Tech Inc. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= | |
21 | */ | |
22 | ||
c2ba9726 | 23 | #include "it913x_priv.h" |
88b38bef | 24 | |
42432b3c | 25 | struct it913x_state { |
88b38bef | 26 | struct i2c_adapter *i2c_adap; |
88b38bef | 27 | u8 i2c_addr; |
10859797 | 28 | u8 chip_ver; |
88b38bef | 29 | u8 tuner_type; |
10859797 | 30 | u8 firmware_ver; |
88b38bef AP |
31 | u16 tun_xtal; |
32 | u8 tun_fdiv; | |
33 | u8 tun_clk_mode; | |
34 | u32 tun_fn_min; | |
88b38bef AP |
35 | }; |
36 | ||
42432b3c AP |
37 | /* read multiple registers */ |
38 | static int it913x_rd_regs(struct it913x_state *state, | |
88b38bef AP |
39 | u32 reg, u8 *data, u8 count) |
40 | { | |
41 | int ret; | |
42 | u8 b[3]; | |
43 | struct i2c_msg msg[2] = { | |
44 | { .addr = state->i2c_addr, .flags = 0, | |
45 | .buf = b, .len = sizeof(b) }, | |
46 | { .addr = state->i2c_addr, .flags = I2C_M_RD, | |
47 | .buf = data, .len = count } | |
48 | }; | |
d1113241 | 49 | |
88b38bef AP |
50 | b[0] = (u8)(reg >> 16) & 0xff; |
51 | b[1] = (u8)(reg >> 8) & 0xff; | |
52 | b[2] = (u8) reg & 0xff; | |
53 | b[0] |= 0x80; /* All reads from demodulator */ | |
54 | ||
55 | ret = i2c_transfer(state->i2c_adap, msg, 2); | |
56 | ||
57 | return ret; | |
58 | } | |
59 | ||
42432b3c AP |
60 | /* read single register */ |
61 | static int it913x_rd_reg(struct it913x_state *state, u32 reg) | |
88b38bef AP |
62 | { |
63 | int ret; | |
64 | u8 b[1]; | |
d1113241 | 65 | |
42432b3c | 66 | ret = it913x_rd_regs(state, reg, &b[0], sizeof(b)); |
88b38bef AP |
67 | return (ret < 0) ? -ENODEV : b[0]; |
68 | } | |
69 | ||
42432b3c AP |
70 | /* write multiple registers */ |
71 | static int it913x_wr_regs(struct it913x_state *state, | |
88b38bef AP |
72 | u8 pro, u32 reg, u8 buf[], u8 count) |
73 | { | |
74 | u8 b[256]; | |
75 | struct i2c_msg msg[1] = { | |
76 | { .addr = state->i2c_addr, .flags = 0, | |
77 | .buf = b, .len = 3 + count } | |
78 | }; | |
79 | int ret; | |
d1113241 | 80 | |
88b38bef AP |
81 | b[0] = (u8)(reg >> 16) & 0xff; |
82 | b[1] = (u8)(reg >> 8) & 0xff; | |
83 | b[2] = (u8) reg & 0xff; | |
84 | memcpy(&b[3], buf, count); | |
85 | ||
86 | if (pro == PRO_DMOD) | |
87 | b[0] |= 0x80; | |
88 | ||
89 | ret = i2c_transfer(state->i2c_adap, msg, 1); | |
90 | ||
91 | if (ret < 0) | |
92 | return -EIO; | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
42432b3c AP |
97 | /* write single register */ |
98 | static int it913x_wr_reg(struct it913x_state *state, | |
88b38bef AP |
99 | u8 pro, u32 reg, u32 data) |
100 | { | |
101 | int ret; | |
102 | u8 b[4]; | |
103 | u8 s; | |
104 | ||
105 | b[0] = data >> 24; | |
106 | b[1] = (data >> 16) & 0xff; | |
107 | b[2] = (data >> 8) & 0xff; | |
108 | b[3] = data & 0xff; | |
109 | /* expand write as needed */ | |
110 | if (data < 0x100) | |
111 | s = 3; | |
112 | else if (data < 0x1000) | |
113 | s = 2; | |
114 | else if (data < 0x100000) | |
115 | s = 1; | |
116 | else | |
117 | s = 0; | |
118 | ||
42432b3c | 119 | ret = it913x_wr_regs(state, pro, reg, &b[s], sizeof(b) - s); |
88b38bef AP |
120 | |
121 | return ret; | |
122 | } | |
123 | ||
42432b3c | 124 | static int it913x_script_loader(struct it913x_state *state, |
88b38bef AP |
125 | struct it913xset *loadscript) |
126 | { | |
127 | int ret, i; | |
d1113241 | 128 | |
88b38bef AP |
129 | if (loadscript == NULL) |
130 | return -EINVAL; | |
131 | ||
132 | for (i = 0; i < 1000; ++i) { | |
133 | if (loadscript[i].pro == 0xff) | |
134 | break; | |
42432b3c | 135 | ret = it913x_wr_regs(state, loadscript[i].pro, |
88b38bef AP |
136 | loadscript[i].address, |
137 | loadscript[i].reg, loadscript[i].count); | |
138 | if (ret < 0) | |
139 | return -ENODEV; | |
140 | } | |
141 | return 0; | |
142 | } | |
143 | ||
42432b3c | 144 | static int it913x_init(struct dvb_frontend *fe) |
88b38bef | 145 | { |
42432b3c | 146 | struct it913x_state *state = fe->tuner_priv; |
88b38bef AP |
147 | int ret, i, reg; |
148 | u8 val, nv_val; | |
149 | u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; | |
150 | u8 b[2]; | |
151 | ||
42432b3c | 152 | reg = it913x_rd_reg(state, 0xec86); |
88b38bef AP |
153 | switch (reg) { |
154 | case 0: | |
155 | state->tun_clk_mode = reg; | |
156 | state->tun_xtal = 2000; | |
157 | state->tun_fdiv = 3; | |
158 | val = 16; | |
159 | break; | |
160 | case -ENODEV: | |
66f63199 AP |
161 | /* FIXME: these are just avoid divide by 0 */ |
162 | state->tun_xtal = 2000; | |
163 | state->tun_fdiv = 3; | |
88b38bef AP |
164 | return -ENODEV; |
165 | case 1: | |
166 | default: | |
167 | state->tun_clk_mode = reg; | |
168 | state->tun_xtal = 640; | |
169 | state->tun_fdiv = 1; | |
170 | val = 6; | |
171 | break; | |
172 | } | |
173 | ||
42432b3c | 174 | reg = it913x_rd_reg(state, 0xed03); |
88b38bef AP |
175 | |
176 | if (reg < 0) | |
177 | return -ENODEV; | |
178 | else if (reg < ARRAY_SIZE(nv)) | |
179 | nv_val = nv[reg]; | |
180 | else | |
181 | nv_val = 2; | |
182 | ||
183 | for (i = 0; i < 50; i++) { | |
42432b3c | 184 | ret = it913x_rd_regs(state, 0xed23, &b[0], sizeof(b)); |
88b38bef AP |
185 | reg = (b[1] << 8) + b[0]; |
186 | if (reg > 0) | |
187 | break; | |
188 | if (ret < 0) | |
189 | return -ENODEV; | |
190 | udelay(2000); | |
191 | } | |
192 | state->tun_fn_min = state->tun_xtal * reg; | |
193 | state->tun_fn_min /= (state->tun_fdiv * nv_val); | |
cfd08f0f AP |
194 | dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__, |
195 | state->tun_fn_min); | |
88b38bef | 196 | |
44af747f | 197 | if (state->chip_ver > 1) |
88b38bef AP |
198 | msleep(50); |
199 | else { | |
200 | for (i = 0; i < 50; i++) { | |
42432b3c | 201 | reg = it913x_rd_reg(state, 0xec82); |
88b38bef AP |
202 | if (reg > 0) |
203 | break; | |
204 | if (reg < 0) | |
205 | return -ENODEV; | |
206 | udelay(2000); | |
207 | } | |
208 | } | |
209 | ||
d19812eb AP |
210 | /* Power Up Tuner - common all versions */ |
211 | ret = it913x_wr_reg(state, PRO_DMOD, 0xec40, 0x1); | |
d19812eb AP |
212 | ret |= it913x_wr_reg(state, PRO_DMOD, 0xec57, 0x0); |
213 | ret |= it913x_wr_reg(state, PRO_DMOD, 0xec58, 0x0); | |
214 | ||
42432b3c | 215 | return it913x_wr_reg(state, PRO_DMOD, 0xed81, val); |
88b38bef AP |
216 | } |
217 | ||
42432b3c | 218 | static int it9137_set_params(struct dvb_frontend *fe) |
88b38bef | 219 | { |
42432b3c | 220 | struct it913x_state *state = fe->tuner_priv; |
88b38bef AP |
221 | struct it913xset *set_tuner = set_it9137_template; |
222 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
223 | u32 bandwidth = p->bandwidth_hz; | |
224 | u32 frequency_m = p->frequency; | |
225 | int ret, reg; | |
226 | u32 frequency = frequency_m / 1000; | |
227 | u32 freq, temp_f, tmp; | |
228 | u16 iqik_m_cal; | |
229 | u16 n_div; | |
230 | u8 n; | |
231 | u8 l_band; | |
232 | u8 lna_band; | |
233 | u8 bw; | |
234 | ||
44af747f | 235 | if (state->firmware_ver == 1) |
88b38bef AP |
236 | set_tuner = set_it9135_template; |
237 | else | |
238 | set_tuner = set_it9137_template; | |
239 | ||
cfd08f0f AP |
240 | dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n", |
241 | __func__, frequency, bandwidth); | |
88b38bef AP |
242 | |
243 | if (frequency >= 51000 && frequency <= 440000) { | |
244 | l_band = 0; | |
245 | lna_band = 0; | |
246 | } else if (frequency > 440000 && frequency <= 484000) { | |
247 | l_band = 1; | |
248 | lna_band = 1; | |
249 | } else if (frequency > 484000 && frequency <= 533000) { | |
250 | l_band = 1; | |
251 | lna_band = 2; | |
252 | } else if (frequency > 533000 && frequency <= 587000) { | |
253 | l_band = 1; | |
254 | lna_band = 3; | |
255 | } else if (frequency > 587000 && frequency <= 645000) { | |
256 | l_band = 1; | |
257 | lna_band = 4; | |
258 | } else if (frequency > 645000 && frequency <= 710000) { | |
259 | l_band = 1; | |
260 | lna_band = 5; | |
261 | } else if (frequency > 710000 && frequency <= 782000) { | |
262 | l_band = 1; | |
263 | lna_band = 6; | |
264 | } else if (frequency > 782000 && frequency <= 860000) { | |
265 | l_band = 1; | |
266 | lna_band = 7; | |
267 | } else if (frequency > 1450000 && frequency <= 1492000) { | |
268 | l_band = 1; | |
269 | lna_band = 0; | |
270 | } else if (frequency > 1660000 && frequency <= 1685000) { | |
271 | l_band = 1; | |
272 | lna_band = 1; | |
273 | } else | |
274 | return -EINVAL; | |
275 | set_tuner[0].reg[0] = lna_band; | |
276 | ||
277 | switch (bandwidth) { | |
278 | case 5000000: | |
279 | bw = 0; | |
280 | break; | |
281 | case 6000000: | |
282 | bw = 2; | |
283 | break; | |
284 | case 7000000: | |
285 | bw = 4; | |
286 | break; | |
287 | default: | |
288 | case 8000000: | |
289 | bw = 6; | |
290 | break; | |
291 | } | |
292 | ||
293 | set_tuner[1].reg[0] = bw; | |
294 | set_tuner[2].reg[0] = 0xa0 | (l_band << 3); | |
295 | ||
296 | if (frequency > 53000 && frequency <= 74000) { | |
297 | n_div = 48; | |
298 | n = 0; | |
299 | } else if (frequency > 74000 && frequency <= 111000) { | |
300 | n_div = 32; | |
301 | n = 1; | |
302 | } else if (frequency > 111000 && frequency <= 148000) { | |
303 | n_div = 24; | |
304 | n = 2; | |
305 | } else if (frequency > 148000 && frequency <= 222000) { | |
306 | n_div = 16; | |
307 | n = 3; | |
308 | } else if (frequency > 222000 && frequency <= 296000) { | |
309 | n_div = 12; | |
310 | n = 4; | |
311 | } else if (frequency > 296000 && frequency <= 445000) { | |
312 | n_div = 8; | |
313 | n = 5; | |
314 | } else if (frequency > 445000 && frequency <= state->tun_fn_min) { | |
315 | n_div = 6; | |
316 | n = 6; | |
317 | } else if (frequency > state->tun_fn_min && frequency <= 950000) { | |
318 | n_div = 4; | |
319 | n = 7; | |
320 | } else if (frequency > 1450000 && frequency <= 1680000) { | |
321 | n_div = 2; | |
322 | n = 0; | |
323 | } else | |
324 | return -EINVAL; | |
325 | ||
42432b3c | 326 | reg = it913x_rd_reg(state, 0xed81); |
88b38bef AP |
327 | iqik_m_cal = (u16)reg * n_div; |
328 | ||
329 | if (reg < 0x20) { | |
330 | if (state->tun_clk_mode == 0) | |
331 | iqik_m_cal = (iqik_m_cal * 9) >> 5; | |
332 | else | |
333 | iqik_m_cal >>= 1; | |
334 | } else { | |
335 | iqik_m_cal = 0x40 - iqik_m_cal; | |
336 | if (state->tun_clk_mode == 0) | |
337 | iqik_m_cal = ~((iqik_m_cal * 9) >> 5); | |
338 | else | |
339 | iqik_m_cal = ~(iqik_m_cal >> 1); | |
340 | } | |
341 | ||
342 | temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv; | |
343 | freq = temp_f / state->tun_xtal; | |
344 | tmp = freq * state->tun_xtal; | |
345 | ||
346 | if ((temp_f - tmp) >= (state->tun_xtal >> 1)) | |
347 | freq++; | |
348 | ||
349 | freq += (u32) n << 13; | |
350 | /* Frequency OMEGA_IQIK_M_CAL_MID*/ | |
351 | temp_f = freq + (u32)iqik_m_cal; | |
352 | ||
353 | set_tuner[3].reg[0] = temp_f & 0xff; | |
354 | set_tuner[4].reg[0] = (temp_f >> 8) & 0xff; | |
355 | ||
cfd08f0f AP |
356 | dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n", |
357 | __func__, temp_f); | |
88b38bef AP |
358 | |
359 | /* Lower frequency */ | |
360 | set_tuner[5].reg[0] = freq & 0xff; | |
361 | set_tuner[6].reg[0] = (freq >> 8) & 0xff; | |
362 | ||
cfd08f0f AP |
363 | dev_dbg(&state->i2c_adap->dev, "%s: low Frequency = %04x\n", |
364 | __func__, freq); | |
88b38bef | 365 | |
42432b3c | 366 | ret = it913x_script_loader(state, set_tuner); |
88b38bef AP |
367 | |
368 | return (ret < 0) ? -ENODEV : 0; | |
369 | } | |
370 | ||
88b38bef AP |
371 | /* Power sequence */ |
372 | /* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */ | |
373 | /* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */ | |
374 | ||
42432b3c | 375 | static int it913x_sleep(struct dvb_frontend *fe) |
88b38bef | 376 | { |
42432b3c | 377 | struct it913x_state *state = fe->tuner_priv; |
9e0a976e AP |
378 | |
379 | if (state->chip_ver == 0x01) | |
380 | return it913x_script_loader(state, it9135ax_tuner_off); | |
381 | else | |
382 | return it913x_script_loader(state, it9137_tuner_off); | |
88b38bef AP |
383 | } |
384 | ||
88b38bef AP |
385 | static int it913x_release(struct dvb_frontend *fe) |
386 | { | |
387 | kfree(fe->tuner_priv); | |
388 | return 0; | |
389 | } | |
390 | ||
391 | static const struct dvb_tuner_ops it913x_tuner_ops = { | |
392 | .info = { | |
393 | .name = "ITE Tech IT913X", | |
394 | .frequency_min = 174000000, | |
395 | .frequency_max = 862000000, | |
396 | }, | |
397 | ||
398 | .release = it913x_release, | |
399 | ||
42432b3c AP |
400 | .init = it913x_init, |
401 | .sleep = it913x_sleep, | |
402 | .set_params = it9137_set_params, | |
88b38bef AP |
403 | }; |
404 | ||
405 | struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, | |
44af747f | 406 | struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 config) |
88b38bef | 407 | { |
42432b3c | 408 | struct it913x_state *state = NULL; |
01b461bb | 409 | int ret; |
88b38bef AP |
410 | |
411 | /* allocate memory for the internal state */ | |
42432b3c | 412 | state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL); |
88b38bef AP |
413 | if (state == NULL) |
414 | return NULL; | |
88b38bef AP |
415 | |
416 | state->i2c_adap = i2c_adap; | |
417 | state->i2c_addr = i2c_addr; | |
88b38bef | 418 | |
44af747f | 419 | switch (config) { |
c0d300a6 AP |
420 | case AF9033_TUNER_IT9135_38: |
421 | case AF9033_TUNER_IT9135_51: | |
422 | case AF9033_TUNER_IT9135_52: | |
44af747f AP |
423 | state->chip_ver = 0x01; |
424 | break; | |
c0d300a6 AP |
425 | case AF9033_TUNER_IT9135_60: |
426 | case AF9033_TUNER_IT9135_61: | |
427 | case AF9033_TUNER_IT9135_62: | |
44af747f | 428 | state->chip_ver = 0x02; |
88b38bef AP |
429 | break; |
430 | default: | |
44af747f AP |
431 | dev_dbg(&i2c_adap->dev, |
432 | "%s: invalid config=%02x\n", __func__, config); | |
433 | goto error; | |
88b38bef AP |
434 | } |
435 | ||
44af747f AP |
436 | state->tuner_type = config; |
437 | state->firmware_ver = 1; | |
438 | ||
01b461bb BC |
439 | /* tuner RF initial */ |
440 | ret = it913x_wr_reg(state, PRO_DMOD, 0xec4c, 0x68); | |
441 | if (ret < 0) | |
442 | goto error; | |
443 | ||
88b38bef AP |
444 | fe->tuner_priv = state; |
445 | memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, | |
446 | sizeof(struct dvb_tuner_ops)); | |
447 | ||
44af747f AP |
448 | dev_info(&i2c_adap->dev, |
449 | "%s: ITE Tech IT913X successfully attached\n", | |
450 | KBUILD_MODNAME); | |
451 | dev_dbg(&i2c_adap->dev, "%s: config=%02x chip_ver=%02x\n", | |
452 | __func__, config, state->chip_ver); | |
88b38bef AP |
453 | |
454 | return fe; | |
455 | error: | |
456 | kfree(state); | |
457 | return NULL; | |
458 | } | |
459 | EXPORT_SYMBOL(it913x_attach); | |
460 | ||
461 | MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver"); | |
462 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | |
463 | MODULE_LICENSE("GPL"); |