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