1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * ITE IT913X silicon tuner driver |
4 | * |
5 | * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) |
6 | * IT9137 Copyright (C) ITE Tech Inc. |
7 | */ |
8 | |
9 | #include "it913x.h" |
10 | #include <linux/platform_device.h> |
11 | #include <linux/regmap.h> |
12 | |
13 | struct it913x_dev { |
14 | struct platform_device *pdev; |
15 | struct regmap *regmap; |
16 | struct dvb_frontend *fe; |
17 | u8 chip_ver:2; |
18 | u8 role:2; |
19 | u16 xtal; |
20 | u8 fdiv; |
21 | u8 clk_mode; |
22 | u32 fn_min; |
23 | bool active; |
24 | }; |
25 | |
26 | static int it913x_init(struct dvb_frontend *fe) |
27 | { |
28 | struct it913x_dev *dev = fe->tuner_priv; |
29 | struct platform_device *pdev = dev->pdev; |
30 | int ret; |
31 | unsigned int utmp; |
32 | u8 iqik_m_cal, nv_val, buf[2]; |
33 | static const u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; |
34 | unsigned long timeout; |
35 | |
36 | dev_dbg(&pdev->dev, "role %u\n" , dev->role); |
37 | |
38 | ret = regmap_write(map: dev->regmap, reg: 0x80ec4c, val: 0x68); |
39 | if (ret) |
40 | goto err; |
41 | |
42 | usleep_range(min: 10000, max: 100000); |
43 | |
44 | ret = regmap_read(map: dev->regmap, reg: 0x80ec86, val: &utmp); |
45 | if (ret) |
46 | goto err; |
47 | |
48 | switch (utmp) { |
49 | case 0: |
50 | /* 12.000 MHz */ |
51 | dev->clk_mode = utmp; |
52 | dev->xtal = 2000; |
53 | dev->fdiv = 3; |
54 | iqik_m_cal = 16; |
55 | break; |
56 | case 1: |
57 | /* 20.480 MHz */ |
58 | dev->clk_mode = utmp; |
59 | dev->xtal = 640; |
60 | dev->fdiv = 1; |
61 | iqik_m_cal = 6; |
62 | break; |
63 | default: |
64 | dev_err(&pdev->dev, "unknown clock identifier %d\n" , utmp); |
65 | ret = -EINVAL; |
66 | goto err; |
67 | } |
68 | |
69 | ret = regmap_read(map: dev->regmap, reg: 0x80ed03, val: &utmp); |
70 | if (ret) |
71 | goto err; |
72 | |
73 | else if (utmp < ARRAY_SIZE(nv)) |
74 | nv_val = nv[utmp]; |
75 | else |
76 | nv_val = 2; |
77 | |
78 | #define TIMEOUT 50 |
79 | timeout = jiffies + msecs_to_jiffies(TIMEOUT); |
80 | while (!time_after(jiffies, timeout)) { |
81 | ret = regmap_bulk_read(map: dev->regmap, reg: 0x80ed23, val: buf, val_count: 2); |
82 | if (ret) |
83 | goto err; |
84 | |
85 | utmp = (buf[1] << 8) | (buf[0] << 0); |
86 | if (utmp) |
87 | break; |
88 | } |
89 | |
90 | dev_dbg(&pdev->dev, "r_fbc_m_bdry took %u ms, val %u\n" , |
91 | jiffies_to_msecs(jiffies) - |
92 | (jiffies_to_msecs(timeout) - TIMEOUT), utmp); |
93 | |
94 | dev->fn_min = dev->xtal * utmp; |
95 | dev->fn_min /= (dev->fdiv * nv_val); |
96 | dev->fn_min *= 1000; |
97 | dev_dbg(&pdev->dev, "fn_min %u\n" , dev->fn_min); |
98 | |
99 | /* |
100 | * Chip version BX never sets that flag so we just wait 50ms in that |
101 | * case. It is possible poll BX similarly than AX and then timeout in |
102 | * order to get 50ms delay, but that causes about 120 extra I2C |
103 | * messages. As for now, we just wait and reduce IO. |
104 | */ |
105 | if (dev->chip_ver == 1) { |
106 | #define TIMEOUT 50 |
107 | timeout = jiffies + msecs_to_jiffies(TIMEOUT); |
108 | while (!time_after(jiffies, timeout)) { |
109 | ret = regmap_read(map: dev->regmap, reg: 0x80ec82, val: &utmp); |
110 | if (ret) |
111 | goto err; |
112 | |
113 | if (utmp) |
114 | break; |
115 | } |
116 | |
117 | dev_dbg(&pdev->dev, "p_tsm_init_mode took %u ms, val %u\n" , |
118 | jiffies_to_msecs(jiffies) - |
119 | (jiffies_to_msecs(timeout) - TIMEOUT), utmp); |
120 | } else { |
121 | msleep(msecs: 50); |
122 | } |
123 | |
124 | ret = regmap_write(map: dev->regmap, reg: 0x80ed81, val: iqik_m_cal); |
125 | if (ret) |
126 | goto err; |
127 | |
128 | ret = regmap_write(map: dev->regmap, reg: 0x80ec57, val: 0x00); |
129 | if (ret) |
130 | goto err; |
131 | |
132 | ret = regmap_write(map: dev->regmap, reg: 0x80ec58, val: 0x00); |
133 | if (ret) |
134 | goto err; |
135 | |
136 | ret = regmap_write(map: dev->regmap, reg: 0x80ec40, val: 0x01); |
137 | if (ret) |
138 | goto err; |
139 | |
140 | dev->active = true; |
141 | |
142 | return 0; |
143 | err: |
144 | dev_dbg(&pdev->dev, "failed %d\n" , ret); |
145 | return ret; |
146 | } |
147 | |
148 | static int it913x_sleep(struct dvb_frontend *fe) |
149 | { |
150 | struct it913x_dev *dev = fe->tuner_priv; |
151 | struct platform_device *pdev = dev->pdev; |
152 | int ret, len; |
153 | |
154 | dev_dbg(&pdev->dev, "role %u\n" , dev->role); |
155 | |
156 | dev->active = false; |
157 | |
158 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x80ec40, val: "\x00" , val_count: 1); |
159 | if (ret) |
160 | goto err; |
161 | |
162 | /* |
163 | * Writing '0x00' to master tuner register '0x80ec08' causes slave tuner |
164 | * communication lost. Due to that, we cannot put master full sleep. |
165 | */ |
166 | if (dev->role == IT913X_ROLE_DUAL_MASTER) |
167 | len = 4; |
168 | else |
169 | len = 15; |
170 | |
171 | dev_dbg(&pdev->dev, "role %u, len %d\n" , dev->role, len); |
172 | |
173 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x80ec02, |
174 | val: "\x3f\x1f\x3f\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , |
175 | val_count: len); |
176 | if (ret) |
177 | goto err; |
178 | |
179 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x80ec12, val: "\x00\x00\x00\x00" , val_count: 4); |
180 | if (ret) |
181 | goto err; |
182 | |
183 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x80ec17, |
184 | val: "\x00\x00\x00\x00\x00\x00\x00\x00\x00" , val_count: 9); |
185 | if (ret) |
186 | goto err; |
187 | |
188 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x80ec22, |
189 | val: "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , val_count: 10); |
190 | if (ret) |
191 | goto err; |
192 | |
193 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x80ec20, val: "\x00" , val_count: 1); |
194 | if (ret) |
195 | goto err; |
196 | |
197 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x80ec3f, val: "\x01" , val_count: 1); |
198 | if (ret) |
199 | goto err; |
200 | |
201 | return 0; |
202 | err: |
203 | dev_dbg(&pdev->dev, "failed %d\n" , ret); |
204 | return ret; |
205 | } |
206 | |
207 | static int it913x_set_params(struct dvb_frontend *fe) |
208 | { |
209 | struct it913x_dev *dev = fe->tuner_priv; |
210 | struct platform_device *pdev = dev->pdev; |
211 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
212 | int ret; |
213 | unsigned int utmp; |
214 | u32 pre_lo_freq, t_cal_freq; |
215 | u16 iqik_m_cal, n_div; |
216 | u8 u8tmp, n, l_band, lna_band; |
217 | |
218 | dev_dbg(&pdev->dev, "role=%u, frequency %u, bandwidth_hz %u\n" , |
219 | dev->role, c->frequency, c->bandwidth_hz); |
220 | |
221 | if (!dev->active) { |
222 | ret = -EINVAL; |
223 | goto err; |
224 | } |
225 | |
226 | if (c->frequency <= 74000000) { |
227 | n_div = 48; |
228 | n = 0; |
229 | } else if (c->frequency <= 111000000) { |
230 | n_div = 32; |
231 | n = 1; |
232 | } else if (c->frequency <= 148000000) { |
233 | n_div = 24; |
234 | n = 2; |
235 | } else if (c->frequency <= 222000000) { |
236 | n_div = 16; |
237 | n = 3; |
238 | } else if (c->frequency <= 296000000) { |
239 | n_div = 12; |
240 | n = 4; |
241 | } else if (c->frequency <= 445000000) { |
242 | n_div = 8; |
243 | n = 5; |
244 | } else if (c->frequency <= dev->fn_min) { |
245 | n_div = 6; |
246 | n = 6; |
247 | } else if (c->frequency <= 950000000) { |
248 | n_div = 4; |
249 | n = 7; |
250 | } else { |
251 | n_div = 2; |
252 | n = 0; |
253 | } |
254 | |
255 | ret = regmap_read(map: dev->regmap, reg: 0x80ed81, val: &utmp); |
256 | if (ret) |
257 | goto err; |
258 | |
259 | iqik_m_cal = utmp * n_div; |
260 | |
261 | if (utmp < 0x20) { |
262 | if (dev->clk_mode == 0) |
263 | iqik_m_cal = (iqik_m_cal * 9) >> 5; |
264 | else |
265 | iqik_m_cal >>= 1; |
266 | } else { |
267 | iqik_m_cal = 0x40 - iqik_m_cal; |
268 | if (dev->clk_mode == 0) |
269 | iqik_m_cal = ~((iqik_m_cal * 9) >> 5); |
270 | else |
271 | iqik_m_cal = ~(iqik_m_cal >> 1); |
272 | } |
273 | |
274 | t_cal_freq = (c->frequency / 1000) * n_div * dev->fdiv; |
275 | pre_lo_freq = t_cal_freq / dev->xtal; |
276 | utmp = pre_lo_freq * dev->xtal; |
277 | |
278 | if ((t_cal_freq - utmp) >= (dev->xtal >> 1)) |
279 | pre_lo_freq++; |
280 | |
281 | pre_lo_freq += (u32) n << 13; |
282 | /* Frequency OMEGA_IQIK_M_CAL_MID*/ |
283 | t_cal_freq = pre_lo_freq + (u32)iqik_m_cal; |
284 | dev_dbg(&pdev->dev, "t_cal_freq %u, pre_lo_freq %u\n" , |
285 | t_cal_freq, pre_lo_freq); |
286 | |
287 | if (c->frequency <= 440000000) { |
288 | l_band = 0; |
289 | lna_band = 0; |
290 | } else if (c->frequency <= 484000000) { |
291 | l_band = 1; |
292 | lna_band = 1; |
293 | } else if (c->frequency <= 533000000) { |
294 | l_band = 1; |
295 | lna_band = 2; |
296 | } else if (c->frequency <= 587000000) { |
297 | l_band = 1; |
298 | lna_band = 3; |
299 | } else if (c->frequency <= 645000000) { |
300 | l_band = 1; |
301 | lna_band = 4; |
302 | } else if (c->frequency <= 710000000) { |
303 | l_band = 1; |
304 | lna_band = 5; |
305 | } else if (c->frequency <= 782000000) { |
306 | l_band = 1; |
307 | lna_band = 6; |
308 | } else if (c->frequency <= 860000000) { |
309 | l_band = 1; |
310 | lna_band = 7; |
311 | } else if (c->frequency <= 1492000000) { |
312 | l_band = 1; |
313 | lna_band = 0; |
314 | } else if (c->frequency <= 1685000000) { |
315 | l_band = 1; |
316 | lna_band = 1; |
317 | } else { |
318 | ret = -EINVAL; |
319 | goto err; |
320 | } |
321 | |
322 | /* XXX: latest windows driver does not set that at all */ |
323 | ret = regmap_write(map: dev->regmap, reg: 0x80ee06, val: lna_band); |
324 | if (ret) |
325 | goto err; |
326 | |
327 | if (c->bandwidth_hz <= 5000000) |
328 | u8tmp = 0; |
329 | else if (c->bandwidth_hz <= 6000000) |
330 | u8tmp = 2; |
331 | else if (c->bandwidth_hz <= 7000000) |
332 | u8tmp = 4; |
333 | else |
334 | u8tmp = 6; /* 8000000 */ |
335 | |
336 | ret = regmap_write(map: dev->regmap, reg: 0x80ec56, val: u8tmp); |
337 | if (ret) |
338 | goto err; |
339 | |
340 | /* XXX: latest windows driver sets different value (a8 != 68) */ |
341 | ret = regmap_write(map: dev->regmap, reg: 0x80ec4c, val: 0xa0 | (l_band << 3)); |
342 | if (ret) |
343 | goto err; |
344 | |
345 | ret = regmap_write(map: dev->regmap, reg: 0x80ec4d, val: (t_cal_freq >> 0) & 0xff); |
346 | if (ret) |
347 | goto err; |
348 | |
349 | ret = regmap_write(map: dev->regmap, reg: 0x80ec4e, val: (t_cal_freq >> 8) & 0xff); |
350 | if (ret) |
351 | goto err; |
352 | |
353 | ret = regmap_write(map: dev->regmap, reg: 0x80011e, val: (pre_lo_freq >> 0) & 0xff); |
354 | if (ret) |
355 | goto err; |
356 | |
357 | ret = regmap_write(map: dev->regmap, reg: 0x80011f, val: (pre_lo_freq >> 8) & 0xff); |
358 | if (ret) |
359 | goto err; |
360 | |
361 | return 0; |
362 | err: |
363 | dev_dbg(&pdev->dev, "failed %d\n" , ret); |
364 | return ret; |
365 | } |
366 | |
367 | static const struct dvb_tuner_ops it913x_tuner_ops = { |
368 | .info = { |
369 | .name = "ITE IT913X" , |
370 | .frequency_min_hz = 174 * MHz, |
371 | .frequency_max_hz = 862 * MHz, |
372 | }, |
373 | |
374 | .init = it913x_init, |
375 | .sleep = it913x_sleep, |
376 | .set_params = it913x_set_params, |
377 | }; |
378 | |
379 | static int it913x_probe(struct platform_device *pdev) |
380 | { |
381 | struct it913x_platform_data *pdata = pdev->dev.platform_data; |
382 | struct dvb_frontend *fe = pdata->fe; |
383 | struct it913x_dev *dev; |
384 | const struct platform_device_id *id = platform_get_device_id(pdev); |
385 | int ret; |
386 | char *chip_ver_str; |
387 | |
388 | dev = kzalloc(size: sizeof(struct it913x_dev), GFP_KERNEL); |
389 | if (dev == NULL) { |
390 | ret = -ENOMEM; |
391 | dev_err(&pdev->dev, "kzalloc() failed\n" ); |
392 | goto err; |
393 | } |
394 | |
395 | dev->pdev = pdev; |
396 | dev->regmap = pdata->regmap; |
397 | dev->fe = pdata->fe; |
398 | dev->chip_ver = id->driver_data; |
399 | dev->role = pdata->role; |
400 | |
401 | fe->tuner_priv = dev; |
402 | memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, |
403 | sizeof(struct dvb_tuner_ops)); |
404 | platform_set_drvdata(pdev, data: dev); |
405 | |
406 | if (dev->chip_ver == 1) |
407 | chip_ver_str = "AX" ; |
408 | else if (dev->chip_ver == 2) |
409 | chip_ver_str = "BX" ; |
410 | else |
411 | chip_ver_str = "??" ; |
412 | |
413 | dev_info(&pdev->dev, "ITE IT913X %s successfully attached\n" , |
414 | chip_ver_str); |
415 | dev_dbg(&pdev->dev, "chip_ver %u, role %u\n" , dev->chip_ver, dev->role); |
416 | return 0; |
417 | err: |
418 | dev_dbg(&pdev->dev, "failed %d\n" , ret); |
419 | return ret; |
420 | } |
421 | |
422 | static void it913x_remove(struct platform_device *pdev) |
423 | { |
424 | struct it913x_dev *dev = platform_get_drvdata(pdev); |
425 | struct dvb_frontend *fe = dev->fe; |
426 | |
427 | dev_dbg(&pdev->dev, "\n" ); |
428 | |
429 | memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); |
430 | fe->tuner_priv = NULL; |
431 | kfree(objp: dev); |
432 | } |
433 | |
434 | static const struct platform_device_id it913x_id_table[] = { |
435 | {"it9133ax-tuner" , 1}, |
436 | {"it9133bx-tuner" , 2}, |
437 | {}, |
438 | }; |
439 | MODULE_DEVICE_TABLE(platform, it913x_id_table); |
440 | |
441 | static struct platform_driver it913x_driver = { |
442 | .driver = { |
443 | .name = "it913x" , |
444 | .suppress_bind_attrs = true, |
445 | }, |
446 | .probe = it913x_probe, |
447 | .remove_new = it913x_remove, |
448 | .id_table = it913x_id_table, |
449 | }; |
450 | |
451 | module_platform_driver(it913x_driver); |
452 | |
453 | MODULE_DESCRIPTION("ITE IT913X silicon tuner driver" ); |
454 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>" ); |
455 | MODULE_LICENSE("GPL" ); |
456 | |