18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * FireDTV driver (formerly known as FireSAT) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/errno.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "firedtv.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int fdtv_dvb_init(struct dvb_frontend *fe) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct firedtv *fdtv = fe->sec_priv; 228c2ecf20Sopenharmony_ci int err; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci /* FIXME - allocate free channel at IRM */ 258c2ecf20Sopenharmony_ci fdtv->isochannel = fdtv->adapter.num; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci err = cmp_establish_pp_connection(fdtv, fdtv->subunit, 288c2ecf20Sopenharmony_ci fdtv->isochannel); 298c2ecf20Sopenharmony_ci if (err) { 308c2ecf20Sopenharmony_ci dev_err(fdtv->device, 318c2ecf20Sopenharmony_ci "could not establish point to point connection\n"); 328c2ecf20Sopenharmony_ci return err; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return fdtv_start_iso(fdtv); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int fdtv_sleep(struct dvb_frontend *fe) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct firedtv *fdtv = fe->sec_priv; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci fdtv_stop_iso(fdtv); 438c2ecf20Sopenharmony_ci cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel); 448c2ecf20Sopenharmony_ci fdtv->isochannel = -1; 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define LNBCONTROL_DONTCARE 0xff 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe, 518c2ecf20Sopenharmony_ci struct dvb_diseqc_master_cmd *cmd) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct firedtv *fdtv = fe->sec_priv; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, 568c2ecf20Sopenharmony_ci LNBCONTROL_DONTCARE, 1, cmd); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int fdtv_diseqc_send_burst(struct dvb_frontend *fe, 608c2ecf20Sopenharmony_ci enum fe_sec_mini_cmd minicmd) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci return 0; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int fdtv_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct firedtv *fdtv = fe->sec_priv; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci fdtv->tone = tone; 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int fdtv_set_voltage(struct dvb_frontend *fe, 748c2ecf20Sopenharmony_ci enum fe_sec_voltage voltage) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct firedtv *fdtv = fe->sec_priv; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci fdtv->voltage = voltage; 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int fdtv_read_status(struct dvb_frontend *fe, enum fe_status *status) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct firedtv *fdtv = fe->sec_priv; 858c2ecf20Sopenharmony_ci struct firedtv_tuner_status stat; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (avc_tuner_status(fdtv, &stat)) 888c2ecf20Sopenharmony_ci return -EINVAL; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (stat.no_rf) 918c2ecf20Sopenharmony_ci *status = 0; 928c2ecf20Sopenharmony_ci else 938c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | 948c2ecf20Sopenharmony_ci FE_HAS_CARRIER | FE_HAS_LOCK; 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct firedtv *fdtv = fe->sec_priv; 1018c2ecf20Sopenharmony_ci struct firedtv_tuner_status stat; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (avc_tuner_status(fdtv, &stat)) 1048c2ecf20Sopenharmony_ci return -EINVAL; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci *ber = stat.ber; 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct firedtv *fdtv = fe->sec_priv; 1138c2ecf20Sopenharmony_ci struct firedtv_tuner_status stat; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (avc_tuner_status(fdtv, &stat)) 1168c2ecf20Sopenharmony_ci return -EINVAL; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci *strength = stat.signal_strength << 8; 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct firedtv *fdtv = fe->sec_priv; 1258c2ecf20Sopenharmony_ci struct firedtv_tuner_status stat; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (avc_tuner_status(fdtv, &stat)) 1288c2ecf20Sopenharmony_ci return -EINVAL; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* C/N[dB] = -10 * log10(snr / 65535) */ 1318c2ecf20Sopenharmony_ci *snr = stat.carrier_noise_ratio * 257; 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic int fdtv_set_frontend(struct dvb_frontend *fe) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 1438c2ecf20Sopenharmony_ci struct firedtv *fdtv = fe->sec_priv; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return avc_tuner_dsd(fdtv, p); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_civoid fdtv_frontend_init(struct firedtv *fdtv, const char *name) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct dvb_frontend_ops *ops = &fdtv->fe.ops; 1518c2ecf20Sopenharmony_ci struct dvb_frontend_internal_info *fi = &ops->info; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci ops->init = fdtv_dvb_init; 1548c2ecf20Sopenharmony_ci ops->sleep = fdtv_sleep; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ops->set_frontend = fdtv_set_frontend; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci ops->read_status = fdtv_read_status; 1598c2ecf20Sopenharmony_ci ops->read_ber = fdtv_read_ber; 1608c2ecf20Sopenharmony_ci ops->read_signal_strength = fdtv_read_signal_strength; 1618c2ecf20Sopenharmony_ci ops->read_snr = fdtv_read_snr; 1628c2ecf20Sopenharmony_ci ops->read_ucblocks = fdtv_read_uncorrected_blocks; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci ops->diseqc_send_master_cmd = fdtv_diseqc_send_master_cmd; 1658c2ecf20Sopenharmony_ci ops->diseqc_send_burst = fdtv_diseqc_send_burst; 1668c2ecf20Sopenharmony_ci ops->set_tone = fdtv_set_tone; 1678c2ecf20Sopenharmony_ci ops->set_voltage = fdtv_set_voltage; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci switch (fdtv->type) { 1708c2ecf20Sopenharmony_ci case FIREDTV_DVB_S: 1718c2ecf20Sopenharmony_ci ops->delsys[0] = SYS_DVBS; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci fi->frequency_min_hz = 950 * MHz; 1748c2ecf20Sopenharmony_ci fi->frequency_max_hz = 2150 * MHz; 1758c2ecf20Sopenharmony_ci fi->frequency_stepsize_hz = 125 * kHz; 1768c2ecf20Sopenharmony_ci fi->symbol_rate_min = 1000000; 1778c2ecf20Sopenharmony_ci fi->symbol_rate_max = 40000000; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci fi->caps = FE_CAN_INVERSION_AUTO | 1808c2ecf20Sopenharmony_ci FE_CAN_FEC_1_2 | 1818c2ecf20Sopenharmony_ci FE_CAN_FEC_2_3 | 1828c2ecf20Sopenharmony_ci FE_CAN_FEC_3_4 | 1838c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | 1848c2ecf20Sopenharmony_ci FE_CAN_FEC_7_8 | 1858c2ecf20Sopenharmony_ci FE_CAN_FEC_AUTO | 1868c2ecf20Sopenharmony_ci FE_CAN_QPSK; 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci case FIREDTV_DVB_S2: 1908c2ecf20Sopenharmony_ci ops->delsys[0] = SYS_DVBS; 1918c2ecf20Sopenharmony_ci ops->delsys[1] = SYS_DVBS2; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci fi->frequency_min_hz = 950 * MHz; 1948c2ecf20Sopenharmony_ci fi->frequency_max_hz = 2150 * MHz; 1958c2ecf20Sopenharmony_ci fi->frequency_stepsize_hz = 125 * kHz; 1968c2ecf20Sopenharmony_ci fi->symbol_rate_min = 1000000; 1978c2ecf20Sopenharmony_ci fi->symbol_rate_max = 40000000; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci fi->caps = FE_CAN_INVERSION_AUTO | 2008c2ecf20Sopenharmony_ci FE_CAN_FEC_1_2 | 2018c2ecf20Sopenharmony_ci FE_CAN_FEC_2_3 | 2028c2ecf20Sopenharmony_ci FE_CAN_FEC_3_4 | 2038c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | 2048c2ecf20Sopenharmony_ci FE_CAN_FEC_7_8 | 2058c2ecf20Sopenharmony_ci FE_CAN_FEC_AUTO | 2068c2ecf20Sopenharmony_ci FE_CAN_QPSK | 2078c2ecf20Sopenharmony_ci FE_CAN_2G_MODULATION; 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci case FIREDTV_DVB_C: 2118c2ecf20Sopenharmony_ci ops->delsys[0] = SYS_DVBC_ANNEX_A; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci fi->frequency_min_hz = 47 * MHz; 2148c2ecf20Sopenharmony_ci fi->frequency_max_hz = 866 * MHz; 2158c2ecf20Sopenharmony_ci fi->frequency_stepsize_hz = 62500; 2168c2ecf20Sopenharmony_ci fi->symbol_rate_min = 870000; 2178c2ecf20Sopenharmony_ci fi->symbol_rate_max = 6900000; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci fi->caps = FE_CAN_INVERSION_AUTO | 2208c2ecf20Sopenharmony_ci FE_CAN_QAM_16 | 2218c2ecf20Sopenharmony_ci FE_CAN_QAM_32 | 2228c2ecf20Sopenharmony_ci FE_CAN_QAM_64 | 2238c2ecf20Sopenharmony_ci FE_CAN_QAM_128 | 2248c2ecf20Sopenharmony_ci FE_CAN_QAM_256 | 2258c2ecf20Sopenharmony_ci FE_CAN_QAM_AUTO; 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci case FIREDTV_DVB_T: 2298c2ecf20Sopenharmony_ci ops->delsys[0] = SYS_DVBT; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci fi->frequency_min_hz = 49 * MHz; 2328c2ecf20Sopenharmony_ci fi->frequency_max_hz = 861 * MHz; 2338c2ecf20Sopenharmony_ci fi->frequency_stepsize_hz = 62500; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci fi->caps = FE_CAN_INVERSION_AUTO | 2368c2ecf20Sopenharmony_ci FE_CAN_FEC_2_3 | 2378c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | 2388c2ecf20Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | 2398c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO; 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci default: 2438c2ecf20Sopenharmony_ci dev_err(fdtv->device, "no frontend for model type %d\n", 2448c2ecf20Sopenharmony_ci fdtv->type); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci strscpy(fi->name, name, sizeof(fi->name)); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci fdtv->fe.dvb = &fdtv->adapter; 2498c2ecf20Sopenharmony_ci fdtv->fe.sec_priv = fdtv; 2508c2ecf20Sopenharmony_ci} 251