1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * c8sectpfe-dvb.c - C8SECTPFE STi DVB driver 4 * 5 * Copyright (c) STMicroelectronics 2015 6 * 7 * Author Peter Griffin <peter.griffin@linaro.org> 8 * 9 */ 10 #include <linux/completion.h> 11 #include <linux/delay.h> 12 #include <linux/i2c.h> 13 #include <linux/interrupt.h> 14 15 #include <dt-bindings/media/c8sectpfe.h> 16 17 #include "c8sectpfe-common.h" 18 #include "c8sectpfe-core.h" 19 #include "c8sectpfe-dvb.h" 20 21 #include "dvb-pll.h" 22 #include "lnbh24.h" 23 #include "stv0367.h" 24 #include "stv0367_priv.h" 25 #include "stv6110x.h" 26 #include "stv090x.h" 27 #include "tda18212.h" 28 29 static inline const char *dvb_card_str(unsigned int c) 30 { 31 switch (c) { 32 case STV0367_TDA18212_NIMA_1: return "STV0367_TDA18212_NIMA_1"; 33 case STV0367_TDA18212_NIMA_2: return "STV0367_TDA18212_NIMA_2"; 34 case STV0367_TDA18212_NIMB_1: return "STV0367_TDA18212_NIMB_1"; 35 case STV0367_TDA18212_NIMB_2: return "STV0367_TDA18212_NIMB_2"; 36 case STV0903_6110_LNB24_NIMA: return "STV0903_6110_LNB24_NIMA"; 37 case STV0903_6110_LNB24_NIMB: return "STV0903_6110_LNB24_NIMB"; 38 default: return "unknown dvb frontend card"; 39 } 40 } 41 42 static struct stv090x_config stv090x_config = { 43 .device = STV0903, 44 .demod_mode = STV090x_SINGLE, 45 .clk_mode = STV090x_CLK_EXT, 46 .xtal = 16000000, 47 .address = 0x69, 48 49 .ts1_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, 50 .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, 51 52 .repeater_level = STV090x_RPTLEVEL_64, 53 54 .tuner_init = NULL, 55 .tuner_set_mode = NULL, 56 .tuner_set_frequency = NULL, 57 .tuner_get_frequency = NULL, 58 .tuner_set_bandwidth = NULL, 59 .tuner_get_bandwidth = NULL, 60 .tuner_set_bbgain = NULL, 61 .tuner_get_bbgain = NULL, 62 .tuner_set_refclk = NULL, 63 .tuner_get_status = NULL, 64 }; 65 66 static struct stv6110x_config stv6110x_config = { 67 .addr = 0x60, 68 .refclk = 16000000, 69 }; 70 71 #define NIMA 0 72 #define NIMB 1 73 74 static struct stv0367_config stv0367_tda18212_config[] = { 75 { 76 .demod_address = 0x1c, 77 .xtal = 16000000, 78 .if_khz = 4500, 79 .if_iq_mode = FE_TER_NORMAL_IF_TUNER, 80 .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, 81 .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, 82 }, { 83 .demod_address = 0x1d, 84 .xtal = 16000000, 85 .if_khz = 4500, 86 .if_iq_mode = FE_TER_NORMAL_IF_TUNER, 87 .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, 88 .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, 89 }, { 90 .demod_address = 0x1e, 91 .xtal = 16000000, 92 .if_khz = 4500, 93 .if_iq_mode = FE_TER_NORMAL_IF_TUNER, 94 .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, 95 .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, 96 }, 97 }; 98 99 static struct tda18212_config tda18212_conf = { 100 .if_dvbt_6 = 4150, 101 .if_dvbt_7 = 4150, 102 .if_dvbt_8 = 4500, 103 .if_dvbc = 5000, 104 }; 105 106 int c8sectpfe_frontend_attach(struct dvb_frontend **fe, 107 struct c8sectpfe *c8sectpfe, 108 struct channel_info *tsin, int chan_num) 109 { 110 struct tda18212_config *tda18212; 111 const struct stv6110x_devctl *fe2; 112 struct i2c_client *client; 113 struct i2c_board_info tda18212_info = { 114 .type = "tda18212", 115 .addr = 0x60, 116 }; 117 118 if (!tsin) 119 return -EINVAL; 120 121 switch (tsin->dvb_card) { 122 123 case STV0367_TDA18212_NIMA_1: 124 case STV0367_TDA18212_NIMA_2: 125 case STV0367_TDA18212_NIMB_1: 126 case STV0367_TDA18212_NIMB_2: 127 if (tsin->dvb_card == STV0367_TDA18212_NIMA_1) 128 *fe = dvb_attach(stv0367ter_attach, 129 &stv0367_tda18212_config[0], 130 tsin->i2c_adapter); 131 else if (tsin->dvb_card == STV0367_TDA18212_NIMB_1) 132 *fe = dvb_attach(stv0367ter_attach, 133 &stv0367_tda18212_config[1], 134 tsin->i2c_adapter); 135 else 136 *fe = dvb_attach(stv0367ter_attach, 137 &stv0367_tda18212_config[2], 138 tsin->i2c_adapter); 139 140 if (!*fe) { 141 dev_err(c8sectpfe->device, 142 "%s: stv0367ter_attach failed for NIM card %s\n" 143 , __func__, dvb_card_str(tsin->dvb_card)); 144 return -ENODEV; 145 } 146 147 /* 148 * init the demod so that i2c gate_ctrl 149 * to the tuner works correctly 150 */ 151 (*fe)->ops.init(*fe); 152 153 /* Allocate the tda18212 structure */ 154 tda18212 = devm_kzalloc(c8sectpfe->device, 155 sizeof(struct tda18212_config), 156 GFP_KERNEL); 157 if (!tda18212) { 158 dev_err(c8sectpfe->device, 159 "%s: devm_kzalloc failed\n", __func__); 160 return -ENOMEM; 161 } 162 163 memcpy(tda18212, &tda18212_conf, 164 sizeof(struct tda18212_config)); 165 166 tda18212->fe = (*fe); 167 168 tda18212_info.platform_data = tda18212; 169 170 /* attach tuner */ 171 request_module("tda18212"); 172 client = i2c_new_client_device(tsin->i2c_adapter, 173 &tda18212_info); 174 if (!i2c_client_has_driver(client)) { 175 dvb_frontend_detach(*fe); 176 return -ENODEV; 177 } 178 179 if (!try_module_get(client->dev.driver->owner)) { 180 i2c_unregister_device(client); 181 dvb_frontend_detach(*fe); 182 return -ENODEV; 183 } 184 185 tsin->i2c_client = client; 186 187 break; 188 189 case STV0903_6110_LNB24_NIMA: 190 *fe = dvb_attach(stv090x_attach, &stv090x_config, 191 tsin->i2c_adapter, STV090x_DEMODULATOR_0); 192 if (!*fe) { 193 dev_err(c8sectpfe->device, "%s: stv090x_attach failed\n" 194 "\tfor NIM card %s\n", 195 __func__, dvb_card_str(tsin->dvb_card)); 196 return -ENODEV; 197 } 198 199 fe2 = dvb_attach(stv6110x_attach, *fe, 200 &stv6110x_config, tsin->i2c_adapter); 201 if (!fe2) { 202 dev_err(c8sectpfe->device, 203 "%s: stv6110x_attach failed for NIM card %s\n" 204 , __func__, dvb_card_str(tsin->dvb_card)); 205 return -ENODEV; 206 } 207 208 stv090x_config.tuner_init = fe2->tuner_init; 209 stv090x_config.tuner_set_mode = fe2->tuner_set_mode; 210 stv090x_config.tuner_set_frequency = fe2->tuner_set_frequency; 211 stv090x_config.tuner_get_frequency = fe2->tuner_get_frequency; 212 stv090x_config.tuner_set_bandwidth = fe2->tuner_set_bandwidth; 213 stv090x_config.tuner_get_bandwidth = fe2->tuner_get_bandwidth; 214 stv090x_config.tuner_set_bbgain = fe2->tuner_set_bbgain; 215 stv090x_config.tuner_get_bbgain = fe2->tuner_get_bbgain; 216 stv090x_config.tuner_set_refclk = fe2->tuner_set_refclk; 217 stv090x_config.tuner_get_status = fe2->tuner_get_status; 218 219 dvb_attach(lnbh24_attach, *fe, tsin->i2c_adapter, 0, 0, 0x9); 220 break; 221 222 default: 223 dev_err(c8sectpfe->device, 224 "%s: DVB frontend card %s not yet supported\n", 225 __func__, dvb_card_str(tsin->dvb_card)); 226 return -ENODEV; 227 } 228 229 (*fe)->id = chan_num; 230 231 dev_info(c8sectpfe->device, 232 "DVB frontend card %s successfully attached", 233 dvb_card_str(tsin->dvb_card)); 234 return 0; 235 } 236