Home | History | Annotate | Line # | Download | only in i2c
lg3303.c revision 1.9
      1 /* $NetBSD: lg3303.c,v 1.9 2015/03/07 14:16:51 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.9 2015/03/07 14:16:51 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, "i2cexec,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