xref: /netbsd/sys/dev/i2c/xc3028.c (revision a8a5c538)
1 /* $NetBSD: xc3028.c,v 1.9 2018/09/03 16:29:31 riastradh Exp $ */
2 
3 /*-
4  * Copyright (c) 2011 Jared D. McNeill <jmcneill@invisible.ca>
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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Xceive XC3028L
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: xc3028.c,v 1.9 2018/09/03 16:29:31 riastradh Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/conf.h>
40 #include <sys/bus.h>
41 #include <sys/kmem.h>
42 #include <sys/mutex.h>
43 #include <sys/module.h>
44 
45 #include <dev/firmload.h>
46 #include <dev/i2c/i2cvar.h>
47 
48 #include <dev/i2c/xc3028reg.h>
49 #include <dev/i2c/xc3028var.h>
50 
51 #define	XC3028_FIRMWARE_DRVNAME	"xc3028"
52 
53 #define	XC3028_FREQ_MIN		1000000
54 #define	XC3028_FREQ_MAX		1023000000
55 
56 #define	XC3028_FW_BASE		(1 << 0)
57 #define	XC3028_FW_D2633		(1 << 4)
58 #define	XC3028_FW_DTV6		(1 << 5)
59 #define	XC3028_FW_QAM		(1 << 6)
60 #define	XC3028_FW_ATSC		(1 << 16)
61 #define	XC3028_FW_LG60		(1 << 18)
62 #define	XC3028_FW_F6MHZ		(1 << 27)
63 #define	XC3028_FW_SCODE		(1 << 29)
64 #define	XC3028_FW_HAS_IF	(1 << 30)
65 
66 #define	XC3028_FW_DEFAULT	(XC3028_FW_ATSC|XC3028_FW_D2633|XC3028_FW_DTV6)
67 
68 static kmutex_t	xc3028_firmware_lock;
69 
70 static int	xc3028_reset(struct xc3028 *);
71 static int	xc3028_read_2(struct xc3028 *, uint16_t, uint16_t *);
72 static int	xc3028_write_buffer(struct xc3028 *, const uint8_t *, size_t);
73 static int	xc3028_firmware_open(struct xc3028 *);
74 static int	xc3028_firmware_parse(struct xc3028 *, const uint8_t *, size_t);
75 static int	xc3028_firmware_upload(struct xc3028 *, struct xc3028_fw *);
76 static int	xc3028_scode_upload(struct xc3028 *, struct xc3028_fw *);
77 static void	xc3028_dump_fw(struct xc3028 *, struct xc3028_fw *,
78 		    const char *);
79 
80 static const char *
xc3028_name(struct xc3028 * xc)81 xc3028_name(struct xc3028 *xc)
82 {
83 	if (xc->type == XC3028L)
84 		return "xc3028l";
85 	else
86 		return "xc3028";
87 }
88 
89 static const char *
xc3028_firmware_name(struct xc3028 * xc)90 xc3028_firmware_name(struct xc3028 *xc)
91 {
92 	if (xc->type == XC3028L)
93 		return "xc3028L-v36.fw";
94 	else
95 		return "xc3028-v27.fw";
96 }
97 
98 static int
xc3028_reset(struct xc3028 * xc)99 xc3028_reset(struct xc3028 *xc)
100 {
101 	int error = 0;
102 
103 	if (xc->reset)
104 		error = xc->reset(xc->reset_priv);
105 
106 	return error;
107 }
108 
109 static struct xc3028_fw *
xc3028_get_basefw(struct xc3028 * xc)110 xc3028_get_basefw(struct xc3028 *xc)
111 {
112 	struct xc3028_fw *fw;
113 	unsigned int i;
114 
115 	for (i = 0; i < xc->nfw; i++) {
116 		fw = &xc->fw[i];
117 		if (fw->type == XC3028_FW_BASE)
118 			return fw;
119 	}
120 
121 	return NULL;
122 }
123 
124 static struct xc3028_fw *
xc3028_get_stdfw(struct xc3028 * xc)125 xc3028_get_stdfw(struct xc3028 *xc)
126 {
127 	struct xc3028_fw *fw;
128 	unsigned int i;
129 
130 	for (i = 0; i < xc->nfw; i++) {
131 		fw = &xc->fw[i];
132 		if (fw->type == (XC3028_FW_D2633|XC3028_FW_DTV6|XC3028_FW_ATSC))
133 			return fw;
134 	}
135 
136 	return NULL;
137 }
138 
139 static struct xc3028_fw *
xc3028_get_scode(struct xc3028 * xc)140 xc3028_get_scode(struct xc3028 *xc)
141 {
142 	struct xc3028_fw *fw;
143 	unsigned int i;
144 
145 	for (i = 0; i < xc->nfw; i++) {
146 		fw = &xc->fw[i];
147 		if (fw->type ==
148 		    (XC3028_FW_DTV6|XC3028_FW_QAM|XC3028_FW_ATSC|XC3028_FW_LG60|
149 		     XC3028_FW_F6MHZ|XC3028_FW_SCODE|XC3028_FW_HAS_IF) &&
150 		    fw->int_freq == 6200)
151 			return fw;
152 	}
153 
154 	return NULL;
155 }
156 
157 static int
xc3028_firmware_open(struct xc3028 * xc)158 xc3028_firmware_open(struct xc3028 *xc)
159 {
160 	firmware_handle_t fwh;
161 	struct xc3028_fw *basefw, *stdfw, *scode;
162 	uint8_t *fw = NULL;
163 	uint16_t xcversion = 0;
164 	size_t fwlen;
165 	int error;
166 
167 	mutex_enter(&xc3028_firmware_lock);
168 
169 	error = firmware_open(XC3028_FIRMWARE_DRVNAME,
170 	    xc3028_firmware_name(xc), &fwh);
171 	if (error)
172 		goto done;
173 	fwlen = firmware_get_size(fwh);
174 	fw = firmware_malloc(fwlen);
175 	if (fw == NULL) {
176 		firmware_close(fwh);
177 		error = ENOMEM;
178 		goto done;
179 	}
180 	error = firmware_read(fwh, 0, fw, fwlen);
181 	firmware_close(fwh);
182 	if (error)
183 		goto done;
184 
185 	device_printf(xc->parent, "%s: loading firmware '%s/%s'\n",
186 	    xc3028_name(xc), XC3028_FIRMWARE_DRVNAME, xc3028_firmware_name(xc));
187 	error = xc3028_firmware_parse(xc, fw, fwlen);
188 	if (!error) {
189 		basefw = xc3028_get_basefw(xc);
190 		stdfw = xc3028_get_stdfw(xc);
191 		scode = xc3028_get_scode(xc);
192 		if (basefw && stdfw) {
193 			xc3028_reset(xc);
194 			xc3028_dump_fw(xc, basefw, "base");
195 			error = xc3028_firmware_upload(xc, basefw);
196 			if (error)
197 				return error;
198 			xc3028_dump_fw(xc, stdfw, "std");
199 			error = xc3028_firmware_upload(xc, stdfw);
200 			if (error)
201 				return error;
202 			if (scode) {
203 				xc3028_dump_fw(xc, scode, "scode");
204 				error = xc3028_scode_upload(xc, scode);
205 				if (error)
206 					return error;
207 			}
208 		} else
209 			error = ENODEV;
210 	}
211 	if (!error) {
212 		xc3028_read_2(xc, XC3028_REG_VERSION, &xcversion);
213 
214 		device_printf(xc->parent, "%s: hw %d.%d, fw %d.%d\n",
215 		    xc3028_name(xc),
216 		    (xcversion >> 12) & 0xf, (xcversion >> 8) & 0xf,
217 		    (xcversion >> 4) & 0xf, (xcversion >> 0) & 0xf);
218 	}
219 
220 done:
221 	if (fw)
222 		firmware_free(fw, fwlen);
223 	mutex_exit(&xc3028_firmware_lock);
224 
225 	if (error)
226 		aprint_error_dev(xc->parent,
227 		    "%s: couldn't open firmware '%s/%s' (error=%d)\n",
228 		    xc3028_name(xc), XC3028_FIRMWARE_DRVNAME,
229 		    xc3028_firmware_name(xc), error);
230 
231 	return error;
232 }
233 
234 static const char *xc3028_fw_types[] = {
235 	"BASE",
236 	"F8MHZ",
237 	"MTS",
238 	"D2620",
239 	"D2633",
240 	"DTV6",
241 	"QAM",
242 	"DTV7",
243 	"DTV78",
244 	"DTV8",
245 	"FM",
246 	"INPUT1",
247 	"LCD",
248 	"NOGD",
249 	"INIT1",
250 	"MONO",
251 	"ATSC",
252 	"IF",
253 	"LG60",
254 	"ATI638",
255 	"OREN538",
256 	"OREN36",
257 	"TOYOTA388",
258 	"TOYOTA794",
259 	"DIBCOM52",
260 	"ZARLINK456",
261 	"CHINA",
262 	"F6MHZ",
263 	"INPUT2",
264 	"SCODE",
265 	"HAS_IF",
266 };
267 
268 static void
xc3028_dump_fw(struct xc3028 * xc,struct xc3028_fw * xcfw,const char * type)269 xc3028_dump_fw(struct xc3028 *xc, struct xc3028_fw *xcfw, const char *type)
270 {
271 	unsigned int i;
272 
273 	device_printf(xc->parent, "%s: %s:", xc3028_name(xc), type);
274 	if (xcfw == NULL) {
275 		printf(" <none>\n");
276 		return;
277 	}
278 	for (i = 0; i < __arraycount(xc3028_fw_types); i++) {
279 		if (xcfw->type & (1 << i))
280 			printf(" %s", xc3028_fw_types[i]);
281 	}
282 	if (xcfw->type & (1 << 30))
283 		printf("_%d", xcfw->int_freq);
284 	if (xcfw->id)
285 		printf(" id=%" PRIx64, xcfw->id);
286 	printf(" size=%u\n", xcfw->data_size);
287 }
288 
289 static int
xc3028_firmware_parse(struct xc3028 * xc,const uint8_t * fw,size_t fwlen)290 xc3028_firmware_parse(struct xc3028 *xc, const uint8_t *fw, size_t fwlen)
291 {
292 	const uint8_t *p = fw, *endp = p + fwlen;
293 	char fwname[32 + 1];
294 	uint16_t fwver, narr;
295 	unsigned int index;
296 	struct xc3028_fw *xcfw;
297 
298 	if (fwlen < 36)
299 		return EINVAL;
300 
301 	/* first 32 bytes are the firmware name string */
302 	memset(fwname, 0, sizeof(fwname));
303 	memcpy(fwname, p, sizeof(fwname) - 1);
304 	p += (sizeof(fwname) - 1);
305 
306 	fwver = le16dec(p);
307 	p += sizeof(fwver);
308 	narr = le16dec(p);
309 	p += sizeof(narr);
310 
311 	aprint_debug_dev(xc->parent, "%s: fw type %s, ver %d.%d, %d images\n",
312 	    xc3028_name(xc), fwname, fwver >> 8, fwver & 0xff, narr);
313 
314 	xc->fw = kmem_zalloc(sizeof(*xc->fw) * narr, KM_SLEEP);
315 	xc->nfw = narr;
316 
317 	for (index = 0; index < xc->nfw && p < endp; index++) {
318 		xcfw = &xc->fw[index];
319 
320 		if (endp - p < 16)
321 			goto corrupt;
322 
323 		xcfw->type = le32dec(p);
324 		p += sizeof(xcfw->type);
325 
326 		xcfw->id = le64dec(p);
327 		p += sizeof(xcfw->id);
328 
329 		if (xcfw->type & XC3028_FW_HAS_IF) {
330 			xcfw->int_freq = le16dec(p);
331 			p += sizeof(xcfw->int_freq);
332 			if ((uint32_t)(endp - p) < sizeof(xcfw->data_size))
333 				goto corrupt;
334 		}
335 
336 		xcfw->data_size = le32dec(p);
337 		p += sizeof(xcfw->data_size);
338 
339 		if (xcfw->data_size == 0 ||
340 		    xcfw->data_size > (uint32_t)(endp - p))
341 			goto corrupt;
342 		xcfw->data = kmem_alloc(xcfw->data_size, KM_SLEEP);
343 		memcpy(xcfw->data, p, xcfw->data_size);
344 		p += xcfw->data_size;
345 	}
346 
347 	return 0;
348 
349 corrupt:
350 	aprint_error_dev(xc->parent, "%s: fw image corrupt\n", xc3028_name(xc));
351 	for (index = 0; index < xc->nfw; index++) {
352 		if (xc->fw[index].data)
353 			kmem_free(xc->fw[index].data, xc->fw[index].data_size);
354 	}
355 	kmem_free(xc->fw, sizeof(*xc->fw) * xc->nfw);
356 	xc->nfw = 0;
357 
358 	return ENXIO;
359 }
360 
361 static int
xc3028_firmware_upload(struct xc3028 * xc,struct xc3028_fw * xcfw)362 xc3028_firmware_upload(struct xc3028 *xc, struct xc3028_fw *xcfw)
363 {
364 	const uint8_t *fw = xcfw->data, *p;
365 	uint32_t fwlen = xcfw->data_size;
366 	uint8_t cmd[64];
367 	unsigned int i;
368 	uint16_t len, rem;
369 	size_t wrlen;
370 	int error;
371 
372 	for (i = 0; i < fwlen - 2;) {
373 		len = le16dec(&fw[i]);
374 		i += 2;
375 		if (len == 0xffff)
376 			break;
377 
378 		/* reset command */
379 		if (len == 0x0000) {
380 			error = xc3028_reset(xc);
381 			if (error)
382 				return error;
383 			continue;
384 		}
385 		/* reset clk command */
386 		if (len == 0xff00) {
387 			continue;
388 		}
389 		/* delay command */
390 		if (len & 0x8000) {
391 			delay((len & 0x7fff) * 1000);
392 			continue;
393 		}
394 
395 		if (i + len > fwlen) {
396 			printf("weird len, i=%u len=%u fwlen=%u'\n", i, len, fwlen);
397 			return EINVAL;
398 		}
399 
400 		cmd[0] = fw[i];
401 		p = &fw[i + 1];
402 		rem = len - 1;
403 		while (rem > 0) {
404 			wrlen = uimin(rem, __arraycount(cmd) - 1);
405 			memcpy(&cmd[1], p, wrlen);
406 			error = xc3028_write_buffer(xc, cmd, wrlen + 1);
407 			if (error)
408 				return error;
409 			p += wrlen;
410 			rem -= wrlen;
411 		}
412 		i += len;
413 	}
414 
415 	return 0;
416 }
417 
418 static int
xc3028_scode_upload(struct xc3028 * xc,struct xc3028_fw * xcfw)419 xc3028_scode_upload(struct xc3028 *xc, struct xc3028_fw *xcfw)
420 {
421 	static uint8_t scode_init[] = {	0xa0, 0x00, 0x00, 0x00 };
422 	static uint8_t scode_fini[] = { 0x00, 0x8c };
423 	int error;
424 
425 	if (xcfw->data_size < 12)
426 		return EINVAL;
427 	error = xc3028_write_buffer(xc, scode_init, sizeof(scode_init));
428 	if (error)
429 		return error;
430 	error = xc3028_write_buffer(xc, xcfw->data, 12);
431 	if (error)
432 		return error;
433 	error = xc3028_write_buffer(xc, scode_fini, sizeof(scode_fini));
434 	if (error)
435 		return error;
436 
437 	return 0;
438 }
439 
440 static int
xc3028_read_2(struct xc3028 * xc,uint16_t reg,uint16_t * val)441 xc3028_read_2(struct xc3028 *xc, uint16_t reg, uint16_t *val)
442 {
443 	uint8_t cmd[2], resp[2];
444 	int error;
445 
446 	cmd[0] = reg >> 8;
447 	cmd[1] = reg & 0xff;
448 	error = iic_exec(xc->i2c, I2C_OP_WRITE, xc->i2c_addr,
449 	    cmd, sizeof(cmd), NULL, 0, 0);
450 	if (error)
451 		return error;
452 	resp[0] = resp[1] = 0;
453 	error = iic_exec(xc->i2c, I2C_OP_READ, xc->i2c_addr,
454 	    NULL, 0, resp, sizeof(resp), 0);
455 	if (error)
456 		return error;
457 
458 	*val = (resp[0] << 8) | resp[1];
459 
460 	return 0;
461 }
462 
463 static int
xc3028_write_buffer(struct xc3028 * xc,const uint8_t * data,size_t datalen)464 xc3028_write_buffer(struct xc3028 *xc, const uint8_t *data, size_t datalen)
465 {
466 	return iic_exec(xc->i2c, I2C_OP_WRITE_WITH_STOP, xc->i2c_addr,
467 	    data, datalen, NULL, 0, 0);
468 }
469 
470 #if notyet
471 static int
xc3028_write_2(struct xc3028 * xc,uint16_t reg,uint16_t val)472 xc3028_write_2(struct xc3028 *xc, uint16_t reg, uint16_t val)
473 {
474 	uint8_t data[4];
475 
476 	data[0] = reg >> 8;
477 	data[1] = reg & 0xff;
478 	data[2] = val >> 8;
479 	data[3] = val & 0xff;
480 
481 	return xc3028_write_buffer(xc, data, sizeof(data));
482 }
483 #endif
484 
485 struct xc3028 *
xc3028_open(device_t parent,i2c_tag_t i2c,i2c_addr_t addr,xc3028_reset_cb reset,void * reset_priv,enum xc3028_type type)486 xc3028_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr,
487     xc3028_reset_cb reset, void *reset_priv, enum xc3028_type type)
488 {
489 	struct xc3028 *xc;
490 
491 	xc = kmem_alloc(sizeof(*xc), KM_SLEEP);
492 	xc->parent = parent;
493 	xc->i2c = i2c;
494 	xc->i2c_addr = addr;
495 	xc->reset = reset;
496 	xc->reset_priv = reset_priv;
497 	xc->type = type;
498 
499 	if (xc3028_firmware_open(xc)) {
500 		aprint_error_dev(parent, "%s: fw open failed\n",
501 		    xc3028_name(xc));
502 		goto failed;
503 	}
504 
505 	return xc;
506 
507 failed:
508 	kmem_free(xc, sizeof(*xc));
509 	return NULL;
510 }
511 
512 void
xc3028_close(struct xc3028 * xc)513 xc3028_close(struct xc3028 *xc)
514 {
515 	unsigned int index;
516 
517 	if (xc->fw) {
518 		for (index = 0; index < xc->nfw; index++) {
519 			if (xc->fw[index].data)
520 				kmem_free(xc->fw[index].data,
521 				    xc->fw[index].data_size);
522 		}
523 		kmem_free(xc->fw, sizeof(*xc->fw) * xc->nfw);
524 	}
525 	kmem_free(xc, sizeof(*xc));
526 }
527 
528 int
xc3028_tune_dtv(struct xc3028 * xc,const struct dvb_frontend_parameters * params)529 xc3028_tune_dtv(struct xc3028 *xc, const struct dvb_frontend_parameters *params)
530 {
531 	static uint8_t freq_init[] = { 0x80, 0x02, 0x00, 0x00 };
532 	uint8_t freq_buf[4];
533 	uint32_t div, offset = 0;
534 	int error;
535 
536 	if (params->u.vsb.modulation == VSB_8) {
537 		offset = 1750000;
538 	} else {
539 		return EINVAL;
540 	}
541 
542 	div = (params->frequency - offset + 15625 / 2) / 15625;
543 
544 	error = xc3028_write_buffer(xc, freq_init, sizeof(freq_init));
545 	if (error)
546 		return error;
547 	delay(10000);
548 
549 	freq_buf[0] = (div >> 24) & 0xff;
550 	freq_buf[1] = (div >> 16) & 0xff;
551 	freq_buf[2] = (div >> 8) & 0xff;
552 	freq_buf[3] = (div >> 0) & 0xff;
553 	error = xc3028_write_buffer(xc, freq_buf, sizeof(freq_buf));
554 	if (error)
555 		return error;
556 	delay(100000);
557 
558 	return 0;
559 }
560 
561 MODULE(MODULE_CLASS_DRIVER, xc3028, "i2cexec");
562 
563 static int
xc3028_modcmd(modcmd_t cmd,void * opaque)564 xc3028_modcmd(modcmd_t cmd, void *opaque)
565 {
566 	switch (cmd) {
567 	case MODULE_CMD_INIT:
568 		mutex_init(&xc3028_firmware_lock, MUTEX_DEFAULT, IPL_NONE);
569 		return 0;
570 	case MODULE_CMD_FINI:
571 		mutex_destroy(&xc3028_firmware_lock);
572 		return 0;
573 	default:
574 		return ENOTTY;
575 	}
576 }
577