1 // SPDX-License-Identifier: GPL-2.0
3 * c8sectpfe-dvb.c - C8SECTPFE STi DVB driver
5 * Copyright (c) STMicroelectronics 2015
7 * Author Peter Griffin <peter.griffin@linaro.org>
10 #include <linux/completion.h>
11 #include <linux/delay.h>
12 #include <linux/i2c.h>
13 #include <linux/interrupt.h>
14 #include <linux/version.h>
16 #include <dt-bindings/media/c8sectpfe.h>
18 #include "c8sectpfe-common.h"
19 #include "c8sectpfe-core.h"
20 #include "c8sectpfe-dvb.h"
25 #include "stv0367_priv.h"
30 static inline const char *dvb_card_str(unsigned int c)
33 case STV0367_TDA18212_NIMA_1: return "STV0367_TDA18212_NIMA_1";
34 case STV0367_TDA18212_NIMA_2: return "STV0367_TDA18212_NIMA_2";
35 case STV0367_TDA18212_NIMB_1: return "STV0367_TDA18212_NIMB_1";
36 case STV0367_TDA18212_NIMB_2: return "STV0367_TDA18212_NIMB_2";
37 case STV0903_6110_LNB24_NIMA: return "STV0903_6110_LNB24_NIMA";
38 case STV0903_6110_LNB24_NIMB: return "STV0903_6110_LNB24_NIMB";
39 default: return "unknown dvb frontend card";
43 static struct stv090x_config stv090x_config = {
45 .demod_mode = STV090x_SINGLE,
46 .clk_mode = STV090x_CLK_EXT,
50 .ts1_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,
51 .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,
53 .repeater_level = STV090x_RPTLEVEL_64,
56 .tuner_set_mode = NULL,
57 .tuner_set_frequency = NULL,
58 .tuner_get_frequency = NULL,
59 .tuner_set_bandwidth = NULL,
60 .tuner_get_bandwidth = NULL,
61 .tuner_set_bbgain = NULL,
62 .tuner_get_bbgain = NULL,
63 .tuner_set_refclk = NULL,
64 .tuner_get_status = NULL,
67 static struct stv6110x_config stv6110x_config = {
75 static struct stv0367_config stv0367_tda18212_config[] = {
77 .demod_address = 0x1c,
80 .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
81 .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
82 .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
84 .demod_address = 0x1d,
87 .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
88 .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
89 .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
91 .demod_address = 0x1e,
94 .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
95 .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
96 .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
100 static struct tda18212_config tda18212_conf = {
107 int c8sectpfe_frontend_attach(struct dvb_frontend **fe,
108 struct c8sectpfe *c8sectpfe,
109 struct channel_info *tsin, int chan_num)
111 struct tda18212_config *tda18212;
112 const struct stv6110x_devctl *fe2;
113 struct i2c_client *client;
114 struct i2c_board_info tda18212_info = {
122 switch (tsin->dvb_card) {
124 case STV0367_TDA18212_NIMA_1:
125 case STV0367_TDA18212_NIMA_2:
126 case STV0367_TDA18212_NIMB_1:
127 case STV0367_TDA18212_NIMB_2:
128 if (tsin->dvb_card == STV0367_TDA18212_NIMA_1)
129 *fe = dvb_attach(stv0367ter_attach,
130 &stv0367_tda18212_config[0],
132 else if (tsin->dvb_card == STV0367_TDA18212_NIMB_1)
133 *fe = dvb_attach(stv0367ter_attach,
134 &stv0367_tda18212_config[1],
137 *fe = dvb_attach(stv0367ter_attach,
138 &stv0367_tda18212_config[2],
142 dev_err(c8sectpfe->device,
143 "%s: stv0367ter_attach failed for NIM card %s\n"
144 , __func__, dvb_card_str(tsin->dvb_card));
149 * init the demod so that i2c gate_ctrl
150 * to the tuner works correctly
152 (*fe)->ops.init(*fe);
154 /* Allocate the tda18212 structure */
155 tda18212 = devm_kzalloc(c8sectpfe->device,
156 sizeof(struct tda18212_config),
159 dev_err(c8sectpfe->device,
160 "%s: devm_kzalloc failed\n", __func__);
164 memcpy(tda18212, &tda18212_conf,
165 sizeof(struct tda18212_config));
167 tda18212->fe = (*fe);
169 tda18212_info.platform_data = tda18212;
172 request_module("tda18212");
173 client = i2c_new_client_device(tsin->i2c_adapter,
175 if (!i2c_client_has_driver(client)) {
176 dvb_frontend_detach(*fe);
180 if (!try_module_get(client->dev.driver->owner)) {
181 i2c_unregister_device(client);
182 dvb_frontend_detach(*fe);
186 tsin->i2c_client = client;
190 case STV0903_6110_LNB24_NIMA:
191 *fe = dvb_attach(stv090x_attach, &stv090x_config,
192 tsin->i2c_adapter, STV090x_DEMODULATOR_0);
194 dev_err(c8sectpfe->device, "%s: stv090x_attach failed\n"
195 "\tfor NIM card %s\n",
196 __func__, dvb_card_str(tsin->dvb_card));
200 fe2 = dvb_attach(stv6110x_attach, *fe,
201 &stv6110x_config, tsin->i2c_adapter);
203 dev_err(c8sectpfe->device,
204 "%s: stv6110x_attach failed for NIM card %s\n"
205 , __func__, dvb_card_str(tsin->dvb_card));
209 stv090x_config.tuner_init = fe2->tuner_init;
210 stv090x_config.tuner_set_mode = fe2->tuner_set_mode;
211 stv090x_config.tuner_set_frequency = fe2->tuner_set_frequency;
212 stv090x_config.tuner_get_frequency = fe2->tuner_get_frequency;
213 stv090x_config.tuner_set_bandwidth = fe2->tuner_set_bandwidth;
214 stv090x_config.tuner_get_bandwidth = fe2->tuner_get_bandwidth;
215 stv090x_config.tuner_set_bbgain = fe2->tuner_set_bbgain;
216 stv090x_config.tuner_get_bbgain = fe2->tuner_get_bbgain;
217 stv090x_config.tuner_set_refclk = fe2->tuner_set_refclk;
218 stv090x_config.tuner_get_status = fe2->tuner_get_status;
220 dvb_attach(lnbh24_attach, *fe, tsin->i2c_adapter, 0, 0, 0x9);
224 dev_err(c8sectpfe->device,
225 "%s: DVB frontend card %s not yet supported\n",
226 __func__, dvb_card_str(tsin->dvb_card));
230 (*fe)->id = chan_num;
232 dev_info(c8sectpfe->device,
233 "DVB frontend card %s successfully attached",
234 dvb_card_str(tsin->dvb_card));