1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * ZyDAS ZD1301 driver (demodulator) |
4 | * |
5 | * Copyright (C) 2015 Antti Palosaari <crope@iki.fi> |
6 | */ |
7 | |
8 | #include "zd1301_demod.h" |
9 | |
10 | static u8 zd1301_demod_gain = 0x38; |
11 | module_param_named(gain, zd1301_demod_gain, byte, 0644); |
12 | MODULE_PARM_DESC(gain, "gain (value: 0x00 - 0x70, default: 0x38)" ); |
13 | |
14 | struct zd1301_demod_dev { |
15 | struct platform_device *pdev; |
16 | struct dvb_frontend frontend; |
17 | struct i2c_adapter adapter; |
18 | u8 gain; |
19 | }; |
20 | |
21 | static int zd1301_demod_wreg(struct zd1301_demod_dev *dev, u16 reg, u8 val) |
22 | { |
23 | struct platform_device *pdev = dev->pdev; |
24 | struct zd1301_demod_platform_data *pdata = pdev->dev.platform_data; |
25 | |
26 | return pdata->reg_write(pdata->reg_priv, reg, val); |
27 | } |
28 | |
29 | static int zd1301_demod_rreg(struct zd1301_demod_dev *dev, u16 reg, u8 *val) |
30 | { |
31 | struct platform_device *pdev = dev->pdev; |
32 | struct zd1301_demod_platform_data *pdata = pdev->dev.platform_data; |
33 | |
34 | return pdata->reg_read(pdata->reg_priv, reg, val); |
35 | } |
36 | |
37 | static int zd1301_demod_set_frontend(struct dvb_frontend *fe) |
38 | { |
39 | struct zd1301_demod_dev *dev = fe->demodulator_priv; |
40 | struct platform_device *pdev = dev->pdev; |
41 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
42 | int ret; |
43 | u32 if_frequency; |
44 | u8 r6a50_val; |
45 | |
46 | dev_dbg(&pdev->dev, "frequency=%u bandwidth_hz=%u\n" , |
47 | c->frequency, c->bandwidth_hz); |
48 | |
49 | /* Program tuner */ |
50 | if (fe->ops.tuner_ops.set_params && |
51 | fe->ops.tuner_ops.get_if_frequency) { |
52 | ret = fe->ops.tuner_ops.set_params(fe); |
53 | if (ret) |
54 | goto err; |
55 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); |
56 | if (ret) |
57 | goto err; |
58 | } else { |
59 | ret = -EINVAL; |
60 | goto err; |
61 | } |
62 | |
63 | dev_dbg(&pdev->dev, "if_frequency=%u\n" , if_frequency); |
64 | if (if_frequency != 36150000) { |
65 | ret = -EINVAL; |
66 | goto err; |
67 | } |
68 | |
69 | switch (c->bandwidth_hz) { |
70 | case 6000000: |
71 | r6a50_val = 0x78; |
72 | break; |
73 | case 7000000: |
74 | r6a50_val = 0x68; |
75 | break; |
76 | case 8000000: |
77 | r6a50_val = 0x58; |
78 | break; |
79 | default: |
80 | ret = -EINVAL; |
81 | goto err; |
82 | } |
83 | |
84 | ret = zd1301_demod_wreg(dev, reg: 0x6a60, val: 0x11); |
85 | if (ret) |
86 | goto err; |
87 | ret = zd1301_demod_wreg(dev, reg: 0x6a47, val: 0x46); |
88 | if (ret) |
89 | goto err; |
90 | ret = zd1301_demod_wreg(dev, reg: 0x6a48, val: 0x46); |
91 | if (ret) |
92 | goto err; |
93 | ret = zd1301_demod_wreg(dev, reg: 0x6a4a, val: 0x15); |
94 | if (ret) |
95 | goto err; |
96 | ret = zd1301_demod_wreg(dev, reg: 0x6a4b, val: 0x63); |
97 | if (ret) |
98 | goto err; |
99 | ret = zd1301_demod_wreg(dev, reg: 0x6a5b, val: 0x99); |
100 | if (ret) |
101 | goto err; |
102 | ret = zd1301_demod_wreg(dev, reg: 0x6a3b, val: 0x10); |
103 | if (ret) |
104 | goto err; |
105 | ret = zd1301_demod_wreg(dev, reg: 0x6806, val: 0x01); |
106 | if (ret) |
107 | goto err; |
108 | ret = zd1301_demod_wreg(dev, reg: 0x6a41, val: 0x08); |
109 | if (ret) |
110 | goto err; |
111 | ret = zd1301_demod_wreg(dev, reg: 0x6a42, val: 0x46); |
112 | if (ret) |
113 | goto err; |
114 | ret = zd1301_demod_wreg(dev, reg: 0x6a44, val: 0x14); |
115 | if (ret) |
116 | goto err; |
117 | ret = zd1301_demod_wreg(dev, reg: 0x6a45, val: 0x67); |
118 | if (ret) |
119 | goto err; |
120 | ret = zd1301_demod_wreg(dev, reg: 0x6a38, val: 0x00); |
121 | if (ret) |
122 | goto err; |
123 | ret = zd1301_demod_wreg(dev, reg: 0x6a4c, val: 0x52); |
124 | if (ret) |
125 | goto err; |
126 | ret = zd1301_demod_wreg(dev, reg: 0x6a49, val: 0x2a); |
127 | if (ret) |
128 | goto err; |
129 | ret = zd1301_demod_wreg(dev, reg: 0x6840, val: 0x2e); |
130 | if (ret) |
131 | goto err; |
132 | ret = zd1301_demod_wreg(dev, reg: 0x6a50, val: r6a50_val); |
133 | if (ret) |
134 | goto err; |
135 | ret = zd1301_demod_wreg(dev, reg: 0x6a38, val: 0x07); |
136 | if (ret) |
137 | goto err; |
138 | |
139 | return 0; |
140 | err: |
141 | dev_dbg(&pdev->dev, "failed=%d\n" , ret); |
142 | return ret; |
143 | } |
144 | |
145 | static int zd1301_demod_sleep(struct dvb_frontend *fe) |
146 | { |
147 | struct zd1301_demod_dev *dev = fe->demodulator_priv; |
148 | struct platform_device *pdev = dev->pdev; |
149 | int ret; |
150 | |
151 | dev_dbg(&pdev->dev, "\n" ); |
152 | |
153 | ret = zd1301_demod_wreg(dev, reg: 0x6a43, val: 0x70); |
154 | if (ret) |
155 | goto err; |
156 | ret = zd1301_demod_wreg(dev, reg: 0x684e, val: 0x00); |
157 | if (ret) |
158 | goto err; |
159 | ret = zd1301_demod_wreg(dev, reg: 0x6849, val: 0x00); |
160 | if (ret) |
161 | goto err; |
162 | ret = zd1301_demod_wreg(dev, reg: 0x68e2, val: 0xd7); |
163 | if (ret) |
164 | goto err; |
165 | ret = zd1301_demod_wreg(dev, reg: 0x68e0, val: 0x39); |
166 | if (ret) |
167 | goto err; |
168 | ret = zd1301_demod_wreg(dev, reg: 0x6840, val: 0x21); |
169 | if (ret) |
170 | goto err; |
171 | |
172 | return 0; |
173 | err: |
174 | dev_dbg(&pdev->dev, "failed=%d\n" , ret); |
175 | return ret; |
176 | } |
177 | |
178 | static int zd1301_demod_init(struct dvb_frontend *fe) |
179 | { |
180 | struct zd1301_demod_dev *dev = fe->demodulator_priv; |
181 | struct platform_device *pdev = dev->pdev; |
182 | int ret; |
183 | |
184 | dev_dbg(&pdev->dev, "\n" ); |
185 | |
186 | ret = zd1301_demod_wreg(dev, reg: 0x6840, val: 0x26); |
187 | if (ret) |
188 | goto err; |
189 | ret = zd1301_demod_wreg(dev, reg: 0x68e0, val: 0xff); |
190 | if (ret) |
191 | goto err; |
192 | ret = zd1301_demod_wreg(dev, reg: 0x68e2, val: 0xd8); |
193 | if (ret) |
194 | goto err; |
195 | ret = zd1301_demod_wreg(dev, reg: 0x6849, val: 0x4e); |
196 | if (ret) |
197 | goto err; |
198 | ret = zd1301_demod_wreg(dev, reg: 0x684e, val: 0x01); |
199 | if (ret) |
200 | goto err; |
201 | ret = zd1301_demod_wreg(dev, reg: 0x6a43, val: zd1301_demod_gain); |
202 | if (ret) |
203 | goto err; |
204 | |
205 | return 0; |
206 | err: |
207 | dev_dbg(&pdev->dev, "failed=%d\n" , ret); |
208 | return ret; |
209 | } |
210 | |
211 | static int zd1301_demod_get_tune_settings(struct dvb_frontend *fe, |
212 | struct dvb_frontend_tune_settings *settings) |
213 | { |
214 | struct zd1301_demod_dev *dev = fe->demodulator_priv; |
215 | struct platform_device *pdev = dev->pdev; |
216 | |
217 | dev_dbg(&pdev->dev, "\n" ); |
218 | |
219 | /* ~180ms seems to be enough */ |
220 | settings->min_delay_ms = 400; |
221 | |
222 | return 0; |
223 | } |
224 | |
225 | static int zd1301_demod_read_status(struct dvb_frontend *fe, |
226 | enum fe_status *status) |
227 | { |
228 | struct zd1301_demod_dev *dev = fe->demodulator_priv; |
229 | struct platform_device *pdev = dev->pdev; |
230 | int ret; |
231 | u8 u8tmp; |
232 | |
233 | ret = zd1301_demod_rreg(dev, reg: 0x6a24, val: &u8tmp); |
234 | if (ret) |
235 | goto err; |
236 | if (u8tmp > 0x00 && u8tmp < 0x20) |
237 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | |
238 | FE_HAS_SYNC | FE_HAS_LOCK; |
239 | else |
240 | *status = 0; |
241 | |
242 | dev_dbg(&pdev->dev, "lock byte=%02x\n" , u8tmp); |
243 | |
244 | /* |
245 | * Interesting registers here are: |
246 | * 0x6a05: get some gain value |
247 | * 0x6a06: get about same gain value than set to 0x6a43 |
248 | * 0x6a07: get some gain value |
249 | * 0x6a43: set gain value by driver |
250 | * 0x6a24: get demod lock bits (FSM stage?) |
251 | * |
252 | * Driver should implement some kind of algorithm to calculate suitable |
253 | * value for register 0x6a43, based likely values from register 0x6a05 |
254 | * and 0x6a07. Looks like gain register 0x6a43 value could be from |
255 | * range 0x00 - 0x70. |
256 | */ |
257 | |
258 | if (dev->gain != zd1301_demod_gain) { |
259 | dev->gain = zd1301_demod_gain; |
260 | |
261 | ret = zd1301_demod_wreg(dev, reg: 0x6a43, val: dev->gain); |
262 | if (ret) |
263 | goto err; |
264 | } |
265 | |
266 | return 0; |
267 | err: |
268 | dev_dbg(&pdev->dev, "failed=%d\n" , ret); |
269 | return ret; |
270 | } |
271 | |
272 | static const struct dvb_frontend_ops zd1301_demod_ops = { |
273 | .delsys = {SYS_DVBT}, |
274 | .info = { |
275 | .name = "ZyDAS ZD1301" , |
276 | .caps = FE_CAN_FEC_1_2 | |
277 | FE_CAN_FEC_2_3 | |
278 | FE_CAN_FEC_3_4 | |
279 | FE_CAN_FEC_5_6 | |
280 | FE_CAN_FEC_7_8 | |
281 | FE_CAN_FEC_AUTO | |
282 | FE_CAN_QPSK | |
283 | FE_CAN_QAM_16 | |
284 | FE_CAN_QAM_64 | |
285 | FE_CAN_QAM_AUTO | |
286 | FE_CAN_TRANSMISSION_MODE_AUTO | |
287 | FE_CAN_GUARD_INTERVAL_AUTO | |
288 | FE_CAN_HIERARCHY_AUTO | |
289 | FE_CAN_MUTE_TS |
290 | }, |
291 | |
292 | .sleep = zd1301_demod_sleep, |
293 | .init = zd1301_demod_init, |
294 | .set_frontend = zd1301_demod_set_frontend, |
295 | .get_tune_settings = zd1301_demod_get_tune_settings, |
296 | .read_status = zd1301_demod_read_status, |
297 | }; |
298 | |
299 | struct dvb_frontend *zd1301_demod_get_dvb_frontend(struct platform_device *pdev) |
300 | { |
301 | struct zd1301_demod_dev *dev = platform_get_drvdata(pdev); |
302 | |
303 | dev_dbg(&pdev->dev, "\n" ); |
304 | |
305 | return &dev->frontend; |
306 | } |
307 | EXPORT_SYMBOL(zd1301_demod_get_dvb_frontend); |
308 | |
309 | static int zd1301_demod_i2c_master_xfer(struct i2c_adapter *adapter, |
310 | struct i2c_msg msg[], int num) |
311 | { |
312 | struct zd1301_demod_dev *dev = i2c_get_adapdata(adap: adapter); |
313 | struct platform_device *pdev = dev->pdev; |
314 | int ret, i; |
315 | unsigned long timeout; |
316 | u8 u8tmp; |
317 | |
318 | #define I2C_XFER_TIMEOUT 5 |
319 | #define ZD1301_IS_I2C_XFER_WRITE_READ(_msg, _num) \ |
320 | (_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags & I2C_M_RD)) |
321 | #define ZD1301_IS_I2C_XFER_WRITE(_msg, _num) \ |
322 | (_num == 1 && !(_msg[0].flags & I2C_M_RD)) |
323 | #define ZD1301_IS_I2C_XFER_READ(_msg, _num) \ |
324 | (_num == 1 && (_msg[0].flags & I2C_M_RD)) |
325 | if (ZD1301_IS_I2C_XFER_WRITE_READ(msg, num)) { |
326 | dev_dbg(&pdev->dev, "write&read msg[0].len=%u msg[1].len=%u\n" , |
327 | msg[0].len, msg[1].len); |
328 | if (msg[0].len > 1 || msg[1].len > 8) { |
329 | ret = -EOPNOTSUPP; |
330 | goto err; |
331 | } |
332 | |
333 | ret = zd1301_demod_wreg(dev, reg: 0x6811, val: 0x80); |
334 | if (ret) |
335 | goto err; |
336 | ret = zd1301_demod_wreg(dev, reg: 0x6812, val: 0x05); |
337 | if (ret) |
338 | goto err; |
339 | ret = zd1301_demod_wreg(dev, reg: 0x6813, val: msg[1].addr << 1); |
340 | if (ret) |
341 | goto err; |
342 | ret = zd1301_demod_wreg(dev, reg: 0x6801, val: msg[0].buf[0]); |
343 | if (ret) |
344 | goto err; |
345 | ret = zd1301_demod_wreg(dev, reg: 0x6802, val: 0x00); |
346 | if (ret) |
347 | goto err; |
348 | ret = zd1301_demod_wreg(dev, reg: 0x6803, val: 0x06); |
349 | if (ret) |
350 | goto err; |
351 | ret = zd1301_demod_wreg(dev, reg: 0x6805, val: 0x00); |
352 | if (ret) |
353 | goto err; |
354 | ret = zd1301_demod_wreg(dev, reg: 0x6804, val: msg[1].len); |
355 | if (ret) |
356 | goto err; |
357 | |
358 | /* Poll xfer ready */ |
359 | timeout = jiffies + msecs_to_jiffies(I2C_XFER_TIMEOUT); |
360 | for (u8tmp = 1; !time_after(jiffies, timeout) && u8tmp;) { |
361 | usleep_range(min: 500, max: 800); |
362 | |
363 | ret = zd1301_demod_rreg(dev, reg: 0x6804, val: &u8tmp); |
364 | if (ret) |
365 | goto err; |
366 | } |
367 | |
368 | for (i = 0; i < msg[1].len; i++) { |
369 | ret = zd1301_demod_rreg(dev, reg: 0x0600 + i, val: &msg[1].buf[i]); |
370 | if (ret) |
371 | goto err; |
372 | } |
373 | } else if (ZD1301_IS_I2C_XFER_WRITE(msg, num)) { |
374 | dev_dbg(&pdev->dev, "write msg[0].len=%u\n" , msg[0].len); |
375 | if (msg[0].len > 1 + 8) { |
376 | ret = -EOPNOTSUPP; |
377 | goto err; |
378 | } |
379 | |
380 | ret = zd1301_demod_wreg(dev, reg: 0x6811, val: 0x80); |
381 | if (ret) |
382 | goto err; |
383 | ret = zd1301_demod_wreg(dev, reg: 0x6812, val: 0x01); |
384 | if (ret) |
385 | goto err; |
386 | ret = zd1301_demod_wreg(dev, reg: 0x6813, val: msg[0].addr << 1); |
387 | if (ret) |
388 | goto err; |
389 | ret = zd1301_demod_wreg(dev, reg: 0x6800, val: msg[0].buf[0]); |
390 | if (ret) |
391 | goto err; |
392 | ret = zd1301_demod_wreg(dev, reg: 0x6802, val: 0x00); |
393 | if (ret) |
394 | goto err; |
395 | ret = zd1301_demod_wreg(dev, reg: 0x6803, val: 0x06); |
396 | if (ret) |
397 | goto err; |
398 | |
399 | for (i = 0; i < msg[0].len - 1; i++) { |
400 | ret = zd1301_demod_wreg(dev, reg: 0x0600 + i, val: msg[0].buf[1 + i]); |
401 | if (ret) |
402 | goto err; |
403 | } |
404 | |
405 | ret = zd1301_demod_wreg(dev, reg: 0x6805, val: 0x80); |
406 | if (ret) |
407 | goto err; |
408 | ret = zd1301_demod_wreg(dev, reg: 0x6804, val: msg[0].len - 1); |
409 | if (ret) |
410 | goto err; |
411 | |
412 | /* Poll xfer ready */ |
413 | timeout = jiffies + msecs_to_jiffies(I2C_XFER_TIMEOUT); |
414 | for (u8tmp = 1; !time_after(jiffies, timeout) && u8tmp;) { |
415 | usleep_range(min: 500, max: 800); |
416 | |
417 | ret = zd1301_demod_rreg(dev, reg: 0x6804, val: &u8tmp); |
418 | if (ret) |
419 | goto err; |
420 | } |
421 | } else { |
422 | dev_dbg(&pdev->dev, "unknown msg[0].len=%u\n" , msg[0].len); |
423 | ret = -EOPNOTSUPP; |
424 | goto err; |
425 | } |
426 | |
427 | return num; |
428 | err: |
429 | dev_dbg(&pdev->dev, "failed=%d\n" , ret); |
430 | return ret; |
431 | } |
432 | |
433 | static u32 zd1301_demod_i2c_functionality(struct i2c_adapter *adapter) |
434 | { |
435 | return I2C_FUNC_I2C; |
436 | } |
437 | |
438 | static const struct i2c_algorithm zd1301_demod_i2c_algorithm = { |
439 | .master_xfer = zd1301_demod_i2c_master_xfer, |
440 | .functionality = zd1301_demod_i2c_functionality, |
441 | }; |
442 | |
443 | struct i2c_adapter *zd1301_demod_get_i2c_adapter(struct platform_device *pdev) |
444 | { |
445 | struct zd1301_demod_dev *dev = platform_get_drvdata(pdev); |
446 | |
447 | dev_dbg(&pdev->dev, "\n" ); |
448 | |
449 | return &dev->adapter; |
450 | } |
451 | EXPORT_SYMBOL(zd1301_demod_get_i2c_adapter); |
452 | |
453 | /* Platform driver interface */ |
454 | static int zd1301_demod_probe(struct platform_device *pdev) |
455 | { |
456 | struct zd1301_demod_dev *dev; |
457 | struct zd1301_demod_platform_data *pdata = pdev->dev.platform_data; |
458 | int ret; |
459 | |
460 | dev_dbg(&pdev->dev, "\n" ); |
461 | |
462 | if (!pdata) { |
463 | ret = -EINVAL; |
464 | dev_err(&pdev->dev, "cannot proceed without platform data\n" ); |
465 | goto err; |
466 | } |
467 | if (!pdev->dev.parent->driver) { |
468 | ret = -EINVAL; |
469 | dev_dbg(&pdev->dev, "no parent device\n" ); |
470 | goto err; |
471 | } |
472 | |
473 | dev = kzalloc(size: sizeof(*dev), GFP_KERNEL); |
474 | if (!dev) { |
475 | ret = -ENOMEM; |
476 | goto err; |
477 | } |
478 | |
479 | /* Setup the state */ |
480 | dev->pdev = pdev; |
481 | dev->gain = zd1301_demod_gain; |
482 | |
483 | /* Sleep */ |
484 | ret = zd1301_demod_wreg(dev, reg: 0x6840, val: 0x21); |
485 | if (ret) |
486 | goto err_kfree; |
487 | ret = zd1301_demod_wreg(dev, reg: 0x6a38, val: 0x07); |
488 | if (ret) |
489 | goto err_kfree; |
490 | |
491 | /* Create I2C adapter */ |
492 | strscpy(p: dev->adapter.name, q: "ZyDAS ZD1301 demod" , |
493 | size: sizeof(dev->adapter.name)); |
494 | dev->adapter.algo = &zd1301_demod_i2c_algorithm; |
495 | dev->adapter.algo_data = NULL; |
496 | dev->adapter.dev.parent = pdev->dev.parent; |
497 | i2c_set_adapdata(adap: &dev->adapter, data: dev); |
498 | ret = i2c_add_adapter(adap: &dev->adapter); |
499 | if (ret) { |
500 | dev_err(&pdev->dev, "I2C adapter add failed %d\n" , ret); |
501 | goto err_kfree; |
502 | } |
503 | |
504 | /* Create dvb frontend */ |
505 | memcpy(&dev->frontend.ops, &zd1301_demod_ops, sizeof(dev->frontend.ops)); |
506 | dev->frontend.demodulator_priv = dev; |
507 | platform_set_drvdata(pdev, data: dev); |
508 | dev_info(&pdev->dev, "ZyDAS ZD1301 demod attached\n" ); |
509 | |
510 | return 0; |
511 | err_kfree: |
512 | kfree(objp: dev); |
513 | err: |
514 | dev_dbg(&pdev->dev, "failed=%d\n" , ret); |
515 | return ret; |
516 | } |
517 | |
518 | static void zd1301_demod_remove(struct platform_device *pdev) |
519 | { |
520 | struct zd1301_demod_dev *dev = platform_get_drvdata(pdev); |
521 | |
522 | dev_dbg(&pdev->dev, "\n" ); |
523 | |
524 | i2c_del_adapter(adap: &dev->adapter); |
525 | kfree(objp: dev); |
526 | } |
527 | |
528 | static struct platform_driver zd1301_demod_driver = { |
529 | .driver = { |
530 | .name = "zd1301_demod" , |
531 | .suppress_bind_attrs = true, |
532 | }, |
533 | .probe = zd1301_demod_probe, |
534 | .remove_new = zd1301_demod_remove, |
535 | }; |
536 | module_platform_driver(zd1301_demod_driver); |
537 | |
538 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>" ); |
539 | MODULE_DESCRIPTION("ZyDAS ZD1301 demodulator driver" ); |
540 | MODULE_LICENSE("GPL" ); |
541 | |