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