1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * cxd2880_tnrdmd_mon.c
4  * Sony CXD2880 DVB-T2/T tuner + demodulator driver
5  * common monitor functions
6  *
7  * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
8  */
9 
10 #include "cxd2880_common.h"
11 #include "cxd2880_tnrdmd_mon.h"
12 
13 static const u8 rf_lvl_seq[2] = {
14 	0x80, 0x00,
15 };
16 
17 int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
18 			      int *rf_lvl_db)
19 {
20 	u8 rdata[2];
21 	int ret;
22 
23 	if (!tnr_dmd || !rf_lvl_db)
24 		return -EINVAL;
25 
26 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
27 		return -EINVAL;
28 
29 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
30 				     CXD2880_IO_TGT_DMD,
31 				     0x00, 0x00);
32 	if (ret)
33 		return ret;
34 
35 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
36 				     CXD2880_IO_TGT_DMD,
37 				     0x10, 0x01);
38 	if (ret)
39 		return ret;
40 
41 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
42 				     CXD2880_IO_TGT_SYS,
43 				     0x00, 0x10);
44 	if (ret)
45 		return ret;
46 
47 	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
48 				      CXD2880_IO_TGT_SYS,
49 				      0x5b, rf_lvl_seq, 2);
50 	if (ret)
51 		return ret;
52 
53 	usleep_range(2000, 3000);
54 
55 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
56 				     CXD2880_IO_TGT_SYS,
57 				     0x00, 0x1a);
58 	if (ret)
59 		return ret;
60 
61 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
62 				     CXD2880_IO_TGT_SYS,
63 				     0x15, rdata, 2);
64 	if (ret)
65 		return ret;
66 
67 	if (rdata[0] || rdata[1])
68 		return -EINVAL;
69 
70 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
71 				     CXD2880_IO_TGT_SYS,
72 				     0x11, rdata, 2);
73 	if (ret)
74 		return ret;
75 
76 	*rf_lvl_db =
77 	    cxd2880_convert2s_complement((rdata[0] << 3) |
78 					 ((rdata[1] & 0xe0) >> 5), 11);
79 
80 	*rf_lvl_db *= 125;
81 
82 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
83 				     CXD2880_IO_TGT_DMD,
84 				     0x00, 0x00);
85 	if (ret)
86 		return ret;
87 
88 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
89 				     CXD2880_IO_TGT_DMD,
90 				     0x10, 0x00);
91 	if (ret)
92 		return ret;
93 
94 	if (tnr_dmd->rf_lvl_cmpstn)
95 		ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db);
96 
97 	return ret;
98 }
99 
100 int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
101 				  int *rf_lvl_db)
102 {
103 	if (!tnr_dmd || !rf_lvl_db)
104 		return -EINVAL;
105 
106 	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
107 		return -EINVAL;
108 
109 	return cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db);
110 }
111 
112 int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
113 					   *tnr_dmd, u16 *status)
114 {
115 	u8 data[2] = { 0 };
116 	int ret;
117 
118 	if (!tnr_dmd || !status)
119 		return -EINVAL;
120 
121 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
122 				     CXD2880_IO_TGT_SYS,
123 				     0x00, 0x1a);
124 	if (ret)
125 		return ret;
126 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
127 				     CXD2880_IO_TGT_SYS,
128 				     0x15, data, 2);
129 	if (ret)
130 		return ret;
131 
132 	*status = (data[0] << 8) | data[1];
133 
134 	return 0;
135 }
136 
137 int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
138 					       cxd2880_tnrdmd
139 					       *tnr_dmd,
140 					       u16 *status)
141 {
142 	if (!tnr_dmd || !status)
143 		return -EINVAL;
144 
145 	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
146 		return -EINVAL;
147 
148 	return cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub,
149 						      status);
150 }
151