1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * The Virtual DVB test driver serves as a reference DVB driver and helps
4  * validate the existing APIs in the media subsystem. It can also aid
5  * developers working on userspace applications.
6  *
7  * The vidtv tuner should support common TV standards such as
8  * DVB-T/T2/S/S2, ISDB-T and ATSC when completed.
9  *
10  * Copyright (C) 2020 Daniel W. S. Almeida
11  */
12 
13 #include <linux/errno.h>
14 #include <linux/i2c.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
17 #include <linux/types.h>
18 #include <media/dvb_frontend.h>
19 #include <linux/printk.h>
20 #include <linux/ratelimit.h>
21 
22 #include "vidtv_tuner.h"
23 
24 struct vidtv_tuner_cnr_to_qual_s {
25 	/* attempt to use the same values as libdvbv5 */
26 	u32 modulation;
27 	u32 fec;
28 	u32 cnr_ok;
29 	u32 cnr_good;
30 };
31 
32 static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_c_cnr_2_qual[] = {
33 	/* from libdvbv5 source code, in milli db */
34 	{ QAM_256, FEC_NONE,  34000, 38000},
35 	{ QAM_64,  FEC_NONE,  30000, 34000},
36 };
37 
38 static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_s_cnr_2_qual[] = {
39 	/* from libdvbv5 source code, in milli db */
40 	{ QPSK, FEC_1_2,  7000, 10000},
41 	{ QPSK, FEC_2_3,  9000, 12000},
42 	{ QPSK, FEC_3_4, 10000, 13000},
43 	{ QPSK, FEC_5_6, 11000, 14000},
44 	{ QPSK, FEC_7_8, 12000, 15000},
45 };
46 
47 static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_s2_cnr_2_qual[] = {
48 	/* from libdvbv5 source code, in milli db */
49 	{ QPSK,  FEC_1_2,   9000,  12000},
50 	{ QPSK,  FEC_2_3,  11000,  14000},
51 	{ QPSK,  FEC_3_4,  12000,  15000},
52 	{ QPSK,  FEC_5_6,  12000,  15000},
53 	{ QPSK,  FEC_8_9,  13000,  16000},
54 	{ QPSK,  FEC_9_10, 13500,  16500},
55 	{ PSK_8, FEC_2_3,  14500,  17500},
56 	{ PSK_8, FEC_3_4,  16000,  19000},
57 	{ PSK_8, FEC_5_6,  17500,  20500},
58 	{ PSK_8, FEC_8_9,  19000,  22000},
59 };
60 
61 static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_t_cnr_2_qual[] = {
62 	/* from libdvbv5 source code, in milli db*/
63 	{   QPSK, FEC_1_2,  4100,  5900},
64 	{   QPSK, FEC_2_3,  6100,  9600},
65 	{   QPSK, FEC_3_4,  7200, 12400},
66 	{   QPSK, FEC_5_6,  8500, 15600},
67 	{   QPSK, FEC_7_8,  9200, 17500},
68 	{ QAM_16, FEC_1_2,  9800, 11800},
69 	{ QAM_16, FEC_2_3, 12100, 15300},
70 	{ QAM_16, FEC_3_4, 13400, 18100},
71 	{ QAM_16, FEC_5_6, 14800, 21300},
72 	{ QAM_16, FEC_7_8, 15700, 23600},
73 	{ QAM_64, FEC_1_2, 14000, 16000},
74 	{ QAM_64, FEC_2_3, 19900, 25400},
75 	{ QAM_64, FEC_3_4, 24900, 27900},
76 	{ QAM_64, FEC_5_6, 21300, 23300},
77 	{ QAM_64, FEC_7_8, 22000, 24000},
78 };
79 
80 /**
81  * struct vidtv_tuner_hardware_state - Simulate the tuner hardware status
82  * @asleep: whether the tuner is asleep, i.e whether _sleep() or _suspend() was
83  * called.
84  * @lock_status: Whether the tuner has managed to lock on the requested
85  * frequency.
86  * @if_frequency: The tuner's intermediate frequency. Hardcoded for the purposes
87  * of simulation.
88  * @tuned_frequency: The actual tuned frequency.
89  * @bandwidth: The actual bandwidth.
90  *
91  * This structure is meant to simulate the status of the tuner hardware, as if
92  * we had a physical tuner hardware.
93  */
94 struct vidtv_tuner_hardware_state {
95 	bool asleep;
96 	u32 lock_status;
97 	u32 if_frequency;
98 	u32 tuned_frequency;
99 	u32 bandwidth;
100 };
101 
102 /**
103  * struct vidtv_tuner_dev - The tuner struct
104  * @fe: A pointer to the dvb_frontend structure allocated by vidtv_demod
105  * @hw_state: A struct to simulate the tuner's hardware state as if we had a
106  * physical tuner hardware.
107  * @config: The configuration used to start the tuner module, usually filled
108  * by a bridge driver. For vidtv, this is filled by vidtv_bridge before the
109  * tuner module is probed.
110  */
111 struct vidtv_tuner_dev {
112 	struct dvb_frontend *fe;
113 	struct vidtv_tuner_hardware_state hw_state;
114 	struct vidtv_tuner_config config;
115 };
116 
117 static struct vidtv_tuner_dev*
118 vidtv_tuner_get_dev(struct dvb_frontend *fe)
119 {
120 	return i2c_get_clientdata(fe->tuner_priv);
121 }
122 
123 static int vidtv_tuner_check_frequency_shift(struct dvb_frontend *fe)
124 {
125 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
126 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
127 	struct vidtv_tuner_config config  = tuner_dev->config;
128 	u32 *valid_freqs = NULL;
129 	u32 array_sz = 0;
130 	u32 i;
131 	u32 shift;
132 
133 	switch (c->delivery_system) {
134 	case SYS_DVBT:
135 	case SYS_DVBT2:
136 		valid_freqs = config.vidtv_valid_dvb_t_freqs;
137 		array_sz    = ARRAY_SIZE(config.vidtv_valid_dvb_t_freqs);
138 		break;
139 	case SYS_DVBS:
140 	case SYS_DVBS2:
141 		valid_freqs = config.vidtv_valid_dvb_s_freqs;
142 		array_sz    = ARRAY_SIZE(config.vidtv_valid_dvb_s_freqs);
143 		break;
144 	case SYS_DVBC_ANNEX_A:
145 		valid_freqs = config.vidtv_valid_dvb_c_freqs;
146 		array_sz    = ARRAY_SIZE(config.vidtv_valid_dvb_c_freqs);
147 		break;
148 
149 	default:
150 		dev_warn(fe->dvb->device,
151 			 "%s: unsupported delivery system: %u\n",
152 			 __func__,
153 			 c->delivery_system);
154 
155 		return -EINVAL;
156 	}
157 
158 	for (i = 0; i < array_sz; i++) {
159 		if (!valid_freqs[i])
160 			break;
161 		shift = abs(c->frequency - valid_freqs[i]);
162 
163 		if (!shift)
164 			return 0;
165 
166 		/*
167 		 * This will provide a value from 0 to 100 that would
168 		 * indicate how far is the tuned frequency from the
169 		 * right one.
170 		 */
171 		if (shift < config.max_frequency_shift_hz)
172 			return shift * 100 / config.max_frequency_shift_hz;
173 	}
174 
175 	return -EINVAL;
176 }
177 
178 static int
179 vidtv_tuner_get_signal_strength(struct dvb_frontend *fe, u16 *strength)
180 {
181 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
182 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
183 	const struct vidtv_tuner_cnr_to_qual_s *cnr2qual = NULL;
184 	struct device *dev = fe->dvb->device;
185 	u32 array_size = 0;
186 	s32 shift;
187 	u32 i;
188 
189 	shift = vidtv_tuner_check_frequency_shift(fe);
190 	if (shift < 0) {
191 		tuner_dev->hw_state.lock_status = 0;
192 		*strength = 0;
193 		return 0;
194 	}
195 
196 	switch (c->delivery_system) {
197 	case SYS_DVBT:
198 	case SYS_DVBT2:
199 		cnr2qual   = vidtv_tuner_t_cnr_2_qual;
200 		array_size = ARRAY_SIZE(vidtv_tuner_t_cnr_2_qual);
201 		break;
202 
203 	case SYS_DVBS:
204 		cnr2qual   = vidtv_tuner_s_cnr_2_qual;
205 		array_size = ARRAY_SIZE(vidtv_tuner_s_cnr_2_qual);
206 		break;
207 
208 	case SYS_DVBS2:
209 		cnr2qual   = vidtv_tuner_s2_cnr_2_qual;
210 		array_size = ARRAY_SIZE(vidtv_tuner_s2_cnr_2_qual);
211 		break;
212 
213 	case SYS_DVBC_ANNEX_A:
214 		cnr2qual   = vidtv_tuner_c_cnr_2_qual;
215 		array_size = ARRAY_SIZE(vidtv_tuner_c_cnr_2_qual);
216 		break;
217 
218 	default:
219 		dev_warn_ratelimited(dev,
220 				     "%s: unsupported delivery system: %u\n",
221 				     __func__,
222 				     c->delivery_system);
223 		return -EINVAL;
224 	}
225 
226 	for (i = 0; i < array_size; i++) {
227 		if (cnr2qual[i].modulation != c->modulation ||
228 		    cnr2qual[i].fec != c->fec_inner)
229 			continue;
230 
231 		if (!shift) {
232 			*strength = cnr2qual[i].cnr_good;
233 			return 0;
234 		}
235 		/*
236 		 * Channel tuned at wrong frequency. Simulate that the
237 		 * Carrier S/N ratio is not too good.
238 		 */
239 
240 		*strength = cnr2qual[i].cnr_ok -
241 			    (cnr2qual[i].cnr_good - cnr2qual[i].cnr_ok);
242 		return 0;
243 	}
244 
245 	/*
246 	 * do a linear interpolation between 34dB and 10dB if we can't
247 	 * match against the table
248 	 */
249 	*strength = 34000 - 24000 * shift / 100;
250 	return 0;
251 }
252 
253 static int vidtv_tuner_init(struct dvb_frontend *fe)
254 {
255 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
256 	struct vidtv_tuner_config config  = tuner_dev->config;
257 
258 	msleep_interruptible(config.mock_power_up_delay_msec);
259 
260 	tuner_dev->hw_state.asleep = false;
261 	tuner_dev->hw_state.if_frequency = 5000;
262 
263 	return 0;
264 }
265 
266 static int vidtv_tuner_sleep(struct dvb_frontend *fe)
267 {
268 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
269 
270 	tuner_dev->hw_state.asleep = true;
271 	return 0;
272 }
273 
274 static int vidtv_tuner_suspend(struct dvb_frontend *fe)
275 {
276 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
277 
278 	tuner_dev->hw_state.asleep = true;
279 	return 0;
280 }
281 
282 static int vidtv_tuner_resume(struct dvb_frontend *fe)
283 {
284 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
285 
286 	tuner_dev->hw_state.asleep = false;
287 	return 0;
288 }
289 
290 static int vidtv_tuner_set_params(struct dvb_frontend *fe)
291 {
292 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
293 	struct vidtv_tuner_config config  = tuner_dev->config;
294 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
295 	s32 shift;
296 
297 	u32 min_freq = fe->ops.tuner_ops.info.frequency_min_hz;
298 	u32 max_freq = fe->ops.tuner_ops.info.frequency_max_hz;
299 	u32 min_bw = fe->ops.tuner_ops.info.bandwidth_min;
300 	u32 max_bw = fe->ops.tuner_ops.info.bandwidth_max;
301 
302 	if (c->frequency < min_freq  || c->frequency > max_freq  ||
303 	    c->bandwidth_hz < min_bw || c->bandwidth_hz > max_bw) {
304 		tuner_dev->hw_state.lock_status = 0;
305 		return -EINVAL;
306 	}
307 
308 	tuner_dev->hw_state.tuned_frequency = c->frequency;
309 	tuner_dev->hw_state.bandwidth = c->bandwidth_hz;
310 	tuner_dev->hw_state.lock_status = TUNER_STATUS_LOCKED;
311 
312 	msleep_interruptible(config.mock_tune_delay_msec);
313 
314 	shift = vidtv_tuner_check_frequency_shift(fe);
315 	if (shift < 0) {
316 		tuner_dev->hw_state.lock_status = 0;
317 		return shift;
318 	}
319 
320 	return 0;
321 }
322 
323 static int vidtv_tuner_set_config(struct dvb_frontend *fe,
324 				  void *priv_cfg)
325 {
326 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
327 
328 	memcpy(&tuner_dev->config, priv_cfg, sizeof(tuner_dev->config));
329 
330 	return 0;
331 }
332 
333 static int vidtv_tuner_get_frequency(struct dvb_frontend *fe,
334 				     u32 *frequency)
335 {
336 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
337 
338 	*frequency = tuner_dev->hw_state.tuned_frequency;
339 
340 	return 0;
341 }
342 
343 static int vidtv_tuner_get_bandwidth(struct dvb_frontend *fe,
344 				     u32 *bandwidth)
345 {
346 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
347 
348 	*bandwidth = tuner_dev->hw_state.bandwidth;
349 
350 	return 0;
351 }
352 
353 static int vidtv_tuner_get_if_frequency(struct dvb_frontend *fe,
354 					u32 *frequency)
355 {
356 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
357 
358 	*frequency = tuner_dev->hw_state.if_frequency;
359 
360 	return 0;
361 }
362 
363 static int vidtv_tuner_get_status(struct dvb_frontend *fe, u32 *status)
364 {
365 	struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
366 
367 	*status = tuner_dev->hw_state.lock_status;
368 
369 	return 0;
370 }
371 
372 static const struct dvb_tuner_ops vidtv_tuner_ops = {
373 	.init             = vidtv_tuner_init,
374 	.sleep            = vidtv_tuner_sleep,
375 	.suspend          = vidtv_tuner_suspend,
376 	.resume           = vidtv_tuner_resume,
377 	.set_params       = vidtv_tuner_set_params,
378 	.set_config       = vidtv_tuner_set_config,
379 	.get_bandwidth    = vidtv_tuner_get_bandwidth,
380 	.get_frequency    = vidtv_tuner_get_frequency,
381 	.get_if_frequency = vidtv_tuner_get_if_frequency,
382 	.get_status       = vidtv_tuner_get_status,
383 	.get_rf_strength  = vidtv_tuner_get_signal_strength
384 };
385 
386 static const struct i2c_device_id vidtv_tuner_i2c_id_table[] = {
387 	{"dvb_vidtv_tuner", 0},
388 	{}
389 };
390 MODULE_DEVICE_TABLE(i2c, vidtv_tuner_i2c_id_table);
391 
392 static int vidtv_tuner_i2c_probe(struct i2c_client *client,
393 				 const struct i2c_device_id *id)
394 {
395 	struct vidtv_tuner_config *config = client->dev.platform_data;
396 	struct dvb_frontend *fe           = config->fe;
397 	struct vidtv_tuner_dev *tuner_dev = NULL;
398 
399 	tuner_dev = kzalloc(sizeof(*tuner_dev), GFP_KERNEL);
400 	if (!tuner_dev)
401 		return -ENOMEM;
402 
403 	tuner_dev->fe = config->fe;
404 	i2c_set_clientdata(client, tuner_dev);
405 
406 	memcpy(&fe->ops.tuner_ops,
407 	       &vidtv_tuner_ops,
408 	       sizeof(struct dvb_tuner_ops));
409 
410 	memcpy(&tuner_dev->config, config, sizeof(tuner_dev->config));
411 	fe->tuner_priv = client;
412 
413 	return 0;
414 }
415 
416 static int vidtv_tuner_i2c_remove(struct i2c_client *client)
417 {
418 	struct vidtv_tuner_dev *tuner_dev = i2c_get_clientdata(client);
419 
420 	kfree(tuner_dev);
421 
422 	return 0;
423 }
424 
425 static struct i2c_driver vidtv_tuner_i2c_driver = {
426 	.driver = {
427 		.name                = "dvb_vidtv_tuner",
428 		.suppress_bind_attrs = true,
429 	},
430 	.probe    = vidtv_tuner_i2c_probe,
431 	.remove   = vidtv_tuner_i2c_remove,
432 	.id_table = vidtv_tuner_i2c_id_table,
433 };
434 module_i2c_driver(vidtv_tuner_i2c_driver);
435 
436 MODULE_DESCRIPTION("Virtual DVB Tuner");
437 MODULE_AUTHOR("Daniel W. S. Almeida");
438 MODULE_LICENSE("GPL");
439