Home | History | Annotate | Line # | Download | only in i2c
xc3028.c revision 1.3
      1 /* $NetBSD: xc3028.c,v 1.3 2011/08/09 01:42:24 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2011 Jared D. McNeill <jmcneill (at) 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.3 2011/08/09 01:42:24 jmcneill 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 *
     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 *
     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
     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 *
    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 *
    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 *
    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
    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, 0);
    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
    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
    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 	if (xc->fw == NULL)
    316 		return ENOMEM;
    317 	xc->nfw = narr;
    318 
    319 	for (index = 0; index < xc->nfw && p < endp; index++) {
    320 		xcfw = &xc->fw[index];
    321 
    322 		if (endp - p < 16)
    323 			goto corrupt;
    324 
    325 		xcfw->type = le32dec(p);
    326 		p += sizeof(xcfw->type);
    327 
    328 		xcfw->id = le64dec(p);
    329 		p += sizeof(xcfw->id);
    330 
    331 		if (xcfw->type & XC3028_FW_HAS_IF) {
    332 			xcfw->int_freq = le16dec(p);
    333 			p += sizeof(xcfw->int_freq);
    334 			if ((uint32_t)(endp - p) < sizeof(xcfw->data_size))
    335 				goto corrupt;
    336 		}
    337 
    338 		xcfw->data_size = le32dec(p);
    339 		p += sizeof(xcfw->data_size);
    340 
    341 		if (xcfw->data_size == 0 ||
    342 		    xcfw->data_size > (uint32_t)(endp - p))
    343 			goto corrupt;
    344 		xcfw->data = kmem_alloc(xcfw->data_size, KM_SLEEP);
    345 		if (xcfw->data == NULL)
    346 			goto corrupt;
    347 		memcpy(xcfw->data, p, xcfw->data_size);
    348 		p += xcfw->data_size;
    349 	}
    350 
    351 	return 0;
    352 
    353 corrupt:
    354 	aprint_error_dev(xc->parent, "%s: fw image corrupt\n", xc3028_name(xc));
    355 	for (index = 0; index < xc->nfw; index++) {
    356 		if (xc->fw[index].data)
    357 			kmem_free(xc->fw[index].data, xc->fw[index].data_size);
    358 	}
    359 	kmem_free(xc->fw, sizeof(*xc->fw) * xc->nfw);
    360 	xc->nfw = 0;
    361 
    362 	return ENXIO;
    363 }
    364 
    365 static int
    366 xc3028_firmware_upload(struct xc3028 *xc, struct xc3028_fw *xcfw)
    367 {
    368 	const uint8_t *fw = xcfw->data, *p;
    369 	uint32_t fwlen = xcfw->data_size;
    370 	uint8_t cmd[64];
    371 	unsigned int i;
    372 	uint16_t len, rem;
    373 	size_t wrlen;
    374 	int error;
    375 
    376 	for (i = 0; i < fwlen - 2;) {
    377 		len = le16dec(&fw[i]);
    378 		i += 2;
    379 		if (len == 0xffff)
    380 			break;
    381 
    382 		/* reset command */
    383 		if (len == 0x0000) {
    384 			error = xc3028_reset(xc);
    385 			if (error)
    386 				return error;
    387 			continue;
    388 		}
    389 		/* reset clk command */
    390 		if (len == 0xff00) {
    391 			continue;
    392 		}
    393 		/* delay command */
    394 		if (len & 0x8000) {
    395 			delay((len & 0x7fff) * 1000);
    396 			continue;
    397 		}
    398 
    399 		if (i + len > fwlen) {
    400 			printf("weird len, i=%u len=%u fwlen=%u'\n", i, len, fwlen);
    401 			return EINVAL;
    402 		}
    403 
    404 		cmd[0] = fw[i];
    405 		p = &fw[i + 1];
    406 		rem = len - 1;
    407 		while (rem > 0) {
    408 			wrlen = min(rem, __arraycount(cmd) - 1);
    409 			memcpy(&cmd[1], p, wrlen);
    410 			error = xc3028_write_buffer(xc, cmd, wrlen + 1);
    411 			if (error)
    412 				return error;
    413 			p += wrlen;
    414 			rem -= wrlen;
    415 		}
    416 		i += len;
    417 	}
    418 
    419 	return 0;
    420 }
    421 
    422 static int
    423 xc3028_scode_upload(struct xc3028 *xc, struct xc3028_fw *xcfw)
    424 {
    425 	static uint8_t scode_init[] = {	0xa0, 0x00, 0x00, 0x00 };
    426 	static uint8_t scode_fini[] = { 0x00, 0x8c };
    427 	int error;
    428 
    429 	if (xcfw->data_size < 12)
    430 		return EINVAL;
    431 	error = xc3028_write_buffer(xc, scode_init, sizeof(scode_init));
    432 	if (error)
    433 		return error;
    434 	error = xc3028_write_buffer(xc, xcfw->data, 12);
    435 	if (error)
    436 		return error;
    437 	error = xc3028_write_buffer(xc, scode_fini, sizeof(scode_fini));
    438 	if (error)
    439 		return error;
    440 
    441 	return 0;
    442 }
    443 
    444 static int
    445 xc3028_read_2(struct xc3028 *xc, uint16_t reg, uint16_t *val)
    446 {
    447 	uint8_t cmd[2], resp[2];
    448 	int error;
    449 
    450 	cmd[0] = reg >> 8;
    451 	cmd[1] = reg & 0xff;
    452 	error = iic_exec(xc->i2c, I2C_OP_WRITE, xc->i2c_addr,
    453 	    cmd, sizeof(cmd), NULL, 0, 0);
    454 	if (error)
    455 		return error;
    456 	resp[0] = resp[1] = 0;
    457 	error = iic_exec(xc->i2c, I2C_OP_READ, xc->i2c_addr,
    458 	    NULL, 0, resp, sizeof(resp), 0);
    459 	if (error)
    460 		return error;
    461 
    462 	*val = (resp[0] << 8) | resp[1];
    463 
    464 	return 0;
    465 }
    466 
    467 static int
    468 xc3028_write_buffer(struct xc3028 *xc, const uint8_t *data, size_t datalen)
    469 {
    470 	return iic_exec(xc->i2c, I2C_OP_WRITE_WITH_STOP, xc->i2c_addr,
    471 	    data, datalen, NULL, 0, 0);
    472 }
    473 
    474 #if notyet
    475 static int
    476 xc3028_write_2(struct xc3028 *xc, uint16_t reg, uint16_t val)
    477 {
    478 	uint8_t data[4];
    479 
    480 	data[0] = reg >> 8;
    481 	data[1] = reg & 0xff;
    482 	data[2] = val >> 8;
    483 	data[3] = val & 0xff;
    484 
    485 	return xc3028_write_buffer(xc, data, sizeof(data));
    486 }
    487 #endif
    488 
    489 struct xc3028 *
    490 xc3028_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr,
    491     xc3028_reset_cb reset, void *reset_priv, enum xc3028_type type)
    492 {
    493 	struct xc3028 *xc;
    494 
    495 	xc = kmem_alloc(sizeof(*xc), KM_SLEEP);
    496 	if (xc == NULL)
    497 		return NULL;
    498 	xc->parent = parent;
    499 	xc->i2c = i2c;
    500 	xc->i2c_addr = addr;
    501 	xc->reset = reset;
    502 	xc->reset_priv = reset_priv;
    503 	xc->type = type;
    504 
    505 	if (xc3028_firmware_open(xc)) {
    506 		aprint_error_dev(parent, "%s: fw open failed\n",
    507 		    xc3028_name(xc));
    508 		goto failed;
    509 	}
    510 
    511 	return xc;
    512 
    513 failed:
    514 	kmem_free(xc, sizeof(*xc));
    515 	return NULL;
    516 }
    517 
    518 void
    519 xc3028_close(struct xc3028 *xc)
    520 {
    521 	unsigned int index;
    522 
    523 	if (xc->fw) {
    524 		for (index = 0; index < xc->nfw; index++) {
    525 			if (xc->fw[index].data)
    526 				kmem_free(xc->fw[index].data,
    527 				    xc->fw[index].data_size);
    528 		}
    529 		kmem_free(xc->fw, sizeof(*xc->fw) * xc->nfw);
    530 	}
    531 	kmem_free(xc, sizeof(*xc));
    532 }
    533 
    534 int
    535 xc3028_tune_dtv(struct xc3028 *xc, const struct dvb_frontend_parameters *params)
    536 {
    537 	static uint8_t freq_init[] = { 0x80, 0x02, 0x00, 0x00 };
    538 	uint8_t freq_buf[4];
    539 	uint32_t div, offset = 0;
    540 	int error;
    541 
    542 	if (params->u.vsb.modulation == VSB_8) {
    543 		offset = 1750000;
    544 	} else {
    545 		return EINVAL;
    546 	}
    547 
    548 	div = (params->frequency - offset + 15625 / 2) / 15625;
    549 
    550 	error = xc3028_write_buffer(xc, freq_init, sizeof(freq_init));
    551 	if (error)
    552 		return error;
    553 	delay(10000);
    554 
    555 	freq_buf[0] = (div >> 24) & 0xff;
    556 	freq_buf[1] = (div >> 16) & 0xff;
    557 	freq_buf[2] = (div >> 8) & 0xff;
    558 	freq_buf[3] = (div >> 0) & 0xff;
    559 	error = xc3028_write_buffer(xc, freq_buf, sizeof(freq_buf));
    560 	if (error)
    561 		return error;
    562 	delay(100000);
    563 
    564 	return 0;
    565 }
    566 
    567 MODULE(MODULE_CLASS_DRIVER, xc3028, "dtv_math");
    568 
    569 static int
    570 xc3028_modcmd(modcmd_t cmd, void *opaque)
    571 {
    572 	switch (cmd) {
    573 	case MODULE_CMD_INIT:
    574 		mutex_init(&xc3028_firmware_lock, MUTEX_DEFAULT, IPL_NONE);
    575 		return 0;
    576 	case MODULE_CMD_FINI:
    577 		mutex_destroy(&xc3028_firmware_lock);
    578 		return 0;
    579 	default:
    580 		return ENOTTY;
    581 	}
    582 }
    583