1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Panasonic MN88473 DVB-T/T2/C demodulator driver |
4 | * |
5 | * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> |
6 | */ |
7 | |
8 | #include "mn88473_priv.h" |
9 | |
10 | static int mn88473_get_tune_settings(struct dvb_frontend *fe, |
11 | struct dvb_frontend_tune_settings *s) |
12 | { |
13 | s->min_delay_ms = 1000; |
14 | return 0; |
15 | } |
16 | |
17 | static int mn88473_set_frontend(struct dvb_frontend *fe) |
18 | { |
19 | struct i2c_client *client = fe->demodulator_priv; |
20 | struct mn88473_dev *dev = i2c_get_clientdata(client); |
21 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
22 | int ret, i; |
23 | unsigned int uitmp; |
24 | u32 if_frequency; |
25 | u8 delivery_system_val, if_val[3], *conf_val_ptr; |
26 | u8 reg_bank2_2d_val, reg_bank0_d2_val; |
27 | |
28 | dev_dbg(&client->dev, |
29 | "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d\n" , |
30 | c->delivery_system, c->modulation, c->frequency, |
31 | c->bandwidth_hz, c->symbol_rate, c->inversion, c->stream_id); |
32 | |
33 | if (!dev->active) { |
34 | ret = -EAGAIN; |
35 | goto err; |
36 | } |
37 | |
38 | switch (c->delivery_system) { |
39 | case SYS_DVBT: |
40 | delivery_system_val = 0x02; |
41 | reg_bank2_2d_val = 0x23; |
42 | reg_bank0_d2_val = 0x2a; |
43 | break; |
44 | case SYS_DVBT2: |
45 | delivery_system_val = 0x03; |
46 | reg_bank2_2d_val = 0x3b; |
47 | reg_bank0_d2_val = 0x29; |
48 | break; |
49 | case SYS_DVBC_ANNEX_A: |
50 | delivery_system_val = 0x04; |
51 | reg_bank2_2d_val = 0x3b; |
52 | reg_bank0_d2_val = 0x29; |
53 | break; |
54 | default: |
55 | ret = -EINVAL; |
56 | goto err; |
57 | } |
58 | |
59 | switch (c->delivery_system) { |
60 | case SYS_DVBT: |
61 | case SYS_DVBT2: |
62 | switch (c->bandwidth_hz) { |
63 | case 6000000: |
64 | conf_val_ptr = "\xe9\x55\x55\x1c\x29\x1c\x29" ; |
65 | break; |
66 | case 7000000: |
67 | conf_val_ptr = "\xc8\x00\x00\x17\x0a\x17\x0a" ; |
68 | break; |
69 | case 8000000: |
70 | conf_val_ptr = "\xaf\x00\x00\x11\xec\x11\xec" ; |
71 | break; |
72 | default: |
73 | ret = -EINVAL; |
74 | goto err; |
75 | } |
76 | break; |
77 | case SYS_DVBC_ANNEX_A: |
78 | conf_val_ptr = "\x10\xab\x0d\xae\x1d\x9d" ; |
79 | break; |
80 | default: |
81 | break; |
82 | } |
83 | |
84 | /* Program tuner */ |
85 | if (fe->ops.tuner_ops.set_params) { |
86 | ret = fe->ops.tuner_ops.set_params(fe); |
87 | if (ret) |
88 | goto err; |
89 | } |
90 | |
91 | if (fe->ops.tuner_ops.get_if_frequency) { |
92 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); |
93 | if (ret) |
94 | goto err; |
95 | |
96 | dev_dbg(&client->dev, "get_if_frequency=%u\n" , if_frequency); |
97 | } else { |
98 | ret = -EINVAL; |
99 | goto err; |
100 | } |
101 | |
102 | /* Calculate IF registers */ |
103 | uitmp = DIV_ROUND_CLOSEST_ULL((u64) if_frequency * 0x1000000, dev->clk); |
104 | if_val[0] = (uitmp >> 16) & 0xff; |
105 | if_val[1] = (uitmp >> 8) & 0xff; |
106 | if_val[2] = (uitmp >> 0) & 0xff; |
107 | |
108 | ret = regmap_write(map: dev->regmap[2], reg: 0x05, val: 0x00); |
109 | if (ret) |
110 | goto err; |
111 | ret = regmap_write(map: dev->regmap[2], reg: 0xfb, val: 0x13); |
112 | if (ret) |
113 | goto err; |
114 | ret = regmap_write(map: dev->regmap[2], reg: 0xef, val: 0x13); |
115 | if (ret) |
116 | goto err; |
117 | ret = regmap_write(map: dev->regmap[2], reg: 0xf9, val: 0x13); |
118 | if (ret) |
119 | goto err; |
120 | ret = regmap_write(map: dev->regmap[2], reg: 0x00, val: 0x18); |
121 | if (ret) |
122 | goto err; |
123 | ret = regmap_write(map: dev->regmap[2], reg: 0x01, val: 0x01); |
124 | if (ret) |
125 | goto err; |
126 | ret = regmap_write(map: dev->regmap[2], reg: 0x02, val: 0x21); |
127 | if (ret) |
128 | goto err; |
129 | ret = regmap_write(map: dev->regmap[2], reg: 0x03, val: delivery_system_val); |
130 | if (ret) |
131 | goto err; |
132 | ret = regmap_write(map: dev->regmap[2], reg: 0x0b, val: 0x00); |
133 | if (ret) |
134 | goto err; |
135 | |
136 | for (i = 0; i < sizeof(if_val); i++) { |
137 | ret = regmap_write(map: dev->regmap[2], reg: 0x10 + i, val: if_val[i]); |
138 | if (ret) |
139 | goto err; |
140 | } |
141 | |
142 | switch (c->delivery_system) { |
143 | case SYS_DVBT: |
144 | case SYS_DVBT2: |
145 | for (i = 0; i < 7; i++) { |
146 | ret = regmap_write(map: dev->regmap[2], reg: 0x13 + i, |
147 | val: conf_val_ptr[i]); |
148 | if (ret) |
149 | goto err; |
150 | } |
151 | break; |
152 | case SYS_DVBC_ANNEX_A: |
153 | ret = regmap_bulk_write(map: dev->regmap[1], reg: 0x10, val: conf_val_ptr, val_count: 6); |
154 | if (ret) |
155 | goto err; |
156 | break; |
157 | default: |
158 | break; |
159 | } |
160 | |
161 | ret = regmap_write(map: dev->regmap[2], reg: 0x2d, val: reg_bank2_2d_val); |
162 | if (ret) |
163 | goto err; |
164 | ret = regmap_write(map: dev->regmap[2], reg: 0x2e, val: 0x00); |
165 | if (ret) |
166 | goto err; |
167 | ret = regmap_write(map: dev->regmap[2], reg: 0x56, val: 0x0d); |
168 | if (ret) |
169 | goto err; |
170 | ret = regmap_bulk_write(map: dev->regmap[0], reg: 0x01, |
171 | val: "\xba\x13\x80\xba\x91\xdd\xe7\x28" , val_count: 8); |
172 | if (ret) |
173 | goto err; |
174 | ret = regmap_write(map: dev->regmap[0], reg: 0x0a, val: 0x1a); |
175 | if (ret) |
176 | goto err; |
177 | ret = regmap_write(map: dev->regmap[0], reg: 0x13, val: 0x1f); |
178 | if (ret) |
179 | goto err; |
180 | ret = regmap_write(map: dev->regmap[0], reg: 0x19, val: 0x03); |
181 | if (ret) |
182 | goto err; |
183 | ret = regmap_write(map: dev->regmap[0], reg: 0x1d, val: 0xb0); |
184 | if (ret) |
185 | goto err; |
186 | ret = regmap_write(map: dev->regmap[0], reg: 0x2a, val: 0x72); |
187 | if (ret) |
188 | goto err; |
189 | ret = regmap_write(map: dev->regmap[0], reg: 0x2d, val: 0x00); |
190 | if (ret) |
191 | goto err; |
192 | ret = regmap_write(map: dev->regmap[0], reg: 0x3c, val: 0x00); |
193 | if (ret) |
194 | goto err; |
195 | ret = regmap_write(map: dev->regmap[0], reg: 0x3f, val: 0xf8); |
196 | if (ret) |
197 | goto err; |
198 | ret = regmap_bulk_write(map: dev->regmap[0], reg: 0x40, val: "\xf4\x08" , val_count: 2); |
199 | if (ret) |
200 | goto err; |
201 | ret = regmap_write(map: dev->regmap[0], reg: 0xd2, val: reg_bank0_d2_val); |
202 | if (ret) |
203 | goto err; |
204 | ret = regmap_write(map: dev->regmap[0], reg: 0xd4, val: 0x55); |
205 | if (ret) |
206 | goto err; |
207 | ret = regmap_write(map: dev->regmap[1], reg: 0xbe, val: 0x08); |
208 | if (ret) |
209 | goto err; |
210 | ret = regmap_write(map: dev->regmap[0], reg: 0xb2, val: 0x37); |
211 | if (ret) |
212 | goto err; |
213 | ret = regmap_write(map: dev->regmap[0], reg: 0xd7, val: 0x04); |
214 | if (ret) |
215 | goto err; |
216 | |
217 | /* PLP */ |
218 | if (c->delivery_system == SYS_DVBT2) { |
219 | ret = regmap_write(map: dev->regmap[2], reg: 0x36, |
220 | val: (c->stream_id == NO_STREAM_ID_FILTER) ? 0 : |
221 | c->stream_id ); |
222 | if (ret) |
223 | goto err; |
224 | } |
225 | |
226 | /* Reset FSM */ |
227 | ret = regmap_write(map: dev->regmap[2], reg: 0xf8, val: 0x9f); |
228 | if (ret) |
229 | goto err; |
230 | |
231 | return 0; |
232 | err: |
233 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
234 | return ret; |
235 | } |
236 | |
237 | static int mn88473_read_status(struct dvb_frontend *fe, enum fe_status *status) |
238 | { |
239 | struct i2c_client *client = fe->demodulator_priv; |
240 | struct mn88473_dev *dev = i2c_get_clientdata(client); |
241 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
242 | int ret, i, stmp; |
243 | unsigned int utmp, utmp1, utmp2; |
244 | u8 buf[5]; |
245 | |
246 | if (!dev->active) { |
247 | ret = -EAGAIN; |
248 | goto err; |
249 | } |
250 | |
251 | /* Lock detection */ |
252 | switch (c->delivery_system) { |
253 | case SYS_DVBT: |
254 | ret = regmap_read(map: dev->regmap[0], reg: 0x62, val: &utmp); |
255 | if (ret) |
256 | goto err; |
257 | |
258 | if (!(utmp & 0xa0)) { |
259 | if ((utmp & 0x0f) >= 0x09) |
260 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | |
261 | FE_HAS_VITERBI | FE_HAS_SYNC | |
262 | FE_HAS_LOCK; |
263 | else if ((utmp & 0x0f) >= 0x03) |
264 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; |
265 | } else { |
266 | *status = 0; |
267 | } |
268 | break; |
269 | case SYS_DVBT2: |
270 | ret = regmap_read(map: dev->regmap[2], reg: 0x8b, val: &utmp); |
271 | if (ret) |
272 | goto err; |
273 | |
274 | if (!(utmp & 0x40)) { |
275 | if ((utmp & 0x0f) >= 0x0d) |
276 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | |
277 | FE_HAS_VITERBI | FE_HAS_SYNC | |
278 | FE_HAS_LOCK; |
279 | else if ((utmp & 0x0f) >= 0x0a) |
280 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | |
281 | FE_HAS_VITERBI; |
282 | else if ((utmp & 0x0f) >= 0x07) |
283 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; |
284 | } else { |
285 | *status = 0; |
286 | } |
287 | break; |
288 | case SYS_DVBC_ANNEX_A: |
289 | ret = regmap_read(map: dev->regmap[1], reg: 0x85, val: &utmp); |
290 | if (ret) |
291 | goto err; |
292 | |
293 | if (!(utmp & 0x40)) { |
294 | ret = regmap_read(map: dev->regmap[1], reg: 0x89, val: &utmp); |
295 | if (ret) |
296 | goto err; |
297 | |
298 | if (utmp & 0x01) |
299 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | |
300 | FE_HAS_VITERBI | FE_HAS_SYNC | |
301 | FE_HAS_LOCK; |
302 | } else { |
303 | *status = 0; |
304 | } |
305 | break; |
306 | default: |
307 | ret = -EINVAL; |
308 | goto err; |
309 | } |
310 | |
311 | /* Signal strength */ |
312 | if (*status & FE_HAS_SIGNAL) { |
313 | for (i = 0; i < 2; i++) { |
314 | ret = regmap_bulk_read(map: dev->regmap[2], reg: 0x86 + i, |
315 | val: &buf[i], val_count: 1); |
316 | if (ret) |
317 | goto err; |
318 | } |
319 | |
320 | /* AGCRD[15:6] gives us a 10bit value ([5:0] are always 0) */ |
321 | utmp1 = buf[0] << 8 | buf[1] << 0 | buf[0] >> 2; |
322 | dev_dbg(&client->dev, "strength=%u\n" , utmp1); |
323 | |
324 | c->strength.stat[0].scale = FE_SCALE_RELATIVE; |
325 | c->strength.stat[0].uvalue = utmp1; |
326 | } else { |
327 | c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
328 | } |
329 | |
330 | /* CNR */ |
331 | if (*status & FE_HAS_VITERBI && c->delivery_system == SYS_DVBT) { |
332 | /* DVB-T CNR */ |
333 | ret = regmap_bulk_read(map: dev->regmap[0], reg: 0x8f, val: buf, val_count: 2); |
334 | if (ret) |
335 | goto err; |
336 | |
337 | utmp = buf[0] << 8 | buf[1] << 0; |
338 | if (utmp) { |
339 | /* CNR[dB]: 10 * (log10(65536 / value) + 0.2) */ |
340 | /* log10(65536) = 80807124, 0.2 = 3355443 */ |
341 | stmp = div_u64(dividend: ((u64)80807124 - intlog10(value: utmp) |
342 | + 3355443) * 10000, divisor: 1 << 24); |
343 | dev_dbg(&client->dev, "cnr=%d value=%u\n" , stmp, utmp); |
344 | } else { |
345 | stmp = 0; |
346 | } |
347 | |
348 | c->cnr.stat[0].svalue = stmp; |
349 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; |
350 | } else if (*status & FE_HAS_VITERBI && |
351 | c->delivery_system == SYS_DVBT2) { |
352 | /* DVB-T2 CNR */ |
353 | for (i = 0; i < 3; i++) { |
354 | ret = regmap_bulk_read(map: dev->regmap[2], reg: 0xb7 + i, |
355 | val: &buf[i], val_count: 1); |
356 | if (ret) |
357 | goto err; |
358 | } |
359 | |
360 | utmp = buf[1] << 8 | buf[2] << 0; |
361 | utmp1 = (buf[0] >> 2) & 0x01; /* 0=SISO, 1=MISO */ |
362 | if (utmp) { |
363 | if (utmp1) { |
364 | /* CNR[dB]: 10 * (log10(16384 / value) - 0.6) */ |
365 | /* log10(16384) = 70706234, 0.6 = 10066330 */ |
366 | stmp = div_u64(dividend: ((u64)70706234 - intlog10(value: utmp) |
367 | - 10066330) * 10000, divisor: 1 << 24); |
368 | dev_dbg(&client->dev, "cnr=%d value=%u MISO\n" , |
369 | stmp, utmp); |
370 | } else { |
371 | /* CNR[dB]: 10 * (log10(65536 / value) + 0.2) */ |
372 | /* log10(65536) = 80807124, 0.2 = 3355443 */ |
373 | stmp = div_u64(dividend: ((u64)80807124 - intlog10(value: utmp) |
374 | + 3355443) * 10000, divisor: 1 << 24); |
375 | dev_dbg(&client->dev, "cnr=%d value=%u SISO\n" , |
376 | stmp, utmp); |
377 | } |
378 | } else { |
379 | stmp = 0; |
380 | } |
381 | |
382 | c->cnr.stat[0].svalue = stmp; |
383 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; |
384 | } else if (*status & FE_HAS_VITERBI && |
385 | c->delivery_system == SYS_DVBC_ANNEX_A) { |
386 | /* DVB-C CNR */ |
387 | ret = regmap_bulk_read(map: dev->regmap[1], reg: 0xa1, val: buf, val_count: 4); |
388 | if (ret) |
389 | goto err; |
390 | |
391 | utmp1 = buf[0] << 8 | buf[1] << 0; /* signal */ |
392 | utmp2 = buf[2] << 8 | buf[3] << 0; /* noise */ |
393 | if (utmp1 && utmp2) { |
394 | /* CNR[dB]: 10 * log10(8 * (signal / noise)) */ |
395 | /* log10(8) = 15151336 */ |
396 | stmp = div_u64(dividend: ((u64)15151336 + intlog10(value: utmp1) |
397 | - intlog10(value: utmp2)) * 10000, divisor: 1 << 24); |
398 | dev_dbg(&client->dev, "cnr=%d signal=%u noise=%u\n" , |
399 | stmp, utmp1, utmp2); |
400 | } else { |
401 | stmp = 0; |
402 | } |
403 | |
404 | c->cnr.stat[0].svalue = stmp; |
405 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; |
406 | } else { |
407 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
408 | } |
409 | |
410 | /* BER */ |
411 | if (*status & FE_HAS_LOCK && (c->delivery_system == SYS_DVBT || |
412 | c->delivery_system == SYS_DVBC_ANNEX_A)) { |
413 | /* DVB-T & DVB-C BER */ |
414 | ret = regmap_bulk_read(map: dev->regmap[0], reg: 0x92, val: buf, val_count: 5); |
415 | if (ret) |
416 | goto err; |
417 | |
418 | utmp1 = buf[0] << 16 | buf[1] << 8 | buf[2] << 0; |
419 | utmp2 = buf[3] << 8 | buf[4] << 0; |
420 | utmp2 = utmp2 * 8 * 204; |
421 | dev_dbg(&client->dev, "post_bit_error=%u post_bit_count=%u\n" , |
422 | utmp1, utmp2); |
423 | |
424 | c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; |
425 | c->post_bit_error.stat[0].uvalue += utmp1; |
426 | c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; |
427 | c->post_bit_count.stat[0].uvalue += utmp2; |
428 | } else { |
429 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
430 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
431 | } |
432 | |
433 | /* PER */ |
434 | if (*status & FE_HAS_LOCK) { |
435 | ret = regmap_bulk_read(map: dev->regmap[0], reg: 0xdd, val: buf, val_count: 4); |
436 | if (ret) |
437 | goto err; |
438 | |
439 | utmp1 = buf[0] << 8 | buf[1] << 0; |
440 | utmp2 = buf[2] << 8 | buf[3] << 0; |
441 | dev_dbg(&client->dev, "block_error=%u block_count=%u\n" , |
442 | utmp1, utmp2); |
443 | |
444 | c->block_error.stat[0].scale = FE_SCALE_COUNTER; |
445 | c->block_error.stat[0].uvalue += utmp1; |
446 | c->block_count.stat[0].scale = FE_SCALE_COUNTER; |
447 | c->block_count.stat[0].uvalue += utmp2; |
448 | } else { |
449 | c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
450 | c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
451 | } |
452 | |
453 | return 0; |
454 | err: |
455 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
456 | return ret; |
457 | } |
458 | |
459 | static int mn88473_init(struct dvb_frontend *fe) |
460 | { |
461 | struct i2c_client *client = fe->demodulator_priv; |
462 | struct mn88473_dev *dev = i2c_get_clientdata(client); |
463 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
464 | int ret, len, remain; |
465 | unsigned int uitmp; |
466 | const struct firmware *fw; |
467 | const char *name = MN88473_FIRMWARE; |
468 | |
469 | dev_dbg(&client->dev, "\n" ); |
470 | |
471 | /* Check if firmware is already running */ |
472 | ret = regmap_read(map: dev->regmap[0], reg: 0xf5, val: &uitmp); |
473 | if (ret) |
474 | goto err; |
475 | |
476 | if (!(uitmp & 0x01)) |
477 | goto warm; |
478 | |
479 | /* Request the firmware, this will block and timeout */ |
480 | ret = request_firmware(fw: &fw, name, device: &client->dev); |
481 | if (ret) { |
482 | dev_err(&client->dev, "firmware file '%s' not found\n" , name); |
483 | goto err; |
484 | } |
485 | |
486 | dev_info(&client->dev, "downloading firmware from file '%s'\n" , name); |
487 | |
488 | ret = regmap_write(map: dev->regmap[0], reg: 0xf5, val: 0x03); |
489 | if (ret) |
490 | goto err_release_firmware; |
491 | |
492 | for (remain = fw->size; remain > 0; remain -= (dev->i2c_wr_max - 1)) { |
493 | len = min(dev->i2c_wr_max - 1, remain); |
494 | ret = regmap_bulk_write(map: dev->regmap[0], reg: 0xf6, |
495 | val: &fw->data[fw->size - remain], val_count: len); |
496 | if (ret) { |
497 | dev_err(&client->dev, "firmware download failed %d\n" , |
498 | ret); |
499 | goto err_release_firmware; |
500 | } |
501 | } |
502 | |
503 | release_firmware(fw); |
504 | |
505 | /* Parity check of firmware */ |
506 | ret = regmap_read(map: dev->regmap[0], reg: 0xf8, val: &uitmp); |
507 | if (ret) |
508 | goto err; |
509 | |
510 | if (uitmp & 0x10) { |
511 | dev_err(&client->dev, "firmware parity check failed\n" ); |
512 | ret = -EINVAL; |
513 | goto err; |
514 | } |
515 | |
516 | ret = regmap_write(map: dev->regmap[0], reg: 0xf5, val: 0x00); |
517 | if (ret) |
518 | goto err; |
519 | warm: |
520 | /* TS config */ |
521 | ret = regmap_write(map: dev->regmap[2], reg: 0x09, val: 0x08); |
522 | if (ret) |
523 | goto err; |
524 | ret = regmap_write(map: dev->regmap[2], reg: 0x08, val: 0x1d); |
525 | if (ret) |
526 | goto err; |
527 | |
528 | dev->active = true; |
529 | |
530 | /* init stats here to indicate which stats are supported */ |
531 | c->strength.len = 1; |
532 | c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
533 | c->cnr.len = 1; |
534 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
535 | c->post_bit_error.len = 1; |
536 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
537 | c->post_bit_count.len = 1; |
538 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
539 | c->block_error.len = 1; |
540 | c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
541 | c->block_count.len = 1; |
542 | c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
543 | |
544 | return 0; |
545 | err_release_firmware: |
546 | release_firmware(fw); |
547 | err: |
548 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
549 | return ret; |
550 | } |
551 | |
552 | static int mn88473_sleep(struct dvb_frontend *fe) |
553 | { |
554 | struct i2c_client *client = fe->demodulator_priv; |
555 | struct mn88473_dev *dev = i2c_get_clientdata(client); |
556 | int ret; |
557 | |
558 | dev_dbg(&client->dev, "\n" ); |
559 | |
560 | dev->active = false; |
561 | |
562 | ret = regmap_write(map: dev->regmap[2], reg: 0x05, val: 0x3e); |
563 | if (ret) |
564 | goto err; |
565 | |
566 | return 0; |
567 | err: |
568 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
569 | return ret; |
570 | } |
571 | |
572 | static const struct dvb_frontend_ops mn88473_ops = { |
573 | .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A}, |
574 | .info = { |
575 | .name = "Panasonic MN88473" , |
576 | .symbol_rate_min = 1000000, |
577 | .symbol_rate_max = 7200000, |
578 | .caps = FE_CAN_FEC_1_2 | |
579 | FE_CAN_FEC_2_3 | |
580 | FE_CAN_FEC_3_4 | |
581 | FE_CAN_FEC_5_6 | |
582 | FE_CAN_FEC_7_8 | |
583 | FE_CAN_FEC_AUTO | |
584 | FE_CAN_QPSK | |
585 | FE_CAN_QAM_16 | |
586 | FE_CAN_QAM_32 | |
587 | FE_CAN_QAM_64 | |
588 | FE_CAN_QAM_128 | |
589 | FE_CAN_QAM_256 | |
590 | FE_CAN_QAM_AUTO | |
591 | FE_CAN_TRANSMISSION_MODE_AUTO | |
592 | FE_CAN_GUARD_INTERVAL_AUTO | |
593 | FE_CAN_HIERARCHY_AUTO | |
594 | FE_CAN_MUTE_TS | |
595 | FE_CAN_2G_MODULATION | |
596 | FE_CAN_MULTISTREAM |
597 | }, |
598 | |
599 | .get_tune_settings = mn88473_get_tune_settings, |
600 | |
601 | .init = mn88473_init, |
602 | .sleep = mn88473_sleep, |
603 | |
604 | .set_frontend = mn88473_set_frontend, |
605 | |
606 | .read_status = mn88473_read_status, |
607 | }; |
608 | |
609 | static int mn88473_probe(struct i2c_client *client) |
610 | { |
611 | struct mn88473_config *config = client->dev.platform_data; |
612 | struct mn88473_dev *dev; |
613 | int ret; |
614 | unsigned int uitmp; |
615 | static const struct regmap_config regmap_config = { |
616 | .reg_bits = 8, |
617 | .val_bits = 8, |
618 | }; |
619 | |
620 | dev_dbg(&client->dev, "\n" ); |
621 | |
622 | /* Caller really need to provide pointer for frontend we create */ |
623 | if (config->fe == NULL) { |
624 | dev_err(&client->dev, "frontend pointer not defined\n" ); |
625 | ret = -EINVAL; |
626 | goto err; |
627 | } |
628 | |
629 | dev = kzalloc(size: sizeof(*dev), GFP_KERNEL); |
630 | if (dev == NULL) { |
631 | ret = -ENOMEM; |
632 | goto err; |
633 | } |
634 | |
635 | if (config->i2c_wr_max) |
636 | dev->i2c_wr_max = config->i2c_wr_max; |
637 | else |
638 | dev->i2c_wr_max = ~0; |
639 | |
640 | if (config->xtal) |
641 | dev->clk = config->xtal; |
642 | else |
643 | dev->clk = 25000000; |
644 | dev->client[0] = client; |
645 | dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); |
646 | if (IS_ERR(ptr: dev->regmap[0])) { |
647 | ret = PTR_ERR(ptr: dev->regmap[0]); |
648 | goto err_kfree; |
649 | } |
650 | |
651 | /* |
652 | * Chip has three I2C addresses for different register banks. Used |
653 | * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, |
654 | * 0x1a and 0x1c, in order to get own I2C client for each register bank. |
655 | * |
656 | * Also, register bank 2 do not support sequential I/O. Only single |
657 | * register write or read is allowed to that bank. |
658 | */ |
659 | dev->client[1] = i2c_new_dummy_device(adapter: client->adapter, address: 0x1a); |
660 | if (IS_ERR(ptr: dev->client[1])) { |
661 | ret = PTR_ERR(ptr: dev->client[1]); |
662 | dev_err(&client->dev, "I2C registration failed\n" ); |
663 | goto err_regmap_0_regmap_exit; |
664 | } |
665 | dev->regmap[1] = regmap_init_i2c(dev->client[1], ®map_config); |
666 | if (IS_ERR(ptr: dev->regmap[1])) { |
667 | ret = PTR_ERR(ptr: dev->regmap[1]); |
668 | goto err_client_1_i2c_unregister_device; |
669 | } |
670 | i2c_set_clientdata(client: dev->client[1], data: dev); |
671 | |
672 | dev->client[2] = i2c_new_dummy_device(adapter: client->adapter, address: 0x1c); |
673 | if (IS_ERR(ptr: dev->client[2])) { |
674 | ret = PTR_ERR(ptr: dev->client[2]); |
675 | dev_err(&client->dev, "2nd I2C registration failed\n" ); |
676 | goto err_regmap_1_regmap_exit; |
677 | } |
678 | dev->regmap[2] = regmap_init_i2c(dev->client[2], ®map_config); |
679 | if (IS_ERR(ptr: dev->regmap[2])) { |
680 | ret = PTR_ERR(ptr: dev->regmap[2]); |
681 | goto err_client_2_i2c_unregister_device; |
682 | } |
683 | i2c_set_clientdata(client: dev->client[2], data: dev); |
684 | |
685 | /* Check demod answers with correct chip id */ |
686 | ret = regmap_read(map: dev->regmap[2], reg: 0xff, val: &uitmp); |
687 | if (ret) |
688 | goto err_regmap_2_regmap_exit; |
689 | |
690 | dev_dbg(&client->dev, "chip id=%02x\n" , uitmp); |
691 | |
692 | if (uitmp != 0x03) { |
693 | ret = -ENODEV; |
694 | goto err_regmap_2_regmap_exit; |
695 | } |
696 | |
697 | /* Sleep because chip is active by default */ |
698 | ret = regmap_write(map: dev->regmap[2], reg: 0x05, val: 0x3e); |
699 | if (ret) |
700 | goto err_regmap_2_regmap_exit; |
701 | |
702 | /* Create dvb frontend */ |
703 | memcpy(&dev->frontend.ops, &mn88473_ops, sizeof(dev->frontend.ops)); |
704 | dev->frontend.demodulator_priv = client; |
705 | *config->fe = &dev->frontend; |
706 | i2c_set_clientdata(client, data: dev); |
707 | |
708 | dev_info(&client->dev, "Panasonic MN88473 successfully identified\n" ); |
709 | |
710 | return 0; |
711 | err_regmap_2_regmap_exit: |
712 | regmap_exit(map: dev->regmap[2]); |
713 | err_client_2_i2c_unregister_device: |
714 | i2c_unregister_device(client: dev->client[2]); |
715 | err_regmap_1_regmap_exit: |
716 | regmap_exit(map: dev->regmap[1]); |
717 | err_client_1_i2c_unregister_device: |
718 | i2c_unregister_device(client: dev->client[1]); |
719 | err_regmap_0_regmap_exit: |
720 | regmap_exit(map: dev->regmap[0]); |
721 | err_kfree: |
722 | kfree(objp: dev); |
723 | err: |
724 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
725 | return ret; |
726 | } |
727 | |
728 | static void mn88473_remove(struct i2c_client *client) |
729 | { |
730 | struct mn88473_dev *dev = i2c_get_clientdata(client); |
731 | |
732 | dev_dbg(&client->dev, "\n" ); |
733 | |
734 | regmap_exit(map: dev->regmap[2]); |
735 | i2c_unregister_device(client: dev->client[2]); |
736 | |
737 | regmap_exit(map: dev->regmap[1]); |
738 | i2c_unregister_device(client: dev->client[1]); |
739 | |
740 | regmap_exit(map: dev->regmap[0]); |
741 | |
742 | kfree(objp: dev); |
743 | } |
744 | |
745 | static const struct i2c_device_id mn88473_id_table[] = { |
746 | {"mn88473" , 0}, |
747 | {} |
748 | }; |
749 | MODULE_DEVICE_TABLE(i2c, mn88473_id_table); |
750 | |
751 | static struct i2c_driver mn88473_driver = { |
752 | .driver = { |
753 | .name = "mn88473" , |
754 | .suppress_bind_attrs = true, |
755 | }, |
756 | .probe = mn88473_probe, |
757 | .remove = mn88473_remove, |
758 | .id_table = mn88473_id_table, |
759 | }; |
760 | |
761 | module_i2c_driver(mn88473_driver); |
762 | |
763 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>" ); |
764 | MODULE_DESCRIPTION("Panasonic MN88473 DVB-T/T2/C demodulator driver" ); |
765 | MODULE_LICENSE("GPL" ); |
766 | MODULE_FIRMWARE(MN88473_FIRMWARE); |
767 | |