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_device(tsin
->i2c_adapter
, &tda18212_info
);
174 if (!client
|| !client
->dev
.driver
) {
175 dvb_frontend_detach(*fe
);
179 if (!try_module_get(client
->dev
.driver
->owner
)) {
180 i2c_unregister_device(client
);
181 dvb_frontend_detach(*fe
);
185 tsin
->i2c_client
= client
;
189 case STV0903_6110_LNB24_NIMA
:
190 *fe
= dvb_attach(stv090x_attach
, &stv090x_config
,
191 tsin
->i2c_adapter
, STV090x_DEMODULATOR_0
);
193 dev_err(c8sectpfe
->device
, "%s: stv090x_attach failed\n"
194 "\tfor NIM card %s\n",
195 __func__
, dvb_card_str(tsin
->dvb_card
));
199 fe2
= dvb_attach(stv6110x_attach
, *fe
,
200 &stv6110x_config
, tsin
->i2c_adapter
);
202 dev_err(c8sectpfe
->device
,
203 "%s: stv6110x_attach failed for NIM card %s\n"
204 , __func__
, dvb_card_str(tsin
->dvb_card
));
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
;
219 dvb_attach(lnbh24_attach
, *fe
, tsin
->i2c_adapter
, 0, 0, 0x9);
223 dev_err(c8sectpfe
->device
,
224 "%s: DVB frontend card %s not yet supported\n",
225 __func__
, dvb_card_str(tsin
->dvb_card
));
229 (*fe
)->id
= chan_num
;
231 dev_info(c8sectpfe
->device
,
232 "DVB frontend card %s successfully attached",
233 dvb_card_str(tsin
->dvb_card
));