xref: /netbsd-src/sys/dev/i2c/lg3303.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /* $NetBSD: lg3303.c,v 1.8 2011/10/02 19:03:56 jmcneill Exp $ */
2 
3 /*-
4  * Copyright 2007 Jason Harmening
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29 
30 #include <sys/param.h>
31 __KERNEL_RCSID(0, "$NetBSD: lg3303.c,v 1.8 2011/10/02 19:03:56 jmcneill Exp $");
32 
33 #include <sys/types.h>
34 #include <sys/kmem.h>
35 #include <sys/module.h>
36 #include <sys/bitops.h>
37 
38 #include <dev/i2c/i2cvar.h>
39 #include <dev/i2c/lg3303var.h>
40 #include <dev/dtv/dtvif.h>
41 #include <dev/dtv/dtv_math.h>
42 
43 #define REG_TOP_CONTROL         0x00
44 #define REG_IRQ_MASK            0x01
45 #define REG_IRQ_STATUS          0x02
46 #define REG_VSB_CARRIER_FREQ0   0x16
47 #define REG_VSB_CARRIER_FREQ1   0x17
48 #define REG_VSB_CARRIER_FREQ2   0x18
49 #define REG_VSB_CARRIER_FREQ3   0x19
50 #define REG_CARRIER_MSEQAM1     0x1a
51 #define REG_CARRIER_MSEQAM2     0x1b
52 #define REG_CARRIER_LOCK        0x1c
53 #define REG_TIMING_RECOVERY     0x1d
54 #define REG_AGC_DELAY0          0x2a
55 #define REG_AGC_DELAY1          0x2b
56 #define REG_AGC_DELAY2          0x2c
57 #define REG_AGC_RF_BANDWIDTH0   0x2d
58 #define REG_AGC_RF_BANDWIDTH1   0x2e
59 #define REG_AGC_RF_BANDWIDTH2   0x2f
60 #define REG_AGC_LOOP_BANDWIDTH0 0x30
61 #define REG_AGC_LOOP_BANDWIDTH1 0x31
62 #define REG_AGC_FUNC_CTRL1      0x32
63 #define REG_AGC_FUNC_CTRL2      0x33
64 #define REG_AGC_FUNC_CTRL3      0x34
65 #define REG_AGC_RFIF_ACC0       0x39
66 #define REG_AGC_RFIF_ACC1       0x3a
67 #define REG_AGC_RFIF_ACC2       0x3b
68 #define REG_AGC_STATUS          0x3f
69 #define REG_SYNC_STATUS_VSB     0x43
70 #define REG_DEMUX_CONTROL       0x66
71 #define REG_EQPH_ERR0           0x6e
72 #define REG_EQ_ERR1             0x6f
73 #define REG_EQ_ERR2             0x70
74 #define REG_PH_ERR1             0x71
75 #define REG_PH_ERR2             0x72
76 #define REG_PACKET_ERR_COUNTER1 0x8b
77 #define REG_PACKET_ERR_COUNTER2 0x8c
78 
79 #define LG3303_DEFAULT_DELAY 250000
80 
81 static int	lg3303_reset(struct lg3303 *);
82 static int	lg3303_init(struct lg3303 *);
83 
84 struct lg3303 *
85 lg3303_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr, int flags)
86 {
87 	struct lg3303 *lg;
88 
89 	lg = kmem_alloc(sizeof(*lg), KM_SLEEP);
90 	if (lg == NULL)
91 		return NULL;
92 	lg->parent = parent;
93 	lg->i2c = i2c;
94 	lg->i2c_addr = addr;
95 	lg->current_modulation = -1;
96 	lg->flags = flags;
97 
98 	if (lg3303_init(lg) != 0) {
99 		kmem_free(lg, sizeof(*lg));
100 		return NULL;
101 	}
102 
103 	device_printf(lg->parent, "lg3303: found @ 0x%02x\n", addr);
104 
105 	return lg;
106 }
107 
108 void
109 lg3303_close(struct lg3303 *lg)
110 {
111 	kmem_free(lg, sizeof(*lg));
112 }
113 
114 static int
115 lg3303_write(struct lg3303 *lg, uint8_t *buf, size_t len)
116 {
117 	unsigned int i;
118 	uint8_t *p = buf;
119 	int error;
120 
121 	for (i = 0; i < len - 1; i += 2) {
122 		error = iic_exec(lg->i2c, I2C_OP_WRITE_WITH_STOP, lg->i2c_addr,
123 		    p, 2, NULL, 0, 0);
124 		if (error)
125 			return error;
126 		p += 2;
127 	}
128 
129 	return 0;
130 }
131 
132 static int
133 lg3303_read(struct lg3303 *lg, uint8_t reg, uint8_t *buf, size_t len)
134 {
135 	int error;
136 
137 	error = iic_exec(lg->i2c, I2C_OP_WRITE, lg->i2c_addr,
138 	    &reg, sizeof(reg), NULL, 0, 0);
139 	if (error)
140 		return error;
141 	return iic_exec(lg->i2c, I2C_OP_READ, lg->i2c_addr,
142 	    NULL, 0, buf, len, 0);
143 }
144 
145 static int
146 lg3303_reset(struct lg3303 *lg)
147 {
148 	uint8_t buffer[] = {REG_IRQ_STATUS, 0x00};
149 	int error = lg3303_write(lg, buffer, 2);
150 	if (error == 0) {
151 		buffer[1] = 0x01;
152 		error = lg3303_write(lg, buffer, 2);
153 	}
154 	return error;
155 }
156 
157 static int
158 lg3303_init(struct lg3303 *lg)
159 {
160 	//static uint8_t init_data[] = {0x4c, 0x14, 0x87, 0xf3};
161 	static uint8_t init_data[] = {0x4c, 0x14};
162 	size_t len;
163 	int error;
164 
165 #if notyet
166 	if (clock_polarity == DVB_IFC_POS_POL)
167 		len = 4;
168 	else
169 #endif
170 	len = 2;
171 
172 	error = lg3303_write(lg, init_data, len);
173 	if (error == 0)
174       		lg3303_reset(lg);
175 
176 	return error;
177 }
178 
179 int
180 lg3303_set_modulation(struct lg3303 *lg, fe_modulation_t modulation)
181 {
182 	int error;
183 	static uint8_t vsb_data[] = {
184 		0x04, 0x00,
185 		0x0d, 0x40,
186 		0x0e, 0x87,
187 		0x0f, 0x8e,
188 		0x10, 0x01,
189 		0x47, 0x8b
190 	};
191 	static uint8_t qam_data[] = {
192 		0x04, 0x00,
193 		0x0d, 0x00,
194 		0x0e, 0x00,
195 		0x0f, 0x00,
196 		0x10, 0x00,
197 		0x51, 0x63,
198 		0x47, 0x66,
199 		0x48, 0x66,
200 		0x4d, 0x1a,
201 		0x49, 0x08,
202 		0x4a, 0x9b
203 	};
204 	uint8_t top_ctrl[] = {REG_TOP_CONTROL, 0x00};
205 
206 	error = lg3303_reset(lg);
207 	if (error)
208 		return error;
209 
210 	if (lg->flags & LG3303_CFG_SERIAL_INPUT)
211 		top_ctrl[1] = 0x40;
212 
213 	switch (modulation) {
214 	case VSB_8:
215 		top_ctrl[1] |= 0x03;
216 		error = lg3303_write(lg, vsb_data, sizeof(vsb_data));
217 		if (error)
218 			return error;
219 		break;
220 	case QAM_256:
221 		top_ctrl[1] |= 0x01;
222 		/* FALLTHROUGH */
223 	case QAM_64:
224 		error = lg3303_write(lg, qam_data, sizeof(qam_data));
225 		if (error)
226 			return error;
227 		break;
228 	default:
229 		device_printf(lg->parent,
230 		    "lg3303: unsupported modulation type (%d)\n",
231 		    modulation);
232 		return EINVAL;
233 	}
234 	error = lg3303_write(lg, top_ctrl, sizeof(top_ctrl));
235 	if (error)
236 		return error;
237 	lg->current_modulation = modulation;
238 	lg3303_reset(lg);
239 
240 	return error;
241 }
242 
243 fe_status_t
244 lg3303_get_dtv_status(struct lg3303 *lg)
245 {
246 	uint8_t reg = 0, value = 0x00;
247 	fe_status_t festatus = 0;
248 	int error = 0;
249 
250 	error = lg3303_read(lg, 0x58, &value, sizeof(value));
251 	if (error)
252 		return 0;
253 
254 	if (value & 0x01)
255 		festatus |= FE_HAS_SIGNAL;
256 
257 	error = lg3303_read(lg, REG_CARRIER_LOCK, &value, sizeof(value));
258 	if (error)
259 		return 0;
260 
261 	switch (lg->current_modulation) {
262 	case VSB_8:
263 		if (value & 0x80)
264 			festatus |= FE_HAS_CARRIER;
265 		reg = 0x38;
266 		break;
267 	case QAM_64:
268 	case QAM_256:
269 		if ((value & 0x07) == 0x07)
270 			festatus |= FE_HAS_CARRIER;
271 		reg = 0x8a;
272 		break;
273 	default:
274 		device_printf(lg->parent,
275 		    "lg3303: unsupported modulation type (%d)\n",
276 		    lg->current_modulation);
277 		return 0;
278 	}
279 
280 	if ((festatus & FE_HAS_CARRIER) == 0)
281 		return festatus;
282 
283 	error = lg3303_read(lg, reg, &value, sizeof(value));
284 	if (!error && (value & 0x01))
285 		festatus |= FE_HAS_LOCK;
286 
287 	if (festatus & FE_HAS_LOCK)
288 		festatus |= (FE_HAS_SYNC | FE_HAS_VITERBI);
289 
290 	return festatus;
291 }
292 
293 uint16_t
294 lg3303_get_snr(struct lg3303 *lg)
295 {
296 	int64_t noise, snr_const;
297 	uint8_t buffer[5];
298 	int64_t snr;
299 	int error;
300 
301 	switch (lg->current_modulation) {
302 	case VSB_8:
303 		error = lg3303_read(lg, REG_EQPH_ERR0, buffer, sizeof(buffer));
304 		if (error)
305 			return 0;
306 		noise = ((buffer[0] & 7) << 16) | (buffer[3] << 8) | buffer[4];
307 		snr_const = 73957994;	/* log10(2560) * pow(2,24) */
308 		break;
309 	case QAM_64:
310 	case QAM_256:
311 		error = lg3303_read(lg, REG_CARRIER_MSEQAM1, buffer, 2);
312 		if (error)
313 			return 0;
314 		noise = (buffer[0] << 8) | buffer[1];
315 		if (lg->current_modulation == QAM_64)
316 			snr_const = 97939837;	/* log10(688128) * pow(2,24) */
317 		else
318 			snr_const = 98026066;	/* log10(696320) * pow(2,24) */
319 		break;
320 	default:
321 		device_printf(lg->parent,
322 		    "lg3303: unsupported modulation type (%d)\n",
323 		    lg->current_modulation);
324 		return 0;
325 	}
326 
327 	if (noise == 0)
328 		return 0;
329 	snr = dtv_intlog10(noise);
330 	if (snr > snr_const)
331 		return 0;
332 	return (10 * (snr_const - snr)) >> 16;
333 }
334 
335 uint16_t
336 lg3303_get_signal_strength(struct lg3303 *lg)
337 {
338 	return ((uint32_t)lg3303_get_snr(lg) << 16) / 8960;
339 }
340 
341 uint32_t
342 lg3303_get_ucblocks(struct lg3303 *lg)
343 {
344 	uint8_t buffer[2];
345 	int error;
346 
347 	error = lg3303_read(lg, REG_PACKET_ERR_COUNTER1, buffer, sizeof(buffer));
348 	if (error)
349 		return 0;
350 
351 	return (buffer[0] << 8) | buffer[1];
352 }
353 
354 MODULE(MODULE_CLASS_DRIVER, lg3303, "iic,dtv_math");
355 
356 static int
357 lg3303_modcmd(modcmd_t cmd, void *opaque)
358 {
359 	if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI)
360 		return 0;
361 	return ENOTTY;
362 }
363