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