18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TTUSB DEC Frontend Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 98c2ecf20Sopenharmony_ci#include "ttusbdecfe.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define LOF_HI 10600000 138c2ecf20Sopenharmony_ci#define LOF_LO 9750000 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct ttusbdecfe_state { 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci /* configuration settings */ 188c2ecf20Sopenharmony_ci const struct ttusbdecfe_config* config; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci u8 hi_band; 238c2ecf20Sopenharmony_ci u8 voltage; 248c2ecf20Sopenharmony_ci}; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe, 288c2ecf20Sopenharmony_ci enum fe_status *status) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | 318c2ecf20Sopenharmony_ci FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; 328c2ecf20Sopenharmony_ci return 0; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, 378c2ecf20Sopenharmony_ci enum fe_status *status) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct ttusbdecfe_state* state = fe->demodulator_priv; 408c2ecf20Sopenharmony_ci u8 b[] = { 0x00, 0x00, 0x00, 0x00, 418c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00 }; 428c2ecf20Sopenharmony_ci u8 result[4]; 438c2ecf20Sopenharmony_ci int len, ret; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci *status=0; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result); 488c2ecf20Sopenharmony_ci if(ret) 498c2ecf20Sopenharmony_ci return ret; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if(len != 4) { 528c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: unexpected reply\n", __func__); 538c2ecf20Sopenharmony_ci return -EIO; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci switch(result[3]) { 578c2ecf20Sopenharmony_ci case 1: /* not tuned yet */ 588c2ecf20Sopenharmony_ci case 2: /* no signal/no lock*/ 598c2ecf20Sopenharmony_ci break; 608c2ecf20Sopenharmony_ci case 3: /* signal found and locked*/ 618c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | 628c2ecf20Sopenharmony_ci FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; 638c2ecf20Sopenharmony_ci break; 648c2ecf20Sopenharmony_ci case 4: 658c2ecf20Sopenharmony_ci *status = FE_TIMEDOUT; 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci default: 688c2ecf20Sopenharmony_ci pr_info("%s: returned unknown value: %d\n", 698c2ecf20Sopenharmony_ci __func__, result[3]); 708c2ecf20Sopenharmony_ci return -EIO; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend *fe) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 798c2ecf20Sopenharmony_ci struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; 808c2ecf20Sopenharmony_ci u8 b[] = { 0x00, 0x00, 0x00, 0x03, 818c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 828c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x01, 838c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0xff, 848c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0xff }; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci __be32 freq = htonl(p->frequency / 1000); 878c2ecf20Sopenharmony_ci memcpy(&b[4], &freq, sizeof (u32)); 888c2ecf20Sopenharmony_ci state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe, 948c2ecf20Sopenharmony_ci struct dvb_frontend_tune_settings* fesettings) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci fesettings->min_delay_ms = 1500; 978c2ecf20Sopenharmony_ci /* Drift compensation makes no sense for DVB-T */ 988c2ecf20Sopenharmony_ci fesettings->step_size = 0; 998c2ecf20Sopenharmony_ci fesettings->max_drift = 0; 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 1068c2ecf20Sopenharmony_ci struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci u8 b[] = { 0x00, 0x00, 0x00, 0x01, 1098c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 1108c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x01, 1118c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 1128c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 1138c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 1148c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 1158c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 1168c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 1178c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00 }; 1188c2ecf20Sopenharmony_ci __be32 freq; 1198c2ecf20Sopenharmony_ci __be32 sym_rate; 1208c2ecf20Sopenharmony_ci __be32 band; 1218c2ecf20Sopenharmony_ci __be32 lnb_voltage; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci freq = htonl(p->frequency + 1248c2ecf20Sopenharmony_ci (state->hi_band ? LOF_HI : LOF_LO)); 1258c2ecf20Sopenharmony_ci memcpy(&b[4], &freq, sizeof(u32)); 1268c2ecf20Sopenharmony_ci sym_rate = htonl(p->symbol_rate); 1278c2ecf20Sopenharmony_ci memcpy(&b[12], &sym_rate, sizeof(u32)); 1288c2ecf20Sopenharmony_ci band = htonl(state->hi_band ? LOF_HI : LOF_LO); 1298c2ecf20Sopenharmony_ci memcpy(&b[24], &band, sizeof(u32)); 1308c2ecf20Sopenharmony_ci lnb_voltage = htonl(state->voltage); 1318c2ecf20Sopenharmony_ci memcpy(&b[28], &lnb_voltage, sizeof(u32)); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; 1418c2ecf20Sopenharmony_ci u8 b[] = { 0x00, 0xff, 0x00, 0x00, 1428c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 1438c2ecf20Sopenharmony_ci 0x00, 0x00 }; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (cmd->msg_len > sizeof(b) - 4) 1468c2ecf20Sopenharmony_ci return -EINVAL; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci memcpy(&b[4], cmd->msg, cmd->msg_len); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci state->config->send_command(fe, 0x72, 1518c2ecf20Sopenharmony_ci sizeof(b) - (6 - cmd->msg_len), b, 1528c2ecf20Sopenharmony_ci NULL, NULL); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic int ttusbdecfe_dvbs_set_tone(struct dvb_frontend *fe, 1598c2ecf20Sopenharmony_ci enum fe_sec_tone_mode tone) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci state->hi_band = (SEC_TONE_ON == tone); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend *fe, 1708c2ecf20Sopenharmony_ci enum fe_sec_voltage voltage) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci switch (voltage) { 1758c2ecf20Sopenharmony_ci case SEC_VOLTAGE_13: 1768c2ecf20Sopenharmony_ci state->voltage = 13; 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci case SEC_VOLTAGE_18: 1798c2ecf20Sopenharmony_ci state->voltage = 18; 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci default: 1828c2ecf20Sopenharmony_ci return -EINVAL; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void ttusbdecfe_release(struct dvb_frontend* fe) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; 1918c2ecf20Sopenharmony_ci kfree(state); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops ttusbdecfe_dvbt_ops; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistruct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct ttusbdecfe_state* state = NULL; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 2018c2ecf20Sopenharmony_ci state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); 2028c2ecf20Sopenharmony_ci if (state == NULL) 2038c2ecf20Sopenharmony_ci return NULL; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* setup the state */ 2068c2ecf20Sopenharmony_ci state->config = config; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* create dvb_frontend */ 2098c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops)); 2108c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 2118c2ecf20Sopenharmony_ci return &state->frontend; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops ttusbdecfe_dvbs_ops; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistruct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct ttusbdecfe_state* state = NULL; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 2218c2ecf20Sopenharmony_ci state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); 2228c2ecf20Sopenharmony_ci if (state == NULL) 2238c2ecf20Sopenharmony_ci return NULL; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* setup the state */ 2268c2ecf20Sopenharmony_ci state->config = config; 2278c2ecf20Sopenharmony_ci state->voltage = 0; 2288c2ecf20Sopenharmony_ci state->hi_band = 0; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* create dvb_frontend */ 2318c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops)); 2328c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 2338c2ecf20Sopenharmony_ci return &state->frontend; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { 2378c2ecf20Sopenharmony_ci .delsys = { SYS_DVBT }, 2388c2ecf20Sopenharmony_ci .info = { 2398c2ecf20Sopenharmony_ci .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", 2408c2ecf20Sopenharmony_ci .frequency_min_hz = 51 * MHz, 2418c2ecf20Sopenharmony_ci .frequency_max_hz = 858 * MHz, 2428c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 62500, 2438c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 2448c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 2458c2ecf20Sopenharmony_ci FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 2468c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | 2478c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO, 2488c2ecf20Sopenharmony_ci }, 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci .release = ttusbdecfe_release, 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci .set_frontend = ttusbdecfe_dvbt_set_frontend, 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci .read_status = ttusbdecfe_dvbt_read_status, 2578c2ecf20Sopenharmony_ci}; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { 2608c2ecf20Sopenharmony_ci .delsys = { SYS_DVBS }, 2618c2ecf20Sopenharmony_ci .info = { 2628c2ecf20Sopenharmony_ci .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", 2638c2ecf20Sopenharmony_ci .frequency_min_hz = 950 * MHz, 2648c2ecf20Sopenharmony_ci .frequency_max_hz = 2150 * MHz, 2658c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 125 * kHz, 2668c2ecf20Sopenharmony_ci .symbol_rate_min = 1000000, /* guessed */ 2678c2ecf20Sopenharmony_ci .symbol_rate_max = 45000000, /* guessed */ 2688c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 2698c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 2708c2ecf20Sopenharmony_ci FE_CAN_QPSK 2718c2ecf20Sopenharmony_ci }, 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci .release = ttusbdecfe_release, 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci .set_frontend = ttusbdecfe_dvbs_set_frontend, 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci .read_status = ttusbdecfe_dvbs_read_status, 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, 2808c2ecf20Sopenharmony_ci .set_voltage = ttusbdecfe_dvbs_set_voltage, 2818c2ecf20Sopenharmony_ci .set_tone = ttusbdecfe_dvbs_set_tone, 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver"); 2858c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alex Woods/Andrew de Quincey"); 2868c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ttusbdecfe_dvbt_attach); 2898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ttusbdecfe_dvbs_attach); 290