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