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