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