18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * c8sectpfe-dvb.c - C8SECTPFE STi DVB driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) STMicroelectronics 2015 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author Peter Griffin <peter.griffin@linaro.org> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/completion.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/i2c.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/version.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <dt-bindings/media/c8sectpfe.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "c8sectpfe-common.h" 198c2ecf20Sopenharmony_ci#include "c8sectpfe-core.h" 208c2ecf20Sopenharmony_ci#include "c8sectpfe-dvb.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "dvb-pll.h" 238c2ecf20Sopenharmony_ci#include "lnbh24.h" 248c2ecf20Sopenharmony_ci#include "stv0367.h" 258c2ecf20Sopenharmony_ci#include "stv0367_priv.h" 268c2ecf20Sopenharmony_ci#include "stv6110x.h" 278c2ecf20Sopenharmony_ci#include "stv090x.h" 288c2ecf20Sopenharmony_ci#include "tda18212.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic inline const char *dvb_card_str(unsigned int c) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci switch (c) { 338c2ecf20Sopenharmony_ci case STV0367_TDA18212_NIMA_1: return "STV0367_TDA18212_NIMA_1"; 348c2ecf20Sopenharmony_ci case STV0367_TDA18212_NIMA_2: return "STV0367_TDA18212_NIMA_2"; 358c2ecf20Sopenharmony_ci case STV0367_TDA18212_NIMB_1: return "STV0367_TDA18212_NIMB_1"; 368c2ecf20Sopenharmony_ci case STV0367_TDA18212_NIMB_2: return "STV0367_TDA18212_NIMB_2"; 378c2ecf20Sopenharmony_ci case STV0903_6110_LNB24_NIMA: return "STV0903_6110_LNB24_NIMA"; 388c2ecf20Sopenharmony_ci case STV0903_6110_LNB24_NIMB: return "STV0903_6110_LNB24_NIMB"; 398c2ecf20Sopenharmony_ci default: return "unknown dvb frontend card"; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic struct stv090x_config stv090x_config = { 448c2ecf20Sopenharmony_ci .device = STV0903, 458c2ecf20Sopenharmony_ci .demod_mode = STV090x_SINGLE, 468c2ecf20Sopenharmony_ci .clk_mode = STV090x_CLK_EXT, 478c2ecf20Sopenharmony_ci .xtal = 16000000, 488c2ecf20Sopenharmony_ci .address = 0x69, 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci .ts1_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, 518c2ecf20Sopenharmony_ci .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci .repeater_level = STV090x_RPTLEVEL_64, 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci .tuner_init = NULL, 568c2ecf20Sopenharmony_ci .tuner_set_mode = NULL, 578c2ecf20Sopenharmony_ci .tuner_set_frequency = NULL, 588c2ecf20Sopenharmony_ci .tuner_get_frequency = NULL, 598c2ecf20Sopenharmony_ci .tuner_set_bandwidth = NULL, 608c2ecf20Sopenharmony_ci .tuner_get_bandwidth = NULL, 618c2ecf20Sopenharmony_ci .tuner_set_bbgain = NULL, 628c2ecf20Sopenharmony_ci .tuner_get_bbgain = NULL, 638c2ecf20Sopenharmony_ci .tuner_set_refclk = NULL, 648c2ecf20Sopenharmony_ci .tuner_get_status = NULL, 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct stv6110x_config stv6110x_config = { 688c2ecf20Sopenharmony_ci .addr = 0x60, 698c2ecf20Sopenharmony_ci .refclk = 16000000, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define NIMA 0 738c2ecf20Sopenharmony_ci#define NIMB 1 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic struct stv0367_config stv0367_tda18212_config[] = { 768c2ecf20Sopenharmony_ci { 778c2ecf20Sopenharmony_ci .demod_address = 0x1c, 788c2ecf20Sopenharmony_ci .xtal = 16000000, 798c2ecf20Sopenharmony_ci .if_khz = 4500, 808c2ecf20Sopenharmony_ci .if_iq_mode = FE_TER_NORMAL_IF_TUNER, 818c2ecf20Sopenharmony_ci .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, 828c2ecf20Sopenharmony_ci .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, 838c2ecf20Sopenharmony_ci }, { 848c2ecf20Sopenharmony_ci .demod_address = 0x1d, 858c2ecf20Sopenharmony_ci .xtal = 16000000, 868c2ecf20Sopenharmony_ci .if_khz = 4500, 878c2ecf20Sopenharmony_ci .if_iq_mode = FE_TER_NORMAL_IF_TUNER, 888c2ecf20Sopenharmony_ci .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, 898c2ecf20Sopenharmony_ci .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, 908c2ecf20Sopenharmony_ci }, { 918c2ecf20Sopenharmony_ci .demod_address = 0x1e, 928c2ecf20Sopenharmony_ci .xtal = 16000000, 938c2ecf20Sopenharmony_ci .if_khz = 4500, 948c2ecf20Sopenharmony_ci .if_iq_mode = FE_TER_NORMAL_IF_TUNER, 958c2ecf20Sopenharmony_ci .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, 968c2ecf20Sopenharmony_ci .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic struct tda18212_config tda18212_conf = { 1018c2ecf20Sopenharmony_ci .if_dvbt_6 = 4150, 1028c2ecf20Sopenharmony_ci .if_dvbt_7 = 4150, 1038c2ecf20Sopenharmony_ci .if_dvbt_8 = 4500, 1048c2ecf20Sopenharmony_ci .if_dvbc = 5000, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ciint c8sectpfe_frontend_attach(struct dvb_frontend **fe, 1088c2ecf20Sopenharmony_ci struct c8sectpfe *c8sectpfe, 1098c2ecf20Sopenharmony_ci struct channel_info *tsin, int chan_num) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct tda18212_config *tda18212; 1128c2ecf20Sopenharmony_ci const struct stv6110x_devctl *fe2; 1138c2ecf20Sopenharmony_ci struct i2c_client *client; 1148c2ecf20Sopenharmony_ci struct i2c_board_info tda18212_info = { 1158c2ecf20Sopenharmony_ci .type = "tda18212", 1168c2ecf20Sopenharmony_ci .addr = 0x60, 1178c2ecf20Sopenharmony_ci }; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (!tsin) 1208c2ecf20Sopenharmony_ci return -EINVAL; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci switch (tsin->dvb_card) { 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci case STV0367_TDA18212_NIMA_1: 1258c2ecf20Sopenharmony_ci case STV0367_TDA18212_NIMA_2: 1268c2ecf20Sopenharmony_ci case STV0367_TDA18212_NIMB_1: 1278c2ecf20Sopenharmony_ci case STV0367_TDA18212_NIMB_2: 1288c2ecf20Sopenharmony_ci if (tsin->dvb_card == STV0367_TDA18212_NIMA_1) 1298c2ecf20Sopenharmony_ci *fe = dvb_attach(stv0367ter_attach, 1308c2ecf20Sopenharmony_ci &stv0367_tda18212_config[0], 1318c2ecf20Sopenharmony_ci tsin->i2c_adapter); 1328c2ecf20Sopenharmony_ci else if (tsin->dvb_card == STV0367_TDA18212_NIMB_1) 1338c2ecf20Sopenharmony_ci *fe = dvb_attach(stv0367ter_attach, 1348c2ecf20Sopenharmony_ci &stv0367_tda18212_config[1], 1358c2ecf20Sopenharmony_ci tsin->i2c_adapter); 1368c2ecf20Sopenharmony_ci else 1378c2ecf20Sopenharmony_ci *fe = dvb_attach(stv0367ter_attach, 1388c2ecf20Sopenharmony_ci &stv0367_tda18212_config[2], 1398c2ecf20Sopenharmony_ci tsin->i2c_adapter); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (!*fe) { 1428c2ecf20Sopenharmony_ci dev_err(c8sectpfe->device, 1438c2ecf20Sopenharmony_ci "%s: stv0367ter_attach failed for NIM card %s\n" 1448c2ecf20Sopenharmony_ci , __func__, dvb_card_str(tsin->dvb_card)); 1458c2ecf20Sopenharmony_ci return -ENODEV; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * init the demod so that i2c gate_ctrl 1508c2ecf20Sopenharmony_ci * to the tuner works correctly 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci (*fe)->ops.init(*fe); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Allocate the tda18212 structure */ 1558c2ecf20Sopenharmony_ci tda18212 = devm_kzalloc(c8sectpfe->device, 1568c2ecf20Sopenharmony_ci sizeof(struct tda18212_config), 1578c2ecf20Sopenharmony_ci GFP_KERNEL); 1588c2ecf20Sopenharmony_ci if (!tda18212) { 1598c2ecf20Sopenharmony_ci dev_err(c8sectpfe->device, 1608c2ecf20Sopenharmony_ci "%s: devm_kzalloc failed\n", __func__); 1618c2ecf20Sopenharmony_ci return -ENOMEM; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci memcpy(tda18212, &tda18212_conf, 1658c2ecf20Sopenharmony_ci sizeof(struct tda18212_config)); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci tda18212->fe = (*fe); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci tda18212_info.platform_data = tda18212; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* attach tuner */ 1728c2ecf20Sopenharmony_ci request_module("tda18212"); 1738c2ecf20Sopenharmony_ci client = i2c_new_client_device(tsin->i2c_adapter, 1748c2ecf20Sopenharmony_ci &tda18212_info); 1758c2ecf20Sopenharmony_ci if (!i2c_client_has_driver(client)) { 1768c2ecf20Sopenharmony_ci dvb_frontend_detach(*fe); 1778c2ecf20Sopenharmony_ci return -ENODEV; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (!try_module_get(client->dev.driver->owner)) { 1818c2ecf20Sopenharmony_ci i2c_unregister_device(client); 1828c2ecf20Sopenharmony_ci dvb_frontend_detach(*fe); 1838c2ecf20Sopenharmony_ci return -ENODEV; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci tsin->i2c_client = client; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci case STV0903_6110_LNB24_NIMA: 1918c2ecf20Sopenharmony_ci *fe = dvb_attach(stv090x_attach, &stv090x_config, 1928c2ecf20Sopenharmony_ci tsin->i2c_adapter, STV090x_DEMODULATOR_0); 1938c2ecf20Sopenharmony_ci if (!*fe) { 1948c2ecf20Sopenharmony_ci dev_err(c8sectpfe->device, "%s: stv090x_attach failed\n" 1958c2ecf20Sopenharmony_ci "\tfor NIM card %s\n", 1968c2ecf20Sopenharmony_ci __func__, dvb_card_str(tsin->dvb_card)); 1978c2ecf20Sopenharmony_ci return -ENODEV; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci fe2 = dvb_attach(stv6110x_attach, *fe, 2018c2ecf20Sopenharmony_ci &stv6110x_config, tsin->i2c_adapter); 2028c2ecf20Sopenharmony_ci if (!fe2) { 2038c2ecf20Sopenharmony_ci dev_err(c8sectpfe->device, 2048c2ecf20Sopenharmony_ci "%s: stv6110x_attach failed for NIM card %s\n" 2058c2ecf20Sopenharmony_ci , __func__, dvb_card_str(tsin->dvb_card)); 2068c2ecf20Sopenharmony_ci return -ENODEV; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci stv090x_config.tuner_init = fe2->tuner_init; 2108c2ecf20Sopenharmony_ci stv090x_config.tuner_set_mode = fe2->tuner_set_mode; 2118c2ecf20Sopenharmony_ci stv090x_config.tuner_set_frequency = fe2->tuner_set_frequency; 2128c2ecf20Sopenharmony_ci stv090x_config.tuner_get_frequency = fe2->tuner_get_frequency; 2138c2ecf20Sopenharmony_ci stv090x_config.tuner_set_bandwidth = fe2->tuner_set_bandwidth; 2148c2ecf20Sopenharmony_ci stv090x_config.tuner_get_bandwidth = fe2->tuner_get_bandwidth; 2158c2ecf20Sopenharmony_ci stv090x_config.tuner_set_bbgain = fe2->tuner_set_bbgain; 2168c2ecf20Sopenharmony_ci stv090x_config.tuner_get_bbgain = fe2->tuner_get_bbgain; 2178c2ecf20Sopenharmony_ci stv090x_config.tuner_set_refclk = fe2->tuner_set_refclk; 2188c2ecf20Sopenharmony_ci stv090x_config.tuner_get_status = fe2->tuner_get_status; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci dvb_attach(lnbh24_attach, *fe, tsin->i2c_adapter, 0, 0, 0x9); 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci default: 2248c2ecf20Sopenharmony_ci dev_err(c8sectpfe->device, 2258c2ecf20Sopenharmony_ci "%s: DVB frontend card %s not yet supported\n", 2268c2ecf20Sopenharmony_ci __func__, dvb_card_str(tsin->dvb_card)); 2278c2ecf20Sopenharmony_ci return -ENODEV; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci (*fe)->id = chan_num; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci dev_info(c8sectpfe->device, 2338c2ecf20Sopenharmony_ci "DVB frontend card %s successfully attached", 2348c2ecf20Sopenharmony_ci dvb_card_str(tsin->dvb_card)); 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 237