162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ddbridge-sx8.c: Digital Devices MAX SX8 driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2018 Digital Devices GmbH 662306a36Sopenharmony_ci * Marcus Metzler <mocm@metzlerbros.de> 762306a36Sopenharmony_ci * Ralph Metzler <rjkm@metzlerbros.de> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "ddbridge.h" 1162306a36Sopenharmony_ci#include "ddbridge-io.h" 1262306a36Sopenharmony_ci#include "ddbridge-mci.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic const u32 MCLK = (1550000000 / 12); 1562306a36Sopenharmony_cistatic const u32 MAX_LDPC_BITRATE = (720000000); 1662306a36Sopenharmony_cistatic const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6); 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define SX8_TUNER_NUM 4 1962306a36Sopenharmony_ci#define SX8_DEMOD_NUM 8 2062306a36Sopenharmony_ci#define SX8_DEMOD_NONE 0xff 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct sx8_base { 2362306a36Sopenharmony_ci struct mci_base mci_base; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci u8 tuner_use_count[SX8_TUNER_NUM]; 2662306a36Sopenharmony_ci u32 gain_mode[SX8_TUNER_NUM]; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci u32 used_ldpc_bitrate[SX8_DEMOD_NUM]; 2962306a36Sopenharmony_ci u8 demod_in_use[SX8_DEMOD_NUM]; 3062306a36Sopenharmony_ci u32 iq_mode; 3162306a36Sopenharmony_ci u32 burst_size; 3262306a36Sopenharmony_ci u32 direct_mode; 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistruct sx8 { 3662306a36Sopenharmony_ci struct mci mci; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci int first_time_lock; 3962306a36Sopenharmony_ci int started; 4062306a36Sopenharmony_ci struct mci_result signal_info; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci u32 bb_mode; 4362306a36Sopenharmony_ci u32 local_frequency; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void release(struct dvb_frontend *fe) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 4962306a36Sopenharmony_ci struct mci_base *mci_base = state->mci.base; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci mci_base->count--; 5262306a36Sopenharmony_ci if (mci_base->count == 0) { 5362306a36Sopenharmony_ci list_del(&mci_base->mci_list); 5462306a36Sopenharmony_ci kfree(mci_base); 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci kfree(state); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int get_info(struct dvb_frontend *fe) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci int stat; 6262306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 6362306a36Sopenharmony_ci struct mci_command cmd; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 6662306a36Sopenharmony_ci cmd.command = MCI_CMD_GETSIGNALINFO; 6762306a36Sopenharmony_ci cmd.demod = state->mci.demod; 6862306a36Sopenharmony_ci stat = ddb_mci_cmd(&state->mci, &cmd, &state->signal_info); 6962306a36Sopenharmony_ci return stat; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int get_snr(struct dvb_frontend *fe) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 7562306a36Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci p->cnr.len = 1; 7862306a36Sopenharmony_ci p->cnr.stat[0].scale = FE_SCALE_DECIBEL; 7962306a36Sopenharmony_ci p->cnr.stat[0].svalue = 8062306a36Sopenharmony_ci (s64)state->signal_info.dvbs2_signal_info.signal_to_noise 8162306a36Sopenharmony_ci * 10; 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int get_strength(struct dvb_frontend *fe) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 8862306a36Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 8962306a36Sopenharmony_ci s32 str; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci str = 100000 - 9262306a36Sopenharmony_ci (state->signal_info.dvbs2_signal_info.channel_power 9362306a36Sopenharmony_ci * 10 + 108750); 9462306a36Sopenharmony_ci p->strength.len = 1; 9562306a36Sopenharmony_ci p->strength.stat[0].scale = FE_SCALE_DECIBEL; 9662306a36Sopenharmony_ci p->strength.stat[0].svalue = str; 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int read_status(struct dvb_frontend *fe, enum fe_status *status) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci int stat; 10362306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 10462306a36Sopenharmony_ci struct mci_command cmd; 10562306a36Sopenharmony_ci struct mci_result res; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci cmd.command = MCI_CMD_GETSTATUS; 10862306a36Sopenharmony_ci cmd.demod = state->mci.demod; 10962306a36Sopenharmony_ci stat = ddb_mci_cmd(&state->mci, &cmd, &res); 11062306a36Sopenharmony_ci if (stat) 11162306a36Sopenharmony_ci return stat; 11262306a36Sopenharmony_ci *status = 0x00; 11362306a36Sopenharmony_ci get_info(fe); 11462306a36Sopenharmony_ci get_strength(fe); 11562306a36Sopenharmony_ci if (res.status == SX8_DEMOD_WAIT_MATYPE) 11662306a36Sopenharmony_ci *status = 0x0f; 11762306a36Sopenharmony_ci if (res.status == SX8_DEMOD_LOCKED) { 11862306a36Sopenharmony_ci *status = 0x1f; 11962306a36Sopenharmony_ci get_snr(fe); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci return stat; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 12762306a36Sopenharmony_ci struct mci_base *mci_base = state->mci.base; 12862306a36Sopenharmony_ci struct sx8_base *sx8_base = (struct sx8_base *)mci_base; 12962306a36Sopenharmony_ci struct mci_command cmd; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 13262306a36Sopenharmony_ci cmd.tuner = state->mci.tuner; 13362306a36Sopenharmony_ci cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE; 13462306a36Sopenharmony_ci cmd.sx8_input_enable.flags = sx8_base->gain_mode[state->mci.tuner]; 13562306a36Sopenharmony_ci return ddb_mci_cmd(&state->mci, &cmd, NULL); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic int stop(struct dvb_frontend *fe) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 14162306a36Sopenharmony_ci struct mci_base *mci_base = state->mci.base; 14262306a36Sopenharmony_ci struct sx8_base *sx8_base = (struct sx8_base *)mci_base; 14362306a36Sopenharmony_ci struct mci_command cmd; 14462306a36Sopenharmony_ci u32 input = state->mci.tuner; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 14762306a36Sopenharmony_ci if (state->mci.demod != SX8_DEMOD_NONE) { 14862306a36Sopenharmony_ci cmd.command = MCI_CMD_STOP; 14962306a36Sopenharmony_ci cmd.demod = state->mci.demod; 15062306a36Sopenharmony_ci ddb_mci_cmd(&state->mci, &cmd, NULL); 15162306a36Sopenharmony_ci if (sx8_base->iq_mode) { 15262306a36Sopenharmony_ci cmd.command = SX8_CMD_DISABLE_IQOUTPUT; 15362306a36Sopenharmony_ci cmd.demod = state->mci.demod; 15462306a36Sopenharmony_ci cmd.output = 0; 15562306a36Sopenharmony_ci ddb_mci_cmd(&state->mci, &cmd, NULL); 15662306a36Sopenharmony_ci ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci mutex_lock(&mci_base->tuner_lock); 16062306a36Sopenharmony_ci sx8_base->tuner_use_count[input]--; 16162306a36Sopenharmony_ci if (!sx8_base->tuner_use_count[input]) 16262306a36Sopenharmony_ci mci_set_tuner(fe, input, 0); 16362306a36Sopenharmony_ci if (state->mci.demod < SX8_DEMOD_NUM) { 16462306a36Sopenharmony_ci sx8_base->demod_in_use[state->mci.demod] = 0; 16562306a36Sopenharmony_ci state->mci.demod = SX8_DEMOD_NONE; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci sx8_base->used_ldpc_bitrate[state->mci.nr] = 0; 16862306a36Sopenharmony_ci sx8_base->iq_mode = 0; 16962306a36Sopenharmony_ci mutex_unlock(&mci_base->tuner_lock); 17062306a36Sopenharmony_ci state->started = 0; 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 17762306a36Sopenharmony_ci struct mci_base *mci_base = state->mci.base; 17862306a36Sopenharmony_ci struct sx8_base *sx8_base = (struct sx8_base *)mci_base; 17962306a36Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 18062306a36Sopenharmony_ci u32 used_ldpc_bitrate = 0, free_ldpc_bitrate; 18162306a36Sopenharmony_ci u32 used_demods = 0; 18262306a36Sopenharmony_ci struct mci_command cmd; 18362306a36Sopenharmony_ci u32 input = state->mci.tuner; 18462306a36Sopenharmony_ci u32 bits_per_symbol = 0; 18562306a36Sopenharmony_ci int i = -1, stat = 0; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (p->symbol_rate >= (MCLK / 2)) 18862306a36Sopenharmony_ci flags &= ~1; 18962306a36Sopenharmony_ci if ((flags & 3) == 0) 19062306a36Sopenharmony_ci return -EINVAL; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (flags & 2) { 19362306a36Sopenharmony_ci u32 tmp = modmask; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci bits_per_symbol = 1; 19662306a36Sopenharmony_ci while (tmp & 1) { 19762306a36Sopenharmony_ci tmp >>= 1; 19862306a36Sopenharmony_ci bits_per_symbol++; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci mutex_lock(&mci_base->tuner_lock); 20362306a36Sopenharmony_ci if (sx8_base->iq_mode) { 20462306a36Sopenharmony_ci stat = -EBUSY; 20562306a36Sopenharmony_ci goto unlock; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (sx8_base->direct_mode) { 20962306a36Sopenharmony_ci if (p->symbol_rate >= MCLK / 2) { 21062306a36Sopenharmony_ci if (state->mci.nr < 4) 21162306a36Sopenharmony_ci i = state->mci.nr; 21262306a36Sopenharmony_ci } else { 21362306a36Sopenharmony_ci i = state->mci.nr; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci } else { 21662306a36Sopenharmony_ci for (i = 0; i < SX8_DEMOD_NUM; i++) { 21762306a36Sopenharmony_ci used_ldpc_bitrate += sx8_base->used_ldpc_bitrate[i]; 21862306a36Sopenharmony_ci if (sx8_base->demod_in_use[i]) 21962306a36Sopenharmony_ci used_demods++; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci if (used_ldpc_bitrate >= MAX_LDPC_BITRATE || 22262306a36Sopenharmony_ci ((ts_config & SX8_TSCONFIG_MODE_MASK) > 22362306a36Sopenharmony_ci SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) { 22462306a36Sopenharmony_ci stat = -EBUSY; 22562306a36Sopenharmony_ci goto unlock; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate; 22862306a36Sopenharmony_ci if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE) 22962306a36Sopenharmony_ci free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate) 23262306a36Sopenharmony_ci bits_per_symbol--; 23362306a36Sopenharmony_ci if (bits_per_symbol < 2) { 23462306a36Sopenharmony_ci stat = -EBUSY; 23562306a36Sopenharmony_ci goto unlock; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci modmask &= ((1 << (bits_per_symbol - 1)) - 1); 23962306a36Sopenharmony_ci if (((flags & 0x02) != 0) && modmask == 0) { 24062306a36Sopenharmony_ci stat = -EBUSY; 24162306a36Sopenharmony_ci goto unlock; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci i = (p->symbol_rate > (MCLK / 2)) ? 3 : 7; 24562306a36Sopenharmony_ci while (i >= 0 && sx8_base->demod_in_use[i]) 24662306a36Sopenharmony_ci i--; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (i < 0) { 25062306a36Sopenharmony_ci stat = -EBUSY; 25162306a36Sopenharmony_ci goto unlock; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci sx8_base->demod_in_use[i] = 1; 25462306a36Sopenharmony_ci sx8_base->used_ldpc_bitrate[state->mci.nr] = p->symbol_rate 25562306a36Sopenharmony_ci * bits_per_symbol; 25662306a36Sopenharmony_ci state->mci.demod = i; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!sx8_base->tuner_use_count[input]) 25962306a36Sopenharmony_ci mci_set_tuner(fe, input, 1); 26062306a36Sopenharmony_ci sx8_base->tuner_use_count[input]++; 26162306a36Sopenharmony_ci sx8_base->iq_mode = (ts_config > 1); 26262306a36Sopenharmony_ciunlock: 26362306a36Sopenharmony_ci mutex_unlock(&mci_base->tuner_lock); 26462306a36Sopenharmony_ci if (stat) 26562306a36Sopenharmony_ci return stat; 26662306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (sx8_base->iq_mode) { 26962306a36Sopenharmony_ci cmd.command = SX8_CMD_ENABLE_IQOUTPUT; 27062306a36Sopenharmony_ci cmd.demod = state->mci.demod; 27162306a36Sopenharmony_ci cmd.output = 0; 27262306a36Sopenharmony_ci ddb_mci_cmd(&state->mci, &cmd, NULL); 27362306a36Sopenharmony_ci ddb_mci_config(&state->mci, ts_config); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci if (p->stream_id != NO_STREAM_ID_FILTER && p->stream_id != 0x80000000) 27662306a36Sopenharmony_ci flags |= 0x80; 27762306a36Sopenharmony_ci dev_dbg(mci_base->dev, "MCI-%d: tuner=%d demod=%d\n", 27862306a36Sopenharmony_ci state->mci.nr, state->mci.tuner, state->mci.demod); 27962306a36Sopenharmony_ci cmd.command = MCI_CMD_SEARCH_DVBS; 28062306a36Sopenharmony_ci cmd.dvbs2_search.flags = flags; 28162306a36Sopenharmony_ci cmd.dvbs2_search.s2_modulation_mask = modmask; 28262306a36Sopenharmony_ci cmd.dvbs2_search.retry = 2; 28362306a36Sopenharmony_ci cmd.dvbs2_search.frequency = p->frequency * 1000; 28462306a36Sopenharmony_ci cmd.dvbs2_search.symbol_rate = p->symbol_rate; 28562306a36Sopenharmony_ci cmd.dvbs2_search.scrambling_sequence_index = 28662306a36Sopenharmony_ci p->scrambling_sequence_index | 0x80000000; 28762306a36Sopenharmony_ci cmd.dvbs2_search.input_stream_id = 28862306a36Sopenharmony_ci (p->stream_id != NO_STREAM_ID_FILTER) ? p->stream_id : 0; 28962306a36Sopenharmony_ci cmd.tuner = state->mci.tuner; 29062306a36Sopenharmony_ci cmd.demod = state->mci.demod; 29162306a36Sopenharmony_ci cmd.output = state->mci.nr; 29262306a36Sopenharmony_ci if (p->stream_id == 0x80000000) 29362306a36Sopenharmony_ci cmd.output |= 0x80; 29462306a36Sopenharmony_ci stat = ddb_mci_cmd(&state->mci, &cmd, NULL); 29562306a36Sopenharmony_ci if (stat) 29662306a36Sopenharmony_ci stop(fe); 29762306a36Sopenharmony_ci return stat; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int start_iq(struct dvb_frontend *fe, u32 flags, u32 roll_off, 30162306a36Sopenharmony_ci u32 ts_config) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 30462306a36Sopenharmony_ci struct mci_base *mci_base = state->mci.base; 30562306a36Sopenharmony_ci struct sx8_base *sx8_base = (struct sx8_base *)mci_base; 30662306a36Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 30762306a36Sopenharmony_ci u32 used_demods = 0; 30862306a36Sopenharmony_ci struct mci_command cmd; 30962306a36Sopenharmony_ci u32 input = state->mci.tuner; 31062306a36Sopenharmony_ci int i, stat = 0; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci mutex_lock(&mci_base->tuner_lock); 31362306a36Sopenharmony_ci if (sx8_base->iq_mode) { 31462306a36Sopenharmony_ci stat = -EBUSY; 31562306a36Sopenharmony_ci goto unlock; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci for (i = 0; i < SX8_DEMOD_NUM; i++) 31862306a36Sopenharmony_ci if (sx8_base->demod_in_use[i]) 31962306a36Sopenharmony_ci used_demods++; 32062306a36Sopenharmony_ci if (used_demods > 0) { 32162306a36Sopenharmony_ci stat = -EBUSY; 32262306a36Sopenharmony_ci goto unlock; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci state->mci.demod = 0; 32562306a36Sopenharmony_ci if (!sx8_base->tuner_use_count[input]) 32662306a36Sopenharmony_ci mci_set_tuner(fe, input, 1); 32762306a36Sopenharmony_ci sx8_base->tuner_use_count[input]++; 32862306a36Sopenharmony_ci sx8_base->iq_mode = (ts_config > 1); 32962306a36Sopenharmony_ciunlock: 33062306a36Sopenharmony_ci mutex_unlock(&mci_base->tuner_lock); 33162306a36Sopenharmony_ci if (stat) 33262306a36Sopenharmony_ci return stat; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 33562306a36Sopenharmony_ci cmd.command = SX8_CMD_START_IQ; 33662306a36Sopenharmony_ci cmd.sx8_start_iq.flags = flags; 33762306a36Sopenharmony_ci cmd.sx8_start_iq.roll_off = roll_off; 33862306a36Sopenharmony_ci cmd.sx8_start_iq.frequency = p->frequency * 1000; 33962306a36Sopenharmony_ci cmd.sx8_start_iq.symbol_rate = p->symbol_rate; 34062306a36Sopenharmony_ci cmd.tuner = state->mci.tuner; 34162306a36Sopenharmony_ci cmd.demod = state->mci.demod; 34262306a36Sopenharmony_ci stat = ddb_mci_cmd(&state->mci, &cmd, NULL); 34362306a36Sopenharmony_ci if (stat) 34462306a36Sopenharmony_ci stop(fe); 34562306a36Sopenharmony_ci ddb_mci_config(&state->mci, ts_config); 34662306a36Sopenharmony_ci return stat; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int set_parameters(struct dvb_frontend *fe) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci int stat = 0; 35262306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 35362306a36Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 35462306a36Sopenharmony_ci u32 ts_config = SX8_TSCONFIG_MODE_NORMAL, iq_mode = 0, isi; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (state->started) 35762306a36Sopenharmony_ci stop(fe); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci isi = p->stream_id; 36062306a36Sopenharmony_ci if (isi != NO_STREAM_ID_FILTER) 36162306a36Sopenharmony_ci iq_mode = (isi & 0x30000000) >> 28; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (iq_mode) 36462306a36Sopenharmony_ci ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ); 36562306a36Sopenharmony_ci if (iq_mode < 3) { 36662306a36Sopenharmony_ci u32 mask; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci switch (p->modulation) { 36962306a36Sopenharmony_ci /* uncomment whenever these modulations hit the DVB API 37062306a36Sopenharmony_ci * case APSK_256: 37162306a36Sopenharmony_ci * mask = 0x7f; 37262306a36Sopenharmony_ci * break; 37362306a36Sopenharmony_ci * case APSK_128: 37462306a36Sopenharmony_ci * mask = 0x3f; 37562306a36Sopenharmony_ci * break; 37662306a36Sopenharmony_ci * case APSK_64: 37762306a36Sopenharmony_ci * mask = 0x1f; 37862306a36Sopenharmony_ci * break; 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci case APSK_32: 38162306a36Sopenharmony_ci mask = 0x0f; 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci case APSK_16: 38462306a36Sopenharmony_ci mask = 0x07; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci default: 38762306a36Sopenharmony_ci mask = 0x03; 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci stat = start(fe, 3, mask, ts_config); 39162306a36Sopenharmony_ci } else { 39262306a36Sopenharmony_ci stat = start_iq(fe, 0, 4, ts_config); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci if (!stat) { 39562306a36Sopenharmony_ci state->started = 1; 39662306a36Sopenharmony_ci state->first_time_lock = 1; 39762306a36Sopenharmony_ci state->signal_info.status = SX8_DEMOD_WAIT_SIGNAL; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return stat; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int tune(struct dvb_frontend *fe, bool re_tune, 40462306a36Sopenharmony_ci unsigned int mode_flags, 40562306a36Sopenharmony_ci unsigned int *delay, enum fe_status *status) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci int r; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (re_tune) { 41062306a36Sopenharmony_ci r = set_parameters(fe); 41162306a36Sopenharmony_ci if (r) 41262306a36Sopenharmony_ci return r; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci r = read_status(fe, status); 41562306a36Sopenharmony_ci if (r) 41662306a36Sopenharmony_ci return r; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (*status & FE_HAS_LOCK) 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci *delay = HZ / 10; 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic enum dvbfe_algo get_algo(struct dvb_frontend *fe) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci return DVBFE_ALGO_HW; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic int set_input(struct dvb_frontend *fe, int input) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct sx8 *state = fe->demodulator_priv; 43262306a36Sopenharmony_ci struct mci_base *mci_base = state->mci.base; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (input >= SX8_TUNER_NUM) 43562306a36Sopenharmony_ci return -EINVAL; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci state->mci.tuner = input; 43862306a36Sopenharmony_ci dev_dbg(mci_base->dev, "MCI-%d: input=%d\n", state->mci.nr, input); 43962306a36Sopenharmony_ci return 0; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic struct dvb_frontend_ops sx8_ops = { 44362306a36Sopenharmony_ci .delsys = { SYS_DVBS, SYS_DVBS2 }, 44462306a36Sopenharmony_ci .info = { 44562306a36Sopenharmony_ci .name = "Digital Devices MaxSX8 MCI DVB-S/S2/S2X", 44662306a36Sopenharmony_ci .frequency_min_hz = 950 * MHz, 44762306a36Sopenharmony_ci .frequency_max_hz = 2150 * MHz, 44862306a36Sopenharmony_ci .symbol_rate_min = 100000, 44962306a36Sopenharmony_ci .symbol_rate_max = 100000000, 45062306a36Sopenharmony_ci .caps = FE_CAN_INVERSION_AUTO | 45162306a36Sopenharmony_ci FE_CAN_FEC_AUTO | 45262306a36Sopenharmony_ci FE_CAN_QPSK | 45362306a36Sopenharmony_ci FE_CAN_2G_MODULATION | 45462306a36Sopenharmony_ci FE_CAN_MULTISTREAM, 45562306a36Sopenharmony_ci }, 45662306a36Sopenharmony_ci .get_frontend_algo = get_algo, 45762306a36Sopenharmony_ci .tune = tune, 45862306a36Sopenharmony_ci .release = release, 45962306a36Sopenharmony_ci .read_status = read_status, 46062306a36Sopenharmony_ci}; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int init(struct mci *mci) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct sx8 *state = (struct sx8 *)mci; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci state->mci.demod = SX8_DEMOD_NONE; 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ciconst struct mci_cfg ddb_max_sx8_cfg = { 47162306a36Sopenharmony_ci .type = 0, 47262306a36Sopenharmony_ci .fe_ops = &sx8_ops, 47362306a36Sopenharmony_ci .base_size = sizeof(struct sx8_base), 47462306a36Sopenharmony_ci .state_size = sizeof(struct sx8), 47562306a36Sopenharmony_ci .init = init, 47662306a36Sopenharmony_ci .set_input = set_input, 47762306a36Sopenharmony_ci}; 478