18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Panasonic MN88472 DVB-T/T2/C demodulator driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "mn88472_priv.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistatic int mn88472_get_tune_settings(struct dvb_frontend *fe, 118c2ecf20Sopenharmony_ci struct dvb_frontend_tune_settings *s) 128c2ecf20Sopenharmony_ci{ 138c2ecf20Sopenharmony_ci s->min_delay_ms = 1000; 148c2ecf20Sopenharmony_ci return 0; 158c2ecf20Sopenharmony_ci} 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct i2c_client *client = fe->demodulator_priv; 208c2ecf20Sopenharmony_ci struct mn88472_dev *dev = i2c_get_clientdata(client); 218c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 228c2ecf20Sopenharmony_ci int ret, i, stmp; 238c2ecf20Sopenharmony_ci unsigned int utmp, utmp1, utmp2; 248c2ecf20Sopenharmony_ci u8 buf[5]; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (!dev->active) { 278c2ecf20Sopenharmony_ci ret = -EAGAIN; 288c2ecf20Sopenharmony_ci goto err; 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci switch (c->delivery_system) { 328c2ecf20Sopenharmony_ci case SYS_DVBT: 338c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap[0], 0x7f, &utmp); 348c2ecf20Sopenharmony_ci if (ret) 358c2ecf20Sopenharmony_ci goto err; 368c2ecf20Sopenharmony_ci if ((utmp & 0x0f) >= 0x09) 378c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | 388c2ecf20Sopenharmony_ci FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; 398c2ecf20Sopenharmony_ci else 408c2ecf20Sopenharmony_ci *status = 0; 418c2ecf20Sopenharmony_ci break; 428c2ecf20Sopenharmony_ci case SYS_DVBT2: 438c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap[2], 0x92, &utmp); 448c2ecf20Sopenharmony_ci if (ret) 458c2ecf20Sopenharmony_ci goto err; 468c2ecf20Sopenharmony_ci if ((utmp & 0x0f) >= 0x0d) 478c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | 488c2ecf20Sopenharmony_ci FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; 498c2ecf20Sopenharmony_ci else if ((utmp & 0x0f) >= 0x0a) 508c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | 518c2ecf20Sopenharmony_ci FE_HAS_VITERBI; 528c2ecf20Sopenharmony_ci else if ((utmp & 0x0f) >= 0x07) 538c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; 548c2ecf20Sopenharmony_ci else 558c2ecf20Sopenharmony_ci *status = 0; 568c2ecf20Sopenharmony_ci break; 578c2ecf20Sopenharmony_ci case SYS_DVBC_ANNEX_A: 588c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap[1], 0x84, &utmp); 598c2ecf20Sopenharmony_ci if (ret) 608c2ecf20Sopenharmony_ci goto err; 618c2ecf20Sopenharmony_ci if ((utmp & 0x0f) >= 0x08) 628c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | 638c2ecf20Sopenharmony_ci FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; 648c2ecf20Sopenharmony_ci else 658c2ecf20Sopenharmony_ci *status = 0; 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci default: 688c2ecf20Sopenharmony_ci ret = -EINVAL; 698c2ecf20Sopenharmony_ci goto err; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Signal strength */ 738c2ecf20Sopenharmony_ci if (*status & FE_HAS_SIGNAL) { 748c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 758c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap[2], 0x8e + i, 768c2ecf20Sopenharmony_ci &buf[i], 1); 778c2ecf20Sopenharmony_ci if (ret) 788c2ecf20Sopenharmony_ci goto err; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci utmp1 = buf[0] << 8 | buf[1] << 0 | buf[0] >> 2; 828c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "strength=%u\n", utmp1); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci c->strength.stat[0].scale = FE_SCALE_RELATIVE; 858c2ecf20Sopenharmony_ci c->strength.stat[0].uvalue = utmp1; 868c2ecf20Sopenharmony_ci } else { 878c2ecf20Sopenharmony_ci c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* CNR */ 918c2ecf20Sopenharmony_ci if (*status & FE_HAS_VITERBI && c->delivery_system == SYS_DVBT) { 928c2ecf20Sopenharmony_ci /* DVB-T CNR */ 938c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap[0], 0x9c, buf, 2); 948c2ecf20Sopenharmony_ci if (ret) 958c2ecf20Sopenharmony_ci goto err; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci utmp = buf[0] << 8 | buf[1] << 0; 988c2ecf20Sopenharmony_ci if (utmp) { 998c2ecf20Sopenharmony_ci /* CNR[dB]: 10 * log10(65536 / value) + 2 */ 1008c2ecf20Sopenharmony_ci /* log10(65536) = 80807124, 0.2 = 3355443 */ 1018c2ecf20Sopenharmony_ci stmp = ((u64)80807124 - intlog10(utmp) + 3355443) 1028c2ecf20Sopenharmony_ci * 10000 >> 24; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "cnr=%d value=%u\n", stmp, utmp); 1058c2ecf20Sopenharmony_ci } else { 1068c2ecf20Sopenharmony_ci stmp = 0; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci c->cnr.stat[0].svalue = stmp; 1108c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 1118c2ecf20Sopenharmony_ci } else if (*status & FE_HAS_VITERBI && 1128c2ecf20Sopenharmony_ci c->delivery_system == SYS_DVBT2) { 1138c2ecf20Sopenharmony_ci /* DVB-T2 CNR */ 1148c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 1158c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap[2], 0xbc + i, 1168c2ecf20Sopenharmony_ci &buf[i], 1); 1178c2ecf20Sopenharmony_ci if (ret) 1188c2ecf20Sopenharmony_ci goto err; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci utmp = buf[1] << 8 | buf[2] << 0; 1228c2ecf20Sopenharmony_ci utmp1 = (buf[0] >> 2) & 0x01; /* 0=SISO, 1=MISO */ 1238c2ecf20Sopenharmony_ci if (utmp) { 1248c2ecf20Sopenharmony_ci if (utmp1) { 1258c2ecf20Sopenharmony_ci /* CNR[dB]: 10 * log10(16384 / value) - 6 */ 1268c2ecf20Sopenharmony_ci /* log10(16384) = 70706234, 0.6 = 10066330 */ 1278c2ecf20Sopenharmony_ci stmp = ((u64)70706234 - intlog10(utmp) 1288c2ecf20Sopenharmony_ci - 10066330) * 10000 >> 24; 1298c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "cnr=%d value=%u MISO\n", 1308c2ecf20Sopenharmony_ci stmp, utmp); 1318c2ecf20Sopenharmony_ci } else { 1328c2ecf20Sopenharmony_ci /* CNR[dB]: 10 * log10(65536 / value) + 2 */ 1338c2ecf20Sopenharmony_ci /* log10(65536) = 80807124, 0.2 = 3355443 */ 1348c2ecf20Sopenharmony_ci stmp = ((u64)80807124 - intlog10(utmp) 1358c2ecf20Sopenharmony_ci + 3355443) * 10000 >> 24; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "cnr=%d value=%u SISO\n", 1388c2ecf20Sopenharmony_ci stmp, utmp); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci } else { 1418c2ecf20Sopenharmony_ci stmp = 0; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci c->cnr.stat[0].svalue = stmp; 1458c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 1468c2ecf20Sopenharmony_ci } else if (*status & FE_HAS_VITERBI && 1478c2ecf20Sopenharmony_ci c->delivery_system == SYS_DVBC_ANNEX_A) { 1488c2ecf20Sopenharmony_ci /* DVB-C CNR */ 1498c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap[1], 0xa1, buf, 4); 1508c2ecf20Sopenharmony_ci if (ret) 1518c2ecf20Sopenharmony_ci goto err; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci utmp1 = buf[0] << 8 | buf[1] << 0; /* signal */ 1548c2ecf20Sopenharmony_ci utmp2 = buf[2] << 8 | buf[3] << 0; /* noise */ 1558c2ecf20Sopenharmony_ci if (utmp1 && utmp2) { 1568c2ecf20Sopenharmony_ci /* CNR[dB]: 10 * log10(8 * (signal / noise)) */ 1578c2ecf20Sopenharmony_ci /* log10(8) = 15151336 */ 1588c2ecf20Sopenharmony_ci stmp = ((u64)15151336 + intlog10(utmp1) 1598c2ecf20Sopenharmony_ci - intlog10(utmp2)) * 10000 >> 24; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "cnr=%d signal=%u noise=%u\n", 1628c2ecf20Sopenharmony_ci stmp, utmp1, utmp2); 1638c2ecf20Sopenharmony_ci } else { 1648c2ecf20Sopenharmony_ci stmp = 0; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci c->cnr.stat[0].svalue = stmp; 1688c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 1698c2ecf20Sopenharmony_ci } else { 1708c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* PER */ 1748c2ecf20Sopenharmony_ci if (*status & FE_HAS_SYNC) { 1758c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap[0], 0xe1, buf, 4); 1768c2ecf20Sopenharmony_ci if (ret) 1778c2ecf20Sopenharmony_ci goto err; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci utmp1 = buf[0] << 8 | buf[1] << 0; 1808c2ecf20Sopenharmony_ci utmp2 = buf[2] << 8 | buf[3] << 0; 1818c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "block_error=%u block_count=%u\n", 1828c2ecf20Sopenharmony_ci utmp1, utmp2); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci c->block_error.stat[0].scale = FE_SCALE_COUNTER; 1858c2ecf20Sopenharmony_ci c->block_error.stat[0].uvalue += utmp1; 1868c2ecf20Sopenharmony_ci c->block_count.stat[0].scale = FE_SCALE_COUNTER; 1878c2ecf20Sopenharmony_ci c->block_count.stat[0].uvalue += utmp2; 1888c2ecf20Sopenharmony_ci } else { 1898c2ecf20Sopenharmony_ci c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1908c2ecf20Sopenharmony_ci c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_cierr: 1958c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 1968c2ecf20Sopenharmony_ci return ret; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int mn88472_set_frontend(struct dvb_frontend *fe) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct i2c_client *client = fe->demodulator_priv; 2028c2ecf20Sopenharmony_ci struct mn88472_dev *dev = i2c_get_clientdata(client); 2038c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 2048c2ecf20Sopenharmony_ci int ret, i; 2058c2ecf20Sopenharmony_ci unsigned int utmp; 2068c2ecf20Sopenharmony_ci u32 if_frequency; 2078c2ecf20Sopenharmony_ci u8 buf[3], delivery_system_val, bandwidth_val, *bandwidth_vals_ptr; 2088c2ecf20Sopenharmony_ci u8 reg_bank0_b4_val, reg_bank0_cd_val, reg_bank0_d4_val; 2098c2ecf20Sopenharmony_ci u8 reg_bank0_d6_val; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 2128c2ecf20Sopenharmony_ci "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d\n", 2138c2ecf20Sopenharmony_ci c->delivery_system, c->modulation, c->frequency, 2148c2ecf20Sopenharmony_ci c->bandwidth_hz, c->symbol_rate, c->inversion, c->stream_id); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (!dev->active) { 2178c2ecf20Sopenharmony_ci ret = -EAGAIN; 2188c2ecf20Sopenharmony_ci goto err; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci switch (c->delivery_system) { 2228c2ecf20Sopenharmony_ci case SYS_DVBT: 2238c2ecf20Sopenharmony_ci delivery_system_val = 0x02; 2248c2ecf20Sopenharmony_ci reg_bank0_b4_val = 0x00; 2258c2ecf20Sopenharmony_ci reg_bank0_cd_val = 0x1f; 2268c2ecf20Sopenharmony_ci reg_bank0_d4_val = 0x0a; 2278c2ecf20Sopenharmony_ci reg_bank0_d6_val = 0x48; 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci case SYS_DVBT2: 2308c2ecf20Sopenharmony_ci delivery_system_val = 0x03; 2318c2ecf20Sopenharmony_ci reg_bank0_b4_val = 0xf6; 2328c2ecf20Sopenharmony_ci reg_bank0_cd_val = 0x01; 2338c2ecf20Sopenharmony_ci reg_bank0_d4_val = 0x09; 2348c2ecf20Sopenharmony_ci reg_bank0_d6_val = 0x46; 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci case SYS_DVBC_ANNEX_A: 2378c2ecf20Sopenharmony_ci delivery_system_val = 0x04; 2388c2ecf20Sopenharmony_ci reg_bank0_b4_val = 0x00; 2398c2ecf20Sopenharmony_ci reg_bank0_cd_val = 0x17; 2408c2ecf20Sopenharmony_ci reg_bank0_d4_val = 0x09; 2418c2ecf20Sopenharmony_ci reg_bank0_d6_val = 0x48; 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci default: 2448c2ecf20Sopenharmony_ci ret = -EINVAL; 2458c2ecf20Sopenharmony_ci goto err; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci switch (c->delivery_system) { 2498c2ecf20Sopenharmony_ci case SYS_DVBT: 2508c2ecf20Sopenharmony_ci case SYS_DVBT2: 2518c2ecf20Sopenharmony_ci switch (c->bandwidth_hz) { 2528c2ecf20Sopenharmony_ci case 5000000: 2538c2ecf20Sopenharmony_ci bandwidth_vals_ptr = "\xe5\x99\x9a\x1b\xa9\x1b\xa9"; 2548c2ecf20Sopenharmony_ci bandwidth_val = 0x03; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case 6000000: 2578c2ecf20Sopenharmony_ci bandwidth_vals_ptr = "\xbf\x55\x55\x15\x6b\x15\x6b"; 2588c2ecf20Sopenharmony_ci bandwidth_val = 0x02; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci case 7000000: 2618c2ecf20Sopenharmony_ci bandwidth_vals_ptr = "\xa4\x00\x00\x0f\x2c\x0f\x2c"; 2628c2ecf20Sopenharmony_ci bandwidth_val = 0x01; 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci case 8000000: 2658c2ecf20Sopenharmony_ci bandwidth_vals_ptr = "\x8f\x80\x00\x08\xee\x08\xee"; 2668c2ecf20Sopenharmony_ci bandwidth_val = 0x00; 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci default: 2698c2ecf20Sopenharmony_ci ret = -EINVAL; 2708c2ecf20Sopenharmony_ci goto err; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci case SYS_DVBC_ANNEX_A: 2748c2ecf20Sopenharmony_ci bandwidth_vals_ptr = NULL; 2758c2ecf20Sopenharmony_ci bandwidth_val = 0x00; 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci default: 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Program tuner */ 2828c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) { 2838c2ecf20Sopenharmony_ci ret = fe->ops.tuner_ops.set_params(fe); 2848c2ecf20Sopenharmony_ci if (ret) 2858c2ecf20Sopenharmony_ci goto err; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_if_frequency) { 2898c2ecf20Sopenharmony_ci ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); 2908c2ecf20Sopenharmony_ci if (ret) 2918c2ecf20Sopenharmony_ci goto err; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); 2948c2ecf20Sopenharmony_ci } else { 2958c2ecf20Sopenharmony_ci ret = -EINVAL; 2968c2ecf20Sopenharmony_ci goto err; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x00, 0x66); 3008c2ecf20Sopenharmony_ci if (ret) 3018c2ecf20Sopenharmony_ci goto err; 3028c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x01, 0x00); 3038c2ecf20Sopenharmony_ci if (ret) 3048c2ecf20Sopenharmony_ci goto err; 3058c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x02, 0x01); 3068c2ecf20Sopenharmony_ci if (ret) 3078c2ecf20Sopenharmony_ci goto err; 3088c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val); 3098c2ecf20Sopenharmony_ci if (ret) 3108c2ecf20Sopenharmony_ci goto err; 3118c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x04, bandwidth_val); 3128c2ecf20Sopenharmony_ci if (ret) 3138c2ecf20Sopenharmony_ci goto err; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* IF */ 3168c2ecf20Sopenharmony_ci utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x1000000, dev->clk); 3178c2ecf20Sopenharmony_ci buf[0] = (utmp >> 16) & 0xff; 3188c2ecf20Sopenharmony_ci buf[1] = (utmp >> 8) & 0xff; 3198c2ecf20Sopenharmony_ci buf[2] = (utmp >> 0) & 0xff; 3208c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 3218c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x10 + i, buf[i]); 3228c2ecf20Sopenharmony_ci if (ret) 3238c2ecf20Sopenharmony_ci goto err; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Bandwidth */ 3278c2ecf20Sopenharmony_ci if (bandwidth_vals_ptr) { 3288c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++) { 3298c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x13 + i, 3308c2ecf20Sopenharmony_ci bandwidth_vals_ptr[i]); 3318c2ecf20Sopenharmony_ci if (ret) 3328c2ecf20Sopenharmony_ci goto err; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[0], 0xb4, reg_bank0_b4_val); 3378c2ecf20Sopenharmony_ci if (ret) 3388c2ecf20Sopenharmony_ci goto err; 3398c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[0], 0xcd, reg_bank0_cd_val); 3408c2ecf20Sopenharmony_ci if (ret) 3418c2ecf20Sopenharmony_ci goto err; 3428c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[0], 0xd4, reg_bank0_d4_val); 3438c2ecf20Sopenharmony_ci if (ret) 3448c2ecf20Sopenharmony_ci goto err; 3458c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[0], 0xd6, reg_bank0_d6_val); 3468c2ecf20Sopenharmony_ci if (ret) 3478c2ecf20Sopenharmony_ci goto err; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci switch (c->delivery_system) { 3508c2ecf20Sopenharmony_ci case SYS_DVBT: 3518c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[0], 0x07, 0x26); 3528c2ecf20Sopenharmony_ci if (ret) 3538c2ecf20Sopenharmony_ci goto err; 3548c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[0], 0x00, 0xba); 3558c2ecf20Sopenharmony_ci if (ret) 3568c2ecf20Sopenharmony_ci goto err; 3578c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[0], 0x01, 0x13); 3588c2ecf20Sopenharmony_ci if (ret) 3598c2ecf20Sopenharmony_ci goto err; 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci case SYS_DVBT2: 3628c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x2b, 0x13); 3638c2ecf20Sopenharmony_ci if (ret) 3648c2ecf20Sopenharmony_ci goto err; 3658c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x4f, 0x05); 3668c2ecf20Sopenharmony_ci if (ret) 3678c2ecf20Sopenharmony_ci goto err; 3688c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[1], 0xf6, 0x05); 3698c2ecf20Sopenharmony_ci if (ret) 3708c2ecf20Sopenharmony_ci goto err; 3718c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x32, 3728c2ecf20Sopenharmony_ci (c->stream_id == NO_STREAM_ID_FILTER) ? 0 : 3738c2ecf20Sopenharmony_ci c->stream_id ); 3748c2ecf20Sopenharmony_ci if (ret) 3758c2ecf20Sopenharmony_ci goto err; 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci case SYS_DVBC_ANNEX_A: 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci default: 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Reset FSM */ 3848c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); 3858c2ecf20Sopenharmony_ci if (ret) 3868c2ecf20Sopenharmony_ci goto err; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_cierr: 3908c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 3918c2ecf20Sopenharmony_ci return ret; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic int mn88472_init(struct dvb_frontend *fe) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct i2c_client *client = fe->demodulator_priv; 3978c2ecf20Sopenharmony_ci struct mn88472_dev *dev = i2c_get_clientdata(client); 3988c2ecf20Sopenharmony_ci int ret, len, rem; 3998c2ecf20Sopenharmony_ci unsigned int utmp; 4008c2ecf20Sopenharmony_ci const struct firmware *firmware; 4018c2ecf20Sopenharmony_ci const char *name = MN88472_FIRMWARE; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* Power up */ 4068c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x05, 0x00); 4078c2ecf20Sopenharmony_ci if (ret) 4088c2ecf20Sopenharmony_ci goto err; 4098c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x0b, 0x00); 4108c2ecf20Sopenharmony_ci if (ret) 4118c2ecf20Sopenharmony_ci goto err; 4128c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x0c, 0x00); 4138c2ecf20Sopenharmony_ci if (ret) 4148c2ecf20Sopenharmony_ci goto err; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Check if firmware is already running */ 4178c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap[0], 0xf5, &utmp); 4188c2ecf20Sopenharmony_ci if (ret) 4198c2ecf20Sopenharmony_ci goto err; 4208c2ecf20Sopenharmony_ci if (!(utmp & 0x01)) 4218c2ecf20Sopenharmony_ci goto warm; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci ret = request_firmware(&firmware, name, &client->dev); 4248c2ecf20Sopenharmony_ci if (ret) { 4258c2ecf20Sopenharmony_ci dev_err(&client->dev, "firmware file '%s' not found\n", name); 4268c2ecf20Sopenharmony_ci goto err; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci dev_info(&client->dev, "downloading firmware from file '%s'\n", name); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[0], 0xf5, 0x03); 4328c2ecf20Sopenharmony_ci if (ret) 4338c2ecf20Sopenharmony_ci goto err_release_firmware; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci for (rem = firmware->size; rem > 0; rem -= (dev->i2c_write_max - 1)) { 4368c2ecf20Sopenharmony_ci len = min(dev->i2c_write_max - 1, rem); 4378c2ecf20Sopenharmony_ci ret = regmap_bulk_write(dev->regmap[0], 0xf6, 4388c2ecf20Sopenharmony_ci &firmware->data[firmware->size - rem], 4398c2ecf20Sopenharmony_ci len); 4408c2ecf20Sopenharmony_ci if (ret) { 4418c2ecf20Sopenharmony_ci dev_err(&client->dev, "firmware download failed %d\n", 4428c2ecf20Sopenharmony_ci ret); 4438c2ecf20Sopenharmony_ci goto err_release_firmware; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Parity check of firmware */ 4488c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap[0], 0xf8, &utmp); 4498c2ecf20Sopenharmony_ci if (ret) 4508c2ecf20Sopenharmony_ci goto err_release_firmware; 4518c2ecf20Sopenharmony_ci if (utmp & 0x10) { 4528c2ecf20Sopenharmony_ci ret = -EINVAL; 4538c2ecf20Sopenharmony_ci dev_err(&client->dev, "firmware did not run\n"); 4548c2ecf20Sopenharmony_ci goto err_release_firmware; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[0], 0xf5, 0x00); 4588c2ecf20Sopenharmony_ci if (ret) 4598c2ecf20Sopenharmony_ci goto err_release_firmware; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci release_firmware(firmware); 4628c2ecf20Sopenharmony_ciwarm: 4638c2ecf20Sopenharmony_ci /* TS config */ 4648c2ecf20Sopenharmony_ci switch (dev->ts_mode) { 4658c2ecf20Sopenharmony_ci case SERIAL_TS_MODE: 4668c2ecf20Sopenharmony_ci utmp = 0x1d; 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci case PARALLEL_TS_MODE: 4698c2ecf20Sopenharmony_ci utmp = 0x00; 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci default: 4728c2ecf20Sopenharmony_ci ret = -EINVAL; 4738c2ecf20Sopenharmony_ci goto err; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x08, utmp); 4768c2ecf20Sopenharmony_ci if (ret) 4778c2ecf20Sopenharmony_ci goto err; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci switch (dev->ts_clk) { 4808c2ecf20Sopenharmony_ci case VARIABLE_TS_CLOCK: 4818c2ecf20Sopenharmony_ci utmp = 0xe3; 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci case FIXED_TS_CLOCK: 4848c2ecf20Sopenharmony_ci utmp = 0xe1; 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci default: 4878c2ecf20Sopenharmony_ci ret = -EINVAL; 4888c2ecf20Sopenharmony_ci goto err; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[0], 0xd9, utmp); 4918c2ecf20Sopenharmony_ci if (ret) 4928c2ecf20Sopenharmony_ci goto err; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci dev->active = true; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci return 0; 4978c2ecf20Sopenharmony_cierr_release_firmware: 4988c2ecf20Sopenharmony_ci release_firmware(firmware); 4998c2ecf20Sopenharmony_cierr: 5008c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 5018c2ecf20Sopenharmony_ci return ret; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int mn88472_sleep(struct dvb_frontend *fe) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct i2c_client *client = fe->demodulator_priv; 5078c2ecf20Sopenharmony_ci struct mn88472_dev *dev = i2c_get_clientdata(client); 5088c2ecf20Sopenharmony_ci int ret; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* Power down */ 5138c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x0c, 0x30); 5148c2ecf20Sopenharmony_ci if (ret) 5158c2ecf20Sopenharmony_ci goto err; 5168c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x0b, 0x30); 5178c2ecf20Sopenharmony_ci if (ret) 5188c2ecf20Sopenharmony_ci goto err; 5198c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x05, 0x3e); 5208c2ecf20Sopenharmony_ci if (ret) 5218c2ecf20Sopenharmony_ci goto err; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return 0; 5248c2ecf20Sopenharmony_cierr: 5258c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 5268c2ecf20Sopenharmony_ci return ret; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops mn88472_ops = { 5308c2ecf20Sopenharmony_ci .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A}, 5318c2ecf20Sopenharmony_ci .info = { 5328c2ecf20Sopenharmony_ci .name = "Panasonic MN88472", 5338c2ecf20Sopenharmony_ci .symbol_rate_min = 1000000, 5348c2ecf20Sopenharmony_ci .symbol_rate_max = 7200000, 5358c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_1_2 | 5368c2ecf20Sopenharmony_ci FE_CAN_FEC_2_3 | 5378c2ecf20Sopenharmony_ci FE_CAN_FEC_3_4 | 5388c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | 5398c2ecf20Sopenharmony_ci FE_CAN_FEC_7_8 | 5408c2ecf20Sopenharmony_ci FE_CAN_FEC_AUTO | 5418c2ecf20Sopenharmony_ci FE_CAN_QPSK | 5428c2ecf20Sopenharmony_ci FE_CAN_QAM_16 | 5438c2ecf20Sopenharmony_ci FE_CAN_QAM_32 | 5448c2ecf20Sopenharmony_ci FE_CAN_QAM_64 | 5458c2ecf20Sopenharmony_ci FE_CAN_QAM_128 | 5468c2ecf20Sopenharmony_ci FE_CAN_QAM_256 | 5478c2ecf20Sopenharmony_ci FE_CAN_QAM_AUTO | 5488c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | 5498c2ecf20Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | 5508c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO | 5518c2ecf20Sopenharmony_ci FE_CAN_MUTE_TS | 5528c2ecf20Sopenharmony_ci FE_CAN_2G_MODULATION | 5538c2ecf20Sopenharmony_ci FE_CAN_MULTISTREAM 5548c2ecf20Sopenharmony_ci }, 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci .get_tune_settings = mn88472_get_tune_settings, 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci .init = mn88472_init, 5598c2ecf20Sopenharmony_ci .sleep = mn88472_sleep, 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci .set_frontend = mn88472_set_frontend, 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci .read_status = mn88472_read_status, 5648c2ecf20Sopenharmony_ci}; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic struct dvb_frontend *mn88472_get_dvb_frontend(struct i2c_client *client) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct mn88472_dev *dev = i2c_get_clientdata(client); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return &dev->fe; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int mn88472_probe(struct i2c_client *client, 5768c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct mn88472_config *pdata = client->dev.platform_data; 5798c2ecf20Sopenharmony_ci struct mn88472_dev *dev; 5808c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c; 5818c2ecf20Sopenharmony_ci int ret; 5828c2ecf20Sopenharmony_ci unsigned int utmp; 5838c2ecf20Sopenharmony_ci static const struct regmap_config regmap_config = { 5848c2ecf20Sopenharmony_ci .reg_bits = 8, 5858c2ecf20Sopenharmony_ci .val_bits = 8, 5868c2ecf20Sopenharmony_ci }; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 5918c2ecf20Sopenharmony_ci if (!dev) { 5928c2ecf20Sopenharmony_ci ret = -ENOMEM; 5938c2ecf20Sopenharmony_ci goto err; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci dev->i2c_write_max = pdata->i2c_wr_max ? pdata->i2c_wr_max : ~0; 5978c2ecf20Sopenharmony_ci dev->clk = pdata->xtal; 5988c2ecf20Sopenharmony_ci dev->ts_mode = pdata->ts_mode; 5998c2ecf20Sopenharmony_ci dev->ts_clk = pdata->ts_clock; 6008c2ecf20Sopenharmony_ci dev->client[0] = client; 6018c2ecf20Sopenharmony_ci dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); 6028c2ecf20Sopenharmony_ci if (IS_ERR(dev->regmap[0])) { 6038c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->regmap[0]); 6048c2ecf20Sopenharmony_ci goto err_kfree; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* 6088c2ecf20Sopenharmony_ci * Chip has three I2C addresses for different register banks. Used 6098c2ecf20Sopenharmony_ci * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, 6108c2ecf20Sopenharmony_ci * 0x1a and 0x1c, in order to get own I2C client for each register bank. 6118c2ecf20Sopenharmony_ci * 6128c2ecf20Sopenharmony_ci * Also, register bank 2 do not support sequential I/O. Only single 6138c2ecf20Sopenharmony_ci * register write or read is allowed to that bank. 6148c2ecf20Sopenharmony_ci */ 6158c2ecf20Sopenharmony_ci dev->client[1] = i2c_new_dummy_device(client->adapter, 0x1a); 6168c2ecf20Sopenharmony_ci if (IS_ERR(dev->client[1])) { 6178c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->client[1]); 6188c2ecf20Sopenharmony_ci dev_err(&client->dev, "I2C registration failed\n"); 6198c2ecf20Sopenharmony_ci goto err_regmap_0_regmap_exit; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci dev->regmap[1] = regmap_init_i2c(dev->client[1], ®map_config); 6228c2ecf20Sopenharmony_ci if (IS_ERR(dev->regmap[1])) { 6238c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->regmap[1]); 6248c2ecf20Sopenharmony_ci goto err_client_1_i2c_unregister_device; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci i2c_set_clientdata(dev->client[1], dev); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci dev->client[2] = i2c_new_dummy_device(client->adapter, 0x1c); 6298c2ecf20Sopenharmony_ci if (IS_ERR(dev->client[2])) { 6308c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->client[2]); 6318c2ecf20Sopenharmony_ci dev_err(&client->dev, "2nd I2C registration failed\n"); 6328c2ecf20Sopenharmony_ci goto err_regmap_1_regmap_exit; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci dev->regmap[2] = regmap_init_i2c(dev->client[2], ®map_config); 6358c2ecf20Sopenharmony_ci if (IS_ERR(dev->regmap[2])) { 6368c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->regmap[2]); 6378c2ecf20Sopenharmony_ci goto err_client_2_i2c_unregister_device; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci i2c_set_clientdata(dev->client[2], dev); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* Check demod answers with correct chip id */ 6428c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap[2], 0xff, &utmp); 6438c2ecf20Sopenharmony_ci if (ret) 6448c2ecf20Sopenharmony_ci goto err_regmap_2_regmap_exit; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "chip id=%02x\n", utmp); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (utmp != 0x02) { 6498c2ecf20Sopenharmony_ci ret = -ENODEV; 6508c2ecf20Sopenharmony_ci goto err_regmap_2_regmap_exit; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* Sleep because chip is active by default */ 6548c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap[2], 0x05, 0x3e); 6558c2ecf20Sopenharmony_ci if (ret) 6568c2ecf20Sopenharmony_ci goto err_regmap_2_regmap_exit; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci /* Create dvb frontend */ 6598c2ecf20Sopenharmony_ci memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops)); 6608c2ecf20Sopenharmony_ci dev->fe.demodulator_priv = client; 6618c2ecf20Sopenharmony_ci *pdata->fe = &dev->fe; 6628c2ecf20Sopenharmony_ci i2c_set_clientdata(client, dev); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* Init stats to indicate which stats are supported */ 6658c2ecf20Sopenharmony_ci c = &dev->fe.dtv_property_cache; 6668c2ecf20Sopenharmony_ci c->strength.len = 1; 6678c2ecf20Sopenharmony_ci c->cnr.len = 1; 6688c2ecf20Sopenharmony_ci c->block_error.len = 1; 6698c2ecf20Sopenharmony_ci c->block_count.len = 1; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* Setup callbacks */ 6728c2ecf20Sopenharmony_ci pdata->get_dvb_frontend = mn88472_get_dvb_frontend; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci dev_info(&client->dev, "Panasonic MN88472 successfully identified\n"); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci return 0; 6778c2ecf20Sopenharmony_cierr_regmap_2_regmap_exit: 6788c2ecf20Sopenharmony_ci regmap_exit(dev->regmap[2]); 6798c2ecf20Sopenharmony_cierr_client_2_i2c_unregister_device: 6808c2ecf20Sopenharmony_ci i2c_unregister_device(dev->client[2]); 6818c2ecf20Sopenharmony_cierr_regmap_1_regmap_exit: 6828c2ecf20Sopenharmony_ci regmap_exit(dev->regmap[1]); 6838c2ecf20Sopenharmony_cierr_client_1_i2c_unregister_device: 6848c2ecf20Sopenharmony_ci i2c_unregister_device(dev->client[1]); 6858c2ecf20Sopenharmony_cierr_regmap_0_regmap_exit: 6868c2ecf20Sopenharmony_ci regmap_exit(dev->regmap[0]); 6878c2ecf20Sopenharmony_cierr_kfree: 6888c2ecf20Sopenharmony_ci kfree(dev); 6898c2ecf20Sopenharmony_cierr: 6908c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 6918c2ecf20Sopenharmony_ci return ret; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic int mn88472_remove(struct i2c_client *client) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct mn88472_dev *dev = i2c_get_clientdata(client); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci regmap_exit(dev->regmap[2]); 7018c2ecf20Sopenharmony_ci i2c_unregister_device(dev->client[2]); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci regmap_exit(dev->regmap[1]); 7048c2ecf20Sopenharmony_ci i2c_unregister_device(dev->client[1]); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci regmap_exit(dev->regmap[0]); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci kfree(dev); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic const struct i2c_device_id mn88472_id_table[] = { 7148c2ecf20Sopenharmony_ci {"mn88472", 0}, 7158c2ecf20Sopenharmony_ci {} 7168c2ecf20Sopenharmony_ci}; 7178c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, mn88472_id_table); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic struct i2c_driver mn88472_driver = { 7208c2ecf20Sopenharmony_ci .driver = { 7218c2ecf20Sopenharmony_ci .name = "mn88472", 7228c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 7238c2ecf20Sopenharmony_ci }, 7248c2ecf20Sopenharmony_ci .probe = mn88472_probe, 7258c2ecf20Sopenharmony_ci .remove = mn88472_remove, 7268c2ecf20Sopenharmony_ci .id_table = mn88472_id_table, 7278c2ecf20Sopenharmony_ci}; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cimodule_i2c_driver(mn88472_driver); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 7328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Panasonic MN88472 DVB-T/T2/C demodulator driver"); 7338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 7348c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MN88472_FIRMWARE); 735