1/*
2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify,
8 * merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <KernelExport.h>
26#include <string.h>
27#include "cx22702.h"
28#include "dtt7592.h"
29#include "config.h"
30#include "dvb.h"
31
32#define TRACE_CX22702
33#ifdef TRACE_CX22702
34  #define TRACE dprintf
35#else
36  #define TRACE(a...)
37#endif
38
39
40#if 0
41static void
42cx22702_reg_dump(i2c_bus *bus)
43{
44	int i;
45	for (i = 0; i < 256; i++) {
46		uint8 data;
47		if (cx22702_reg_read(bus, i, &data) != B_OK)
48			dprintf("cx22702_reg 0x%02x error\n", i);
49		else
50			dprintf("cx22702_reg 0x%02x value 0x%02x\n", i, data);
51	}
52}
53#endif
54
55
56status_t
57cx22702_reg_write(i2c_bus *bus, uint8 reg, uint8 data)
58{
59	status_t res;
60	uint8 buf[2] = {reg, data};
61	res = i2c_write(bus, I2C_ADDR_DEMOD, buf, 2);
62	if (res != B_OK)
63		TRACE("cx22702_reg_write error, reg 0x%02x, value 0x%02x\n", reg, data);
64	return res;
65}
66
67
68status_t
69cx22702_reg_read(i2c_bus *bus, uint8 reg, uint8 *data)
70{
71	status_t res;
72	res = i2c_xfer(bus, I2C_ADDR_DEMOD, &reg, 1, data, 1);
73	if (res != B_OK)
74		TRACE("cx22702_reg_read error, reg 0x%02x\n", reg);
75	return res;
76}
77
78
79status_t
80cx22702_init(i2c_bus *bus)
81{
82	if (cx22702_reg_write(bus, 0x00, 0x02) != B_OK) return B_ERROR;
83	if (cx22702_reg_write(bus, 0x00, 0x00) != B_OK) return B_ERROR;
84	snooze(10000);
85	if (cx22702_reg_write(bus, 0x00, 0x00) != B_OK) return B_ERROR;
86	if (cx22702_reg_write(bus, 0x09, 0x01) != B_OK) return B_ERROR;
87	if (cx22702_reg_write(bus, 0x0B, 0x04) != B_OK) return B_ERROR;
88	if (cx22702_reg_write(bus, 0x0C, 0x00) != B_OK) return B_ERROR;
89	if (cx22702_reg_write(bus, 0x0D, 0x80) != B_OK) return B_ERROR;
90	if (cx22702_reg_write(bus, 0x26, 0x80) != B_OK) return B_ERROR;
91	if (cx22702_reg_write(bus, 0x2D, 0xff) != B_OK) return B_ERROR;
92	if (cx22702_reg_write(bus, 0xDC, 0x00) != B_OK) return B_ERROR;
93	if (cx22702_reg_write(bus, 0xE4, 0x00) != B_OK) return B_ERROR;
94	if (cx22702_reg_write(bus, 0xF8, 0x02) != B_OK) return B_ERROR;
95	if (cx22702_reg_write(bus, 0x00, 0x01) != B_OK) return B_ERROR;
96	return B_OK;
97}
98
99
100status_t
101cx22702_get_frequency_info(i2c_bus *bus, dvb_frequency_info_t *info)
102{
103	memset(info, 0, sizeof(*info));
104	info->frequency_min = 149000000;
105	info->frequency_max = 860000000;
106	info->frequency_step = 166667;
107	return B_OK;
108}
109
110
111status_t
112cx22702_set_tuning_parameters(i2c_bus *bus, const dvb_t_tuning_parameters_t *params)
113{
114	uint8 data;
115	status_t res;
116
117	if (cx22702_reg_write(bus, 0x00, 0x00) != B_OK)
118		return B_ERROR;
119
120	res = dtt7592_set_frequency(bus, params->frequency, params->bandwidth);
121	if (res != B_OK)
122		return res;
123
124	if (cx22702_reg_read(bus, 0x0c, &data) != B_OK)
125		 return B_ERROR;
126	switch (params->inversion) {
127		case DVB_INVERSION_ON:		data |= 0x01; break;
128		case DVB_INVERSION_OFF:		data &= ~0x01; break;
129		default:					return B_ERROR;
130	}
131	switch (params->bandwidth) {
132		case DVB_BANDWIDTH_6_MHZ:	data = (data & ~0x10) | 0x20; break;
133		case DVB_BANDWIDTH_7_MHZ:	data = (data & ~0x20) | 0x10; break;
134		case DVB_BANDWIDTH_8_MHZ:	data &= ~0x30;	break;
135		default:					return B_ERROR;
136	}
137	if (cx22702_reg_write(bus, 0x0c, data) != B_OK)
138		return B_ERROR;
139
140	switch (params->modulation) {
141		case DVB_MODULATION_QPSK:	data = 0x00; break;
142		case DVB_MODULATION_16_QAM:	data = 0x08; break;
143		case DVB_MODULATION_64_QAM:	data = 0x10; break;
144		default:					return B_ERROR;
145	}
146	switch (params->hierarchy) {
147		case DVB_HIERARCHY_NONE:	break;
148		case DVB_HIERARCHY_1:		data |= 0x01; break;
149		case DVB_HIERARCHY_2:		data |= 0x02; break;
150		case DVB_HIERARCHY_4:		data |= 0x03; break;
151		default:					return B_ERROR;
152	}
153	if (cx22702_reg_write(bus, 0x06, data) != B_OK)
154		return B_ERROR;
155
156	switch (params->code_rate_hp) {
157		case DVB_FEC_NONE:			data = 0x00; break;
158		case DVB_FEC_1_2:			data = 0x00; break;
159		case DVB_FEC_2_3:			data = 0x08; break;
160		case DVB_FEC_3_4:			data = 0x10; break;
161		case DVB_FEC_5_6:			data = 0x18; break;
162		case DVB_FEC_6_7:			data = 0x20; break;
163		default:					return B_ERROR;
164	}
165	switch (params->code_rate_lp) {
166		case DVB_FEC_NONE:			break;
167		case DVB_FEC_1_2:			break;
168		case DVB_FEC_2_3:			data |= 0x01; break;
169		case DVB_FEC_3_4:			data |= 0x02; break;
170		case DVB_FEC_5_6:			data |= 0x03; break;
171		case DVB_FEC_6_7:			data |= 0x04; break;
172		default:					return B_ERROR;
173	}
174	if (cx22702_reg_write(bus, 0x07, data) != B_OK)
175		return B_ERROR;
176
177	switch (params->transmission_mode) {
178		case DVB_TRANSMISSION_MODE_2K:	data = 0x00; break;
179		case DVB_TRANSMISSION_MODE_8K:	data = 0x01; break;
180		default:						return B_ERROR;
181	}
182	switch (params->guard_interval) {
183		case DVB_GUARD_INTERVAL_1_4:	data |= 0x0c; break;
184		case DVB_GUARD_INTERVAL_1_8:	data |= 0x08; break;
185		case DVB_GUARD_INTERVAL_1_16:	data |= 0x04; break;
186		case DVB_GUARD_INTERVAL_1_32:	break;
187		default: return B_ERROR;
188	}
189	if (cx22702_reg_write(bus, 0x08, data) != B_OK)
190		return B_ERROR;
191
192	if (cx22702_reg_read(bus, 0x0b, &data) != B_OK)
193		 return B_ERROR;
194	if (cx22702_reg_write(bus, 0x0b, data | 0x02) != B_OK)
195		return B_ERROR;
196
197	if (cx22702_reg_write(bus, 0x00, 0x01) != B_OK)
198		return B_ERROR;
199
200//	cx22702_reg_dump(bus);
201
202	return B_OK;
203}
204
205
206status_t
207cx22702_get_tuning_parameters(i2c_bus *bus, dvb_t_tuning_parameters_t *params)
208{
209	uint8 reg01, reg02, reg03, reg0A, reg0C;
210
211	if (cx22702_reg_read(bus, 0x01, &reg01) != B_OK)
212		return B_ERROR;
213	if (cx22702_reg_read(bus, 0x02, &reg02) != B_OK)
214		return B_ERROR;
215	if (cx22702_reg_read(bus, 0x03, &reg03) != B_OK)
216		return B_ERROR;
217	if (cx22702_reg_read(bus, 0x0a, &reg0A) != B_OK)
218		return B_ERROR;
219	if (cx22702_reg_read(bus, 0x0c, &reg0C) != B_OK)
220		return B_ERROR;
221
222	memset(params, 0, sizeof(*params));
223	params->inversion = (reg0C & 0x01) ? DVB_INVERSION_ON : DVB_INVERSION_OFF;
224
225	// XXX TODO...
226
227	return B_OK;
228}
229
230
231status_t
232cx22702_get_status(i2c_bus *bus, dvb_status_t *status)
233{
234	uint8 reg0A, reg23;
235
236	if (cx22702_reg_read(bus, 0x0a, &reg0A) != B_OK)
237		return B_ERROR;
238	if (cx22702_reg_read(bus, 0x23, &reg23) != B_OK)
239		return B_ERROR;
240
241	*status = 0;
242	if (reg0A & 0x10)
243		*status |= DVB_STATUS_LOCK | DVB_STATUS_VITERBI | DVB_STATUS_SYNC;
244	if (reg0A & 0x20)
245		*status |= DVB_STATUS_CARRIER;
246	if (reg23 < 0xf0)
247		*status |= DVB_STATUS_SIGNAL;
248
249	return B_OK;
250}
251
252
253status_t
254cx22702_get_ss(i2c_bus *bus, uint32 *ss)
255{
256	uint8 reg23;
257	if (cx22702_reg_read(bus, 0x23, &reg23) != B_OK)
258		return B_ERROR;
259	*ss = reg23;
260	return B_OK;
261}
262
263
264status_t
265cx22702_get_ber(i2c_bus *bus, uint32 *ber)
266{
267	uint8 regDE_1, regDE_2, regDF;
268	int trys;
269
270	trys = 50;
271	do {
272		if (cx22702_reg_read(bus, 0xDE, &regDE_1) != B_OK)
273			return B_ERROR;
274		if (cx22702_reg_read(bus, 0xDF, &regDF) != B_OK)
275			return B_ERROR;
276		if (cx22702_reg_read(bus, 0xDE, &regDE_2) != B_OK)
277			return B_ERROR;
278	} while (regDE_1 != regDE_2 && --trys > 0);
279	if (trys == 0)
280		return B_ERROR;
281
282	*ber = (regDE_1 & 0x7f) << 7 | (regDF & 0x7f);
283
284	return B_OK;
285}
286
287
288status_t
289cx22702_get_snr(i2c_bus *bus, uint32 *snr)
290{
291	uint32 ber;
292	status_t stat = cx22702_get_ber(bus, &ber);
293	*snr = 16384 - ber;
294	return stat;
295}
296
297
298status_t
299cx22702_get_upc(i2c_bus *bus, uint32 *upc)
300{
301	uint8 regE3;
302
303	if (cx22702_reg_read(bus, 0xE3, &regE3) != B_OK)
304		return B_ERROR;
305	if (cx22702_reg_write(bus, 0xE3, 0) != B_OK)
306		return B_ERROR;
307	*upc = regE3;
308	return B_OK;
309}
310