Home | History | Annotate | Line # | Download | only in i2c
      1 /* $NetBSD: cx24227.c,v 1.11 2019/12/31 14:25:33 thorpej Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2008, 2011 Jonathan A. Kollasch
      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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER OR
     20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: cx24227.c,v 1.11 2019/12/31 14:25:33 thorpej Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/systm.h>
     34 #include <sys/device.h>
     35 #include <sys/kmem.h>
     36 #include <sys/module.h>
     37 
     38 #include <dev/i2c/cx24227var.h>
     39 
     40 /* #define CX24227_DEBUG */
     41 
     42 struct cx24227 {
     43 	device_t        parent;
     44 	i2c_tag_t       tag;
     45 	i2c_addr_t      addr;
     46 };
     47 
     48 static int cx24227_writereg(struct cx24227 *, uint8_t, uint16_t);
     49 static int cx24227_readreg(struct cx24227 *, uint8_t, uint16_t *);
     50 
     51 static int cx24227_init(struct cx24227 *);
     52 
     53 static struct documentation_wanted {
     54 	uint8_t		r;
     55 	uint16_t	v;
     56 } documentation_wanted[] = {
     57 	{ 0x00, 0x0071, },
     58 	{ 0x01, 0x3213, },
     59 	{ 0x09, 0x0025, },
     60 	{ 0x1c, 0x001d, },
     61 	{ 0x1f, 0x002d, },
     62 	{ 0x20, 0x001d, },
     63 	{ 0x22, 0x0022, },
     64 	{ 0x23, 0x0020, },
     65 	{ 0x29, 0x110f, },
     66 	{ 0x2a, 0x10b4, },
     67 	{ 0x2b, 0x10ae, },
     68 	{ 0x2c, 0x0031, },
     69 	{ 0x31, 0x010d, },
     70 	{ 0x32, 0x0100, },
     71 	{ 0x44, 0x0510, },
     72 	{ 0x54, 0x0104, },
     73 	{ 0x58, 0x2222, },
     74 	{ 0x59, 0x1162, },
     75 	{ 0x5a, 0x3211, },
     76 	{ 0x5d, 0x0370, },
     77 	{ 0x5e, 0x0296, },
     78 	{ 0x61, 0x0010, },
     79 	{ 0x63, 0x4a00, },
     80 	{ 0x65, 0x0800, },
     81 	{ 0x71, 0x0003, },
     82 	{ 0x72, 0x0470, },
     83 	{ 0x81, 0x0002, },
     84 	{ 0x82, 0x0600, },
     85 	{ 0x86, 0x0002, },
     86 	{ 0x8a, 0x2c38, },
     87 	{ 0x8b, 0x2a37, },
     88 	{ 0x92, 0x302f, },
     89 	{ 0x93, 0x3332, },
     90 	{ 0x96, 0x000c, },
     91 	{ 0x99, 0x0101, },
     92 	{ 0x9c, 0x2e37, },
     93 	{ 0x9d, 0x2c37, },
     94 	{ 0x9e, 0x2c37, },
     95 	{ 0xab, 0x0100, },
     96 	{ 0xac, 0x1003, },
     97 	{ 0xad, 0x103f, },
     98 	{ 0xe2, 0x0100, },
     99 	{ 0xe3, 0x1000, },
    100 	{ 0x28, 0x1010, },
    101 	{ 0xb1, 0x000e, },
    102 };
    103 
    104 
    105 static int
    106 cx24227_writereg(struct cx24227 *sc, uint8_t reg, uint16_t data)
    107 {
    108 	int error;
    109 	uint8_t r[3];
    110 
    111 	if ((error = iic_acquire_bus(sc->tag, 0)) != 0)
    112 		return error;
    113 
    114 	r[0] = reg;
    115 	r[1] = (data >> 8) & 0xff;
    116 	r[2] = data & 0xff;
    117 	error = iic_exec(sc->tag, I2C_OP_WRITE_WITH_STOP, sc->addr,
    118 	    r, 3, NULL, 0, 0);
    119 
    120 	iic_release_bus(sc->tag, 0);
    121 
    122 	return error;
    123 }
    124 
    125 static int
    126 cx24227_readreg(struct cx24227 *sc, uint8_t reg, uint16_t *data)
    127 {
    128 	int error;
    129 	uint8_t r[2];
    130 
    131 	*data = 0x0000;
    132 
    133 	if ((error = iic_acquire_bus(sc->tag, 0)) != 0)
    134 		return error;
    135 
    136 	error = iic_exec(sc->tag, I2C_OP_READ_WITH_STOP, sc->addr,
    137 			 &reg, 1, r, 2, 0);
    138 
    139 	iic_release_bus(sc->tag, 0);
    140 
    141 	*data |= r[0] << 8;
    142 	*data |= r[1];
    143 
    144 	return error;
    145 }
    146 
    147 uint16_t
    148 cx24227_get_signal(struct cx24227 *sc)
    149 {
    150 	uint16_t sig = 0;
    151 
    152 	cx24227_readreg(sc, 0xf1, &sig);
    153 
    154 	return sig;
    155 }
    156 
    157 fe_status_t
    158 cx24227_get_dtv_status(struct cx24227 *sc)
    159 {
    160 	uint16_t reg;
    161 	fe_status_t status = 0;
    162 
    163 	cx24227_readreg(sc, 0xf1, &reg);
    164 
    165 	if(reg & 0x1000)
    166 		status = FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
    167 	if(reg & 0x8000)
    168 		status |= FE_HAS_LOCK | FE_HAS_SYNC;
    169 
    170 	return status;
    171 }
    172 
    173 int
    174 cx24227_set_modulation(struct cx24227 *sc, fe_modulation_t modulation)
    175 {
    176 	switch (modulation) {
    177 	case VSB_8:
    178 	case QAM_64:
    179 	case QAM_256:
    180 	case QAM_AUTO:
    181 		break;
    182 	default:
    183 		return EINVAL;
    184 	}
    185 
    186 	/* soft reset */
    187 	cx24227_writereg(sc, 0xf5, 0x0000);
    188 	cx24227_writereg(sc, 0xf5, 0x0001);
    189 
    190 	switch (modulation) {
    191 	case VSB_8:
    192 		/* VSB8 */
    193 		cx24227_writereg(sc, 0xf4, 0x0000);
    194 		break;
    195 	default:
    196 		/* QAM */
    197 		cx24227_writereg(sc, 0xf4, 0x0001);
    198 		cx24227_writereg(sc, 0x85, 0x0110);
    199 		break;
    200 	}
    201 
    202 	/* soft reset */
    203 	cx24227_writereg(sc, 0xf5, 0x0000);
    204 	cx24227_writereg(sc, 0xf5, 0x0001);
    205 
    206 #if 0
    207 	delay(100);
    208 
    209 	/* open the i2c gate */
    210 	cx24227_writereg(sc, 0xf3, 0x0001);
    211 
    212 	/* we could tune in here? */
    213 
    214 	/* close the i2c gate */
    215 	cx24227_writereg(sc, 0xf3, 0x0000);
    216 
    217 #endif
    218 	return 0;
    219 }
    220 
    221 void
    222 cx24227_enable(struct cx24227* sc, bool enable)
    223 {
    224 	if (enable == true) {
    225 		cx24227_init(sc);
    226 	}
    227 }
    228 
    229 struct cx24227 *
    230 cx24227_open(device_t parent, i2c_tag_t tag, i2c_addr_t addr)
    231 {
    232 	struct cx24227 *sc;
    233 	int e;
    234 	uint16_t value;
    235 
    236 	sc = kmem_alloc(sizeof(*sc), KM_SLEEP);
    237 	sc->parent = parent;
    238 	sc->tag = tag;
    239 	sc->addr = addr;
    240 
    241 	/* read chip ids */
    242 	value = 0;
    243 	e = cx24227_readreg(sc, 0x04, &value);
    244 	if (e) {
    245 		device_printf(parent, "cx24227: read failed: %d\n", e);
    246 		kmem_free(sc, sizeof(*sc));
    247 		return NULL;
    248 	}
    249 #ifdef CX24227_DEBUG
    250 	device_printf(parent, "cx24227: chipid %04x\n", value);
    251 #endif
    252 
    253 
    254 	value = 0x0001; /* open the i2c gate */
    255 	e = cx24227_writereg(sc, 0xf3, value);
    256 #if 0
    257 	if (e) {
    258 		device_printf(parent, "cx24227: write failed: %d\n", e);
    259 		kmem_free(sc, sizeof(*sc));
    260 		return NULL;
    261 	}
    262 #endif
    263 
    264 	cx24227_init(sc);
    265 
    266 	return sc;
    267 }
    268 
    269 void
    270 cx24227_close(struct cx24227 *sc)
    271 {
    272 	kmem_free(sc, sizeof(*sc));
    273 }
    274 
    275 
    276 static void
    277 cx24227_sleepreset(struct cx24227 *sc)
    278 {
    279 	cx24227_writereg(sc, 0xf2, 0);
    280 	cx24227_writereg(sc, 0xfa, 0);
    281 }
    282 
    283 static int
    284 cx24227_init(struct cx24227 *sc)
    285 {
    286 	unsigned int i;
    287 	uint16_t reg;
    288 
    289 	cx24227_sleepreset(sc);
    290 
    291 	for(i = 0; i < __arraycount(documentation_wanted); i++)
    292 		cx24227_writereg(sc, documentation_wanted[i].r, documentation_wanted[i].v);
    293 
    294 	/* Serial */
    295 	cx24227_readreg(sc, 0xab, &reg);
    296 	reg |= 0x0100;
    297 	cx24227_writereg(sc, 0xab, reg);
    298 
    299 	/* no spectral inversion */
    300 	cx24227_writereg(sc, 0x1b, 0x0110);
    301 
    302 	/* 44MHz IF */
    303 	cx24227_writereg(sc, 0x87, 0x01be);
    304 	cx24227_writereg(sc, 0x88, 0x0436);
    305 	cx24227_writereg(sc, 0x89, 0x054d);
    306 
    307 	/* GPIO on */
    308 	cx24227_readreg(sc, 0xe3, &reg);
    309 	reg |= 0x1100;
    310 	cx24227_writereg(sc, 0xe3, reg);
    311 
    312 	/* clocking */
    313 	cx24227_readreg(sc, 0xac, &reg);
    314 	reg &= ~0x3000;
    315 	reg |= 0x1000;
    316 	cx24227_writereg(sc, 0xac, reg);
    317 
    318 	/* soft reset */
    319 	cx24227_writereg(sc, 0xf5, 0x0000);
    320 	cx24227_writereg(sc, 0xf5, 0x0001);
    321 
    322 	/* open gate */
    323 	cx24227_writereg(sc, 0xf3, 0x0001);
    324 
    325 	return 0;
    326 }
    327 
    328 MODULE(MODULE_CLASS_DRIVER, cx24227, "i2cexec");
    329 
    330 static int
    331 cx24227_modcmd(modcmd_t cmd, void *priv)
    332 {
    333 	if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI)
    334 		return 0;
    335 	return ENOTTY;
    336 }
    337