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
13static const u8 rf_lvl_seq[2] = {
14	0x80, 0x00,
15};
16
17int 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
100int 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
112int 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
137int 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