1// SPDX-License-Identifier: GPL-2.0
2/*
3 * cxd2880_tnrdmd_dvbt.c
4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver
5 * control functions for DVB-T
6 *
7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
8 */
9
10#include <media/dvb_frontend.h>
11
12#include "cxd2880_tnrdmd_dvbt.h"
13#include "cxd2880_tnrdmd_dvbt_mon.h"
14
15static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = {
16	{0x00, 0x00}, {0x31, 0x01},
17};
18
19static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = {
20	{0x00, 0x04}, {0x5c, 0xfb}, {0x00, 0x10}, {0xa4, 0x03},
21	{0x00, 0x14}, {0xb0, 0x00}, {0x00, 0x25},
22};
23
24static const struct cxd2880_reg_value tune_dmd_setting_seq3[] = {
25	{0x00, 0x12}, {0x44, 0x00},
26};
27
28static const struct cxd2880_reg_value tune_dmd_setting_seq4[] = {
29	{0x00, 0x11}, {0x87, 0xd2},
30};
31
32static const struct cxd2880_reg_value tune_dmd_setting_seq5[] = {
33	{0x00, 0x00}, {0xfd, 0x01},
34};
35
36static const struct cxd2880_reg_value sleep_dmd_setting_seq1[] = {
37	{0x00, 0x04}, {0x5c, 0xd8}, {0x00, 0x10}, {0xa4, 0x00},
38};
39
40static const struct cxd2880_reg_value sleep_dmd_setting_seq2[] = {
41	{0x00, 0x11}, {0x87, 0x04},
42};
43
44static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
45				     *tnr_dmd,
46				     enum cxd2880_dtv_bandwidth
47				     bandwidth,
48				     enum cxd2880_tnrdmd_clockmode
49				     clk_mode)
50{
51	static const u8 clk_mode_ckffrq_a[2] = { 0x52, 0x49 };
52	static const u8 clk_mode_ckffrq_b[2] = { 0x5d, 0x55 };
53	static const u8 clk_mode_ckffrq_c[2] = { 0x60, 0x00 };
54	static const u8 ratectl_margin[2] = { 0x01, 0xf0 };
55	static const u8 maxclkcnt_a[3] = { 0x73, 0xca, 0x49 };
56	static const u8 maxclkcnt_b[3] = { 0xc8, 0x13, 0xaa };
57	static const u8 maxclkcnt_c[3] = { 0xdc, 0x6c, 0x00 };
58
59	static const u8 bw8_nomi_ac[5] = { 0x15, 0x00, 0x00, 0x00, 0x00};
60	static const u8 bw8_nomi_b[5] = { 0x14, 0x6a, 0xaa, 0xaa, 0xaa};
61	static const u8 bw8_gtdofst_a[2] = { 0x01, 0x28 };
62	static const u8 bw8_gtdofst_b[2] = { 0x11, 0x44 };
63	static const u8 bw8_gtdofst_c[2] = { 0x15, 0x28 };
64	static const u8 bw8_mrc_a[5] = { 0x30, 0x00, 0x00, 0x90, 0x00 };
65	static const u8 bw8_mrc_b[5] = { 0x36, 0x71, 0x00, 0xa3, 0x55 };
66	static const u8 bw8_mrc_c[5] = { 0x38, 0x00, 0x00, 0xa8, 0x00 };
67	static const u8 bw8_notch[4] = { 0xb3, 0x00, 0x01, 0x02 };
68
69	static const u8 bw7_nomi_ac[5] = { 0x18, 0x00, 0x00, 0x00, 0x00};
70	static const u8 bw7_nomi_b[5] = { 0x17, 0x55, 0x55, 0x55, 0x55};
71	static const u8 bw7_gtdofst_a[2] = { 0x12, 0x4c };
72	static const u8 bw7_gtdofst_b[2] = { 0x1f, 0x15 };
73	static const u8 bw7_gtdofst_c[2] = { 0x1f, 0xf8 };
74	static const u8 bw7_mrc_a[5] = { 0x36, 0xdb, 0x00, 0xa4, 0x92 };
75	static const u8 bw7_mrc_b[5] = { 0x3e, 0x38, 0x00, 0xba, 0xaa };
76	static const u8 bw7_mrc_c[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
77	static const u8 bw7_notch[4] = { 0xb8, 0x00, 0x00, 0x03 };
78
79	static const u8 bw6_nomi_ac[5] = { 0x1c, 0x00, 0x00, 0x00, 0x00};
80	static const u8 bw6_nomi_b[5] = { 0x1b, 0x38, 0xe3, 0x8e, 0x38};
81	static const u8 bw6_gtdofst_a[2] = { 0x1f, 0xf8 };
82	static const u8 bw6_gtdofst_b[2] = { 0x24, 0x43 };
83	static const u8 bw6_gtdofst_c[2] = { 0x25, 0x4c };
84	static const u8 bw6_mrc_a[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
85	static const u8 bw6_mrc_b[5] = { 0x48, 0x97, 0x00, 0xd9, 0xc7 };
86	static const u8 bw6_mrc_c[5] = { 0x4a, 0xaa, 0x00, 0xdf, 0xff };
87	static const u8 bw6_notch[4] = { 0xbe, 0xab, 0x00, 0x03 };
88
89	static const u8 bw5_nomi_ac[5] = { 0x21, 0x99, 0x99, 0x99, 0x99};
90	static const u8 bw5_nomi_b[5] = { 0x20, 0xaa, 0xaa, 0xaa, 0xaa};
91	static const u8 bw5_gtdofst_a[2] = { 0x26, 0x5d };
92	static const u8 bw5_gtdofst_b[2] = { 0x2b, 0x84 };
93	static const u8 bw5_gtdofst_c[2] = { 0x2c, 0xc2 };
94	static const u8 bw5_mrc_a[5] = { 0x4c, 0xcc, 0x00, 0xe6, 0x66 };
95	static const u8 bw5_mrc_b[5] = { 0x57, 0x1c, 0x01, 0x05, 0x55 };
96	static const u8 bw5_mrc_c[5] = { 0x59, 0x99, 0x01, 0x0c, 0xcc };
97	static const u8 bw5_notch[4] = { 0xc8, 0x01, 0x00, 0x03 };
98	const u8 *data = NULL;
99	u8 sst_data;
100	int ret;
101
102	if (!tnr_dmd)
103		return -EINVAL;
104
105	ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
106					  CXD2880_IO_TGT_SYS,
107					  tune_dmd_setting_seq1,
108					  ARRAY_SIZE(tune_dmd_setting_seq1));
109	if (ret)
110		return ret;
111
112	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
113				     CXD2880_IO_TGT_DMD,
114				     0x00, 0x04);
115	if (ret)
116		return ret;
117
118	switch (clk_mode) {
119	case CXD2880_TNRDMD_CLOCKMODE_A:
120		data = clk_mode_ckffrq_a;
121		break;
122	case CXD2880_TNRDMD_CLOCKMODE_B:
123		data = clk_mode_ckffrq_b;
124		break;
125	case CXD2880_TNRDMD_CLOCKMODE_C:
126		data = clk_mode_ckffrq_c;
127		break;
128	default:
129		return -EINVAL;
130	}
131
132	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
133				      CXD2880_IO_TGT_DMD,
134				      0x65, data, 2);
135	if (ret)
136		return ret;
137
138	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
139				     CXD2880_IO_TGT_DMD,
140				     0x5d, 0x07);
141	if (ret)
142		return ret;
143
144	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
145		u8 data[2] = { 0x01, 0x01 };
146
147		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
148					     CXD2880_IO_TGT_DMD,
149					     0x00, 0x00);
150		if (ret)
151			return ret;
152
153		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
154					      CXD2880_IO_TGT_DMD,
155					      0xce, data, 2);
156		if (ret)
157			return ret;
158	}
159
160	ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
161					  CXD2880_IO_TGT_DMD,
162					  tune_dmd_setting_seq2,
163					  ARRAY_SIZE(tune_dmd_setting_seq2));
164	if (ret)
165		return ret;
166
167	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
168				      CXD2880_IO_TGT_DMD,
169				      0xf0, ratectl_margin, 2);
170	if (ret)
171		return ret;
172
173	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN ||
174	    tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
175		ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
176						  CXD2880_IO_TGT_DMD,
177						  tune_dmd_setting_seq3,
178						  ARRAY_SIZE(tune_dmd_setting_seq3));
179		if (ret)
180			return ret;
181	}
182
183	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
184		ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
185						  CXD2880_IO_TGT_DMD,
186						  tune_dmd_setting_seq4,
187						  ARRAY_SIZE(tune_dmd_setting_seq4));
188		if (ret)
189			return ret;
190	}
191
192	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
193		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
194					     CXD2880_IO_TGT_DMD,
195					     0x00, 0x04);
196		if (ret)
197			return ret;
198
199		switch (clk_mode) {
200		case CXD2880_TNRDMD_CLOCKMODE_A:
201			data = maxclkcnt_a;
202			break;
203		case CXD2880_TNRDMD_CLOCKMODE_B:
204			data = maxclkcnt_b;
205			break;
206		case CXD2880_TNRDMD_CLOCKMODE_C:
207			data = maxclkcnt_c;
208			break;
209		default:
210			return -EINVAL;
211		}
212
213		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
214					      CXD2880_IO_TGT_DMD,
215					      0x68, data, 3);
216		if (ret)
217			return ret;
218	}
219
220	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
221				     CXD2880_IO_TGT_DMD,
222				     0x00, 0x04);
223	if (ret)
224		return ret;
225
226	switch (bandwidth) {
227	case CXD2880_DTV_BW_8_MHZ:
228		switch (clk_mode) {
229		case CXD2880_TNRDMD_CLOCKMODE_A:
230		case CXD2880_TNRDMD_CLOCKMODE_C:
231			data = bw8_nomi_ac;
232			break;
233		case CXD2880_TNRDMD_CLOCKMODE_B:
234			data = bw8_nomi_b;
235			break;
236		default:
237			return -EINVAL;
238		}
239
240		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
241					      CXD2880_IO_TGT_DMD,
242					      0x60, data, 5);
243		if (ret)
244			return ret;
245
246		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
247					     CXD2880_IO_TGT_DMD,
248					     0x4a, 0x00);
249		if (ret)
250			return ret;
251
252		switch (clk_mode) {
253		case CXD2880_TNRDMD_CLOCKMODE_A:
254			data = bw8_gtdofst_a;
255			break;
256		case CXD2880_TNRDMD_CLOCKMODE_B:
257			data = bw8_gtdofst_b;
258			break;
259		case CXD2880_TNRDMD_CLOCKMODE_C:
260			data = bw8_gtdofst_c;
261			break;
262		default:
263			return -EINVAL;
264		}
265
266		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
267					      CXD2880_IO_TGT_DMD,
268					      0x7d, data, 2);
269		if (ret)
270			return ret;
271
272		switch (clk_mode) {
273		case CXD2880_TNRDMD_CLOCKMODE_A:
274		case CXD2880_TNRDMD_CLOCKMODE_B:
275			sst_data = 0x35;
276			break;
277		case CXD2880_TNRDMD_CLOCKMODE_C:
278			sst_data = 0x34;
279			break;
280		default:
281			return -EINVAL;
282		}
283
284		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
285					     CXD2880_IO_TGT_DMD,
286					     0x71, sst_data);
287		if (ret)
288			return ret;
289
290		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
291			switch (clk_mode) {
292			case CXD2880_TNRDMD_CLOCKMODE_A:
293				data = bw8_mrc_a;
294				break;
295			case CXD2880_TNRDMD_CLOCKMODE_B:
296				data = bw8_mrc_b;
297				break;
298			case CXD2880_TNRDMD_CLOCKMODE_C:
299				data = bw8_mrc_c;
300				break;
301			default:
302				return -EINVAL;
303			}
304
305			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
306						      CXD2880_IO_TGT_DMD,
307						      0x4b, &data[0], 2);
308			if (ret)
309				return ret;
310
311			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
312						      CXD2880_IO_TGT_DMD,
313						      0x51, &data[2], 3);
314			if (ret)
315				return ret;
316		}
317
318		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
319					      CXD2880_IO_TGT_DMD,
320					      0x72, &bw8_notch[0], 2);
321		if (ret)
322			return ret;
323
324		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
325					      CXD2880_IO_TGT_DMD,
326					      0x6b, &bw8_notch[2], 2);
327		if (ret)
328			return ret;
329		break;
330
331	case CXD2880_DTV_BW_7_MHZ:
332		switch (clk_mode) {
333		case CXD2880_TNRDMD_CLOCKMODE_A:
334		case CXD2880_TNRDMD_CLOCKMODE_C:
335			data = bw7_nomi_ac;
336			break;
337		case CXD2880_TNRDMD_CLOCKMODE_B:
338			data = bw7_nomi_b;
339			break;
340		default:
341			return -EINVAL;
342		}
343
344		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
345					      CXD2880_IO_TGT_DMD,
346					      0x60, data, 5);
347		if (ret)
348			return ret;
349
350		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
351					     CXD2880_IO_TGT_DMD,
352					     0x4a, 0x02);
353		if (ret)
354			return ret;
355
356		switch (clk_mode) {
357		case CXD2880_TNRDMD_CLOCKMODE_A:
358			data = bw7_gtdofst_a;
359			break;
360		case CXD2880_TNRDMD_CLOCKMODE_B:
361			data = bw7_gtdofst_b;
362			break;
363		case CXD2880_TNRDMD_CLOCKMODE_C:
364			data = bw7_gtdofst_c;
365			break;
366		default:
367			return -EINVAL;
368		}
369
370		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
371					      CXD2880_IO_TGT_DMD,
372					      0x7d, data, 2);
373		if (ret)
374			return ret;
375
376		switch (clk_mode) {
377		case CXD2880_TNRDMD_CLOCKMODE_A:
378		case CXD2880_TNRDMD_CLOCKMODE_B:
379			sst_data = 0x2f;
380			break;
381		case CXD2880_TNRDMD_CLOCKMODE_C:
382			sst_data = 0x2e;
383			break;
384		default:
385			return -EINVAL;
386		}
387
388		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
389					     CXD2880_IO_TGT_DMD,
390					     0x71, sst_data);
391		if (ret)
392			return ret;
393
394		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
395			switch (clk_mode) {
396			case CXD2880_TNRDMD_CLOCKMODE_A:
397				data = bw7_mrc_a;
398				break;
399			case CXD2880_TNRDMD_CLOCKMODE_B:
400				data = bw7_mrc_b;
401				break;
402			case CXD2880_TNRDMD_CLOCKMODE_C:
403				data = bw7_mrc_c;
404				break;
405			default:
406				return -EINVAL;
407			}
408
409			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
410						      CXD2880_IO_TGT_DMD,
411						      0x4b, &data[0], 2);
412			if (ret)
413				return ret;
414
415			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
416						      CXD2880_IO_TGT_DMD,
417						      0x51, &data[2], 3);
418			if (ret)
419				return ret;
420		}
421
422		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
423					      CXD2880_IO_TGT_DMD,
424					      0x72, &bw7_notch[0], 2);
425		if (ret)
426			return ret;
427
428		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
429					      CXD2880_IO_TGT_DMD,
430					      0x6b, &bw7_notch[2], 2);
431		if (ret)
432			return ret;
433		break;
434
435	case CXD2880_DTV_BW_6_MHZ:
436		switch (clk_mode) {
437		case CXD2880_TNRDMD_CLOCKMODE_A:
438		case CXD2880_TNRDMD_CLOCKMODE_C:
439			data = bw6_nomi_ac;
440			break;
441		case CXD2880_TNRDMD_CLOCKMODE_B:
442			data = bw6_nomi_b;
443			break;
444		default:
445			return -EINVAL;
446		}
447
448		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
449					      CXD2880_IO_TGT_DMD,
450					      0x60, data, 5);
451		if (ret)
452			return ret;
453
454		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
455					     CXD2880_IO_TGT_DMD,
456					     0x4a, 0x04);
457		if (ret)
458			return ret;
459
460		switch (clk_mode) {
461		case CXD2880_TNRDMD_CLOCKMODE_A:
462			data = bw6_gtdofst_a;
463			break;
464		case CXD2880_TNRDMD_CLOCKMODE_B:
465			data = bw6_gtdofst_b;
466			break;
467		case CXD2880_TNRDMD_CLOCKMODE_C:
468			data = bw6_gtdofst_c;
469			break;
470		default:
471			return -EINVAL;
472		}
473
474		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
475					      CXD2880_IO_TGT_DMD,
476					      0x7d, data, 2);
477		if (ret)
478			return ret;
479
480		switch (clk_mode) {
481		case CXD2880_TNRDMD_CLOCKMODE_A:
482		case CXD2880_TNRDMD_CLOCKMODE_C:
483			sst_data = 0x29;
484			break;
485		case CXD2880_TNRDMD_CLOCKMODE_B:
486			sst_data = 0x2a;
487			break;
488		default:
489			return -EINVAL;
490		}
491
492		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
493					     CXD2880_IO_TGT_DMD,
494					     0x71, sst_data);
495		if (ret)
496			return ret;
497
498		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
499			switch (clk_mode) {
500			case CXD2880_TNRDMD_CLOCKMODE_A:
501				data = bw6_mrc_a;
502				break;
503			case CXD2880_TNRDMD_CLOCKMODE_B:
504				data = bw6_mrc_b;
505				break;
506			case CXD2880_TNRDMD_CLOCKMODE_C:
507				data = bw6_mrc_c;
508				break;
509			default:
510				return -EINVAL;
511			}
512
513			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
514						      CXD2880_IO_TGT_DMD,
515						      0x4b, &data[0], 2);
516			if (ret)
517				return ret;
518
519			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
520						      CXD2880_IO_TGT_DMD,
521						      0x51, &data[2], 3);
522			if (ret)
523				return ret;
524		}
525
526		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
527					      CXD2880_IO_TGT_DMD,
528					      0x72, &bw6_notch[0], 2);
529		if (ret)
530			return ret;
531
532		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
533					      CXD2880_IO_TGT_DMD,
534					      0x6b, &bw6_notch[2], 2);
535		if (ret)
536			return ret;
537		break;
538
539	case CXD2880_DTV_BW_5_MHZ:
540		switch (clk_mode) {
541		case CXD2880_TNRDMD_CLOCKMODE_A:
542		case CXD2880_TNRDMD_CLOCKMODE_C:
543			data = bw5_nomi_ac;
544			break;
545		case CXD2880_TNRDMD_CLOCKMODE_B:
546			data = bw5_nomi_b;
547			break;
548		default:
549			return -EINVAL;
550		}
551
552		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
553					      CXD2880_IO_TGT_DMD,
554					      0x60, data, 5);
555		if (ret)
556			return ret;
557
558		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
559					     CXD2880_IO_TGT_DMD,
560					     0x4a, 0x06);
561		if (ret)
562			return ret;
563
564		switch (clk_mode) {
565		case CXD2880_TNRDMD_CLOCKMODE_A:
566			data = bw5_gtdofst_a;
567			break;
568		case CXD2880_TNRDMD_CLOCKMODE_B:
569			data = bw5_gtdofst_b;
570			break;
571		case CXD2880_TNRDMD_CLOCKMODE_C:
572			data = bw5_gtdofst_c;
573			break;
574		default:
575			return -EINVAL;
576		}
577
578		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
579					      CXD2880_IO_TGT_DMD,
580					      0x7d, data, 2);
581		if (ret)
582			return ret;
583
584		switch (clk_mode) {
585		case CXD2880_TNRDMD_CLOCKMODE_A:
586		case CXD2880_TNRDMD_CLOCKMODE_B:
587			sst_data = 0x24;
588			break;
589		case CXD2880_TNRDMD_CLOCKMODE_C:
590			sst_data = 0x23;
591			break;
592		default:
593			return -EINVAL;
594		}
595
596		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
597					     CXD2880_IO_TGT_DMD,
598					     0x71, sst_data);
599		if (ret)
600			return ret;
601
602		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
603			switch (clk_mode) {
604			case CXD2880_TNRDMD_CLOCKMODE_A:
605				data = bw5_mrc_a;
606				break;
607			case CXD2880_TNRDMD_CLOCKMODE_B:
608				data = bw5_mrc_b;
609				break;
610			case CXD2880_TNRDMD_CLOCKMODE_C:
611				data = bw5_mrc_c;
612				break;
613			default:
614				return -EINVAL;
615			}
616
617			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
618						      CXD2880_IO_TGT_DMD,
619						      0x4b, &data[0], 2);
620			if (ret)
621				return ret;
622
623			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
624						      CXD2880_IO_TGT_DMD,
625						      0x51, &data[2], 3);
626			if (ret)
627				return ret;
628		}
629
630		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
631					      CXD2880_IO_TGT_DMD,
632					      0x72, &bw5_notch[0], 2);
633		if (ret)
634			return ret;
635
636		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
637					      CXD2880_IO_TGT_DMD,
638					      0x6b, &bw5_notch[2], 2);
639		if (ret)
640			return ret;
641		break;
642
643	default:
644		return -EINVAL;
645	}
646
647	return cxd2880_io_write_multi_regs(tnr_dmd->io,
648					   CXD2880_IO_TGT_DMD,
649					   tune_dmd_setting_seq5,
650					   ARRAY_SIZE(tune_dmd_setting_seq5));
651}
652
653static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
654						   *tnr_dmd)
655{
656	int ret;
657
658	if (!tnr_dmd)
659		return -EINVAL;
660
661	ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
662					  CXD2880_IO_TGT_DMD,
663					  sleep_dmd_setting_seq1,
664					  ARRAY_SIZE(sleep_dmd_setting_seq1));
665	if (ret)
666		return ret;
667
668	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
669		ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
670						  CXD2880_IO_TGT_DMD,
671						  sleep_dmd_setting_seq2,
672						  ARRAY_SIZE(sleep_dmd_setting_seq2));
673
674	return ret;
675}
676
677static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
678			    enum cxd2880_dvbt_profile profile)
679{
680	int ret;
681
682	if (!tnr_dmd)
683		return -EINVAL;
684
685	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
686				     CXD2880_IO_TGT_DMD,
687				     0x00, 0x10);
688	if (ret)
689		return ret;
690
691	return tnr_dmd->io->write_reg(tnr_dmd->io,
692				      CXD2880_IO_TGT_DMD,
693				      0x67,
694				      (profile == CXD2880_DVBT_PROFILE_HP)
695				      ? 0x00 : 0x01);
696}
697
698int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
699			      struct cxd2880_dvbt_tune_param
700			      *tune_param)
701{
702	int ret;
703
704	if (!tnr_dmd || !tune_param)
705		return -EINVAL;
706
707	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
708		return -EINVAL;
709
710	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
711	    tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
712		return -EINVAL;
713
714	ret =
715	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT,
716						tune_param->center_freq_khz,
717						tune_param->bandwidth, 0, 0);
718	if (ret)
719		return ret;
720
721	ret =
722	    x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth,
723				      tnr_dmd->clk_mode);
724	if (ret)
725		return ret;
726
727	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
728		ret =
729		    x_tune_dvbt_demod_setting(tnr_dmd->diver_sub,
730					      tune_param->bandwidth,
731					      tnr_dmd->diver_sub->clk_mode);
732		if (ret)
733			return ret;
734	}
735
736	return dvbt_set_profile(tnr_dmd, tune_param->profile);
737}
738
739int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
740			      struct cxd2880_dvbt_tune_param
741			      *tune_param)
742{
743	int ret;
744
745	if (!tnr_dmd || !tune_param)
746		return -EINVAL;
747
748	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
749		return -EINVAL;
750
751	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
752	    tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
753		return -EINVAL;
754
755	ret =
756	    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT,
757						0);
758	if (ret)
759		return ret;
760
761	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
762	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
763	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT;
764	tnr_dmd->bandwidth = tune_param->bandwidth;
765
766	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
767		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
768		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
769		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT;
770		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
771	}
772
773	return 0;
774}
775
776int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd)
777{
778	int ret;
779
780	if (!tnr_dmd)
781		return -EINVAL;
782
783	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
784		return -EINVAL;
785
786	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
787	    tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
788		return -EINVAL;
789
790	ret = x_sleep_dvbt_demod_setting(tnr_dmd);
791	if (ret)
792		return ret;
793
794	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
795		ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
796
797	return ret;
798}
799
800int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
801					 *tnr_dmd,
802					 enum
803					 cxd2880_tnrdmd_lock_result
804					 *lock)
805{
806	int ret;
807
808	u8 sync_stat = 0;
809	u8 ts_lock = 0;
810	u8 unlock_detected = 0;
811	u8 unlock_detected_sub = 0;
812
813	if (!tnr_dmd || !lock)
814		return -EINVAL;
815
816	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
817		return -EINVAL;
818
819	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
820		return -EINVAL;
821
822	ret =
823	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
824					      &unlock_detected);
825	if (ret)
826		return ret;
827
828	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
829		if (sync_stat == 6)
830			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
831		else if (unlock_detected)
832			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
833		else
834			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
835
836		return 0;
837	}
838
839	if (sync_stat == 6) {
840		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
841		return 0;
842	}
843
844	ret =
845	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
846						  &unlock_detected_sub);
847	if (ret)
848		return ret;
849
850	if (sync_stat == 6)
851		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
852	else if (unlock_detected && unlock_detected_sub)
853		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
854	else
855		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
856
857	return 0;
858}
859
860int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
861				      *tnr_dmd,
862				      enum
863				      cxd2880_tnrdmd_lock_result
864				      *lock)
865{
866	int ret;
867
868	u8 sync_stat = 0;
869	u8 ts_lock = 0;
870	u8 unlock_detected = 0;
871	u8 unlock_detected_sub = 0;
872
873	if (!tnr_dmd || !lock)
874		return -EINVAL;
875
876	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
877		return -EINVAL;
878
879	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
880		return -EINVAL;
881
882	ret =
883	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
884					      &unlock_detected);
885	if (ret)
886		return ret;
887
888	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
889		if (ts_lock)
890			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
891		else if (unlock_detected)
892			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
893		else
894			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
895
896		return 0;
897	}
898
899	if (ts_lock) {
900		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
901		return 0;
902	} else if (!unlock_detected) {
903		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
904		return 0;
905	}
906
907	ret =
908	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
909						  &unlock_detected_sub);
910	if (ret)
911		return ret;
912
913	if (unlock_detected && unlock_detected_sub)
914		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
915	else
916		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
917
918	return 0;
919}
920