18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Afatech AF9013 demodulator driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> 68c2ecf20Sopenharmony_ci * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Thanks to Afatech who kindly provided information. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "af9013_priv.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistruct af9013_state { 148c2ecf20Sopenharmony_ci struct i2c_client *client; 158c2ecf20Sopenharmony_ci struct regmap *regmap; 168c2ecf20Sopenharmony_ci struct i2c_mux_core *muxc; 178c2ecf20Sopenharmony_ci struct dvb_frontend fe; 188c2ecf20Sopenharmony_ci u32 clk; 198c2ecf20Sopenharmony_ci u8 tuner; 208c2ecf20Sopenharmony_ci u32 if_frequency; 218c2ecf20Sopenharmony_ci u8 ts_mode; 228c2ecf20Sopenharmony_ci u8 ts_output_pin; 238c2ecf20Sopenharmony_ci bool spec_inv; 248c2ecf20Sopenharmony_ci u8 api_version[4]; 258c2ecf20Sopenharmony_ci u8 gpio[4]; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci u32 bandwidth_hz; 288c2ecf20Sopenharmony_ci enum fe_status fe_status; 298c2ecf20Sopenharmony_ci /* RF and IF AGC limits used for signal strength calc */ 308c2ecf20Sopenharmony_ci u8 strength_en, rf_agc_50, rf_agc_80, if_agc_50, if_agc_80; 318c2ecf20Sopenharmony_ci unsigned long set_frontend_jiffies; 328c2ecf20Sopenharmony_ci unsigned long read_status_jiffies; 338c2ecf20Sopenharmony_ci unsigned long strength_jiffies; 348c2ecf20Sopenharmony_ci unsigned long cnr_jiffies; 358c2ecf20Sopenharmony_ci unsigned long ber_ucb_jiffies; 368c2ecf20Sopenharmony_ci u16 dvbv3_snr; 378c2ecf20Sopenharmony_ci u16 dvbv3_strength; 388c2ecf20Sopenharmony_ci u32 dvbv3_ber; 398c2ecf20Sopenharmony_ci u32 dvbv3_ucblocks; 408c2ecf20Sopenharmony_ci bool first_tune; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 468c2ecf20Sopenharmony_ci int ret; 478c2ecf20Sopenharmony_ci u8 pos; 488c2ecf20Sopenharmony_ci u16 addr; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "gpio %u, gpioval %02x\n", gpio, gpioval); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* 538c2ecf20Sopenharmony_ci * GPIO0 & GPIO1 0xd735 548c2ecf20Sopenharmony_ci * GPIO2 & GPIO3 0xd736 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci switch (gpio) { 588c2ecf20Sopenharmony_ci case 0: 598c2ecf20Sopenharmony_ci case 1: 608c2ecf20Sopenharmony_ci addr = 0xd735; 618c2ecf20Sopenharmony_ci break; 628c2ecf20Sopenharmony_ci case 2: 638c2ecf20Sopenharmony_ci case 3: 648c2ecf20Sopenharmony_ci addr = 0xd736; 658c2ecf20Sopenharmony_ci break; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci default: 688c2ecf20Sopenharmony_ci ret = -EINVAL; 698c2ecf20Sopenharmony_ci goto err; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci switch (gpio) { 738c2ecf20Sopenharmony_ci case 0: 748c2ecf20Sopenharmony_ci case 2: 758c2ecf20Sopenharmony_ci pos = 0; 768c2ecf20Sopenharmony_ci break; 778c2ecf20Sopenharmony_ci case 1: 788c2ecf20Sopenharmony_ci case 3: 798c2ecf20Sopenharmony_ci default: 808c2ecf20Sopenharmony_ci pos = 4; 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, addr, 0x0f << pos, 858c2ecf20Sopenharmony_ci gpioval << pos); 868c2ecf20Sopenharmony_ci if (ret) 878c2ecf20Sopenharmony_ci goto err; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return 0; 908c2ecf20Sopenharmony_cierr: 918c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 928c2ecf20Sopenharmony_ci return ret; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int af9013_get_tune_settings(struct dvb_frontend *fe, 968c2ecf20Sopenharmony_ci struct dvb_frontend_tune_settings *fesettings) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci fesettings->min_delay_ms = 800; 998c2ecf20Sopenharmony_ci fesettings->step_size = 0; 1008c2ecf20Sopenharmony_ci fesettings->max_drift = 0; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int af9013_set_frontend(struct dvb_frontend *fe) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 1088c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 1098c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 1108c2ecf20Sopenharmony_ci int ret, i, sampling_freq; 1118c2ecf20Sopenharmony_ci bool auto_mode, spec_inv; 1128c2ecf20Sopenharmony_ci u8 buf[6]; 1138c2ecf20Sopenharmony_ci u32 if_frequency, freq_cw; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "frequency %u, bandwidth_hz %u\n", 1168c2ecf20Sopenharmony_ci c->frequency, c->bandwidth_hz); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* program tuner */ 1198c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) { 1208c2ecf20Sopenharmony_ci ret = fe->ops.tuner_ops.set_params(fe); 1218c2ecf20Sopenharmony_ci if (ret) 1228c2ecf20Sopenharmony_ci goto err; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* program CFOE coefficients */ 1268c2ecf20Sopenharmony_ci if (c->bandwidth_hz != state->bandwidth_hz) { 1278c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { 1288c2ecf20Sopenharmony_ci if (coeff_lut[i].clock == state->clk && 1298c2ecf20Sopenharmony_ci coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Return an error if can't find bandwidth or the right clock */ 1358c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(coeff_lut)) { 1368c2ecf20Sopenharmony_ci ret = -EINVAL; 1378c2ecf20Sopenharmony_ci goto err; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, 0xae00, coeff_lut[i].val, 1418c2ecf20Sopenharmony_ci sizeof(coeff_lut[i].val)); 1428c2ecf20Sopenharmony_ci if (ret) 1438c2ecf20Sopenharmony_ci goto err; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* program frequency control */ 1478c2ecf20Sopenharmony_ci if (c->bandwidth_hz != state->bandwidth_hz || state->first_tune) { 1488c2ecf20Sopenharmony_ci /* get used IF frequency */ 1498c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_if_frequency) { 1508c2ecf20Sopenharmony_ci ret = fe->ops.tuner_ops.get_if_frequency(fe, 1518c2ecf20Sopenharmony_ci &if_frequency); 1528c2ecf20Sopenharmony_ci if (ret) 1538c2ecf20Sopenharmony_ci goto err; 1548c2ecf20Sopenharmony_ci } else { 1558c2ecf20Sopenharmony_ci if_frequency = state->if_frequency; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "if_frequency %u\n", if_frequency); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci sampling_freq = if_frequency; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci while (sampling_freq > (state->clk / 2)) 1638c2ecf20Sopenharmony_ci sampling_freq -= state->clk; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (sampling_freq < 0) { 1668c2ecf20Sopenharmony_ci sampling_freq *= -1; 1678c2ecf20Sopenharmony_ci spec_inv = state->spec_inv; 1688c2ecf20Sopenharmony_ci } else { 1698c2ecf20Sopenharmony_ci spec_inv = !state->spec_inv; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci freq_cw = DIV_ROUND_CLOSEST_ULL((u64)sampling_freq * 0x800000, 1738c2ecf20Sopenharmony_ci state->clk); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (spec_inv) 1768c2ecf20Sopenharmony_ci freq_cw = 0x800000 - freq_cw; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci buf[0] = (freq_cw >> 0) & 0xff; 1798c2ecf20Sopenharmony_ci buf[1] = (freq_cw >> 8) & 0xff; 1808c2ecf20Sopenharmony_ci buf[2] = (freq_cw >> 16) & 0x7f; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci freq_cw = 0x800000 - freq_cw; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci buf[3] = (freq_cw >> 0) & 0xff; 1858c2ecf20Sopenharmony_ci buf[4] = (freq_cw >> 8) & 0xff; 1868c2ecf20Sopenharmony_ci buf[5] = (freq_cw >> 16) & 0x7f; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, 0xd140, buf, 3); 1898c2ecf20Sopenharmony_ci if (ret) 1908c2ecf20Sopenharmony_ci goto err; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, 0x9be7, buf, 6); 1938c2ecf20Sopenharmony_ci if (ret) 1948c2ecf20Sopenharmony_ci goto err; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* clear TPS lock flag */ 1988c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd330, 0x08, 0x08); 1998c2ecf20Sopenharmony_ci if (ret) 2008c2ecf20Sopenharmony_ci goto err; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* clear MPEG2 lock flag */ 2038c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd507, 0x40, 0x00); 2048c2ecf20Sopenharmony_ci if (ret) 2058c2ecf20Sopenharmony_ci goto err; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* empty channel function */ 2088c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0x9bfe, 0x01, 0x00); 2098c2ecf20Sopenharmony_ci if (ret) 2108c2ecf20Sopenharmony_ci goto err; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* empty DVB-T channel function */ 2138c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0x9bc2, 0x01, 0x00); 2148c2ecf20Sopenharmony_ci if (ret) 2158c2ecf20Sopenharmony_ci goto err; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* transmission parameters */ 2188c2ecf20Sopenharmony_ci auto_mode = false; 2198c2ecf20Sopenharmony_ci memset(buf, 0, 3); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci switch (c->transmission_mode) { 2228c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_AUTO: 2238c2ecf20Sopenharmony_ci auto_mode = true; 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_2K: 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_8K: 2288c2ecf20Sopenharmony_ci buf[0] |= (1 << 0); 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci default: 2318c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid transmission_mode\n"); 2328c2ecf20Sopenharmony_ci auto_mode = true; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci switch (c->guard_interval) { 2368c2ecf20Sopenharmony_ci case GUARD_INTERVAL_AUTO: 2378c2ecf20Sopenharmony_ci auto_mode = true; 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_32: 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_16: 2428c2ecf20Sopenharmony_ci buf[0] |= (1 << 2); 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_8: 2458c2ecf20Sopenharmony_ci buf[0] |= (2 << 2); 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_4: 2488c2ecf20Sopenharmony_ci buf[0] |= (3 << 2); 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci default: 2518c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid guard_interval\n"); 2528c2ecf20Sopenharmony_ci auto_mode = true; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci switch (c->hierarchy) { 2568c2ecf20Sopenharmony_ci case HIERARCHY_AUTO: 2578c2ecf20Sopenharmony_ci auto_mode = true; 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci case HIERARCHY_NONE: 2608c2ecf20Sopenharmony_ci break; 2618c2ecf20Sopenharmony_ci case HIERARCHY_1: 2628c2ecf20Sopenharmony_ci buf[0] |= (1 << 4); 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci case HIERARCHY_2: 2658c2ecf20Sopenharmony_ci buf[0] |= (2 << 4); 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci case HIERARCHY_4: 2688c2ecf20Sopenharmony_ci buf[0] |= (3 << 4); 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci default: 2718c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid hierarchy\n"); 2728c2ecf20Sopenharmony_ci auto_mode = true; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci switch (c->modulation) { 2768c2ecf20Sopenharmony_ci case QAM_AUTO: 2778c2ecf20Sopenharmony_ci auto_mode = true; 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci case QPSK: 2808c2ecf20Sopenharmony_ci break; 2818c2ecf20Sopenharmony_ci case QAM_16: 2828c2ecf20Sopenharmony_ci buf[1] |= (1 << 6); 2838c2ecf20Sopenharmony_ci break; 2848c2ecf20Sopenharmony_ci case QAM_64: 2858c2ecf20Sopenharmony_ci buf[1] |= (2 << 6); 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci default: 2888c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid modulation\n"); 2898c2ecf20Sopenharmony_ci auto_mode = true; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Use HP. How and which case we can switch to LP? */ 2938c2ecf20Sopenharmony_ci buf[1] |= (1 << 4); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci switch (c->code_rate_HP) { 2968c2ecf20Sopenharmony_ci case FEC_AUTO: 2978c2ecf20Sopenharmony_ci auto_mode = true; 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci case FEC_1_2: 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci case FEC_2_3: 3028c2ecf20Sopenharmony_ci buf[2] |= (1 << 0); 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci case FEC_3_4: 3058c2ecf20Sopenharmony_ci buf[2] |= (2 << 0); 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci case FEC_5_6: 3088c2ecf20Sopenharmony_ci buf[2] |= (3 << 0); 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case FEC_7_8: 3118c2ecf20Sopenharmony_ci buf[2] |= (4 << 0); 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci default: 3148c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid code_rate_HP\n"); 3158c2ecf20Sopenharmony_ci auto_mode = true; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci switch (c->code_rate_LP) { 3198c2ecf20Sopenharmony_ci case FEC_AUTO: 3208c2ecf20Sopenharmony_ci auto_mode = true; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci case FEC_1_2: 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci case FEC_2_3: 3258c2ecf20Sopenharmony_ci buf[2] |= (1 << 3); 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci case FEC_3_4: 3288c2ecf20Sopenharmony_ci buf[2] |= (2 << 3); 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci case FEC_5_6: 3318c2ecf20Sopenharmony_ci buf[2] |= (3 << 3); 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci case FEC_7_8: 3348c2ecf20Sopenharmony_ci buf[2] |= (4 << 3); 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci case FEC_NONE: 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci default: 3398c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid code_rate_LP\n"); 3408c2ecf20Sopenharmony_ci auto_mode = true; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci switch (c->bandwidth_hz) { 3448c2ecf20Sopenharmony_ci case 6000000: 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci case 7000000: 3478c2ecf20Sopenharmony_ci buf[1] |= (1 << 2); 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci case 8000000: 3508c2ecf20Sopenharmony_ci buf[1] |= (2 << 2); 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci default: 3538c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid bandwidth_hz\n"); 3548c2ecf20Sopenharmony_ci ret = -EINVAL; 3558c2ecf20Sopenharmony_ci goto err; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, 0xd3c0, buf, 3); 3598c2ecf20Sopenharmony_ci if (ret) 3608c2ecf20Sopenharmony_ci goto err; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (auto_mode) { 3638c2ecf20Sopenharmony_ci /* clear easy mode flag */ 3648c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0xaefd, 0x00); 3658c2ecf20Sopenharmony_ci if (ret) 3668c2ecf20Sopenharmony_ci goto err; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "auto params\n"); 3698c2ecf20Sopenharmony_ci } else { 3708c2ecf20Sopenharmony_ci /* set easy mode flag */ 3718c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0xaefd, 0x01); 3728c2ecf20Sopenharmony_ci if (ret) 3738c2ecf20Sopenharmony_ci goto err; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0xaefe, 0x00); 3768c2ecf20Sopenharmony_ci if (ret) 3778c2ecf20Sopenharmony_ci goto err; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "manual params\n"); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* Reset FSM */ 3838c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0xffff, 0x00); 3848c2ecf20Sopenharmony_ci if (ret) 3858c2ecf20Sopenharmony_ci goto err; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci state->bandwidth_hz = c->bandwidth_hz; 3888c2ecf20Sopenharmony_ci state->set_frontend_jiffies = jiffies; 3898c2ecf20Sopenharmony_ci state->first_tune = false; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return 0; 3928c2ecf20Sopenharmony_cierr: 3938c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 3948c2ecf20Sopenharmony_ci return ret; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int af9013_get_frontend(struct dvb_frontend *fe, 3988c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 4018c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 4028c2ecf20Sopenharmony_ci int ret; 4038c2ecf20Sopenharmony_ci u8 buf[3]; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ret = regmap_bulk_read(state->regmap, 0xd3c0, buf, 3); 4088c2ecf20Sopenharmony_ci if (ret) 4098c2ecf20Sopenharmony_ci goto err; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci switch ((buf[1] >> 6) & 3) { 4128c2ecf20Sopenharmony_ci case 0: 4138c2ecf20Sopenharmony_ci c->modulation = QPSK; 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci case 1: 4168c2ecf20Sopenharmony_ci c->modulation = QAM_16; 4178c2ecf20Sopenharmony_ci break; 4188c2ecf20Sopenharmony_ci case 2: 4198c2ecf20Sopenharmony_ci c->modulation = QAM_64; 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci switch ((buf[0] >> 0) & 3) { 4248c2ecf20Sopenharmony_ci case 0: 4258c2ecf20Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_2K; 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci case 1: 4288c2ecf20Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_8K; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci switch ((buf[0] >> 2) & 3) { 4328c2ecf20Sopenharmony_ci case 0: 4338c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_32; 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci case 1: 4368c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_16; 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci case 2: 4398c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_8; 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci case 3: 4428c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_4; 4438c2ecf20Sopenharmony_ci break; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci switch ((buf[0] >> 4) & 7) { 4478c2ecf20Sopenharmony_ci case 0: 4488c2ecf20Sopenharmony_ci c->hierarchy = HIERARCHY_NONE; 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci case 1: 4518c2ecf20Sopenharmony_ci c->hierarchy = HIERARCHY_1; 4528c2ecf20Sopenharmony_ci break; 4538c2ecf20Sopenharmony_ci case 2: 4548c2ecf20Sopenharmony_ci c->hierarchy = HIERARCHY_2; 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci case 3: 4578c2ecf20Sopenharmony_ci c->hierarchy = HIERARCHY_4; 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci switch ((buf[2] >> 0) & 7) { 4628c2ecf20Sopenharmony_ci case 0: 4638c2ecf20Sopenharmony_ci c->code_rate_HP = FEC_1_2; 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci case 1: 4668c2ecf20Sopenharmony_ci c->code_rate_HP = FEC_2_3; 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci case 2: 4698c2ecf20Sopenharmony_ci c->code_rate_HP = FEC_3_4; 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci case 3: 4728c2ecf20Sopenharmony_ci c->code_rate_HP = FEC_5_6; 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci case 4: 4758c2ecf20Sopenharmony_ci c->code_rate_HP = FEC_7_8; 4768c2ecf20Sopenharmony_ci break; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci switch ((buf[2] >> 3) & 7) { 4808c2ecf20Sopenharmony_ci case 0: 4818c2ecf20Sopenharmony_ci c->code_rate_LP = FEC_1_2; 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci case 1: 4848c2ecf20Sopenharmony_ci c->code_rate_LP = FEC_2_3; 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci case 2: 4878c2ecf20Sopenharmony_ci c->code_rate_LP = FEC_3_4; 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci case 3: 4908c2ecf20Sopenharmony_ci c->code_rate_LP = FEC_5_6; 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci case 4: 4938c2ecf20Sopenharmony_ci c->code_rate_LP = FEC_7_8; 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci switch ((buf[1] >> 2) & 3) { 4988c2ecf20Sopenharmony_ci case 0: 4998c2ecf20Sopenharmony_ci c->bandwidth_hz = 6000000; 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci case 1: 5028c2ecf20Sopenharmony_ci c->bandwidth_hz = 7000000; 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci case 2: 5058c2ecf20Sopenharmony_ci c->bandwidth_hz = 8000000; 5068c2ecf20Sopenharmony_ci break; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_cierr: 5118c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 5128c2ecf20Sopenharmony_ci return ret; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 5188c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 5198c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 5208c2ecf20Sopenharmony_ci int ret, stmp1; 5218c2ecf20Sopenharmony_ci unsigned int utmp, utmp1, utmp2, utmp3, utmp4; 5228c2ecf20Sopenharmony_ci u8 buf[7]; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* 5278c2ecf20Sopenharmony_ci * Return status from the cache if it is younger than 2000ms with the 5288c2ecf20Sopenharmony_ci * exception of last tune is done during 4000ms. 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_ci if (time_is_after_jiffies(state->read_status_jiffies + msecs_to_jiffies(2000)) && 5318c2ecf20Sopenharmony_ci time_is_before_jiffies(state->set_frontend_jiffies + msecs_to_jiffies(4000))) { 5328c2ecf20Sopenharmony_ci *status = state->fe_status; 5338c2ecf20Sopenharmony_ci } else { 5348c2ecf20Sopenharmony_ci /* MPEG2 lock */ 5358c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0xd507, &utmp); 5368c2ecf20Sopenharmony_ci if (ret) 5378c2ecf20Sopenharmony_ci goto err; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if ((utmp >> 6) & 0x01) { 5408c2ecf20Sopenharmony_ci utmp1 = FE_HAS_SIGNAL | FE_HAS_CARRIER | 5418c2ecf20Sopenharmony_ci FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; 5428c2ecf20Sopenharmony_ci } else { 5438c2ecf20Sopenharmony_ci /* TPS lock */ 5448c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0xd330, &utmp); 5458c2ecf20Sopenharmony_ci if (ret) 5468c2ecf20Sopenharmony_ci goto err; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if ((utmp >> 3) & 0x01) 5498c2ecf20Sopenharmony_ci utmp1 = FE_HAS_SIGNAL | FE_HAS_CARRIER | 5508c2ecf20Sopenharmony_ci FE_HAS_VITERBI; 5518c2ecf20Sopenharmony_ci else 5528c2ecf20Sopenharmony_ci utmp1 = 0; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "fe_status %02x\n", utmp1); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci state->read_status_jiffies = jiffies; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci state->fe_status = utmp1; 5608c2ecf20Sopenharmony_ci *status = utmp1; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* Signal strength */ 5648c2ecf20Sopenharmony_ci switch (state->strength_en) { 5658c2ecf20Sopenharmony_ci case 0: 5668c2ecf20Sopenharmony_ci /* Check if we support signal strength */ 5678c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0x9bee, &utmp); 5688c2ecf20Sopenharmony_ci if (ret) 5698c2ecf20Sopenharmony_ci goto err; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if ((utmp >> 0) & 0x01) { 5728c2ecf20Sopenharmony_ci /* Read agc values for signal strength estimation */ 5738c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0x9bbd, &utmp1); 5748c2ecf20Sopenharmony_ci if (ret) 5758c2ecf20Sopenharmony_ci goto err; 5768c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0x9bd0, &utmp2); 5778c2ecf20Sopenharmony_ci if (ret) 5788c2ecf20Sopenharmony_ci goto err; 5798c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0x9be2, &utmp3); 5808c2ecf20Sopenharmony_ci if (ret) 5818c2ecf20Sopenharmony_ci goto err; 5828c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0x9be4, &utmp4); 5838c2ecf20Sopenharmony_ci if (ret) 5848c2ecf20Sopenharmony_ci goto err; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci state->rf_agc_50 = utmp1; 5878c2ecf20Sopenharmony_ci state->rf_agc_80 = utmp2; 5888c2ecf20Sopenharmony_ci state->if_agc_50 = utmp3; 5898c2ecf20Sopenharmony_ci state->if_agc_80 = utmp4; 5908c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 5918c2ecf20Sopenharmony_ci "rf_agc_50 %u, rf_agc_80 %u, if_agc_50 %u, if_agc_80 %u\n", 5928c2ecf20Sopenharmony_ci utmp1, utmp2, utmp3, utmp4); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci state->strength_en = 1; 5958c2ecf20Sopenharmony_ci } else { 5968c2ecf20Sopenharmony_ci /* Signal strength is not supported */ 5978c2ecf20Sopenharmony_ci state->strength_en = 2; 5988c2ecf20Sopenharmony_ci break; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci fallthrough; 6018c2ecf20Sopenharmony_ci case 1: 6028c2ecf20Sopenharmony_ci if (time_is_after_jiffies(state->strength_jiffies + msecs_to_jiffies(2000))) 6038c2ecf20Sopenharmony_ci break; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* Read value */ 6068c2ecf20Sopenharmony_ci ret = regmap_bulk_read(state->regmap, 0xd07c, buf, 2); 6078c2ecf20Sopenharmony_ci if (ret) 6088c2ecf20Sopenharmony_ci goto err; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* 6118c2ecf20Sopenharmony_ci * Construct line equation from tuner dependent -80/-50 dBm agc 6128c2ecf20Sopenharmony_ci * limits and use it to map current agc value to dBm estimate 6138c2ecf20Sopenharmony_ci */ 6148c2ecf20Sopenharmony_ci #define agc_gain (buf[0] + buf[1]) 6158c2ecf20Sopenharmony_ci #define agc_gain_50dbm (state->rf_agc_50 + state->if_agc_50) 6168c2ecf20Sopenharmony_ci #define agc_gain_80dbm (state->rf_agc_80 + state->if_agc_80) 6178c2ecf20Sopenharmony_ci stmp1 = 30000 * (agc_gain - agc_gain_80dbm) / 6188c2ecf20Sopenharmony_ci (agc_gain_50dbm - agc_gain_80dbm) - 80000; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 6218c2ecf20Sopenharmony_ci "strength %d, agc_gain %d, agc_gain_50dbm %d, agc_gain_80dbm %d\n", 6228c2ecf20Sopenharmony_ci stmp1, agc_gain, agc_gain_50dbm, agc_gain_80dbm); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci state->strength_jiffies = jiffies; 6258c2ecf20Sopenharmony_ci /* Convert [-90, -30] dBm to [0x0000, 0xffff] for dvbv3 */ 6268c2ecf20Sopenharmony_ci utmp1 = clamp(stmp1 + 90000, 0, 60000); 6278c2ecf20Sopenharmony_ci state->dvbv3_strength = div_u64((u64)utmp1 * 0xffff, 60000); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci c->strength.stat[0].scale = FE_SCALE_DECIBEL; 6308c2ecf20Sopenharmony_ci c->strength.stat[0].svalue = stmp1; 6318c2ecf20Sopenharmony_ci break; 6328c2ecf20Sopenharmony_ci default: 6338c2ecf20Sopenharmony_ci c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 6348c2ecf20Sopenharmony_ci break; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* CNR */ 6388c2ecf20Sopenharmony_ci switch (state->fe_status & FE_HAS_VITERBI) { 6398c2ecf20Sopenharmony_ci case FE_HAS_VITERBI: 6408c2ecf20Sopenharmony_ci if (time_is_after_jiffies(state->cnr_jiffies + msecs_to_jiffies(2000))) 6418c2ecf20Sopenharmony_ci break; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* Check if cnr ready */ 6448c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0xd2e1, &utmp); 6458c2ecf20Sopenharmony_ci if (ret) 6468c2ecf20Sopenharmony_ci goto err; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (!((utmp >> 3) & 0x01)) { 6498c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "cnr not ready\n"); 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* Read value */ 6548c2ecf20Sopenharmony_ci ret = regmap_bulk_read(state->regmap, 0xd2e3, buf, 3); 6558c2ecf20Sopenharmony_ci if (ret) 6568c2ecf20Sopenharmony_ci goto err; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci utmp1 = buf[2] << 16 | buf[1] << 8 | buf[0] << 0; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* Read current modulation */ 6618c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0xd3c1, &utmp); 6628c2ecf20Sopenharmony_ci if (ret) 6638c2ecf20Sopenharmony_ci goto err; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci switch ((utmp >> 6) & 3) { 6668c2ecf20Sopenharmony_ci case 0: 6678c2ecf20Sopenharmony_ci /* 6688c2ecf20Sopenharmony_ci * QPSK 6698c2ecf20Sopenharmony_ci * CNR[dB] 13 * -log10((1690000 - value) / value) + 2.6 6708c2ecf20Sopenharmony_ci * value [653799, 1689999], 2.6 / 13 = 3355443 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_ci utmp1 = clamp(utmp1, 653799U, 1689999U); 6738c2ecf20Sopenharmony_ci utmp1 = ((u64)(intlog10(utmp1) 6748c2ecf20Sopenharmony_ci - intlog10(1690000 - utmp1) 6758c2ecf20Sopenharmony_ci + 3355443) * 13 * 1000) >> 24; 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci case 1: 6788c2ecf20Sopenharmony_ci /* 6798c2ecf20Sopenharmony_ci * QAM-16 6808c2ecf20Sopenharmony_ci * CNR[dB] 6 * log10((value - 370000) / (828000 - value)) + 15.7 6818c2ecf20Sopenharmony_ci * value [371105, 827999], 15.7 / 6 = 43900382 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_ci utmp1 = clamp(utmp1, 371105U, 827999U); 6848c2ecf20Sopenharmony_ci utmp1 = ((u64)(intlog10(utmp1 - 370000) 6858c2ecf20Sopenharmony_ci - intlog10(828000 - utmp1) 6868c2ecf20Sopenharmony_ci + 43900382) * 6 * 1000) >> 24; 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci case 2: 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * QAM-64 6918c2ecf20Sopenharmony_ci * CNR[dB] 8 * log10((value - 193000) / (425000 - value)) + 23.8 6928c2ecf20Sopenharmony_ci * value [193246, 424999], 23.8 / 8 = 49912218 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_ci utmp1 = clamp(utmp1, 193246U, 424999U); 6958c2ecf20Sopenharmony_ci utmp1 = ((u64)(intlog10(utmp1 - 193000) 6968c2ecf20Sopenharmony_ci - intlog10(425000 - utmp1) 6978c2ecf20Sopenharmony_ci + 49912218) * 8 * 1000) >> 24; 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci default: 7008c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid modulation %u\n", 7018c2ecf20Sopenharmony_ci (utmp >> 6) & 3); 7028c2ecf20Sopenharmony_ci utmp1 = 0; 7038c2ecf20Sopenharmony_ci break; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "cnr %u\n", utmp1); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci state->cnr_jiffies = jiffies; 7098c2ecf20Sopenharmony_ci state->dvbv3_snr = utmp1 / 100; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 7128c2ecf20Sopenharmony_ci c->cnr.stat[0].svalue = utmp1; 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci default: 7158c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 7168c2ecf20Sopenharmony_ci break; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* BER / PER */ 7208c2ecf20Sopenharmony_ci switch (state->fe_status & FE_HAS_SYNC) { 7218c2ecf20Sopenharmony_ci case FE_HAS_SYNC: 7228c2ecf20Sopenharmony_ci if (time_is_after_jiffies(state->ber_ucb_jiffies + msecs_to_jiffies(2000))) 7238c2ecf20Sopenharmony_ci break; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* Check if ber / ucb is ready */ 7268c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0xd391, &utmp); 7278c2ecf20Sopenharmony_ci if (ret) 7288c2ecf20Sopenharmony_ci goto err; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (!((utmp >> 4) & 0x01)) { 7318c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "ber not ready\n"); 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* Read value */ 7368c2ecf20Sopenharmony_ci ret = regmap_bulk_read(state->regmap, 0xd385, buf, 7); 7378c2ecf20Sopenharmony_ci if (ret) 7388c2ecf20Sopenharmony_ci goto err; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci utmp1 = buf[4] << 16 | buf[3] << 8 | buf[2] << 0; 7418c2ecf20Sopenharmony_ci utmp2 = (buf[1] << 8 | buf[0] << 0) * 204 * 8; 7428c2ecf20Sopenharmony_ci utmp3 = buf[6] << 8 | buf[5] << 0; 7438c2ecf20Sopenharmony_ci utmp4 = buf[1] << 8 | buf[0] << 0; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Use 10000 TS packets for measure */ 7468c2ecf20Sopenharmony_ci if (utmp4 != 10000) { 7478c2ecf20Sopenharmony_ci buf[0] = (10000 >> 0) & 0xff; 7488c2ecf20Sopenharmony_ci buf[1] = (10000 >> 8) & 0xff; 7498c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, 0xd385, buf, 2); 7508c2ecf20Sopenharmony_ci if (ret) 7518c2ecf20Sopenharmony_ci goto err; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* Reset ber / ucb counter */ 7558c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd391, 0x20, 0x20); 7568c2ecf20Sopenharmony_ci if (ret) 7578c2ecf20Sopenharmony_ci goto err; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "post_bit_error %u, post_bit_count %u\n", 7608c2ecf20Sopenharmony_ci utmp1, utmp2); 7618c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "block_error %u, block_count %u\n", 7628c2ecf20Sopenharmony_ci utmp3, utmp4); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci state->ber_ucb_jiffies = jiffies; 7658c2ecf20Sopenharmony_ci state->dvbv3_ber = utmp1; 7668c2ecf20Sopenharmony_ci state->dvbv3_ucblocks += utmp3; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 7698c2ecf20Sopenharmony_ci c->post_bit_error.stat[0].uvalue += utmp1; 7708c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 7718c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].uvalue += utmp2; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci c->block_error.stat[0].scale = FE_SCALE_COUNTER; 7748c2ecf20Sopenharmony_ci c->block_error.stat[0].uvalue += utmp3; 7758c2ecf20Sopenharmony_ci c->block_count.stat[0].scale = FE_SCALE_COUNTER; 7768c2ecf20Sopenharmony_ci c->block_count.stat[0].uvalue += utmp4; 7778c2ecf20Sopenharmony_ci break; 7788c2ecf20Sopenharmony_ci default: 7798c2ecf20Sopenharmony_ci c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 7808c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 7838c2ecf20Sopenharmony_ci c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci return 0; 7888c2ecf20Sopenharmony_cierr: 7898c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 7908c2ecf20Sopenharmony_ci return ret; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci *snr = state->dvbv3_snr; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci return 0; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci *strength = state->dvbv3_strength; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci return 0; 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci *ber = state->dvbv3_ber; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci return 0; 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistatic int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci *ucblocks = state->dvbv3_ucblocks; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci return 0; 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic int af9013_init(struct dvb_frontend *fe) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 8328c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 8338c2ecf20Sopenharmony_ci int ret, i, len; 8348c2ecf20Sopenharmony_ci unsigned int utmp; 8358c2ecf20Sopenharmony_ci u8 buf[3]; 8368c2ecf20Sopenharmony_ci const struct af9013_reg_mask_val *tab; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci /* ADC on */ 8418c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd73a, 0x08, 0x00); 8428c2ecf20Sopenharmony_ci if (ret) 8438c2ecf20Sopenharmony_ci goto err; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* Clear reset */ 8468c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd417, 0x02, 0x00); 8478c2ecf20Sopenharmony_ci if (ret) 8488c2ecf20Sopenharmony_ci goto err; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* Disable reset */ 8518c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd417, 0x10, 0x00); 8528c2ecf20Sopenharmony_ci if (ret) 8538c2ecf20Sopenharmony_ci goto err; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* write API version to firmware */ 8568c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, 0x9bf2, state->api_version, 4); 8578c2ecf20Sopenharmony_ci if (ret) 8588c2ecf20Sopenharmony_ci goto err; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* program ADC control */ 8618c2ecf20Sopenharmony_ci switch (state->clk) { 8628c2ecf20Sopenharmony_ci case 28800000: /* 28.800 MHz */ 8638c2ecf20Sopenharmony_ci utmp = 0; 8648c2ecf20Sopenharmony_ci break; 8658c2ecf20Sopenharmony_ci case 20480000: /* 20.480 MHz */ 8668c2ecf20Sopenharmony_ci utmp = 1; 8678c2ecf20Sopenharmony_ci break; 8688c2ecf20Sopenharmony_ci case 28000000: /* 28.000 MHz */ 8698c2ecf20Sopenharmony_ci utmp = 2; 8708c2ecf20Sopenharmony_ci break; 8718c2ecf20Sopenharmony_ci case 25000000: /* 25.000 MHz */ 8728c2ecf20Sopenharmony_ci utmp = 3; 8738c2ecf20Sopenharmony_ci break; 8748c2ecf20Sopenharmony_ci default: 8758c2ecf20Sopenharmony_ci ret = -EINVAL; 8768c2ecf20Sopenharmony_ci goto err; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0x9bd2, 0x0f, utmp); 8808c2ecf20Sopenharmony_ci if (ret) 8818c2ecf20Sopenharmony_ci goto err; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci utmp = div_u64((u64)state->clk * 0x80000, 1000000); 8848c2ecf20Sopenharmony_ci buf[0] = (utmp >> 0) & 0xff; 8858c2ecf20Sopenharmony_ci buf[1] = (utmp >> 8) & 0xff; 8868c2ecf20Sopenharmony_ci buf[2] = (utmp >> 16) & 0xff; 8878c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, 0xd180, buf, 3); 8888c2ecf20Sopenharmony_ci if (ret) 8898c2ecf20Sopenharmony_ci goto err; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci /* Demod core settings */ 8928c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "load demod core settings\n"); 8938c2ecf20Sopenharmony_ci len = ARRAY_SIZE(demod_init_tab); 8948c2ecf20Sopenharmony_ci tab = demod_init_tab; 8958c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 8968c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, tab[i].reg, tab[i].mask, 8978c2ecf20Sopenharmony_ci tab[i].val); 8988c2ecf20Sopenharmony_ci if (ret) 8998c2ecf20Sopenharmony_ci goto err; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* Demod tuner specific settings */ 9038c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "load tuner specific settings\n"); 9048c2ecf20Sopenharmony_ci switch (state->tuner) { 9058c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5003D: 9068c2ecf20Sopenharmony_ci len = ARRAY_SIZE(tuner_init_tab_mxl5003d); 9078c2ecf20Sopenharmony_ci tab = tuner_init_tab_mxl5003d; 9088c2ecf20Sopenharmony_ci break; 9098c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5005D: 9108c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5005R: 9118c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5007T: 9128c2ecf20Sopenharmony_ci len = ARRAY_SIZE(tuner_init_tab_mxl5005); 9138c2ecf20Sopenharmony_ci tab = tuner_init_tab_mxl5005; 9148c2ecf20Sopenharmony_ci break; 9158c2ecf20Sopenharmony_ci case AF9013_TUNER_ENV77H11D5: 9168c2ecf20Sopenharmony_ci len = ARRAY_SIZE(tuner_init_tab_env77h11d5); 9178c2ecf20Sopenharmony_ci tab = tuner_init_tab_env77h11d5; 9188c2ecf20Sopenharmony_ci break; 9198c2ecf20Sopenharmony_ci case AF9013_TUNER_MT2060: 9208c2ecf20Sopenharmony_ci len = ARRAY_SIZE(tuner_init_tab_mt2060); 9218c2ecf20Sopenharmony_ci tab = tuner_init_tab_mt2060; 9228c2ecf20Sopenharmony_ci break; 9238c2ecf20Sopenharmony_ci case AF9013_TUNER_MC44S803: 9248c2ecf20Sopenharmony_ci len = ARRAY_SIZE(tuner_init_tab_mc44s803); 9258c2ecf20Sopenharmony_ci tab = tuner_init_tab_mc44s803; 9268c2ecf20Sopenharmony_ci break; 9278c2ecf20Sopenharmony_ci case AF9013_TUNER_QT1010: 9288c2ecf20Sopenharmony_ci case AF9013_TUNER_QT1010A: 9298c2ecf20Sopenharmony_ci len = ARRAY_SIZE(tuner_init_tab_qt1010); 9308c2ecf20Sopenharmony_ci tab = tuner_init_tab_qt1010; 9318c2ecf20Sopenharmony_ci break; 9328c2ecf20Sopenharmony_ci case AF9013_TUNER_MT2060_2: 9338c2ecf20Sopenharmony_ci len = ARRAY_SIZE(tuner_init_tab_mt2060_2); 9348c2ecf20Sopenharmony_ci tab = tuner_init_tab_mt2060_2; 9358c2ecf20Sopenharmony_ci break; 9368c2ecf20Sopenharmony_ci case AF9013_TUNER_TDA18271: 9378c2ecf20Sopenharmony_ci case AF9013_TUNER_TDA18218: 9388c2ecf20Sopenharmony_ci len = ARRAY_SIZE(tuner_init_tab_tda18271); 9398c2ecf20Sopenharmony_ci tab = tuner_init_tab_tda18271; 9408c2ecf20Sopenharmony_ci break; 9418c2ecf20Sopenharmony_ci case AF9013_TUNER_UNKNOWN: 9428c2ecf20Sopenharmony_ci default: 9438c2ecf20Sopenharmony_ci len = ARRAY_SIZE(tuner_init_tab_unknown); 9448c2ecf20Sopenharmony_ci tab = tuner_init_tab_unknown; 9458c2ecf20Sopenharmony_ci break; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 9498c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, tab[i].reg, tab[i].mask, 9508c2ecf20Sopenharmony_ci tab[i].val); 9518c2ecf20Sopenharmony_ci if (ret) 9528c2ecf20Sopenharmony_ci goto err; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci /* TS interface */ 9568c2ecf20Sopenharmony_ci if (state->ts_output_pin == 7) 9578c2ecf20Sopenharmony_ci utmp = 1 << 3 | state->ts_mode << 1; 9588c2ecf20Sopenharmony_ci else 9598c2ecf20Sopenharmony_ci utmp = 0 << 3 | state->ts_mode << 1; 9608c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd500, 0x0e, utmp); 9618c2ecf20Sopenharmony_ci if (ret) 9628c2ecf20Sopenharmony_ci goto err; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci /* enable lock led */ 9658c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd730, 0x01, 0x01); 9668c2ecf20Sopenharmony_ci if (ret) 9678c2ecf20Sopenharmony_ci goto err; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci state->first_tune = true; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci return 0; 9728c2ecf20Sopenharmony_cierr: 9738c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 9748c2ecf20Sopenharmony_ci return ret; 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic int af9013_sleep(struct dvb_frontend *fe) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 9808c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 9818c2ecf20Sopenharmony_ci int ret; 9828c2ecf20Sopenharmony_ci unsigned int utmp; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* disable lock led */ 9878c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd730, 0x01, 0x00); 9888c2ecf20Sopenharmony_ci if (ret) 9898c2ecf20Sopenharmony_ci goto err; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci /* Enable reset */ 9928c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd417, 0x10, 0x10); 9938c2ecf20Sopenharmony_ci if (ret) 9948c2ecf20Sopenharmony_ci goto err; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* Start reset execution */ 9978c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0xaeff, 0x01); 9988c2ecf20Sopenharmony_ci if (ret) 9998c2ecf20Sopenharmony_ci goto err; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* Wait reset performs */ 10028c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(state->regmap, 0xd417, utmp, 10038c2ecf20Sopenharmony_ci (utmp >> 1) & 0x01, 5000, 1000000); 10048c2ecf20Sopenharmony_ci if (ret) 10058c2ecf20Sopenharmony_ci goto err; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (!((utmp >> 1) & 0x01)) { 10088c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 10098c2ecf20Sopenharmony_ci goto err; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* ADC off */ 10138c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd73a, 0x08, 0x08); 10148c2ecf20Sopenharmony_ci if (ret) 10158c2ecf20Sopenharmony_ci goto err; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci return 0; 10188c2ecf20Sopenharmony_cierr: 10198c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 10208c2ecf20Sopenharmony_ci return ret; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops af9013_ops; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cistatic int af9013_download_firmware(struct af9013_state *state) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 10288c2ecf20Sopenharmony_ci int ret, i, len, rem; 10298c2ecf20Sopenharmony_ci unsigned int utmp; 10308c2ecf20Sopenharmony_ci u8 buf[4]; 10318c2ecf20Sopenharmony_ci u16 checksum = 0; 10328c2ecf20Sopenharmony_ci const struct firmware *firmware; 10338c2ecf20Sopenharmony_ci const char *name = AF9013_FIRMWARE; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* Check whether firmware is already running */ 10388c2ecf20Sopenharmony_ci ret = regmap_read(state->regmap, 0x98be, &utmp); 10398c2ecf20Sopenharmony_ci if (ret) 10408c2ecf20Sopenharmony_ci goto err; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "firmware status %02x\n", utmp); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (utmp == 0x0c) 10458c2ecf20Sopenharmony_ci return 0; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci dev_info(&client->dev, "found a '%s' in cold state, will try to load a firmware\n", 10488c2ecf20Sopenharmony_ci af9013_ops.info.name); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* Request the firmware, will block and timeout */ 10518c2ecf20Sopenharmony_ci ret = request_firmware(&firmware, name, &client->dev); 10528c2ecf20Sopenharmony_ci if (ret) { 10538c2ecf20Sopenharmony_ci dev_info(&client->dev, "firmware file '%s' not found %d\n", 10548c2ecf20Sopenharmony_ci name, ret); 10558c2ecf20Sopenharmony_ci goto err; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci dev_info(&client->dev, "downloading firmware from file '%s'\n", 10598c2ecf20Sopenharmony_ci name); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci /* Write firmware checksum & size */ 10628c2ecf20Sopenharmony_ci for (i = 0; i < firmware->size; i++) 10638c2ecf20Sopenharmony_ci checksum += firmware->data[i]; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci buf[0] = (checksum >> 8) & 0xff; 10668c2ecf20Sopenharmony_ci buf[1] = (checksum >> 0) & 0xff; 10678c2ecf20Sopenharmony_ci buf[2] = (firmware->size >> 8) & 0xff; 10688c2ecf20Sopenharmony_ci buf[3] = (firmware->size >> 0) & 0xff; 10698c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, 0x50fc, buf, 4); 10708c2ecf20Sopenharmony_ci if (ret) 10718c2ecf20Sopenharmony_ci goto err_release_firmware; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Download firmware */ 10748c2ecf20Sopenharmony_ci #define LEN_MAX 16 10758c2ecf20Sopenharmony_ci for (rem = firmware->size; rem > 0; rem -= LEN_MAX) { 10768c2ecf20Sopenharmony_ci len = min(LEN_MAX, rem); 10778c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, 10788c2ecf20Sopenharmony_ci 0x5100 + firmware->size - rem, 10798c2ecf20Sopenharmony_ci &firmware->data[firmware->size - rem], 10808c2ecf20Sopenharmony_ci len); 10818c2ecf20Sopenharmony_ci if (ret) { 10828c2ecf20Sopenharmony_ci dev_err(&client->dev, "firmware download failed %d\n", 10838c2ecf20Sopenharmony_ci ret); 10848c2ecf20Sopenharmony_ci goto err_release_firmware; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci release_firmware(firmware); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci /* Boot firmware */ 10918c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0xe205, 0x01); 10928c2ecf20Sopenharmony_ci if (ret) 10938c2ecf20Sopenharmony_ci goto err; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* Check firmware status. 0c=OK, 04=fail */ 10968c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(state->regmap, 0x98be, utmp, 10978c2ecf20Sopenharmony_ci (utmp == 0x0c || utmp == 0x04), 10988c2ecf20Sopenharmony_ci 5000, 1000000); 10998c2ecf20Sopenharmony_ci if (ret) 11008c2ecf20Sopenharmony_ci goto err; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "firmware status %02x\n", utmp); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci if (utmp == 0x04) { 11058c2ecf20Sopenharmony_ci ret = -ENODEV; 11068c2ecf20Sopenharmony_ci dev_err(&client->dev, "firmware did not run\n"); 11078c2ecf20Sopenharmony_ci goto err; 11088c2ecf20Sopenharmony_ci } else if (utmp != 0x0c) { 11098c2ecf20Sopenharmony_ci ret = -ENODEV; 11108c2ecf20Sopenharmony_ci dev_err(&client->dev, "firmware boot timeout\n"); 11118c2ecf20Sopenharmony_ci goto err; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci dev_info(&client->dev, "found a '%s' in warm state\n", 11158c2ecf20Sopenharmony_ci af9013_ops.info.name); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci return 0; 11188c2ecf20Sopenharmony_cierr_release_firmware: 11198c2ecf20Sopenharmony_ci release_firmware(firmware); 11208c2ecf20Sopenharmony_cierr: 11218c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 11228c2ecf20Sopenharmony_ci return ret; 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops af9013_ops = { 11268c2ecf20Sopenharmony_ci .delsys = { SYS_DVBT }, 11278c2ecf20Sopenharmony_ci .info = { 11288c2ecf20Sopenharmony_ci .name = "Afatech AF9013", 11298c2ecf20Sopenharmony_ci .frequency_min_hz = 174 * MHz, 11308c2ecf20Sopenharmony_ci .frequency_max_hz = 862 * MHz, 11318c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 250 * kHz, 11328c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_1_2 | 11338c2ecf20Sopenharmony_ci FE_CAN_FEC_2_3 | 11348c2ecf20Sopenharmony_ci FE_CAN_FEC_3_4 | 11358c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | 11368c2ecf20Sopenharmony_ci FE_CAN_FEC_7_8 | 11378c2ecf20Sopenharmony_ci FE_CAN_FEC_AUTO | 11388c2ecf20Sopenharmony_ci FE_CAN_QPSK | 11398c2ecf20Sopenharmony_ci FE_CAN_QAM_16 | 11408c2ecf20Sopenharmony_ci FE_CAN_QAM_64 | 11418c2ecf20Sopenharmony_ci FE_CAN_QAM_AUTO | 11428c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | 11438c2ecf20Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | 11448c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO | 11458c2ecf20Sopenharmony_ci FE_CAN_RECOVER | 11468c2ecf20Sopenharmony_ci FE_CAN_MUTE_TS 11478c2ecf20Sopenharmony_ci }, 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci .init = af9013_init, 11508c2ecf20Sopenharmony_ci .sleep = af9013_sleep, 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci .get_tune_settings = af9013_get_tune_settings, 11538c2ecf20Sopenharmony_ci .set_frontend = af9013_set_frontend, 11548c2ecf20Sopenharmony_ci .get_frontend = af9013_get_frontend, 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci .read_status = af9013_read_status, 11578c2ecf20Sopenharmony_ci .read_snr = af9013_read_snr, 11588c2ecf20Sopenharmony_ci .read_signal_strength = af9013_read_signal_strength, 11598c2ecf20Sopenharmony_ci .read_ber = af9013_read_ber, 11608c2ecf20Sopenharmony_ci .read_ucblocks = af9013_read_ucblocks, 11618c2ecf20Sopenharmony_ci}; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cistatic int af9013_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 11668c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 11678c2ecf20Sopenharmony_ci int ret; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "onoff %d\n", onoff); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd503, 0x01, onoff); 11728c2ecf20Sopenharmony_ci if (ret) 11738c2ecf20Sopenharmony_ci goto err; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci return 0; 11768c2ecf20Sopenharmony_cierr: 11778c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 11788c2ecf20Sopenharmony_ci return ret; 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_cistatic int af9013_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, 11828c2ecf20Sopenharmony_ci int onoff) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci struct af9013_state *state = fe->demodulator_priv; 11858c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 11868c2ecf20Sopenharmony_ci int ret; 11878c2ecf20Sopenharmony_ci u8 buf[2]; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "index %d, pid %04x, onoff %d\n", 11908c2ecf20Sopenharmony_ci index, pid, onoff); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (pid > 0x1fff) { 11938c2ecf20Sopenharmony_ci /* 0x2000 is kernel virtual pid for whole ts (all pids) */ 11948c2ecf20Sopenharmony_ci ret = 0; 11958c2ecf20Sopenharmony_ci goto err; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci buf[0] = (pid >> 0) & 0xff; 11998c2ecf20Sopenharmony_ci buf[1] = (pid >> 8) & 0xff; 12008c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, 0xd505, buf, 2); 12018c2ecf20Sopenharmony_ci if (ret) 12028c2ecf20Sopenharmony_ci goto err; 12038c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0xd504, onoff << 5 | index << 0); 12048c2ecf20Sopenharmony_ci if (ret) 12058c2ecf20Sopenharmony_ci goto err; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci return 0; 12088c2ecf20Sopenharmony_cierr: 12098c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 12108c2ecf20Sopenharmony_ci return ret; 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci struct af9013_state *state = i2c_get_clientdata(client); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci return &state->fe; 12208c2ecf20Sopenharmony_ci} 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_cistatic struct i2c_adapter *af9013_get_i2c_adapter(struct i2c_client *client) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci struct af9013_state *state = i2c_get_clientdata(client); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci return state->muxc->adapter[0]; 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci/* 12328c2ecf20Sopenharmony_ci * XXX: Hackish solution. We use virtual register, reg bit 16, to carry info 12338c2ecf20Sopenharmony_ci * about i2c adapter locking. Own locking is needed because i2c mux call has 12348c2ecf20Sopenharmony_ci * already locked i2c adapter. 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_cistatic int af9013_select(struct i2c_mux_core *muxc, u32 chan) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci struct af9013_state *state = i2c_mux_priv(muxc); 12398c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 12408c2ecf20Sopenharmony_ci int ret; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci if (state->ts_mode == AF9013_TS_MODE_USB) 12458c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0x1d417, 0x08, 0x08); 12468c2ecf20Sopenharmony_ci else 12478c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0x1d607, 0x04, 0x04); 12488c2ecf20Sopenharmony_ci if (ret) 12498c2ecf20Sopenharmony_ci goto err; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci return 0; 12528c2ecf20Sopenharmony_cierr: 12538c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 12548c2ecf20Sopenharmony_ci return ret; 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic int af9013_deselect(struct i2c_mux_core *muxc, u32 chan) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci struct af9013_state *state = i2c_mux_priv(muxc); 12608c2ecf20Sopenharmony_ci struct i2c_client *client = state->client; 12618c2ecf20Sopenharmony_ci int ret; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci if (state->ts_mode == AF9013_TS_MODE_USB) 12668c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0x1d417, 0x08, 0x00); 12678c2ecf20Sopenharmony_ci else 12688c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0x1d607, 0x04, 0x00); 12698c2ecf20Sopenharmony_ci if (ret) 12708c2ecf20Sopenharmony_ci goto err; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci return 0; 12738c2ecf20Sopenharmony_cierr: 12748c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 12758c2ecf20Sopenharmony_ci return ret; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci/* Own I2C access routines needed for regmap as chip uses extra command byte */ 12798c2ecf20Sopenharmony_cistatic int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg, 12808c2ecf20Sopenharmony_ci const u8 *val, int len, u8 lock) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci int ret; 12838c2ecf20Sopenharmony_ci u8 buf[21]; 12848c2ecf20Sopenharmony_ci struct i2c_msg msg[1] = { 12858c2ecf20Sopenharmony_ci { 12868c2ecf20Sopenharmony_ci .addr = client->addr, 12878c2ecf20Sopenharmony_ci .flags = 0, 12888c2ecf20Sopenharmony_ci .len = 3 + len, 12898c2ecf20Sopenharmony_ci .buf = buf, 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci }; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (3 + len > sizeof(buf)) { 12948c2ecf20Sopenharmony_ci ret = -EINVAL; 12958c2ecf20Sopenharmony_ci goto err; 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci buf[0] = (reg >> 8) & 0xff; 12998c2ecf20Sopenharmony_ci buf[1] = (reg >> 0) & 0xff; 13008c2ecf20Sopenharmony_ci buf[2] = cmd; 13018c2ecf20Sopenharmony_ci memcpy(&buf[3], val, len); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (lock) 13048c2ecf20Sopenharmony_ci i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); 13058c2ecf20Sopenharmony_ci ret = __i2c_transfer(client->adapter, msg, 1); 13068c2ecf20Sopenharmony_ci if (lock) 13078c2ecf20Sopenharmony_ci i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); 13088c2ecf20Sopenharmony_ci if (ret < 0) { 13098c2ecf20Sopenharmony_ci goto err; 13108c2ecf20Sopenharmony_ci } else if (ret != 1) { 13118c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 13128c2ecf20Sopenharmony_ci goto err; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci return 0; 13168c2ecf20Sopenharmony_cierr: 13178c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 13188c2ecf20Sopenharmony_ci return ret; 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg, 13228c2ecf20Sopenharmony_ci u8 *val, int len, u8 lock) 13238c2ecf20Sopenharmony_ci{ 13248c2ecf20Sopenharmony_ci int ret; 13258c2ecf20Sopenharmony_ci u8 buf[3]; 13268c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { 13278c2ecf20Sopenharmony_ci { 13288c2ecf20Sopenharmony_ci .addr = client->addr, 13298c2ecf20Sopenharmony_ci .flags = 0, 13308c2ecf20Sopenharmony_ci .len = 3, 13318c2ecf20Sopenharmony_ci .buf = buf, 13328c2ecf20Sopenharmony_ci }, { 13338c2ecf20Sopenharmony_ci .addr = client->addr, 13348c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 13358c2ecf20Sopenharmony_ci .len = len, 13368c2ecf20Sopenharmony_ci .buf = val, 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci }; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci buf[0] = (reg >> 8) & 0xff; 13418c2ecf20Sopenharmony_ci buf[1] = (reg >> 0) & 0xff; 13428c2ecf20Sopenharmony_ci buf[2] = cmd; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (lock) 13458c2ecf20Sopenharmony_ci i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); 13468c2ecf20Sopenharmony_ci ret = __i2c_transfer(client->adapter, msg, 2); 13478c2ecf20Sopenharmony_ci if (lock) 13488c2ecf20Sopenharmony_ci i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); 13498c2ecf20Sopenharmony_ci if (ret < 0) { 13508c2ecf20Sopenharmony_ci goto err; 13518c2ecf20Sopenharmony_ci } else if (ret != 2) { 13528c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 13538c2ecf20Sopenharmony_ci goto err; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci return 0; 13578c2ecf20Sopenharmony_cierr: 13588c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 13598c2ecf20Sopenharmony_ci return ret; 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cistatic int af9013_regmap_write(void *context, const void *data, size_t count) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci struct i2c_client *client = context; 13658c2ecf20Sopenharmony_ci struct af9013_state *state = i2c_get_clientdata(client); 13668c2ecf20Sopenharmony_ci int ret, i; 13678c2ecf20Sopenharmony_ci u8 cmd; 13688c2ecf20Sopenharmony_ci u8 lock = !((u8 *)data)[0]; 13698c2ecf20Sopenharmony_ci u16 reg = ((u8 *)data)[1] << 8 | ((u8 *)data)[2] << 0; 13708c2ecf20Sopenharmony_ci u8 *val = &((u8 *)data)[3]; 13718c2ecf20Sopenharmony_ci const unsigned int len = count - 3; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) { 13748c2ecf20Sopenharmony_ci cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|1 << 0; 13758c2ecf20Sopenharmony_ci ret = af9013_wregs(client, cmd, reg, val, len, lock); 13768c2ecf20Sopenharmony_ci if (ret) 13778c2ecf20Sopenharmony_ci goto err; 13788c2ecf20Sopenharmony_ci } else if (reg >= 0x5100 && reg < 0x8fff) { 13798c2ecf20Sopenharmony_ci /* Firmware download */ 13808c2ecf20Sopenharmony_ci cmd = 1 << 7|1 << 6|(len - 1) << 2|1 << 1|1 << 0; 13818c2ecf20Sopenharmony_ci ret = af9013_wregs(client, cmd, reg, val, len, lock); 13828c2ecf20Sopenharmony_ci if (ret) 13838c2ecf20Sopenharmony_ci goto err; 13848c2ecf20Sopenharmony_ci } else { 13858c2ecf20Sopenharmony_ci cmd = 0 << 7|0 << 6|(1 - 1) << 2|1 << 1|1 << 0; 13868c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 13878c2ecf20Sopenharmony_ci ret = af9013_wregs(client, cmd, reg + i, val + i, 1, 13888c2ecf20Sopenharmony_ci lock); 13898c2ecf20Sopenharmony_ci if (ret) 13908c2ecf20Sopenharmony_ci goto err; 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci return 0; 13958c2ecf20Sopenharmony_cierr: 13968c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 13978c2ecf20Sopenharmony_ci return ret; 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic int af9013_regmap_read(void *context, const void *reg_buf, 14018c2ecf20Sopenharmony_ci size_t reg_size, void *val_buf, size_t val_size) 14028c2ecf20Sopenharmony_ci{ 14038c2ecf20Sopenharmony_ci struct i2c_client *client = context; 14048c2ecf20Sopenharmony_ci struct af9013_state *state = i2c_get_clientdata(client); 14058c2ecf20Sopenharmony_ci int ret, i; 14068c2ecf20Sopenharmony_ci u8 cmd; 14078c2ecf20Sopenharmony_ci u8 lock = !((u8 *)reg_buf)[0]; 14088c2ecf20Sopenharmony_ci u16 reg = ((u8 *)reg_buf)[1] << 8 | ((u8 *)reg_buf)[2] << 0; 14098c2ecf20Sopenharmony_ci u8 *val = &((u8 *)val_buf)[0]; 14108c2ecf20Sopenharmony_ci const unsigned int len = val_size; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) { 14138c2ecf20Sopenharmony_ci cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|0 << 0; 14148c2ecf20Sopenharmony_ci ret = af9013_rregs(client, cmd, reg, val_buf, len, lock); 14158c2ecf20Sopenharmony_ci if (ret) 14168c2ecf20Sopenharmony_ci goto err; 14178c2ecf20Sopenharmony_ci } else { 14188c2ecf20Sopenharmony_ci cmd = 0 << 7|0 << 6|(1 - 1) << 2|1 << 1|0 << 0; 14198c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 14208c2ecf20Sopenharmony_ci ret = af9013_rregs(client, cmd, reg + i, val + i, 1, 14218c2ecf20Sopenharmony_ci lock); 14228c2ecf20Sopenharmony_ci if (ret) 14238c2ecf20Sopenharmony_ci goto err; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci return 0; 14288c2ecf20Sopenharmony_cierr: 14298c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 14308c2ecf20Sopenharmony_ci return ret; 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_cistatic int af9013_probe(struct i2c_client *client, 14348c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 14358c2ecf20Sopenharmony_ci{ 14368c2ecf20Sopenharmony_ci struct af9013_state *state; 14378c2ecf20Sopenharmony_ci struct af9013_platform_data *pdata = client->dev.platform_data; 14388c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c; 14398c2ecf20Sopenharmony_ci int ret, i; 14408c2ecf20Sopenharmony_ci u8 firmware_version[4]; 14418c2ecf20Sopenharmony_ci static const struct regmap_bus regmap_bus = { 14428c2ecf20Sopenharmony_ci .read = af9013_regmap_read, 14438c2ecf20Sopenharmony_ci .write = af9013_regmap_write, 14448c2ecf20Sopenharmony_ci }; 14458c2ecf20Sopenharmony_ci static const struct regmap_config regmap_config = { 14468c2ecf20Sopenharmony_ci /* Actual reg is 16 bits, see i2c adapter lock */ 14478c2ecf20Sopenharmony_ci .reg_bits = 24, 14488c2ecf20Sopenharmony_ci .val_bits = 8, 14498c2ecf20Sopenharmony_ci }; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci state = kzalloc(sizeof(*state), GFP_KERNEL); 14528c2ecf20Sopenharmony_ci if (!state) { 14538c2ecf20Sopenharmony_ci ret = -ENOMEM; 14548c2ecf20Sopenharmony_ci goto err; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci /* Setup the state */ 14608c2ecf20Sopenharmony_ci state->client = client; 14618c2ecf20Sopenharmony_ci i2c_set_clientdata(client, state); 14628c2ecf20Sopenharmony_ci state->clk = pdata->clk; 14638c2ecf20Sopenharmony_ci state->tuner = pdata->tuner; 14648c2ecf20Sopenharmony_ci state->if_frequency = pdata->if_frequency; 14658c2ecf20Sopenharmony_ci state->ts_mode = pdata->ts_mode; 14668c2ecf20Sopenharmony_ci state->ts_output_pin = pdata->ts_output_pin; 14678c2ecf20Sopenharmony_ci state->spec_inv = pdata->spec_inv; 14688c2ecf20Sopenharmony_ci memcpy(&state->api_version, pdata->api_version, sizeof(state->api_version)); 14698c2ecf20Sopenharmony_ci memcpy(&state->gpio, pdata->gpio, sizeof(state->gpio)); 14708c2ecf20Sopenharmony_ci state->regmap = regmap_init(&client->dev, ®map_bus, client, 14718c2ecf20Sopenharmony_ci ®map_config); 14728c2ecf20Sopenharmony_ci if (IS_ERR(state->regmap)) { 14738c2ecf20Sopenharmony_ci ret = PTR_ERR(state->regmap); 14748c2ecf20Sopenharmony_ci goto err_kfree; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci /* Create mux i2c adapter */ 14778c2ecf20Sopenharmony_ci state->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, 0, 14788c2ecf20Sopenharmony_ci af9013_select, af9013_deselect); 14798c2ecf20Sopenharmony_ci if (!state->muxc) { 14808c2ecf20Sopenharmony_ci ret = -ENOMEM; 14818c2ecf20Sopenharmony_ci goto err_regmap_exit; 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci state->muxc->priv = state; 14848c2ecf20Sopenharmony_ci ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0); 14858c2ecf20Sopenharmony_ci if (ret) 14868c2ecf20Sopenharmony_ci goto err_regmap_exit; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci /* Download firmware */ 14898c2ecf20Sopenharmony_ci if (state->ts_mode != AF9013_TS_MODE_USB) { 14908c2ecf20Sopenharmony_ci ret = af9013_download_firmware(state); 14918c2ecf20Sopenharmony_ci if (ret) 14928c2ecf20Sopenharmony_ci goto err_i2c_mux_del_adapters; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci /* Firmware version */ 14968c2ecf20Sopenharmony_ci ret = regmap_bulk_read(state->regmap, 0x5103, firmware_version, 14978c2ecf20Sopenharmony_ci sizeof(firmware_version)); 14988c2ecf20Sopenharmony_ci if (ret) 14998c2ecf20Sopenharmony_ci goto err_i2c_mux_del_adapters; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci /* Set GPIOs */ 15028c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(state->gpio); i++) { 15038c2ecf20Sopenharmony_ci ret = af9013_set_gpio(state, i, state->gpio[i]); 15048c2ecf20Sopenharmony_ci if (ret) 15058c2ecf20Sopenharmony_ci goto err_i2c_mux_del_adapters; 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci /* Create dvb frontend */ 15098c2ecf20Sopenharmony_ci memcpy(&state->fe.ops, &af9013_ops, sizeof(state->fe.ops)); 15108c2ecf20Sopenharmony_ci state->fe.demodulator_priv = state; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci /* Setup callbacks */ 15138c2ecf20Sopenharmony_ci pdata->get_dvb_frontend = af9013_get_dvb_frontend; 15148c2ecf20Sopenharmony_ci pdata->get_i2c_adapter = af9013_get_i2c_adapter; 15158c2ecf20Sopenharmony_ci pdata->pid_filter = af9013_pid_filter; 15168c2ecf20Sopenharmony_ci pdata->pid_filter_ctrl = af9013_pid_filter_ctrl; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci /* Init stats to indicate which stats are supported */ 15198c2ecf20Sopenharmony_ci c = &state->fe.dtv_property_cache; 15208c2ecf20Sopenharmony_ci c->strength.len = 1; 15218c2ecf20Sopenharmony_ci c->cnr.len = 1; 15228c2ecf20Sopenharmony_ci c->post_bit_error.len = 1; 15238c2ecf20Sopenharmony_ci c->post_bit_count.len = 1; 15248c2ecf20Sopenharmony_ci c->block_error.len = 1; 15258c2ecf20Sopenharmony_ci c->block_count.len = 1; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci dev_info(&client->dev, "Afatech AF9013 successfully attached\n"); 15288c2ecf20Sopenharmony_ci dev_info(&client->dev, "firmware version: %d.%d.%d.%d\n", 15298c2ecf20Sopenharmony_ci firmware_version[0], firmware_version[1], 15308c2ecf20Sopenharmony_ci firmware_version[2], firmware_version[3]); 15318c2ecf20Sopenharmony_ci return 0; 15328c2ecf20Sopenharmony_cierr_i2c_mux_del_adapters: 15338c2ecf20Sopenharmony_ci i2c_mux_del_adapters(state->muxc); 15348c2ecf20Sopenharmony_cierr_regmap_exit: 15358c2ecf20Sopenharmony_ci regmap_exit(state->regmap); 15368c2ecf20Sopenharmony_cierr_kfree: 15378c2ecf20Sopenharmony_ci kfree(state); 15388c2ecf20Sopenharmony_cierr: 15398c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed %d\n", ret); 15408c2ecf20Sopenharmony_ci return ret; 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic int af9013_remove(struct i2c_client *client) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci struct af9013_state *state = i2c_get_clientdata(client); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci i2c_mux_del_adapters(state->muxc); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci regmap_exit(state->regmap); 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci kfree(state); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci return 0; 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_cistatic const struct i2c_device_id af9013_id_table[] = { 15598c2ecf20Sopenharmony_ci {"af9013", 0}, 15608c2ecf20Sopenharmony_ci {} 15618c2ecf20Sopenharmony_ci}; 15628c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, af9013_id_table); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_cistatic struct i2c_driver af9013_driver = { 15658c2ecf20Sopenharmony_ci .driver = { 15668c2ecf20Sopenharmony_ci .name = "af9013", 15678c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 15688c2ecf20Sopenharmony_ci }, 15698c2ecf20Sopenharmony_ci .probe = af9013_probe, 15708c2ecf20Sopenharmony_ci .remove = af9013_remove, 15718c2ecf20Sopenharmony_ci .id_table = af9013_id_table, 15728c2ecf20Sopenharmony_ci}; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_cimodule_i2c_driver(af9013_driver); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 15778c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver"); 15788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 15798c2ecf20Sopenharmony_ciMODULE_FIRMWARE(AF9013_FIRMWARE); 1580