summaryrefslogblamecommitdiffstats
path: root/drivers/media/dvb-frontends/cxd2841er.c
blob: db51790c14fd16ddebcc7ff730cf05ff824449a7 (plain) (tree)
1
2
3
4
5
6
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677


              


                                                






























                                                                       

                                  















                                                      
                                             








































































































































                                                                            


                                                                            















                                                                         
                                      





                                                           
                                       



                                   
                                     
                                                                              



                                       






























































































































































































































































































































































































































































                                                                            






































                                                                      
















                                                                          


















                                                                         
























































































































                                                                                            
                       

                                                     




                                                                   

















































































                                                                             


















                                                               
























                                                                            













                                                                       











































































                                                                           

                                                                       





































                                                                              

                                                                      
























































                                                                              































                                                                      












































































































































































































































































                                                                              
                                                                       
























                                                                           






























                                                                            










                                                                           















                                                                           




















































                                                                           



                                                              
























                                                                    


                                                 

























                                                                              


                                                               



































































































































































































































                                                                             
                                   
                   























                                                                  
 

































                                                                            

                                                        




                                                            



                                                        
































                                                                     

                      
































                                                                     

                      
































                                                                     

                      
































































































































































































                                                                                


                                                                        
                                                     

                               















































































                                                                            
                                           
















                                                        




                                            


























                                                                 








                                                                       




















































































                                                                       













































































                                                                      

























































                                                                      

                                                                    




                                                           












































                                                                         
                                                                                  

                                                                      
                                                        






















































































                                                                            














                                                                            




















































































































































                                                                             


                                                             

































































































































































                                                                              
                                                   
















                                                                          
                               













                                                         





                                                                 


















                                                                   
                                                                           
























                                                                          






                                                                     






































































                                                                        



































                                                             






























                                                             

                                                                                     
                      
/*
 * cxd2841er.c
 *
 * Sony digital demodulator driver for
 *	CXD2441ER - DVB-S/S2/T/T2/C/C2
 *	CXD2454ER - DVB-S/S2/T/T2/C/C2, ISDB-T/S
 *
 * Copyright 2012 Sony Corporation
 * Copyright (C) 2014 NetUP Inc.
 * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
 * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
  */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/math64.h>
#include <linux/log2.h>
#include <linux/dynamic_debug.h>

#include "dvb_math.h"
#include "dvb_frontend.h"
#include "cxd2841er.h"
#include "cxd2841er_priv.h"

#define MAX_WRITE_REGSIZE	16

enum cxd2841er_state {
	STATE_SHUTDOWN = 0,
	STATE_SLEEP_S,
	STATE_ACTIVE_S,
	STATE_SLEEP_TC,
	STATE_ACTIVE_TC
};

struct cxd2841er_priv {
	struct dvb_frontend		frontend;
	struct i2c_adapter		*i2c;
	u8				i2c_addr_slvx;
	u8				i2c_addr_slvt;
	const struct cxd2841er_config	*config;
	enum cxd2841er_state		state;
	u8				system;
	enum cxd2841er_xtal		xtal;
};

static const struct cxd2841er_cnr_data s_cn_data[] = {
	{ 0x033e, 0 }, { 0x0339, 100 }, { 0x0333, 200 },
	{ 0x032e, 300 }, { 0x0329, 400 }, { 0x0324, 500 },
	{ 0x031e, 600 }, { 0x0319, 700 }, { 0x0314, 800 },
	{ 0x030f, 900 }, { 0x030a, 1000 }, { 0x02ff, 1100 },
	{ 0x02f4, 1200 }, { 0x02e9, 1300 }, { 0x02de, 1400 },
	{ 0x02d4, 1500 }, { 0x02c9, 1600 }, { 0x02bf, 1700 },
	{ 0x02b5, 1800 }, { 0x02ab, 1900 }, { 0x02a1, 2000 },
	{ 0x029b, 2100 }, { 0x0295, 2200 }, { 0x0290, 2300 },
	{ 0x028a, 2400 }, { 0x0284, 2500 }, { 0x027f, 2600 },
	{ 0x0279, 2700 }, { 0x0274, 2800 }, { 0x026e, 2900 },
	{ 0x0269, 3000 }, { 0x0262, 3100 }, { 0x025c, 3200 },
	{ 0x0255, 3300 }, { 0x024f, 3400 }, { 0x0249, 3500 },
	{ 0x0242, 3600 }, { 0x023c, 3700 }, { 0x0236, 3800 },
	{ 0x0230, 3900 }, { 0x022a, 4000 }, { 0x0223, 4100 },
	{ 0x021c, 4200 }, { 0x0215, 4300 }, { 0x020e, 4400 },
	{ 0x0207, 4500 }, { 0x0201, 4600 }, { 0x01fa, 4700 },
	{ 0x01f4, 4800 }, { 0x01ed, 4900 }, { 0x01e7, 5000 },
	{ 0x01e0, 5100 }, { 0x01d9, 5200 }, { 0x01d2, 5300 },
	{ 0x01cb, 5400 }, { 0x01c4, 5500 }, { 0x01be, 5600 },
	{ 0x01b7, 5700 }, { 0x01b1, 5800 }, { 0x01aa, 5900 },
	{ 0x01a4, 6000 }, { 0x019d, 6100 }, { 0x0196, 6200 },
	{ 0x018f, 6300 }, { 0x0189, 6400 }, { 0x0182, 6500 },
	{ 0x017c, 6600 }, { 0x0175, 6700 }, { 0x016f, 6800 },
	{ 0x0169, 6900 }, { 0x0163, 7000 }, { 0x015c, 7100 },
	{ 0x0156, 7200 }, { 0x0150, 7300 }, { 0x014a, 7400 },
	{ 0x0144, 7500 }, { 0x013e, 7600 }, { 0x0138, 7700 },
	{ 0x0132, 7800 }, { 0x012d, 7900 }, { 0x0127, 8000 },
	{ 0x0121, 8100 }, { 0x011c, 8200 }, { 0x0116, 8300 },
	{ 0x0111, 8400 }, { 0x010b, 8500 }, { 0x0106, 8600 },
	{ 0x0101, 8700 }, { 0x00fc, 8800 }, { 0x00f7, 8900 },
	{ 0x00f2, 9000 }, { 0x00ee, 9100 }, { 0x00ea, 9200 },
	{ 0x00e6, 9300 }, { 0x00e2, 9400 }, { 0x00de, 9500 },
	{ 0x00da, 9600 }, { 0x00d7, 9700 }, { 0x00d3, 9800 },
	{ 0x00d0, 9900 }, { 0x00cc, 10000 }, { 0x00c7, 10100 },
	{ 0x00c3, 10200 }, { 0x00bf, 10300 }, { 0x00ba, 10400 },
	{ 0x00b6, 10500 }, { 0x00b2, 10600 }, { 0x00ae, 10700 },
	{ 0x00aa, 10800 }, { 0x00a7, 10900 }, { 0x00a3, 11000 },
	{ 0x009f, 11100 }, { 0x009c, 11200 }, { 0x0098, 11300 },
	{ 0x0094, 11400 }, { 0x0091, 11500 }, { 0x008e, 11600 },
	{ 0x008a, 11700 }, { 0x0087, 11800 }, { 0x0084, 11900 },
	{ 0x0081, 12000 }, { 0x007e, 12100 }, { 0x007b, 12200 },
	{ 0x0079, 12300 }, { 0x0076, 12400 }, { 0x0073, 12500 },
	{ 0x0071, 12600 }, { 0x006e, 12700 }, { 0x006c, 12800 },
	{ 0x0069, 12900 }, { 0x0067, 13000 }, { 0x0065, 13100 },
	{ 0x0062, 13200 }, { 0x0060, 13300 }, { 0x005e, 13400 },
	{ 0x005c, 13500 }, { 0x005a, 13600 }, { 0x0058, 13700 },
	{ 0x0056, 13800 }, { 0x0054, 13900 }, { 0x0052, 14000 },
	{ 0x0050, 14100 }, { 0x004e, 14200 }, { 0x004c, 14300 },
	{ 0x004b, 14400 }, { 0x0049, 14500 }, { 0x0047, 14600 },
	{ 0x0046, 14700 }, { 0x0044, 14800 }, { 0x0043, 14900 },
	{ 0x0041, 15000 }, { 0x003f, 15100 }, { 0x003e, 15200 },
	{ 0x003c, 15300 }, { 0x003b, 15400 }, { 0x003a, 15500 },
	{ 0x0037, 15700 }, { 0x0036, 15800 }, { 0x0034, 15900 },
	{ 0x0033, 16000 }, { 0x0032, 16100 }, { 0x0031, 16200 },
	{ 0x0030, 16300 }, { 0x002f, 16400 }, { 0x002e, 16500 },
	{ 0x002d, 16600 }, { 0x002c, 16700 }, { 0x002b, 16800 },
	{ 0x002a, 16900 }, { 0x0029, 17000 }, { 0x0028, 17100 },
	{ 0x0027, 17200 }, { 0x0026, 17300 }, { 0x0025, 17400 },
	{ 0x0024, 17500 }, { 0x0023, 17600 }, { 0x0022, 17800 },
	{ 0x0021, 17900 }, { 0x0020, 18000 }, { 0x001f, 18200 },
	{ 0x001e, 18300 }, { 0x001d, 18500 }, { 0x001c, 18700 },
	{ 0x001b, 18900 }, { 0x001a, 19000 }, { 0x0019, 19200 },
	{ 0x0018, 19300 }, { 0x0017, 19500 }, { 0x0016, 19700 },
	{ 0x0015, 19900 }, { 0x0014, 20000 },
};

static const struct cxd2841er_cnr_data s2_cn_data[] = {
	{ 0x05af, 0 }, { 0x0597, 100 }, { 0x057e, 200 },
	{ 0x0567, 300 }, { 0x0550, 400 }, { 0x0539, 500 },
	{ 0x0522, 600 }, { 0x050c, 700 }, { 0x04f6, 800 },
	{ 0x04e1, 900 }, { 0x04cc, 1000 }, { 0x04b6, 1100 },
	{ 0x04a1, 1200 }, { 0x048c, 1300 }, { 0x0477, 1400 },
	{ 0x0463, 1500 }, { 0x044f, 1600 }, { 0x043c, 1700 },
	{ 0x0428, 1800 }, { 0x0416, 1900 }, { 0x0403, 2000 },
	{ 0x03ef, 2100 }, { 0x03dc, 2200 }, { 0x03c9, 2300 },
	{ 0x03b6, 2400 }, { 0x03a4, 2500 }, { 0x0392, 2600 },
	{ 0x0381, 2700 }, { 0x036f, 2800 }, { 0x035f, 2900 },
	{ 0x034e, 3000 }, { 0x033d, 3100 }, { 0x032d, 3200 },
	{ 0x031d, 3300 }, { 0x030d, 3400 }, { 0x02fd, 3500 },
	{ 0x02ee, 3600 }, { 0x02df, 3700 }, { 0x02d0, 3800 },
	{ 0x02c2, 3900 }, { 0x02b4, 4000 }, { 0x02a6, 4100 },
	{ 0x0299, 4200 }, { 0x028c, 4300 }, { 0x027f, 4400 },
	{ 0x0272, 4500 }, { 0x0265, 4600 }, { 0x0259, 4700 },
	{ 0x024d, 4800 }, { 0x0241, 4900 }, { 0x0236, 5000 },
	{ 0x022b, 5100 }, { 0x0220, 5200 }, { 0x0215, 5300 },
	{ 0x020a, 5400 }, { 0x0200, 5500 }, { 0x01f6, 5600 },
	{ 0x01ec, 5700 }, { 0x01e2, 5800 }, { 0x01d8, 5900 },
	{ 0x01cf, 6000 }, { 0x01c6, 6100 }, { 0x01bc, 6200 },
	{ 0x01b3, 6300 }, { 0x01aa, 6400 }, { 0x01a2, 6500 },
	{ 0x0199, 6600 }, { 0x0191, 6700 }, { 0x0189, 6800 },
	{ 0x0181, 6900 }, { 0x0179, 7000 }, { 0x0171, 7100 },
	{ 0x0169, 7200 }, { 0x0161, 7300 }, { 0x015a, 7400 },
	{ 0x0153, 7500 }, { 0x014b, 7600 }, { 0x0144, 7700 },
	{ 0x013d, 7800 }, { 0x0137, 7900 }, { 0x0130, 8000 },
	{ 0x012a, 8100 }, { 0x0124, 8200 }, { 0x011e, 8300 },
	{ 0x0118, 8400 }, { 0x0112, 8500 }, { 0x010c, 8600 },
	{ 0x0107, 8700 }, { 0x0101, 8800 }, { 0x00fc, 8900 },
	{ 0x00f7, 9000 }, { 0x00f2, 9100 }, { 0x00ec, 9200 },
	{ 0x00e7, 9300 }, { 0x00e2, 9400 }, { 0x00dd, 9500 },
	{ 0x00d8, 9600 }, { 0x00d4, 9700 }, { 0x00cf, 9800 },
	{ 0x00ca, 9900 }, { 0x00c6, 10000 }, { 0x00c2, 10100 },
	{ 0x00be, 10200 }, { 0x00b9, 10300 }, { 0x00b5, 10400 },
	{ 0x00b1, 10500 }, { 0x00ae, 10600 }, { 0x00aa, 10700 },
	{ 0x00a6, 10800 }, { 0x00a3, 10900 }, { 0x009f, 11000 },
	{ 0x009b, 11100 }, { 0x0098, 11200 }, { 0x0095, 11300 },
	{ 0x0091, 11400 }, { 0x008e, 11500 }, { 0x008b, 11600 },
	{ 0x0088, 11700 }, { 0x0085, 11800 }, { 0x0082, 11900 },
	{ 0x007f, 12000 }, { 0x007c, 12100 }, { 0x007a, 12200 },
	{ 0x0077, 12300 }, { 0x0074, 12400 }, { 0x0072, 12500 },
	{ 0x006f, 12600 }, { 0x006d, 12700 }, { 0x006b, 12800 },
	{ 0x0068, 12900 }, { 0x0066, 13000 }, { 0x0064, 13100 },
	{ 0x0061, 13200 }, { 0x005f, 13300 }, { 0x005d, 13400 },
	{ 0x005b, 13500 }, { 0x0059, 13600 }, { 0x0057, 13700 },
	{ 0x0055, 13800 }, { 0x0053, 13900 }, { 0x0051, 14000 },
	{ 0x004f, 14100 }, { 0x004e, 14200 }, { 0x004c, 14300 },
	{ 0x004a, 14400 }, { 0x0049, 14500 }, { 0x0047, 14600 },
	{ 0x0045, 14700 }, { 0x0044, 14800 }, { 0x0042, 14900 },
	{ 0x0041, 15000 }, { 0x003f, 15100 }, { 0x003e, 15200 },
	{ 0x003c, 15300 }, { 0x003b, 15400 }, { 0x003a, 15500 },
	{ 0x0038, 15600 }, { 0x0037, 15700 }, { 0x0036, 15800 },
	{ 0x0034, 15900 }, { 0x0033, 16000 }, { 0x0032, 16100 },
	{ 0x0031, 16200 }, { 0x0030, 16300 }, { 0x002f, 16400 },
	{ 0x002e, 16500 }, { 0x002d, 16600 }, { 0x002c, 16700 },
	{ 0x002b, 16800 }, { 0x002a, 16900 }, { 0x0029, 17000 },
	{ 0x0028, 17100 }, { 0x0027, 17200 }, { 0x0026, 17300 },
	{ 0x0025, 17400 }, { 0x0024, 17500 }, { 0x0023, 17600 },
	{ 0x0022, 17800 }, { 0x0021, 17900 }, { 0x0020, 18000 },
	{ 0x001f, 18200 }, { 0x001e, 18300 }, { 0x001d, 18500 },
	{ 0x001c, 18700 }, { 0x001b, 18900 }, { 0x001a, 19000 },
	{ 0x0019, 19200 }, { 0x0018, 19300 }, { 0x0017, 19500 },
	{ 0x0016, 19700 }, { 0x0015, 19900 }, { 0x0014, 20000 },
};

#define MAKE_IFFREQ_CONFIG(iffreq) ((u32)(((iffreq)/41.0)*16777216.0 + 0.5))
#define MAKE_IFFREQ_CONFIG_XTAL(xtal, iffreq) ((xtal == SONY_XTAL_24000) ? \
		(u32)(((iffreq)/48.0)*16777216.0 + 0.5) : \
		(u32)(((iffreq)/41.0)*16777216.0 + 0.5))

static void cxd2841er_i2c_debug(struct cxd2841er_priv *priv,
				u8 addr, u8 reg, u8 write,
				const u8 *data, u32 len)
{
	dev_dbg(&priv->i2c->dev,
		"cxd2841er: I2C %s addr %02x reg 0x%02x size %d\n",
		(write == 0 ? "read" : "write"), addr, reg, len);
	print_hex_dump_bytes("cxd2841er: I2C data: ",
		DUMP_PREFIX_OFFSET, data, len);
}

static int cxd2841er_write_regs(struct cxd2841er_priv *priv,
				u8 addr, u8 reg, const u8 *data, u32 len)
{
	int ret;
	u8 buf[MAX_WRITE_REGSIZE + 1];
	u8 i2c_addr = (addr == I2C_SLVX ?
		priv->i2c_addr_slvx : priv->i2c_addr_slvt);
	struct i2c_msg msg[1] = {
		{
			.addr = i2c_addr,
			.flags = 0,
			.len = len + 1,
			.buf = buf,
		}
	};

	if (len + 1 >= sizeof(buf)) {
		dev_warn(&priv->i2c->dev, "wr reg=%04x: len=%d is too big!\n",
			 reg, len + 1);
		return -E2BIG;
	}

	cxd2841er_i2c_debug(priv, i2c_addr, reg, 1, data, len);
	buf[0] = reg;
	memcpy(&buf[1], data, len);

	ret = i2c_transfer(priv->i2c, msg, 1);
	if (ret >= 0 && ret != 1)
		ret = -EIO;
	if (ret < 0) {
		dev_warn(&priv->i2c->dev,
			"%s: i2c wr failed=%d addr=%02x reg=%02x len=%d\n",
			KBUILD_MODNAME, ret, i2c_addr, reg, len);
		return ret;
	}
	return 0;
}

static int cxd2841er_write_reg(struct cxd2841er_priv *priv,
			       u8 addr, u8 reg, u8 val)
{
	return cxd2841er_write_regs(priv, addr, reg, &val, 1);
}

static int cxd2841er_read_regs(struct cxd2841er_priv *priv,
			       u8 addr, u8 reg, u8 *val, u32 len)
{
	int ret;
	u8 i2c_addr = (addr == I2C_SLVX ?
		priv->i2c_addr_slvx : priv->i2c_addr_slvt);
	struct i2c_msg msg[2] = {
		{
			.addr = i2c_addr,
			.flags = 0,
			.len = 1,
			.buf = &reg,
		}, {
			.addr = i2c_addr,
			.flags = I2C_M_RD,
			.len = len,
			.buf = val,
		}
	};

	ret = i2c_transfer(priv->i2c, &msg[0], 1);
	if (ret >= 0 && ret != 1)
		ret = -EIO;
	if (ret < 0) {
		dev_warn(&priv->i2c->dev,
			"%s: i2c rw failed=%d addr=%02x reg=%02x\n",
			KBUILD_MODNAME, ret, i2c_addr, reg);
		return ret;
	}
	ret = i2c_transfer(priv->i2c, &msg[1], 1);
	if (ret >= 0 && ret != 1)
		ret = -EIO;
	if (ret < 0) {
		dev_warn(&priv->i2c->dev,
			"%s: i2c rd failed=%d addr=%02x reg=%02x\n",
			KBUILD_MODNAME, ret, i2c_addr, reg);
		return ret;
	}
	return 0;
}

static int cxd2841er_read_reg(struct cxd2841er_priv *priv,
			      u8 addr, u8 reg, u8 *val)
{
	return cxd2841er_read_regs(priv, addr, reg, val, 1);
}

static int cxd2841er_set_reg_bits(struct cxd2841er_priv *priv,
				  u8 addr, u8 reg, u8 data, u8 mask)
{
	int res;
	u8 rdata;

	if (mask != 0xff) {
		res = cxd2841er_read_reg(priv, addr, reg, &rdata);
		if (res)
			return res;
		data = ((data & mask) | (rdata & (mask ^ 0xFF)));
	}
	return cxd2841er_write_reg(priv, addr, reg, data);
}

static int cxd2841er_dvbs2_set_symbol_rate(struct cxd2841er_priv *priv,
					   u32 symbol_rate)
{
	u32 reg_value = 0;
	u8 data[3] = {0, 0, 0};

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	/*
	 * regValue = (symbolRateKSps * 2^14 / 1000) + 0.5
	 *          = ((symbolRateKSps * 2^14) + 500) / 1000
	 *          = ((symbolRateKSps * 16384) + 500) / 1000
	 */
	reg_value = DIV_ROUND_CLOSEST(symbol_rate * 16384, 1000);
	if ((reg_value == 0) || (reg_value > 0xFFFFF)) {
		dev_err(&priv->i2c->dev,
			"%s(): reg_value is out of range\n", __func__);
		return -EINVAL;
	}
	data[0] = (u8)((reg_value >> 16) & 0x0F);
	data[1] = (u8)((reg_value >>  8) & 0xFF);
	data[2] = (u8)(reg_value & 0xFF);
	/* Set SLV-T Bank : 0xAE */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xae);
	cxd2841er_write_regs(priv, I2C_SLVT, 0x20, data, 3);
	return 0;
}

static void cxd2841er_set_ts_clock_mode(struct cxd2841er_priv *priv,
					u8 system);

static int cxd2841er_sleep_s_to_active_s(struct cxd2841er_priv *priv,
					 u8 system, u32 symbol_rate)
{
	int ret;
	u8 data[4] = { 0, 0, 0, 0 };

	if (priv->state != STATE_SLEEP_S) {
		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, (int)priv->state);
		return -EINVAL;
	}
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	cxd2841er_set_ts_clock_mode(priv, SYS_DVBS);
	/* Set demod mode */
	if (system == SYS_DVBS) {
		data[0] = 0x0A;
	} else if (system == SYS_DVBS2) {
		data[0] = 0x0B;
	} else {
		dev_err(&priv->i2c->dev, "%s(): invalid delsys %d\n",
			__func__, system);
		return -EINVAL;
	}
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, data[0]);
	/* DVB-S/S2 */
	data[0] = 0x00;
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Enable S/S2 auto detection 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2d, data[0]);
	/* Set SLV-T Bank : 0xAE */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xae);
	/* Enable S/S2 auto detection 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, data[0]);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Enable demod clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01);
	/* Enable ADC clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x31, 0x01);
	/* Enable ADC 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x63, 0x16);
	/* Enable ADC 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x65, 0x3f);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Enable ADC 3 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00);
	/* Set SLV-T Bank : 0xA3 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa3);
	cxd2841er_write_reg(priv, I2C_SLVT, 0xac, 0x00);
	data[0] = 0x07;
	data[1] = 0x3B;
	data[2] = 0x08;
	data[3] = 0xC5;
	/* Set SLV-T Bank : 0xAB */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xab);
	cxd2841er_write_regs(priv, I2C_SLVT, 0x98, data, 4);
	data[0] = 0x05;
	data[1] = 0x80;
	data[2] = 0x0A;
	data[3] = 0x80;
	cxd2841er_write_regs(priv, I2C_SLVT, 0xa8, data, 4);
	data[0] = 0x0C;
	data[1] = 0xCC;
	cxd2841er_write_regs(priv, I2C_SLVT, 0xc3, data, 2);
	/* Set demod parameter */
	ret = cxd2841er_dvbs2_set_symbol_rate(priv, symbol_rate);
	if (ret != 0)
		return ret;
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* disable Hi-Z setting 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x10);
	/* disable Hi-Z setting 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00);
	priv->state = STATE_ACTIVE_S;
	return 0;
}

static int cxd2841er_sleep_tc_to_active_t_band(struct cxd2841er_priv *priv,
					       u32 bandwidth);

static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv,
						u32 bandwidth);

static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv,
					       u32 bandwidth);

static int cxd2841er_retune_active(struct cxd2841er_priv *priv,
				   struct dtv_frontend_properties *p)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_S &&
			priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* disable TS output */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
	if (priv->state == STATE_ACTIVE_S)
		return cxd2841er_dvbs2_set_symbol_rate(
				priv, p->symbol_rate / 1000);
	else if (priv->state == STATE_ACTIVE_TC) {
		switch (priv->system) {
		case SYS_DVBT:
			return cxd2841er_sleep_tc_to_active_t_band(
					priv, p->bandwidth_hz);
		case SYS_DVBT2:
			return cxd2841er_sleep_tc_to_active_t2_band(
					priv, p->bandwidth_hz);
		case SYS_DVBC_ANNEX_A:
			return cxd2841er_sleep_tc_to_active_c_band(
					priv, 8000000);
		}
	}
	dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n",
		__func__, priv->system);
	return -EINVAL;
}

static int cxd2841er_active_s_to_sleep_s(struct cxd2841er_priv *priv)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_S) {
		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* disable TS output */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
	/* enable Hi-Z setting 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x1f);
	/* enable Hi-Z setting 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* disable ADC 1 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* disable ADC clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x31, 0x00);
	/* disable ADC 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x63, 0x16);
	/* disable ADC 3 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x65, 0x27);
	/* SADC Bias ON */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x69, 0x06);
	/* disable demod clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00);
	/* Set SLV-T Bank : 0xAE */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xae);
	/* disable S/S2 auto detection1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* disable S/S2 auto detection2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2d, 0x00);
	priv->state = STATE_SLEEP_S;
	return 0;
}

static int cxd2841er_sleep_s_to_shutdown(struct cxd2841er_priv *priv)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_SLEEP_S) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Disable DSQOUT */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f);
	/* Disable DSQIN */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x9c, 0x00);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Disable oscillator */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x15, 0x01);
	/* Set demod mode */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x01);
	priv->state = STATE_SHUTDOWN;
	return 0;
}

static int cxd2841er_sleep_tc_to_shutdown(struct cxd2841er_priv *priv)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_SLEEP_TC) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Disable oscillator */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x15, 0x01);
	/* Set demod mode */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x01);
	priv->state = STATE_SHUTDOWN;
	return 0;
}

static int cxd2841er_active_t_to_sleep_tc(struct cxd2841er_priv *priv)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_TC) {
		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* disable TS output */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
	/* enable Hi-Z setting 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f);
	/* enable Hi-Z setting 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* disable ADC 1 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Disable ADC 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
	/* Disable ADC 3 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
	/* Disable ADC clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
	/* Disable RF level monitor */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
	/* Disable demod clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00);
	priv->state = STATE_SLEEP_TC;
	return 0;
}

static int cxd2841er_active_t2_to_sleep_tc(struct cxd2841er_priv *priv)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_TC) {
		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* disable TS output */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
	/* enable Hi-Z setting 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f);
	/* enable Hi-Z setting 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff);
	/* Cancel DVB-T2 setting */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x83, 0x40);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x86, 0x21);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x9e, 0x09, 0x0f);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x9f, 0xfb);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2a);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x38, 0x00, 0x0f);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x11, 0x00, 0x3f);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* disable ADC 1 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Disable ADC 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
	/* Disable ADC 3 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
	/* Disable ADC clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
	/* Disable RF level monitor */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
	/* Disable demod clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00);
	priv->state = STATE_SLEEP_TC;
	return 0;
}

static int cxd2841er_active_c_to_sleep_tc(struct cxd2841er_priv *priv)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_TC) {
		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* disable TS output */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
	/* enable Hi-Z setting 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f);
	/* enable Hi-Z setting 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff);
	/* Cancel DVB-C setting */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa3, 0x00, 0x1f);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* disable ADC 1 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Disable ADC 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
	/* Disable ADC 3 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
	/* Disable ADC clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
	/* Disable RF level monitor */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
	/* Disable demod clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00);
	priv->state = STATE_SLEEP_TC;
	return 0;
}

static int cxd2841er_active_i_to_sleep_tc(struct cxd2841er_priv *priv)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_TC) {
		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
				__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* disable TS output */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
	/* enable Hi-Z setting 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f);
	/* enable Hi-Z setting 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff);

	/* TODO: Cancel demod parameter */

	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* disable ADC 1 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Disable ADC 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
	/* Disable ADC 3 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
	/* Disable ADC clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
	/* Disable RF level monitor */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
	/* Disable demod clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00);
	priv->state = STATE_SLEEP_TC;
	return 0;
}

static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_SHUTDOWN) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Clear all demodulator registers */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x02, 0x00);
	usleep_range(3000, 5000);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Set demod SW reset */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01);

	switch (priv->xtal) {
	case SONY_XTAL_20500:
		cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00);
		break;
	case SONY_XTAL_24000:
		/* Select demod frequency */
		cxd2841er_write_reg(priv, I2C_SLVX, 0x12, 0x00);
		cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x03);
		break;
	case SONY_XTAL_41000:
		cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x01);
		break;
	default:
		dev_dbg(&priv->i2c->dev, "%s(): invalid demod xtal %d\n",
				__func__, priv->xtal);
		return -EINVAL;
	}

	/* Set demod mode */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x0a);
	/* Clear demod SW reset */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x00);
	usleep_range(1000, 2000);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* enable DSQOUT */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x1F);
	/* enable DSQIN */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x9C, 0x40);
	/* TADC Bias On */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
	/* SADC Bias On */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x63, 0x16);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x65, 0x27);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x69, 0x06);
	priv->state = STATE_SLEEP_S;
	return 0;
}

static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_SHUTDOWN) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Clear all demodulator registers */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x02, 0x00);
	usleep_range(3000, 5000);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Set demod SW reset */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01);
	/* Set X'tal clock to 20.5Mhz */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x13, 0x00);
	cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00);
	/* Clear demod SW reset */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x00);
	usleep_range(1000, 2000);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* TADC Bias On */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
	/* SADC Bias On */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x63, 0x16);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x65, 0x27);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x69, 0x06);
	priv->state = STATE_SLEEP_TC;
	return 0;
}

static int cxd2841er_tune_done(struct cxd2841er_priv *priv)
{
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0, 0);
	/* SW Reset */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xfe, 0x01);
	/* Enable TS output */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x00);
	return 0;
}

/* Set TS parallel mode */
static void cxd2841er_set_ts_clock_mode(struct cxd2841er_priv *priv,
					u8 system)
{
	u8 serial_ts, ts_rate_ctrl_off, ts_in_off;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	cxd2841er_read_reg(priv, I2C_SLVT, 0xc4, &serial_ts);
	cxd2841er_read_reg(priv, I2C_SLVT, 0xd3, &ts_rate_ctrl_off);
	cxd2841er_read_reg(priv, I2C_SLVT, 0xde, &ts_in_off);
	dev_dbg(&priv->i2c->dev, "%s(): ser_ts=0x%02x rate_ctrl_off=0x%02x in_off=0x%02x\n",
		__func__, serial_ts, ts_rate_ctrl_off, ts_in_off);

	/*
	 * slave    Bank    Addr    Bit    default    Name
	 * <SLV-T>  00h     D9h     [7:0]  8'h08      OTSCKPERIOD
	 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xd9, 0x08);
	/*
	 * Disable TS IF Clock
	 * slave    Bank    Addr    Bit    default    Name
	 * <SLV-T>  00h     32h     [0]    1'b1       OREG_CK_TSIF_EN
	 */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x32, 0x00, 0x01);
	/*
	 * slave    Bank    Addr    Bit    default    Name
	 * <SLV-T>  00h     33h     [1:0]  2'b01      OREG_CKSEL_TSIF
	 */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x33, 0x00, 0x03);
	/*
	 * Enable TS IF Clock
	 * slave    Bank    Addr    Bit    default    Name
	 * <SLV-T>  00h     32h     [0]    1'b1       OREG_CK_TSIF_EN
	 */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x32, 0x01, 0x01);

	if (system == SYS_DVBT) {
		/* Enable parity period for DVB-T */
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
		cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x66, 0x01, 0x01);
	} else if (system == SYS_DVBC_ANNEX_A) {
		/* Enable parity period for DVB-C */
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40);
		cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x66, 0x01, 0x01);
	}
}

static u8 cxd2841er_chip_id(struct cxd2841er_priv *priv)
{
	u8 chip_id = 0;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (cxd2841er_write_reg(priv, I2C_SLVT, 0, 0) == 0)
		cxd2841er_read_reg(priv, I2C_SLVT, 0xfd, &chip_id);
	else if (cxd2841er_write_reg(priv, I2C_SLVX, 0, 0) == 0)
		cxd2841er_read_reg(priv, I2C_SLVX, 0xfd, &chip_id);

	return chip_id;
}

static int cxd2841er_read_status_s(struct dvb_frontend *fe,
				   enum fe_status *status)
{
	u8 reg = 0;
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	*status = 0;
	if (priv->state != STATE_ACTIVE_S) {
		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/* Set SLV-T Bank : 0xA0 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
	/*
	 *  slave     Bank      Addr      Bit      Signal name
	 * <SLV-T>    A0h       11h       [2]      ITSLOCK
	 */
	cxd2841er_read_reg(priv, I2C_SLVT, 0x11, &reg);
	if (reg & 0x04) {
		*status = FE_HAS_SIGNAL
			| FE_HAS_CARRIER
			| FE_HAS_VITERBI
			| FE_HAS_SYNC
			| FE_HAS_LOCK;
	}
	dev_dbg(&priv->i2c->dev, "%s(): result 0x%x\n", __func__, *status);
	return 0;
}

static int cxd2841er_read_status_t_t2(struct cxd2841er_priv *priv,
				      u8 *sync, u8 *tslock, u8 *unlock)
{
	u8 data = 0;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_TC)
		return -EINVAL;
	if (priv->system == SYS_DVBT) {
		/* Set SLV-T Bank : 0x10 */
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	} else {
		/* Set SLV-T Bank : 0x20 */
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20);
	}
	cxd2841er_read_reg(priv, I2C_SLVT, 0x10, &data);
	if ((data & 0x07) == 0x07) {
		dev_dbg(&priv->i2c->dev,
			"%s(): invalid hardware state detected\n", __func__);
		*sync = 0;
		*tslock = 0;
		*unlock = 0;
	} else {
		*sync = ((data & 0x07) == 0x6 ? 1 : 0);
		*tslock = ((data & 0x20) ? 1 : 0);
		*unlock = ((data & 0x10) ? 1 : 0);
	}
	return 0;
}

static int cxd2841er_read_status_c(struct cxd2841er_priv *priv, u8 *tslock)
{
	u8 data;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_TC)
		return -EINVAL;
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40);
	cxd2841er_read_reg(priv, I2C_SLVT, 0x88, &data);
	if ((data & 0x01) == 0) {
		*tslock = 0;
	} else {
		cxd2841er_read_reg(priv, I2C_SLVT, 0x10, &data);
		*tslock = ((data & 0x20) ? 1 : 0);
	}
	return 0;
}

static int cxd2841er_read_status_i(struct cxd2841er_priv *priv,
		u8 *sync, u8 *tslock, u8 *unlock)
{
	u8 data = 0;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_TC)
		return -EINVAL;
	/* Set SLV-T Bank : 0x60 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60);
	cxd2841er_read_reg(priv, I2C_SLVT, 0x10, &data);
	dev_dbg(&priv->i2c->dev,
			"%s(): lock=0x%x\n", __func__, data);
	*sync = ((data & 0x02) ? 1 : 0);
	*tslock = ((data & 0x01) ? 1 : 0);
	*unlock = ((data & 0x10) ? 1 : 0);
	return 0;
}

static int cxd2841er_read_status_tc(struct dvb_frontend *fe,
				    enum fe_status *status)
{
	int ret = 0;
	u8 sync = 0;
	u8 tslock = 0;
	u8 unlock = 0;
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	*status = 0;
	if (priv->state == STATE_ACTIVE_TC) {
		if (priv->system == SYS_DVBT || priv->system == SYS_DVBT2) {
			ret = cxd2841er_read_status_t_t2(
				priv, &sync, &tslock, &unlock);
			if (ret)
				goto done;
			if (unlock)
				goto done;
			if (sync)
				*status = FE_HAS_SIGNAL |
					FE_HAS_CARRIER |
					FE_HAS_VITERBI |
					FE_HAS_SYNC;
			if (tslock)
				*status |= FE_HAS_LOCK;
		} else if (priv->system == SYS_ISDBT) {
			ret = cxd2841er_read_status_i(
					priv, &sync, &tslock, &unlock);
			if (ret)
				goto done;
			if (unlock)
				goto done;
			if (sync)
				*status = FE_HAS_SIGNAL |
					FE_HAS_CARRIER |
					FE_HAS_VITERBI |
					FE_HAS_SYNC;
			if (tslock)
				*status |= FE_HAS_LOCK;
		} else if (priv->system == SYS_DVBC_ANNEX_A) {
			ret = cxd2841er_read_status_c(priv, &tslock);
			if (ret)
				goto done;
			if (tslock)
				*status = FE_HAS_SIGNAL |
					FE_HAS_CARRIER |
					FE_HAS_VITERBI |
					FE_HAS_SYNC |
					FE_HAS_LOCK;
		}
	}
done:
	dev_dbg(&priv->i2c->dev, "%s(): status 0x%x\n", __func__, *status);
	return ret;
}

static int cxd2841er_get_carrier_offset_s_s2(struct cxd2841er_priv *priv,
					     int *offset)
{
	u8 data[3];
	u8 is_hs_mode;
	s32 cfrl_ctrlval;
	s32 temp_div, temp_q, temp_r;

	if (priv->state != STATE_ACTIVE_S) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	/*
	 * Get High Sampling Rate mode
	 *  slave     Bank      Addr      Bit      Signal name
	 * <SLV-T>    A0h       10h       [0]      ITRL_LOCK
	 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
	cxd2841er_read_reg(priv, I2C_SLVT, 0x10, &data[0]);
	if (data[0] & 0x01) {
		/*
		 *  slave     Bank      Addr      Bit      Signal name
		 * <SLV-T>    A0h       50h       [4]      IHSMODE
		 */
		cxd2841er_read_reg(priv, I2C_SLVT, 0x50, &data[0]);
		is_hs_mode = (data[0] & 0x10 ? 1 : 0);
	} else {
		dev_dbg(&priv->i2c->dev,
			"%s(): unable to detect sampling rate mode\n",
			__func__);
		return -EINVAL;
	}
	/*
	 *  slave     Bank      Addr      Bit      Signal name
	 * <SLV-T>    A0h       45h       [4:0]    ICFRL_CTRLVAL[20:16]
	 * <SLV-T>    A0h       46h       [7:0]    ICFRL_CTRLVAL[15:8]
	 * <SLV-T>    A0h       47h       [7:0]    ICFRL_CTRLVAL[7:0]
	 */
	cxd2841er_read_regs(priv, I2C_SLVT, 0x45, data, 3);
	cfrl_ctrlval = sign_extend32((((u32)data[0] & 0x1F) << 16) |
				(((u32)data[1] & 0xFF) <<  8) |
				((u32)data[2] & 0xFF), 20);
	temp_div = (is_hs_mode ? 1048576 : 1572864);
	if (cfrl_ctrlval > 0) {
		temp_q = div_s64_rem(97375LL * cfrl_ctrlval,
			temp_div, &temp_r);
	} else {
		temp_q = div_s64_rem(-97375LL * cfrl_ctrlval,
			temp_div, &temp_r);
	}
	if (temp_r >= temp_div / 2)
		temp_q++;
	if (cfrl_ctrlval > 0)
		temp_q *= -1;
	*offset = temp_q;
	return 0;
}

static int cxd2841er_get_carrier_offset_t2(struct cxd2841er_priv *priv,
					   u32 bandwidth, int *offset)
{
	u8 data[4];

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	if (priv->system != SYS_DVBT2) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n",
			__func__, priv->system);
		return -EINVAL;
	}
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20);
	cxd2841er_read_regs(priv, I2C_SLVT, 0x4c, data, sizeof(data));
	*offset = -1 * sign_extend32(
		((u32)(data[0] & 0x0F) << 24) | ((u32)data[1] << 16) |
		((u32)data[2] << 8) | (u32)data[3], 27);
	switch (bandwidth) {
	case 1712000:
		*offset /= 582;
		break;
	case 5000000:
	case 6000000:
	case 7000000:
	case 8000000:
		*offset *= (bandwidth / 1000000);
		*offset /= 940;
		break;
	default:
		dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n",
			__func__, bandwidth);
		return -EINVAL;
	}
	return 0;
}

static int cxd2841er_get_carrier_offset_c(struct cxd2841er_priv *priv,
					  int *offset)
{
	u8 data[2];

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	if (priv->system != SYS_DVBC_ANNEX_A) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n",
			__func__, priv->system);
		return -EINVAL;
	}
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40);
	cxd2841er_read_regs(priv, I2C_SLVT, 0x15, data, sizeof(data));
	*offset = div_s64(41000LL * sign_extend32((((u32)data[0] & 0x3f) << 8)
						| (u32)data[1], 13), 16384);
	return 0;
}

static int cxd2841er_read_packet_errors_t(
		struct cxd2841er_priv *priv, u32 *penum)
{
	u8 data[3];

	*penum = 0;
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	cxd2841er_read_regs(priv, I2C_SLVT, 0xea, data, sizeof(data));
	if (data[2] & 0x01)
		*penum = ((u32)data[0] << 8) | (u32)data[1];
	return 0;
}

static int cxd2841er_read_packet_errors_t2(
		struct cxd2841er_priv *priv, u32 *penum)
{
	u8 data[3];

	*penum = 0;
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x24);
	cxd2841er_read_regs(priv, I2C_SLVT, 0xfd, data, sizeof(data));
	if (data[0] & 0x01)
		*penum = ((u32)data[1] << 8) | (u32)data[2];
	return 0;
}

static int cxd2841er_read_packet_errors_i(
		struct cxd2841er_priv *priv, u32 *penum)
{
	u8 data[2];

	*penum = 0;
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
				__func__, priv->state);
		return -EINVAL;
	}
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60);
	cxd2841er_read_regs(priv, I2C_SLVT, 0xA1, data, 1);

	if (!(data[0] & 0x01))
		return 0;

	/* Layer A */
	cxd2841er_read_regs(priv, I2C_SLVT, 0xA2, data, sizeof(data));
	*penum = ((u32)data[0] << 8) | (u32)data[1];

	/* Layer B */
	cxd2841er_read_regs(priv, I2C_SLVT, 0xA4, data, sizeof(data));
	*penum += ((u32)data[0] << 8) | (u32)data[1];

	/* Layer C */
	cxd2841er_read_regs(priv, I2C_SLVT, 0xA6, data, sizeof(data));
	*penum += ((u32)data[0] << 8) | (u32)data[1];

	return 0;
}

static u32 cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv)
{
	u8 data[11];
	u32 bit_error, bit_count;
	u32 temp_q, temp_r;

	/* Set SLV-T Bank : 0xA0 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
	/*
	 *  slave     Bank      Addr      Bit      Signal name
	 * <SLV-T>    A0h       35h       [0]      IFVBER_VALID
	 * <SLV-T>    A0h       36h       [5:0]    IFVBER_BITERR[21:16]
	 * <SLV-T>    A0h       37h       [7:0]    IFVBER_BITERR[15:8]
	 * <SLV-T>    A0h       38h       [7:0]    IFVBER_BITERR[7:0]
	 * <SLV-T>    A0h       3Dh       [5:0]    IFVBER_BITNUM[21:16]
	 * <SLV-T>    A0h       3Eh       [7:0]    IFVBER_BITNUM[15:8]
	 * <SLV-T>    A0h       3Fh       [7:0]    IFVBER_BITNUM[7:0]
	 */
	cxd2841er_read_regs(priv, I2C_SLVT, 0x35, data, 11);
	if (data[0] & 0x01) {
		bit_error = ((u32)(data[1]  & 0x3F) << 16) |
			((u32)(data[2]  & 0xFF) <<  8) |
			(u32)(data[3]  & 0xFF);
		bit_count = ((u32)(data[8]  & 0x3F) << 16) |
			((u32)(data[9]  & 0xFF) <<  8) |
			(u32)(data[10] & 0xFF);
		/*
		 *	BER = bitError / bitCount
		 *	= (bitError * 10^7) / bitCount
		 *	= ((bitError * 625 * 125 * 128) / bitCount
		 */
		if ((bit_count == 0) || (bit_error > bit_count)) {
			dev_dbg(&priv->i2c->dev,
				"%s(): invalid bit_error %d, bit_count %d\n",
				__func__, bit_error, bit_count);
			return 0;
		}
		temp_q = div_u64_rem(10000000ULL * bit_error,
						bit_count, &temp_r);
		if (bit_count != 1 && temp_r >= bit_count / 2)
			temp_q++;
		return temp_q;
	}
	dev_dbg(&priv->i2c->dev, "%s(): no data available\n", __func__);
	return 0;
}


static u32 cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv)
{
	u8 data[5];
	u32 bit_error, period;
	u32 temp_q, temp_r;
	u32 result = 0;

	/* Set SLV-T Bank : 0xB2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xb2);
	/*
	 *  slave     Bank      Addr      Bit      Signal name
	 * <SLV-T>    B2h       30h       [0]      IFLBER_VALID
	 * <SLV-T>    B2h       31h       [3:0]    IFLBER_BITERR[27:24]
	 * <SLV-T>    B2h       32h       [7:0]    IFLBER_BITERR[23:16]
	 * <SLV-T>    B2h       33h       [7:0]    IFLBER_BITERR[15:8]
	 * <SLV-T>    B2h       34h       [7:0]    IFLBER_BITERR[7:0]
	 */
	cxd2841er_read_regs(priv, I2C_SLVT, 0x30, data, 5);
	if (data[0] & 0x01) {
		/* Bit error count */
		bit_error = ((u32)(data[1] & 0x0F) << 24) |
			((u32)(data[2] & 0xFF) << 16) |
			((u32)(data[3] & 0xFF) <<  8) |
			(u32)(data[4] & 0xFF);

		/* Set SLV-T Bank : 0xA0 */
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
		cxd2841er_read_reg(priv, I2C_SLVT, 0x7a, data);
		/* Measurement period */
		period = (u32)(1 << (data[0] & 0x0F));
		if (period == 0) {
			dev_dbg(&priv->i2c->dev,
				"%s(): period is 0\n", __func__);
			return 0;
		}
		if (bit_error > (period * 64800)) {
			dev_dbg(&priv->i2c->dev,
				"%s(): invalid bit_err 0x%x period 0x%x\n",
				__func__, bit_error, period);
			return 0;
		}
		/*
		 * BER = bitError / (period * 64800)
		 *	= (bitError * 10^7) / (period * 64800)
		 *	= (bitError * 10^5) / (period * 648)
		 *	= (bitError * 12500) / (period * 81)
		 *	= (bitError * 10) * 1250 / (period * 81)
		 */
		temp_q = div_u64_rem(12500ULL * bit_error,
					period * 81, &temp_r);
		if (temp_r >= period * 40)
			temp_q++;
		result = temp_q;
	} else {
		dev_dbg(&priv->i2c->dev,
			"%s(): no data available\n", __func__);
	}
	return result;
}

static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, u32 *ber)
{
	u8 data[4];
	u32 div, q, r;
	u32 bit_err, period_exp, n_ldpc;

	*ber = 0;
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev,
			"%s(): invalid state %d\n", __func__, priv->state);
		return -EINVAL;
	}
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20);
	cxd2841er_read_regs(priv, I2C_SLVT, 0x39, data, sizeof(data));
	if (!(data[0] & 0x10)) {
		dev_dbg(&priv->i2c->dev,
			"%s(): no valid BER data\n", __func__);
		return 0;
	}
	bit_err = ((u32)(data[0] & 0x0f) << 24) |
		((u32)data[1] << 16) |
		((u32)data[2] << 8) |
		(u32)data[3];
	cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data);
	period_exp = data[0] & 0x0f;
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x22);
	cxd2841er_read_reg(priv, I2C_SLVT, 0x5e, data);
	n_ldpc = ((data[0] & 0x03) == 0 ? 16200 : 64800);
	if (bit_err > ((1U << period_exp) * n_ldpc)) {
		dev_dbg(&priv->i2c->dev,
			"%s(): invalid BER value\n", __func__);
		return -EINVAL;
	}
	if (period_exp >= 4) {
		div = (1U << (period_exp - 4)) * (n_ldpc / 200);
		q = div_u64_rem(3125ULL * bit_err, div, &r);
	} else {
		div = (1U << period_exp) * (n_ldpc / 200);
		q = div_u64_rem(50000ULL * bit_err, div, &r);
	}
	*ber = (r >= div / 2) ? q + 1 : q;
	return 0;
}

static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, u32 *ber)
{
	u8 data[2];
	u32 div, q, r;
	u32 bit_err, period;

	*ber = 0;
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev,
			"%s(): invalid state %d\n", __func__, priv->state);
		return -EINVAL;
	}
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	cxd2841er_read_reg(priv, I2C_SLVT, 0x39, data);
	if (!(data[0] & 0x01)) {
		dev_dbg(&priv->i2c->dev,
			"%s(): no valid BER data\n", __func__);
		return 0;
	}
	cxd2841er_read_regs(priv, I2C_SLVT, 0x22, data, sizeof(data));
	bit_err = ((u32)data[0] << 8) | (u32)data[1];
	cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data);
	period = ((data[0] & 0x07) == 0) ? 256 : (4096 << (data[0] & 0x07));
	div = period / 128;
	q = div_u64_rem(78125ULL * bit_err, div, &r);
	*ber = (r >= div / 2) ? q + 1 : q;
	return 0;
}

static u32 cxd2841er_dvbs_read_snr(struct cxd2841er_priv *priv, u8 delsys)
{
	u8 data[3];
	u32 res = 0, value;
	int min_index, max_index, index;
	static const struct cxd2841er_cnr_data *cn_data;

	/* Set SLV-T Bank : 0xA1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa1);
	/*
	 *  slave     Bank      Addr      Bit     Signal name
	 * <SLV-T>    A1h       10h       [0]     ICPM_QUICKRDY
	 * <SLV-T>    A1h       11h       [4:0]   ICPM_QUICKCNDT[12:8]
	 * <SLV-T>    A1h       12h       [7:0]   ICPM_QUICKCNDT[7:0]
	 */
	cxd2841er_read_regs(priv, I2C_SLVT, 0x10, data, 3);
	if (data[0] & 0x01) {
		value = ((u32)(data[1] & 0x1F) << 8) | (u32)(data[2] & 0xFF);
		min_index = 0;
		if (delsys == SYS_DVBS) {
			cn_data = s_cn_data;
			max_index = sizeof(s_cn_data) /
				sizeof(s_cn_data[0]) - 1;
		} else {
			cn_data = s2_cn_data;
			max_index = sizeof(s2_cn_data) /
				sizeof(s2_cn_data[0]) - 1;
		}
		if (value >= cn_data[min_index].value) {
			res = cn_data[min_index].cnr_x1000;
			goto done;
		}
		if (value <= cn_data[max_index].value) {
			res = cn_data[max_index].cnr_x1000;
			goto done;
		}
		while ((max_index - min_index) > 1) {
			index = (max_index + min_index) / 2;
			if (value == cn_data[index].value) {
				res = cn_data[index].cnr_x1000;
				goto done;
			} else if (value > cn_data[index].value)
				max_index = index;
			else
				min_index = index;
			if ((max_index - min_index) <= 1) {
				if (value == cn_data[max_index].value) {
					res = cn_data[max_index].cnr_x1000;
					goto done;
				} else {
					res = cn_data[min_index].cnr_x1000;
					goto done;
				}
			}
		}
	} else {
		dev_dbg(&priv->i2c->dev,
			"%s(): no data available\n", __func__);
	}
done:
	return res;
}

static int cxd2841er_read_snr_t(struct cxd2841er_priv *priv, u32 *snr)
{
	u32 reg;
	u8 data[2];

	*snr = 0;
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev,
			"%s(): invalid state %d\n", __func__, priv->state);
		return -EINVAL;
	}
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data));
	reg = ((u32)data[0] << 8) | (u32)data[1];
	if (reg == 0) {
		dev_dbg(&priv->i2c->dev,
			"%s(): reg value out of range\n", __func__);
		return 0;
	}
	if (reg > 4996)
		reg = 4996;
	*snr = 10000 * ((intlog10(reg) - intlog10(5350 - reg)) >> 24) + 28500;
	return 0;
}

static int cxd2841er_read_snr_t2(struct cxd2841er_priv *priv, u32 *snr)
{
	u32 reg;
	u8 data[2];

	*snr = 0;
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev,
			"%s(): invalid state %d\n", __func__, priv->state);
		return -EINVAL;
	}
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20);
	cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data));
	reg = ((u32)data[0] << 8) | (u32)data[1];
	if (reg == 0) {
		dev_dbg(&priv->i2c->dev,
			"%s(): reg value out of range\n", __func__);
		return 0;
	}
	if (reg > 10876)
		reg = 10876;
	*snr = 10000 * ((intlog10(reg) -
		intlog10(12600 - reg)) >> 24) + 32000;
	return 0;
}

static int cxd2841er_read_snr_i(struct cxd2841er_priv *priv, u32 *snr)
{
	u32 reg;
	u8 data[2];

	*snr = 0;
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev,
				"%s(): invalid state %d\n", __func__,
				priv->state);
		return -EINVAL;
	}

	/* Freeze all registers */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x01, 0x01);


	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60);
	cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data));
	reg = ((u32)data[0] << 8) | (u32)data[1];
	if (reg == 0) {
		dev_dbg(&priv->i2c->dev,
				"%s(): reg value out of range\n", __func__);
		return 0;
	}
	if (reg > 4996)
		reg = 4996;
	*snr = 100 * intlog10(reg) - 9031;
	return 0;
}

static u16 cxd2841er_read_agc_gain_t_t2(struct cxd2841er_priv *priv,
					u8 delsys)
{
	u8 data[2];

	cxd2841er_write_reg(
		priv, I2C_SLVT, 0x00, (delsys == SYS_DVBT ? 0x10 : 0x20));
	cxd2841er_read_regs(priv, I2C_SLVT, 0x26, data, 2);
	return ((((u16)data[0] & 0x0F) << 8) | (u16)(data[1] & 0xFF)) << 4;
}

static u16 cxd2841er_read_agc_gain_i(struct cxd2841er_priv *priv,
		u8 delsys)
{
	u8 data[2];

	cxd2841er_write_reg(
			priv, I2C_SLVT, 0x00, 0x60);
	cxd2841er_read_regs(priv, I2C_SLVT, 0x26, data, 2);

	dev_dbg(&priv->i2c->dev,
			"%s(): AGC value=%u\n",
			__func__, (((u16)data[0] & 0x0F) << 8) |
			(u16)(data[1] & 0xFF));
	return ((((u16)data[0] & 0x0F) << 8) | (u16)(data[1] & 0xFF)) << 4;
}

static u16 cxd2841er_read_agc_gain_s(struct cxd2841er_priv *priv)
{
	u8 data[2];

	/* Set SLV-T Bank : 0xA0 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
	/*
	 *  slave     Bank      Addr      Bit       Signal name
	 * <SLV-T>    A0h       1Fh       [4:0]     IRFAGC_GAIN[12:8]
	 * <SLV-T>    A0h       20h       [7:0]     IRFAGC_GAIN[7:0]
	 */
	cxd2841er_read_regs(priv, I2C_SLVT, 0x1f, data, 2);
	return ((((u16)data[0] & 0x1F) << 8) | (u16)(data[1] & 0xFF)) << 3;
}

static int cxd2841er_read_ber(struct dvb_frontend *fe, u32 *ber)
{
	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	*ber = 0;
	switch (p->delivery_system) {
	case SYS_DVBS:
		*ber = cxd2841er_mon_read_ber_s(priv);
		break;
	case SYS_DVBS2:
		*ber = cxd2841er_mon_read_ber_s2(priv);
		break;
	case SYS_DVBT:
		return cxd2841er_read_ber_t(priv, ber);
	case SYS_DVBT2:
		return cxd2841er_read_ber_t2(priv, ber);
	default:
		*ber = 0;
		break;
	}
	return 0;
}

static int cxd2841er_read_signal_strength(struct dvb_frontend *fe,
					  u16 *strength)
{
	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	switch (p->delivery_system) {
	case SYS_DVBT:
	case SYS_DVBT2:
		*strength = 65535 - cxd2841er_read_agc_gain_t_t2(
			priv, p->delivery_system);
		break;
	case SYS_ISDBT:
		*strength = 65535 - cxd2841er_read_agc_gain_i(
				priv, p->delivery_system);
		break;
	case SYS_DVBS:
	case SYS_DVBS2:
		*strength = 65535 - cxd2841er_read_agc_gain_s(priv);
		break;
	default:
		*strength = 0;
		break;
	}
	return 0;
}

static int cxd2841er_read_snr(struct dvb_frontend *fe, u16 *snr)
{
	u32 tmp = 0;
	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	switch (p->delivery_system) {
	case SYS_DVBT:
		cxd2841er_read_snr_t(priv, &tmp);
		break;
	case SYS_DVBT2:
		cxd2841er_read_snr_t2(priv, &tmp);
		break;
	case SYS_ISDBT:
		cxd2841er_read_snr_i(priv, &tmp);
		break;
	case SYS_DVBS:
	case SYS_DVBS2:
		tmp = cxd2841er_dvbs_read_snr(priv, p->delivery_system);
		break;
	default:
		dev_dbg(&priv->i2c->dev, "%s(): unknown delivery system %d\n",
			__func__, p->delivery_system);
		break;
	}
	*snr = tmp & 0xffff;
	return 0;
}

static int cxd2841er_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	switch (p->delivery_system) {
	case SYS_DVBT:
		cxd2841er_read_packet_errors_t(priv, ucblocks);
		break;
	case SYS_DVBT2:
		cxd2841er_read_packet_errors_t2(priv, ucblocks);
		break;
	case SYS_ISDBT:
		cxd2841er_read_packet_errors_i(priv, ucblocks);
		break;
	default:
		*ucblocks = 0;
		break;
	}
	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	return 0;
}

static int cxd2841er_dvbt2_set_profile(
	struct cxd2841er_priv *priv, enum cxd2841er_dvbt2_profile_t profile)
{
	u8 tune_mode;
	u8 seq_not2d_time;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	switch (profile) {
	case DVBT2_PROFILE_BASE:
		tune_mode = 0x01;
		seq_not2d_time = 12;
		break;
	case DVBT2_PROFILE_LITE:
		tune_mode = 0x05;
		seq_not2d_time = 40;
		break;
	case DVBT2_PROFILE_ANY:
		tune_mode = 0x00;
		seq_not2d_time = 40;
		break;
	default:
		return -EINVAL;
	}
	/* Set SLV-T Bank : 0x2E */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2e);
	/* Set profile and tune mode */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x10, tune_mode, 0x07);
	/* Set SLV-T Bank : 0x2B */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b);
	/* Set early unlock detection time */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x9d, seq_not2d_time);
	return 0;
}

static int cxd2841er_dvbt2_set_plp_config(struct cxd2841er_priv *priv,
					  u8 is_auto, u8 plp_id)
{
	if (is_auto) {
		dev_dbg(&priv->i2c->dev,
			"%s() using auto PLP selection\n", __func__);
	} else {
		dev_dbg(&priv->i2c->dev,
			"%s() using manual PLP selection, ID %d\n",
			__func__, plp_id);
	}
	/* Set SLV-T Bank : 0x23 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x23);
	if (!is_auto) {
		/* Manual PLP selection mode. Set the data PLP Id. */
		cxd2841er_write_reg(priv, I2C_SLVT, 0xaf, plp_id);
	}
	/* Auto PLP select (Scanning mode = 0x00). Data PLP select = 0x01. */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xad, (is_auto ? 0x00 : 0x01));
	return 0;
}

static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv,
						u32 bandwidth)
{
	u32 iffreq;
	u8 b20_9f[5];
	u8 b10_a6[14];
	u8 b10_b6[3];
	u8 b10_d7;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	switch (bandwidth) {
	case 8000000:
		/* bank 0x20, reg 0x9f */
		b20_9f[0] = 0x11;
		b20_9f[1] = 0xf0;
		b20_9f[2] = 0x00;
		b20_9f[3] = 0x00;
		b20_9f[4] = 0x00;
		/* bank 0x10, reg 0xa6 */
		b10_a6[0] = 0x26;
		b10_a6[1] = 0xaf;
		b10_a6[2] = 0x06;
		b10_a6[3] = 0xcd;
		b10_a6[4] = 0x13;
		b10_a6[5] = 0xbb;
		b10_a6[6] = 0x28;
		b10_a6[7] = 0xba;
		b10_a6[8] = 0x23;
		b10_a6[9] = 0xa9;
		b10_a6[10] = 0x1f;
		b10_a6[11] = 0xa8;
		b10_a6[12] = 0x2c;
		b10_a6[13] = 0xc8;
		iffreq = MAKE_IFFREQ_CONFIG(4.80);
		b10_d7 = 0x00;
		break;
	case 7000000:
		/* bank 0x20, reg 0x9f */
		b20_9f[0] = 0x14;
		b20_9f[1] = 0x80;
		b20_9f[2] = 0x00;
		b20_9f[3] = 0x00;
		b20_9f[4] = 0x00;
		/* bank 0x10, reg 0xa6 */
		b10_a6[0] = 0x2C;
		b10_a6[1] = 0xBD;
		b10_a6[2] = 0x02;
		b10_a6[3] = 0xCF;
		b10_a6[4] = 0x04;
		b10_a6[5] = 0xF8;
		b10_a6[6] = 0x23;
		b10_a6[7] = 0xA6;
		b10_a6[8] = 0x29;
		b10_a6[9] = 0xB0;
		b10_a6[10] = 0x26;
		b10_a6[11] = 0xA9;
		b10_a6[12] = 0x21;
		b10_a6[13] = 0xA5;
		iffreq = MAKE_IFFREQ_CONFIG(4.2);
		b10_d7 = 0x02;
		break;
	case 6000000:
		/* bank 0x20, reg 0x9f */
		b20_9f[0] = 0x17;
		b20_9f[1] = 0xEA;
		b20_9f[2] = 0xAA;
		b20_9f[3] = 0xAA;
		b20_9f[4] = 0xAA;
		/* bank 0x10, reg 0xa6 */
		b10_a6[0] = 0x27;
		b10_a6[1] = 0xA7;
		b10_a6[2] = 0x28;
		b10_a6[3] = 0xB3;
		b10_a6[4] = 0x02;
		b10_a6[5] = 0xF0;
		b10_a6[6] = 0x01;
		b10_a6[7] = 0xE8;
		b10_a6[8] = 0x00;
		b10_a6[9] = 0xCF;
		b10_a6[10] = 0x00;
		b10_a6[11] = 0xE6;
		b10_a6[12] = 0x23;
		b10_a6[13] = 0xA4;
		iffreq = MAKE_IFFREQ_CONFIG(3.6);
		b10_d7 = 0x04;
		break;
	case 5000000:
		/* bank 0x20, reg 0x9f */
		b20_9f[0] = 0x1C;
		b20_9f[1] = 0xB3;
		b20_9f[2] = 0x33;
		b20_9f[3] = 0x33;
		b20_9f[4] = 0x33;
		/* bank 0x10, reg 0xa6 */
		b10_a6[0] = 0x27;
		b10_a6[1] = 0xA7;
		b10_a6[2] = 0x28;
		b10_a6[3] = 0xB3;
		b10_a6[4] = 0x02;
		b10_a6[5] = 0xF0;
		b10_a6[6] = 0x01;
		b10_a6[7] = 0xE8;
		b10_a6[8] = 0x00;
		b10_a6[9] = 0xCF;
		b10_a6[10] = 0x00;
		b10_a6[11] = 0xE6;
		b10_a6[12] = 0x23;
		b10_a6[13] = 0xA4;
		iffreq = MAKE_IFFREQ_CONFIG(3.6);
		b10_d7 = 0x06;
		break;
	case 1712000:
		/* bank 0x20, reg 0x9f */
		b20_9f[0] = 0x58;
		b20_9f[1] = 0xE2;
		b20_9f[2] = 0xAF;
		b20_9f[3] = 0xE0;
		b20_9f[4] = 0xBC;
		/* bank 0x10, reg 0xa6 */
		b10_a6[0] = 0x25;
		b10_a6[1] = 0xA0;
		b10_a6[2] = 0x36;
		b10_a6[3] = 0x8D;
		b10_a6[4] = 0x2E;
		b10_a6[5] = 0x94;
		b10_a6[6] = 0x28;
		b10_a6[7] = 0x9B;
		b10_a6[8] = 0x32;
		b10_a6[9] = 0x90;
		b10_a6[10] = 0x2C;
		b10_a6[11] = 0x9D;
		b10_a6[12] = 0x29;
		b10_a6[13] = 0x99;
		iffreq = MAKE_IFFREQ_CONFIG(3.5);
		b10_d7 = 0x03;
		break;
	default:
		return -EINVAL;
	}
	/* Set SLV-T Bank : 0x20 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x20);
	cxd2841er_write_regs(priv, I2C_SLVT, 0x9f, b20_9f, sizeof(b20_9f));
	/* Set SLV-T Bank : 0x27 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27);
	cxd2841er_set_reg_bits(
		priv, I2C_SLVT, 0x7a,
		(bandwidth == 1712000 ? 0x03 : 0x00), 0x0f);
	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	/* Group delay equaliser sett. for ASCOT2E */
	cxd2841er_write_regs(priv, I2C_SLVT, 0xa6, b10_a6, sizeof(b10_a6));
	/* <IF freq setting> */
	b10_b6[0] = (u8) ((iffreq >> 16) & 0xff);
	b10_b6[1] = (u8)((iffreq >> 8) & 0xff);
	b10_b6[2] = (u8)(iffreq & 0xff);
	cxd2841er_write_regs(priv, I2C_SLVT, 0xb6, b10_b6, sizeof(b10_b6));
	/* System bandwidth setting */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, b10_d7, 0x07);
	return 0;
}

static int cxd2841er_sleep_tc_to_active_t_band(
		struct cxd2841er_priv *priv, u32 bandwidth)
{
	u8 data[MAX_WRITE_REGSIZE];
	u32 iffreq;
	u8 nominalRate8bw[3][5] = {
		/* TRCG Nominal Rate [37:0] */
		{0x11, 0xF0, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */
		{0x15, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */
		{0x11, 0xF0, 0x00, 0x00, 0x00}  /* 41MHz XTal */
	};
	u8 nominalRate7bw[3][5] = {
		/* TRCG Nominal Rate [37:0] */
		{0x14, 0x80, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */
		{0x18, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */
		{0x14, 0x80, 0x00, 0x00, 0x00}  /* 41MHz XTal */
	};
	u8 nominalRate6bw[3][5] = {
		/* TRCG Nominal Rate [37:0] */
		{0x17, 0xEA, 0xAA, 0xAA, 0xAA}, /* 20.5MHz XTal */
		{0x1C, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */
		{0x17, 0xEA, 0xAA, 0xAA, 0xAA}  /* 41MHz XTal */
	};
	u8 nominalRate5bw[3][5] = {
		/* TRCG Nominal Rate [37:0] */
		{0x1C, 0xB3, 0x33, 0x33, 0x33}, /* 20.5MHz XTal */
		{0x21, 0x99, 0x99, 0x99, 0x99}, /* 24MHz XTal */
		{0x1C, 0xB3, 0x33, 0x33, 0x33}  /* 41MHz XTal */
	};

	u8 itbCoef8bw[3][14] = {
		{0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, 0x23, 0xA9,
			0x1F, 0xA8, 0x2C, 0xC8}, /* 20.5MHz XTal */
		{0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, 0x29, 0xA5,
			0x2A, 0xAC, 0x29, 0xB5}, /* 24MHz XTal   */
		{0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, 0x23, 0xA9,
			0x1F, 0xA8, 0x2C, 0xC8}  /* 41MHz XTal   */
	};
	u8 itbCoef7bw[3][14] = {
		{0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, 0x29, 0xB0,
			0x26, 0xA9, 0x21, 0xA5}, /* 20.5MHz XTal */
		{0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, 0x29, 0xA2,
			0x2B, 0xA6, 0x2B, 0xAD}, /* 24MHz XTal   */
		{0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, 0x29, 0xB0,
			0x26, 0xA9, 0x21, 0xA5}  /* 41MHz XTal   */
	};
	u8 itbCoef6bw[3][14] = {
		{0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF,
			0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */
		{0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, 0xA4,
			0x29, 0xA2, 0x29, 0xA8}, /* 24MHz XTal   */
		{0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF,
			0x00, 0xE6, 0x23, 0xA4}  /* 41MHz XTal   */
	};
	u8 itbCoef5bw[3][14] = {
		{0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF,
			0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */
		{0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, 0xA4,
			0x29, 0xA2, 0x29, 0xA8}, /* 24MHz XTal   */
		{0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF,
			0x00, 0xE6, 0x23, 0xA4}  /* 41MHz XTal   */
	};

	/* Set SLV-T Bank : 0x13 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13);
	/* Echo performance optimization setting */
	data[0] = 0x01;
	data[1] = 0x14;
	cxd2841er_write_regs(priv, I2C_SLVT, 0x9C, data, 2);

	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);

	switch (bandwidth) {
	case 8000000:
		/* <Timing Recovery setting> */
		cxd2841er_write_regs(priv, I2C_SLVT,
				0x9F, nominalRate8bw[priv->xtal], 5);
		/* Group delay equaliser settings for
		 * ASCOT2D, ASCOT2E and ASCOT3 tuners
		*/
		cxd2841er_write_regs(priv, I2C_SLVT,
				0xA6, itbCoef8bw[priv->xtal], 14);
		/* <IF freq setting> */
		iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.80);
		data[0] = (u8) ((iffreq >> 16) & 0xff);
		data[1] = (u8)((iffreq >> 8) & 0xff);
		data[2] = (u8)(iffreq & 0xff);
		cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3);
		/* System bandwidth setting */
		cxd2841er_set_reg_bits(
			priv, I2C_SLVT, 0xD7, 0x00, 0x07);

		/* Demod core latency setting */
		if (priv->xtal == SONY_XTAL_24000) {
			data[0] = 0x15;
			data[1] = 0x28;
		} else {
			data[0] = 0x01;
			data[1] = 0xE0;
		}
		cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2);

		/* Notch filter setting */
		data[0] = 0x01;
		data[1] = 0x02;
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17);
		cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2);
		break;
	case 7000000:
		/* <Timing Recovery setting> */
		cxd2841er_write_regs(priv, I2C_SLVT,
				0x9F, nominalRate7bw[priv->xtal], 5);
		/* Group delay equaliser settings for
		 * ASCOT2D, ASCOT2E and ASCOT3 tuners
		*/
		cxd2841er_write_regs(priv, I2C_SLVT,
				0xA6, itbCoef7bw[priv->xtal], 14);
		/* <IF freq setting> */
		iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.20);
		data[0] = (u8) ((iffreq >> 16) & 0xff);
		data[1] = (u8)((iffreq >> 8) & 0xff);
		data[2] = (u8)(iffreq & 0xff);
		cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3);
		/* System bandwidth setting */
		cxd2841er_set_reg_bits(
			priv, I2C_SLVT, 0xD7, 0x02, 0x07);

		/* Demod core latency setting */
		if (priv->xtal == SONY_XTAL_24000) {
			data[0] = 0x1F;
			data[1] = 0xF8;
		} else {
			data[0] = 0x12;
			data[1] = 0xF8;
		}
		cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2);

		/* Notch filter setting */
		data[0] = 0x00;
		data[1] = 0x03;
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17);
		cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2);
		break;
	case 6000000:
		/* <Timing Recovery setting> */
		cxd2841er_write_regs(priv, I2C_SLVT,
				0x9F, nominalRate6bw[priv->xtal], 5);
		/* Group delay equaliser settings for
		 * ASCOT2D, ASCOT2E and ASCOT3 tuners
		*/
		cxd2841er_write_regs(priv, I2C_SLVT,
				0xA6, itbCoef6bw[priv->xtal], 14);
		/* <IF freq setting> */
		iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60);
		data[0] = (u8) ((iffreq >> 16) & 0xff);
		data[1] = (u8)((iffreq >> 8) & 0xff);
		data[2] = (u8)(iffreq & 0xff);
		cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3);
		/* System bandwidth setting */
		cxd2841er_set_reg_bits(
			priv, I2C_SLVT, 0xD7, 0x04, 0x07);

		/* Demod core latency setting */
		if (priv->xtal == SONY_XTAL_24000) {
			data[0] = 0x25;
			data[1] = 0x4C;
		} else {
			data[0] = 0x1F;
			data[1] = 0xDC;
		}
		cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2);

		/* Notch filter setting */
		data[0] = 0x00;
		data[1] = 0x03;
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17);
		cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2);
		break;
	case 5000000:
		/* <Timing Recovery setting> */
		cxd2841er_write_regs(priv, I2C_SLVT,
				0x9F, nominalRate5bw[priv->xtal], 5);
		/* Group delay equaliser settings for
		 * ASCOT2D, ASCOT2E and ASCOT3 tuners
		*/
		cxd2841er_write_regs(priv, I2C_SLVT,
				0xA6, itbCoef5bw[priv->xtal], 14);
		/* <IF freq setting> */
		iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60);
		data[0] = (u8) ((iffreq >> 16) & 0xff);
		data[1] = (u8)((iffreq >> 8) & 0xff);
		data[2] = (u8)(iffreq & 0xff);
		cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3);
		/* System bandwidth setting */
		cxd2841er_set_reg_bits(
			priv, I2C_SLVT, 0xD7, 0x06, 0x07);

		/* Demod core latency setting */
		if (priv->xtal == SONY_XTAL_24000) {
			data[0] = 0x2C;
			data[1] = 0xC2;
		} else {
			data[0] = 0x26;
			data[1] = 0x3C;
		}
		cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2);

		/* Notch filter setting */
		data[0] = 0x00;
		data[1] = 0x03;
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17);
		cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2);
		break;
	}

	return 0;
}

static int cxd2841er_sleep_tc_to_active_i_band(
		struct cxd2841er_priv *priv, u32 bandwidth)
{
	u32 iffreq;
	u8 data[3];

	/* TRCG Nominal Rate */
	u8 nominalRate8bw[3][5] = {
		{0x00, 0x00, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */
		{0x11, 0xB8, 0x00, 0x00, 0x00}, /* 24MHz XTal */
		{0x00, 0x00, 0x00, 0x00, 0x00}  /* 41MHz XTal */
	};

	u8 nominalRate7bw[3][5] = {
		{0x00, 0x00, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */
		{0x14, 0x40, 0x00, 0x00, 0x00}, /* 24MHz XTal */
		{0x00, 0x00, 0x00, 0x00, 0x00}  /* 41MHz XTal */
	};

	u8 nominalRate6bw[3][5] = {
		{0x14, 0x2E, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */
		{0x17, 0xA0, 0x00, 0x00, 0x00}, /* 24MHz XTal */
		{0x14, 0x2E, 0x00, 0x00, 0x00}  /* 41MHz XTal */
	};

	u8 itbCoef8bw[3][14] = {
		{0x00}, /* 20.5MHz XTal */
		{0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, 0x29,
			0xA5, 0x2A, 0xAC, 0x29, 0xB5}, /* 24MHz Xtal */
		{0x0}, /* 41MHz XTal   */
	};

	u8 itbCoef7bw[3][14] = {
		{0x00}, /* 20.5MHz XTal */
		{0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, 0x29,
			0xA2, 0x2B, 0xA6, 0x2B, 0xAD}, /* 24MHz Xtal */
		{0x00}, /* 41MHz XTal   */
	};

	u8 itbCoef6bw[3][14] = {
		{0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00,
			0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */
		{0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29,
			0xA4, 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz Xtal   */
		{0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00,
			0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 41MHz XTal   */
	};

	dev_dbg(&priv->i2c->dev, "%s() bandwidth=%u\n", __func__, bandwidth);
	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);

	/*  20.5/41MHz Xtal support is not available
	 *  on ISDB-T 7MHzBW and 8MHzBW
	*/
	if (priv->xtal != SONY_XTAL_24000 && bandwidth > 6000000) {
		dev_err(&priv->i2c->dev,
			"%s(): bandwidth %d supported only for 24MHz xtal\n",
			__func__, bandwidth);
		return -EINVAL;
	}

	switch (bandwidth) {
	case 8000000:
		/* TRCG Nominal Rate */
		cxd2841er_write_regs(priv, I2C_SLVT,
				0x9F, nominalRate8bw[priv->xtal], 5);
		/*  Group delay equaliser settings for ASCOT tuners optimized */
		cxd2841er_write_regs(priv, I2C_SLVT,
				0xA6, itbCoef8bw[priv->xtal], 14);

		/* IF freq setting */
		iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.75);
		data[0] = (u8) ((iffreq >> 16) & 0xff);
		data[1] = (u8)((iffreq >> 8) & 0xff);
		data[2] = (u8)(iffreq & 0xff);
		cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3);

		/* System bandwidth setting */
		cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, 0x0, 0x7);

		/* Demod core latency setting */
		data[0] = 0x13;
		data[1] = 0xFC;
		cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2);

		/* Acquisition optimization setting */
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x12);
		cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x71, 0x03, 0x07);
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15);
		cxd2841er_write_reg(priv, I2C_SLVT, 0xBE, 0x03);
		break;
	case 7000000:
		/* TRCG Nominal Rate */
		cxd2841er_write_regs(priv, I2C_SLVT,
				0x9F, nominalRate7bw[priv->xtal], 5);
		/*  Group delay equaliser settings for ASCOT tuners optimized */
		cxd2841er_write_regs(priv, I2C_SLVT,
				0xA6, itbCoef7bw[priv->xtal], 14);

		/* IF freq setting */
		iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.15);
		data[0] = (u8) ((iffreq >> 16) & 0xff);
		data[1] = (u8)((iffreq >> 8) & 0xff);
		data[2] = (u8)(iffreq & 0xff);
		cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3);

		/* System bandwidth setting */
		cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, 0x02, 0x7);

		/* Demod core latency setting */
		data[0] = 0x1A;
		data[1] = 0xFA;
		cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2);

		/* Acquisition optimization setting */
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x12);
		cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x71, 0x03, 0x07);
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15);
		cxd2841er_write_reg(priv, I2C_SLVT, 0xBE, 0x02);
		break;
	case 6000000:
		/* TRCG Nominal Rate */
		cxd2841er_write_regs(priv, I2C_SLVT,
				0x9F, nominalRate6bw[priv->xtal], 5);
		/*  Group delay equaliser settings for ASCOT tuners optimized */
		cxd2841er_write_regs(priv, I2C_SLVT,
				0xA6, itbCoef6bw[priv->xtal], 14);

		/* IF freq setting */
		iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.55);
		data[0] = (u8) ((iffreq >> 16) & 0xff);
		data[1] = (u8)((iffreq >> 8) & 0xff);
		data[2] = (u8)(iffreq & 0xff);
		cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3);

		/* System bandwidth setting */
		cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, 0x04, 0x7);

		/* Demod core latency setting */
		if (priv->xtal == SONY_XTAL_24000) {
			data[0] = 0x1F;
			data[1] = 0x79;
		} else {
			data[0] = 0x1A;
			data[1] = 0xE2;
		}
		cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2);

		/* Acquisition optimization setting */
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x12);
		cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x71, 0x07, 0x07);
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15);
		cxd2841er_write_reg(priv, I2C_SLVT, 0xBE, 0x02);
		break;
	default:
		dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n",
				__func__, bandwidth);
		return -EINVAL;
	}
	return 0;
}

static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv,
					       u32 bandwidth)
{
	u8 bw7_8mhz_b10_a6[] = {
		0x2D, 0xC7, 0x04, 0xF4, 0x07, 0xC5, 0x2A, 0xB8,
		0x27, 0x9E, 0x27, 0xA4, 0x29, 0xAB };
	u8 bw6mhz_b10_a6[] = {
		0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8,
		0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4 };
	u8 b10_b6[3];
	u32 iffreq;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	switch (bandwidth) {
	case 8000000:
	case 7000000:
		cxd2841er_write_regs(
			priv, I2C_SLVT, 0xa6,
			bw7_8mhz_b10_a6, sizeof(bw7_8mhz_b10_a6));
		iffreq = MAKE_IFFREQ_CONFIG(4.9);
		break;
	case 6000000:
		cxd2841er_write_regs(
			priv, I2C_SLVT, 0xa6,
			bw6mhz_b10_a6, sizeof(bw6mhz_b10_a6));
		iffreq = MAKE_IFFREQ_CONFIG(3.7);
		break;
	default:
		dev_dbg(&priv->i2c->dev, "%s(): unsupported bandwidth %d\n",
			__func__, bandwidth);
		return -EINVAL;
	}
	/* <IF freq setting> */
	b10_b6[0] = (u8) ((iffreq >> 16) & 0xff);
	b10_b6[1] = (u8)((iffreq >> 8) & 0xff);
	b10_b6[2] = (u8)(iffreq & 0xff);
	cxd2841er_write_regs(priv, I2C_SLVT, 0xb6, b10_b6, sizeof(b10_b6));
	/* Set SLV-T Bank : 0x11 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11);
	switch (bandwidth) {
	case 8000000:
	case 7000000:
		cxd2841er_set_reg_bits(
			priv, I2C_SLVT, 0xa3, 0x00, 0x1f);
		break;
	case 6000000:
		cxd2841er_set_reg_bits(
			priv, I2C_SLVT, 0xa3, 0x14, 0x1f);
		break;
	}
	/* Set SLV-T Bank : 0x40 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40);
	switch (bandwidth) {
	case 8000000:
		cxd2841er_set_reg_bits(
			priv, I2C_SLVT, 0x26, 0x0b, 0x0f);
		cxd2841er_write_reg(priv, I2C_SLVT,  0x27, 0x3e);
		break;
	case 7000000:
		cxd2841er_set_reg_bits(
			priv, I2C_SLVT, 0x26, 0x09, 0x0f);
		cxd2841er_write_reg(priv, I2C_SLVT,  0x27, 0xd6);
		break;
	case 6000000:
		cxd2841er_set_reg_bits(
			priv, I2C_SLVT, 0x26, 0x08, 0x0f);
		cxd2841er_write_reg(priv, I2C_SLVT,  0x27, 0x6e);
		break;
	}
	return 0;
}

static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv,
					  u32 bandwidth)
{
	u8 data[2] = { 0x09, 0x54 };
	u8 data24m[3] = {0xDC, 0x6C, 0x00};

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	cxd2841er_set_ts_clock_mode(priv, SYS_DVBT);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Set demod mode */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x01);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Enable demod clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01);
	/* Disable RF level monitor */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
	/* Enable ADC clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
	/* Enable ADC 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a);
	/* Enable ADC 2 & 3 */
	if (priv->xtal == SONY_XTAL_41000) {
		data[0] = 0x0A;
		data[1] = 0xD4;
	}
	cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2);
	/* Enable ADC 4 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00);
	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	/* IFAGC gain settings */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd2, 0x0c, 0x1f);
	/* Set SLV-T Bank : 0x11 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11);
	/* BBAGC TARGET level setting */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x6a, 0x50);
	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	/* ASCOT setting ON */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa5, 0x01, 0x01);
	/* Set SLV-T Bank : 0x18 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x18);
	/* Pre-RS BER moniter setting */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x36, 0x40, 0x07);
	/* FEC Auto Recovery setting */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x30, 0x01, 0x01);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x31, 0x01, 0x01);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* TSIF setting */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01);

	if (priv->xtal == SONY_XTAL_24000) {
		/* Set SLV-T Bank : 0x10 */
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
		cxd2841er_write_reg(priv, I2C_SLVT, 0xBF, 0x60);
		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x18);
		cxd2841er_write_regs(priv, I2C_SLVT, 0x24, data24m, 3);
	}

	cxd2841er_sleep_tc_to_active_t_band(priv, bandwidth);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Disable HiZ Setting 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x28);
	/* Disable HiZ Setting 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00);
	priv->state = STATE_ACTIVE_TC;
	return 0;
}

static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv,
					   u32 bandwidth)
{
	u8 data[2] = { 0x09, 0x54 };

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	cxd2841er_set_ts_clock_mode(priv, SYS_DVBT2);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Set demod mode */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x02);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Enable demod clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01);
	/* Disable RF level monitor */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
	/* Enable ADC clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
	/* Enable ADC 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a);
	/* xtal freq 20.5MHz */
	cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2);
	/* Enable ADC 4 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00);
	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	/* IFAGC gain settings */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd2, 0x0c, 0x1f);
	/* Set SLV-T Bank : 0x11 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11);
	/* BBAGC TARGET level setting */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x6a, 0x50);
	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	/* ASCOT setting ON */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa5, 0x01, 0x01);
	/* Set SLV-T Bank : 0x20 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20);
	/* Acquisition optimization setting */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x8b, 0x3c);
	/* Set SLV-T Bank : 0x2b */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x76, 0x20, 0x70);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* TSIF setting */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01);
	/* DVB-T2 initial setting */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x83, 0x10);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x86, 0x34);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x9e, 0x09, 0x0f);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x9f, 0xd8);
	/* Set SLV-T Bank : 0x2a */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2a);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x38, 0x04, 0x0f);
	/* Set SLV-T Bank : 0x2b */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x11, 0x20, 0x3f);

	cxd2841er_sleep_tc_to_active_t2_band(priv, bandwidth);

	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Disable HiZ Setting 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x28);
	/* Disable HiZ Setting 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00);
	priv->state = STATE_ACTIVE_TC;
	return 0;
}

/* ISDB-Tb part */
static int cxd2841er_sleep_tc_to_active_i(struct cxd2841er_priv *priv,
		u32 bandwidth)
{
	u8 data[2] = { 0x09, 0x54 };
	u8 data24m[2] = {0x60, 0x00};
	u8 data24m2[3] = {0xB7, 0x1B, 0x00};

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	cxd2841er_set_ts_clock_mode(priv, SYS_DVBT);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Set demod mode */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x06);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Enable demod clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01);
	/* Enable RF level monitor */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x01);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x59, 0x01);
	/* Enable ADC clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
	/* Enable ADC 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a);
	/* xtal freq 20.5MHz or 24M */
	cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2);
	/* Enable ADC 4 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00);
	/* ASCOT setting ON */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa5, 0x01, 0x01);
	/* FEC Auto Recovery setting */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x30, 0x01, 0x01);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x31, 0x00, 0x01);
	/* ISDB-T initial setting */
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x00, 0x01);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x00, 0x01);
	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x69, 0x04, 0x07);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x6B, 0x03, 0x07);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x9D, 0x50, 0xFF);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xD3, 0x06, 0x1F);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xED, 0x00, 0x01);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xE2, 0xCE, 0x80);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xF2, 0x13, 0x10);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xDE, 0x2E, 0x3F);
	/* Set SLV-T Bank : 0x15 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xDE, 0x02, 0x03);
	/* Set SLV-T Bank : 0x1E */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x1E);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x73, 0x68, 0xFF);
	/* Set SLV-T Bank : 0x63 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x63);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x81, 0x00, 0x01);

	/* for xtal 24MHz */
	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	cxd2841er_write_regs(priv, I2C_SLVT, 0xBF, data24m, 2);
	/* Set SLV-T Bank : 0x60 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60);
	cxd2841er_write_regs(priv, I2C_SLVT, 0xA8, data24m2, 3);

	cxd2841er_sleep_tc_to_active_i_band(priv, bandwidth);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Disable HiZ Setting 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x28);
	/* Disable HiZ Setting 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00);
	priv->state = STATE_ACTIVE_TC;
	return 0;
}

static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv,
					  u32 bandwidth)
{
	u8 data[2] = { 0x09, 0x54 };

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	cxd2841er_set_ts_clock_mode(priv, SYS_DVBC_ANNEX_A);
	/* Set SLV-X Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
	/* Set demod mode */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x04);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Enable demod clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01);
	/* Disable RF level monitor */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
	/* Enable ADC clock */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
	/* Enable ADC 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a);
	/* xtal freq 20.5MHz */
	cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2);
	/* Enable ADC 4 */
	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00);
	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	/* IFAGC gain settings */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd2, 0x09, 0x1f);
	/* Set SLV-T Bank : 0x11 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11);
	/* BBAGC TARGET level setting */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x6a, 0x48);
	/* Set SLV-T Bank : 0x10 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	/* ASCOT setting ON */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa5, 0x01, 0x01);
	/* Set SLV-T Bank : 0x40 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40);
	/* Demod setting */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xc3, 0x00, 0x04);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* TSIF setting */
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01);

	cxd2841er_sleep_tc_to_active_c_band(priv, 8000000);
	/* Set SLV-T Bank : 0x00 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	/* Disable HiZ Setting 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x28);
	/* Disable HiZ Setting 2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00);
	priv->state = STATE_ACTIVE_TC;
	return 0;
}

static int cxd2841er_get_frontend(struct dvb_frontend *fe,
				  struct dtv_frontend_properties *p)
{
	enum fe_status status = 0;
	u16 strength = 0, snr = 0;
	u32 errors = 0, ber = 0;
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state == STATE_ACTIVE_S)
		cxd2841er_read_status_s(fe, &status);
	else if (priv->state == STATE_ACTIVE_TC)
		cxd2841er_read_status_tc(fe, &status);

	if (status & FE_HAS_LOCK) {
		cxd2841er_read_signal_strength(fe, &strength);
		p->strength.len = 1;
		p->strength.stat[0].scale = FE_SCALE_RELATIVE;
		p->strength.stat[0].uvalue = strength;
		cxd2841er_read_snr(fe, &snr);
		p->cnr.len = 1;
		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
		p->cnr.stat[0].svalue = snr;
		cxd2841er_read_ucblocks(fe, &errors);
		p->block_error.len = 1;
		p->block_error.stat[0].scale = FE_SCALE_COUNTER;
		p->block_error.stat[0].uvalue = errors;
		cxd2841er_read_ber(fe, &ber);
		p->post_bit_error.len = 1;
		p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
		p->post_bit_error.stat[0].uvalue = ber;
	} else {
		p->strength.len = 1;
		p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
		p->cnr.len = 1;
		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
		p->block_error.len = 1;
		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
		p->post_bit_error.len = 1;
		p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
	}
	return 0;
}

static int cxd2841er_set_frontend_s(struct dvb_frontend *fe)
{
	int ret = 0, i, timeout, carr_offset;
	enum fe_status status;
	struct cxd2841er_priv *priv = fe->demodulator_priv;
	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
	u32 symbol_rate = p->symbol_rate/1000;

	dev_dbg(&priv->i2c->dev, "%s(): %s frequency=%d symbol_rate=%d xtal=%d\n",
		__func__,
		(p->delivery_system == SYS_DVBS ? "DVB-S" : "DVB-S2"),
		 p->frequency, symbol_rate, priv->xtal);
	switch (priv->state) {
	case STATE_SLEEP_S:
		ret = cxd2841er_sleep_s_to_active_s(
			priv, p->delivery_system, symbol_rate);
		break;
	case STATE_ACTIVE_S:
		ret = cxd2841er_retune_active(priv, p);
		break;
	default:
		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		ret = -EINVAL;
		goto done;
	}
	if (ret) {
		dev_dbg(&priv->i2c->dev, "%s(): tune failed\n", __func__);
		goto done;
	}
	if (fe->ops.i2c_gate_ctrl)
		fe->ops.i2c_gate_ctrl(fe, 1);
	if (fe->ops.tuner_ops.set_params)
		fe->ops.tuner_ops.set_params(fe);
	if (fe->ops.i2c_gate_ctrl)
		fe->ops.i2c_gate_ctrl(fe, 0);
	cxd2841er_tune_done(priv);
	timeout = ((3000000 + (symbol_rate - 1)) / symbol_rate) + 150;
	for (i = 0; i < timeout / CXD2841ER_DVBS_POLLING_INVL; i++) {
		usleep_range(CXD2841ER_DVBS_POLLING_INVL*1000,
			(CXD2841ER_DVBS_POLLING_INVL + 2) * 1000);
		cxd2841er_read_status_s(fe, &status);
		if (status & FE_HAS_LOCK)
			break;
	}
	if (status & FE_HAS_LOCK) {
		if (cxd2841er_get_carrier_offset_s_s2(
				priv, &carr_offset)) {
			ret = -EINVAL;
			goto done;
		}
		dev_dbg(&priv->i2c->dev, "%s(): carrier_offset=%d\n",
			__func__, carr_offset);
	}
done:
	return ret;
}

static int cxd2841er_set_frontend_tc(struct dvb_frontend *fe)
{
	int ret = 0, timeout;
	enum fe_status status;
	struct cxd2841er_priv *priv = fe->demodulator_priv;
	struct dtv_frontend_properties *p = &fe->dtv_property_cache;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (p->delivery_system == SYS_DVBT) {
		priv->system = SYS_DVBT;
		switch (priv->state) {
		case STATE_SLEEP_TC:
			ret = cxd2841er_sleep_tc_to_active_t(
				priv, p->bandwidth_hz);
			break;
		case STATE_ACTIVE_TC:
			ret = cxd2841er_retune_active(priv, p);
			break;
		default:
			dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
				__func__, priv->state);
			ret = -EINVAL;
		}
	} else if (p->delivery_system == SYS_DVBT2) {
		priv->system = SYS_DVBT2;
		cxd2841er_dvbt2_set_plp_config(priv,
			(int)(p->stream_id > 255), p->stream_id);
		cxd2841er_dvbt2_set_profile(priv, DVBT2_PROFILE_BASE);
		switch (priv->state) {
		case STATE_SLEEP_TC:
			ret = cxd2841er_sleep_tc_to_active_t2(priv,
				p->bandwidth_hz);
			break;
		case STATE_ACTIVE_TC:
			ret = cxd2841er_retune_active(priv, p);
			break;
		default:
			dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
				__func__, priv->state);
			ret = -EINVAL;
		}
	} else if (p->delivery_system == SYS_ISDBT) {
		priv->system = SYS_ISDBT;
		switch (priv->state) {
		case STATE_SLEEP_TC:
			ret = cxd2841er_sleep_tc_to_active_i(
					priv, p->bandwidth_hz);
			break;
		case STATE_ACTIVE_TC:
			ret = cxd2841er_retune_active(priv, p);
			break;
		default:
			dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
					__func__, priv->state);
			ret = -EINVAL;
		}
	} else if (p->delivery_system == SYS_DVBC_ANNEX_A ||
			p->delivery_system == SYS_DVBC_ANNEX_C) {
		priv->system = SYS_DVBC_ANNEX_A;
		switch (priv->state) {
		case STATE_SLEEP_TC:
			ret = cxd2841er_sleep_tc_to_active_c(
				priv, p->bandwidth_hz);
			break;
		case STATE_ACTIVE_TC:
			ret = cxd2841er_retune_active(priv, p);
			break;
		default:
			dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
				__func__, priv->state);
			ret = -EINVAL;
		}
	} else {
		dev_dbg(&priv->i2c->dev,
			"%s(): invalid delivery system %d\n",
			__func__, p->delivery_system);
		ret = -EINVAL;
	}
	if (ret)
		goto done;
	if (fe->ops.i2c_gate_ctrl)
		fe->ops.i2c_gate_ctrl(fe, 1);
	if (fe->ops.tuner_ops.set_params)
		fe->ops.tuner_ops.set_params(fe);
	if (fe->ops.i2c_gate_ctrl)
		fe->ops.i2c_gate_ctrl(fe, 0);
	cxd2841er_tune_done(priv);
	timeout = 2500;
	while (timeout > 0) {
		ret = cxd2841er_read_status_tc(fe, &status);
		if (ret)
			goto done;
		if (status & FE_HAS_LOCK)
			break;
		msleep(20);
		timeout -= 20;
	}
	if (timeout < 0)
		dev_dbg(&priv->i2c->dev,
			"%s(): LOCK wait timeout\n", __func__);
done:
	return ret;
}

static int cxd2841er_tune_s(struct dvb_frontend *fe,
			    bool re_tune,
			    unsigned int mode_flags,
			    unsigned int *delay,
			    enum fe_status *status)
{
	int ret, carrier_offset;
	struct cxd2841er_priv *priv = fe->demodulator_priv;
	struct dtv_frontend_properties *p = &fe->dtv_property_cache;

	dev_dbg(&priv->i2c->dev, "%s() re_tune=%d\n", __func__, re_tune);
	if (re_tune) {
		ret = cxd2841er_set_frontend_s(fe);
		if (ret)
			return ret;
		cxd2841er_read_status_s(fe, status);
		if (*status & FE_HAS_LOCK) {
			if (cxd2841er_get_carrier_offset_s_s2(
					priv, &carrier_offset))
				return -EINVAL;
			p->frequency += carrier_offset;
			ret = cxd2841er_set_frontend_s(fe);
			if (ret)
				return ret;
		}
	}
	*delay = HZ / 5;
	return cxd2841er_read_status_s(fe, status);
}

static int cxd2841er_tune_tc(struct dvb_frontend *fe,
			     bool re_tune,
			     unsigned int mode_flags,
			     unsigned int *delay,
			     enum fe_status *status)
{
	int ret, carrier_offset;
	struct cxd2841er_priv *priv = fe->demodulator_priv;
	struct dtv_frontend_properties *p = &fe->dtv_property_cache;

	dev_dbg(&priv->i2c->dev, "%s(): re_tune %d\n", __func__, re_tune);
	if (re_tune) {
		ret = cxd2841er_set_frontend_tc(fe);
		if (ret)
			return ret;
		cxd2841er_read_status_tc(fe, status);
		if (*status & FE_HAS_LOCK) {
			switch (priv->system) {
			case SYS_DVBT:
			case SYS_DVBT2:
				ret = cxd2841er_get_carrier_offset_t2(
					priv, p->bandwidth_hz,
					&carrier_offset);
				break;
			case SYS_DVBC_ANNEX_A:
				ret = cxd2841er_get_carrier_offset_c(
					priv, &carrier_offset);
				break;
			default:
				dev_dbg(&priv->i2c->dev,
					"%s(): invalid delivery system %d\n",
					__func__, priv->system);
				return -EINVAL;
			}
			if (ret)
				return ret;
			dev_dbg(&priv->i2c->dev, "%s(): carrier offset %d\n",
				__func__, carrier_offset);
			p->frequency += carrier_offset;
			ret = cxd2841er_set_frontend_tc(fe);
			if (ret)
				return ret;
		}
	}
	*delay = HZ / 5;
	return cxd2841er_read_status_tc(fe, status);
}

static int cxd2841er_sleep_s(struct dvb_frontend *fe)
{
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	cxd2841er_active_s_to_sleep_s(fe->demodulator_priv);
	cxd2841er_sleep_s_to_shutdown(fe->demodulator_priv);
	return 0;
}

static int cxd2841er_sleep_tc(struct dvb_frontend *fe)
{
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	if (priv->state == STATE_ACTIVE_TC) {
		switch (priv->system) {
		case SYS_DVBT:
			cxd2841er_active_t_to_sleep_tc(priv);
			break;
		case SYS_DVBT2:
			cxd2841er_active_t2_to_sleep_tc(priv);
			break;
		case SYS_ISDBT:
			cxd2841er_active_i_to_sleep_tc(priv);
			break;
		case SYS_DVBC_ANNEX_A:
			cxd2841er_active_c_to_sleep_tc(priv);
			break;
		default:
			dev_warn(&priv->i2c->dev,
				"%s(): unknown delivery system %d\n",
				__func__, priv->system);
		}
	}
	if (priv->state != STATE_SLEEP_TC) {
		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	cxd2841er_sleep_tc_to_shutdown(priv);
	return 0;
}

static int cxd2841er_send_burst(struct dvb_frontend *fe,
				enum fe_sec_mini_cmd burst)
{
	u8 data;
	struct cxd2841er_priv *priv  = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s(): burst mode %s\n", __func__,
		(burst == SEC_MINI_A ? "A" : "B"));
	if (priv->state != STATE_SLEEP_S &&
			priv->state != STATE_ACTIVE_S) {
		dev_err(&priv->i2c->dev, "%s(): invalid demod state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	data = (burst == SEC_MINI_A ? 0 : 1);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xbb);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x34, 0x01);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x35, data);
	return 0;
}

static int cxd2841er_set_tone(struct dvb_frontend *fe,
			      enum fe_sec_tone_mode tone)
{
	u8 data;
	struct cxd2841er_priv *priv  = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s(): tone %s\n", __func__,
		(tone == SEC_TONE_ON ? "On" : "Off"));
	if (priv->state != STATE_SLEEP_S &&
			priv->state != STATE_ACTIVE_S) {
		dev_err(&priv->i2c->dev, "%s(): invalid demod state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	data = (tone == SEC_TONE_ON ? 1 : 0);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xbb);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x36, data);
	return 0;
}

static int cxd2841er_send_diseqc_msg(struct dvb_frontend *fe,
				     struct dvb_diseqc_master_cmd *cmd)
{
	int i;
	u8 data[12];
	struct cxd2841er_priv *priv  = fe->demodulator_priv;

	if (priv->state != STATE_SLEEP_S &&
			priv->state != STATE_ACTIVE_S) {
		dev_err(&priv->i2c->dev, "%s(): invalid demod state %d\n",
			__func__, priv->state);
		return -EINVAL;
	}
	dev_dbg(&priv->i2c->dev,
		"%s(): cmd->len %d\n", __func__, cmd->msg_len);
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xbb);
	/* DiDEqC enable */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x33, 0x01);
	/* cmd1 length & data */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x3d, cmd->msg_len);
	memset(data, 0, sizeof(data));
	for (i = 0; i < cmd->msg_len && i < sizeof(data); i++)
		data[i] = cmd->msg[i];
	cxd2841er_write_regs(priv, I2C_SLVT, 0x3e, data, sizeof(data));
	/* repeat count for cmd1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x37, 1);
	/* repeat count for cmd2: always 0 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x38, 0);
	/* start transmit */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x32, 0x01);
	/* wait for 1 sec timeout */
	for (i = 0; i < 50; i++) {
		cxd2841er_read_reg(priv, I2C_SLVT, 0x10, data);
		if (!data[0]) {
			dev_dbg(&priv->i2c->dev,
				"%s(): DiSEqC cmd has been sent\n", __func__);
			return 0;
		}
		msleep(20);
	}
	dev_dbg(&priv->i2c->dev,
		"%s(): DiSEqC cmd transmit timeout\n", __func__);
	return -ETIMEDOUT;
}

static void cxd2841er_release(struct dvb_frontend *fe)
{
	struct cxd2841er_priv *priv  = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	kfree(priv);
}

static int cxd2841er_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s(): enable=%d\n", __func__, enable);
	cxd2841er_set_reg_bits(
		priv, I2C_SLVX, 0x8, (enable ? 0x01 : 0x00), 0x01);
	return 0;
}

static enum dvbfe_algo cxd2841er_get_algo(struct dvb_frontend *fe)
{
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	return DVBFE_ALGO_HW;
}

static int cxd2841er_init_s(struct dvb_frontend *fe)
{
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	cxd2841er_shutdown_to_sleep_s(priv);
	/* SONY_DEMOD_CONFIG_SAT_IFAGCNEG set to 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xb9, 0x01, 0x01);
	return 0;
}

static int cxd2841er_init_tc(struct dvb_frontend *fe)
{
	struct cxd2841er_priv *priv = fe->demodulator_priv;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	cxd2841er_shutdown_to_sleep_tc(priv);
	/* SONY_DEMOD_CONFIG_IFAGCNEG = 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcb, 0x40, 0x40);
	/* SONY_DEMOD_CONFIG_IFAGC_ADC_FS = 0 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0xcd, 0x50);
	/* SONY_DEMOD_CONFIG_PARALLEL_SEL = 1 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xc4, 0x00, 0x80);
	return 0;
}

static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops;
static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops;
static struct dvb_frontend_ops cxd2841er_dvbc_ops;
static struct dvb_frontend_ops cxd2841er_isdbt_ops;

static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg,
					     struct i2c_adapter *i2c,
					     u8 system)
{
	u8 chip_id = 0;
	const char *type;
	struct cxd2841er_priv *priv = NULL;

	/* allocate memory for the internal state */
	priv = kzalloc(sizeof(struct cxd2841er_priv), GFP_KERNEL);
	if (!priv)
		return NULL;
	priv->i2c = i2c;
	priv->config = cfg;
	priv->i2c_addr_slvx = (cfg->i2c_addr + 4) >> 1;
	priv->i2c_addr_slvt = (cfg->i2c_addr) >> 1;
	priv->xtal = cfg->xtal;
	/* create dvb_frontend */
	switch (system) {
	case SYS_DVBS:
		memcpy(&priv->frontend.ops,
			&cxd2841er_dvbs_s2_ops,
			sizeof(struct dvb_frontend_ops));
		type = "S/S2";
		break;
	case SYS_DVBT:
		memcpy(&priv->frontend.ops,
			&cxd2841er_dvbt_t2_ops,
			sizeof(struct dvb_frontend_ops));
		type = "T/T2";
		break;
	case SYS_ISDBT:
		memcpy(&priv->frontend.ops,
				&cxd2841er_isdbt_ops,
				sizeof(struct dvb_frontend_ops));
		type = "ISDBT";
		break;
	case SYS_DVBC_ANNEX_A:
		memcpy(&priv->frontend.ops,
			&cxd2841er_dvbc_ops,
			sizeof(struct dvb_frontend_ops));
		type = "C/C2";
		break;
	default:
		kfree(priv);
		return NULL;
	}
	priv->frontend.demodulator_priv = priv;
	dev_info(&priv->i2c->dev,
		"%s(): attaching CXD2841ER DVB-%s frontend\n",
		__func__, type);
	dev_info(&priv->i2c->dev,
		"%s(): I2C adapter %p SLVX addr %x SLVT addr %x\n",
		__func__, priv->i2c,
		priv->i2c_addr_slvx, priv->i2c_addr_slvt);
	chip_id = cxd2841er_chip_id(priv);
	if (chip_id != CXD2841ER_CHIP_ID && chip_id != CXD2854ER_CHIP_ID) {
		dev_err(&priv->i2c->dev, "%s(): invalid chip ID 0x%02x\n",
			__func__, chip_id);
		priv->frontend.demodulator_priv = NULL;
		kfree(priv);
		return NULL;
	}
	dev_info(&priv->i2c->dev, "%s(): chip ID 0x%02x OK.\n",
		__func__, chip_id);
	return &priv->frontend;
}

struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg,
					struct i2c_adapter *i2c)
{
	return cxd2841er_attach(cfg, i2c, SYS_DVBS);
}
EXPORT_SYMBOL(cxd2841er_attach_s);

struct dvb_frontend *cxd2841er_attach_t(struct cxd2841er_config *cfg,
					struct i2c_adapter *i2c)
{
	return cxd2841er_attach(cfg, i2c, SYS_DVBT);
}
EXPORT_SYMBOL(cxd2841er_attach_t);

struct dvb_frontend *cxd2841er_attach_i(struct cxd2841er_config *cfg,
		struct i2c_adapter *i2c)
{
	return cxd2841er_attach(cfg, i2c, SYS_ISDBT);
}
EXPORT_SYMBOL(cxd2841er_attach_i);

struct dvb_frontend *cxd2841er_attach_c(struct cxd2841er_config *cfg,
					struct i2c_adapter *i2c)
{
	return cxd2841er_attach(cfg, i2c, SYS_DVBC_ANNEX_A);
}
EXPORT_SYMBOL(cxd2841er_attach_c);

static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = {
	.delsys = { SYS_DVBS, SYS_DVBS2 },
	.info = {
		.name		= "Sony CXD2841ER DVB-S/S2 demodulator",
		.frequency_min	= 500000,
		.frequency_max	= 2500000,
		.frequency_stepsize	= 0,
		.symbol_rate_min = 1000000,
		.symbol_rate_max = 45000000,
		.symbol_rate_tolerance = 500,
		.caps = FE_CAN_INVERSION_AUTO |
			FE_CAN_FEC_AUTO |
			FE_CAN_QPSK,
	},
	.init = cxd2841er_init_s,
	.sleep = cxd2841er_sleep_s,
	.release = cxd2841er_release,
	.set_frontend = cxd2841er_set_frontend_s,
	.get_frontend = cxd2841er_get_frontend,
	.read_status = cxd2841er_read_status_s,
	.i2c_gate_ctrl = cxd2841er_i2c_gate_ctrl,
	.get_frontend_algo = cxd2841er_get_algo,
	.set_tone = cxd2841er_set_tone,
	.diseqc_send_burst = cxd2841er_send_burst,
	.diseqc_send_master_cmd = cxd2841er_send_diseqc_msg,
	.tune = cxd2841er_tune_s
};

static struct  dvb_frontend_ops cxd2841er_dvbt_t2_ops = {
	.delsys = { SYS_DVBT, SYS_DVBT2 },
	.info = {
		.name	= "Sony CXD2841ER DVB-T/T2 demodulator",
		.caps = FE_CAN_FEC_1_2 |
			FE_CAN_FEC_2_3 |
			FE_CAN_FEC_3_4 |
			FE_CAN_FEC_5_6 |
			FE_CAN_FEC_7_8 |
			FE_CAN_FEC_AUTO |
			FE_CAN_QPSK |
			FE_CAN_QAM_16 |
			FE_CAN_QAM_32 |
			FE_CAN_QAM_64 |
			FE_CAN_QAM_128 |
			FE_CAN_QAM_256 |
			FE_CAN_QAM_AUTO |
			FE_CAN_TRANSMISSION_MODE_AUTO |
			FE_CAN_GUARD_INTERVAL_AUTO |
			FE_CAN_HIERARCHY_AUTO |
			FE_CAN_MUTE_TS |
			FE_CAN_2G_MODULATION,
		.frequency_min = 42000000,
		.frequency_max = 1002000000
	},
	.init = cxd2841er_init_tc,
	.sleep = cxd2841er_sleep_tc,
	.release = cxd2841er_release,
	.set_frontend = cxd2841er_set_frontend_tc,
	.get_frontend = cxd2841er_get_frontend,
	.read_status = cxd2841er_read_status_tc,
	.tune = cxd2841er_tune_tc,
	.i2c_gate_ctrl = cxd2841er_i2c_gate_ctrl,
	.get_frontend_algo = cxd2841er_get_algo
};

static struct  dvb_frontend_ops cxd2841er_isdbt_ops = {
	.delsys = { SYS_ISDBT },
	.info = {
		.name	= "Sony CXD2854ER ISDBT demodulator",
		.caps = FE_CAN_FEC_1_2 |
			FE_CAN_FEC_2_3 |
			FE_CAN_FEC_3_4 |
			FE_CAN_FEC_5_6 |
			FE_CAN_FEC_7_8 |
			FE_CAN_FEC_AUTO |
			FE_CAN_QPSK |
			FE_CAN_QAM_16 |
			FE_CAN_QAM_32 |
			FE_CAN_QAM_64 |
			FE_CAN_QAM_128 |
			FE_CAN_QAM_256 |
			FE_CAN_QAM_AUTO |
			FE_CAN_TRANSMISSION_MODE_AUTO |
			FE_CAN_GUARD_INTERVAL_AUTO |
			FE_CAN_HIERARCHY_AUTO |
			FE_CAN_MUTE_TS |
			FE_CAN_2G_MODULATION,
		.frequency_min = 42000000,
		.frequency_max = 1002000000
	},
	.init = cxd2841er_init_tc,
	.sleep = cxd2841er_sleep_tc,
	.release = cxd2841er_release,
	.set_frontend = cxd2841er_set_frontend_tc,
	.get_frontend = cxd2841er_get_frontend,
	.read_status = cxd2841er_read_status_tc,
	.tune = cxd2841er_tune_tc,
	.i2c_gate_ctrl = cxd2841er_i2c_gate_ctrl,
	.get_frontend_algo = cxd2841er_get_algo
};

static struct  dvb_frontend_ops cxd2841er_dvbc_ops = {
	.delsys = { SYS_DVBC_ANNEX_A },
	.info = {
		.name	= "Sony CXD2841ER DVB-C demodulator",
		.caps = FE_CAN_FEC_1_2 |
			FE_CAN_FEC_2_3 |
			FE_CAN_FEC_3_4 |
			FE_CAN_FEC_5_6 |
			FE_CAN_FEC_7_8 |
			FE_CAN_FEC_AUTO |
			FE_CAN_QAM_16 |
			FE_CAN_QAM_32 |
			FE_CAN_QAM_64 |
			FE_CAN_QAM_128 |
			FE_CAN_QAM_256 |
			FE_CAN_QAM_AUTO |
			FE_CAN_INVERSION_AUTO,
		.frequency_min = 42000000,
		.frequency_max = 1002000000
	},
	.init = cxd2841er_init_tc,
	.sleep = cxd2841er_sleep_tc,
	.release = cxd2841er_release,
	.set_frontend = cxd2841er_set_frontend_tc,
	.get_frontend = cxd2841er_get_frontend,
	.read_status = cxd2841er_read_status_tc,
	.tune = cxd2841er_tune_tc,
	.i2c_gate_ctrl = cxd2841er_i2c_gate_ctrl,
	.get_frontend_algo = cxd2841er_get_algo,
};

MODULE_DESCRIPTION("Sony CXD2841ER/CXD2854ER DVB-C/C2/T/T2/S/S2 demodulator driver");
MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>, Abylay Ospan <aospan@netup.ru>");
MODULE_LICENSE("GPL");