Home | History | Annotate | Line # | Download | only in i2c
lg3303.c revision 1.5
      1 /* $NetBSD: lg3303.c,v 1.5 2011/07/15 20:28:38 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.5 2011/07/15 20:28:38 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 
     42 #define REG_TOP_CONTROL         0x00
     43 #define REG_IRQ_MASK            0x01
     44 #define REG_IRQ_STATUS          0x02
     45 #define REG_VSB_CARRIER_FREQ0   0x16
     46 #define REG_VSB_CARRIER_FREQ1   0x17
     47 #define REG_VSB_CARRIER_FREQ2   0x18
     48 #define REG_VSB_CARRIER_FREQ3   0x19
     49 #define REG_CARRIER_MSEQAM1     0x1a
     50 #define REG_CARRIER_MSEQAM2     0x1b
     51 #define REG_CARRIER_LOCK        0x1c
     52 #define REG_TIMING_RECOVERY     0x1d
     53 #define REG_AGC_DELAY0          0x2a
     54 #define REG_AGC_DELAY1          0x2b
     55 #define REG_AGC_DELAY2          0x2c
     56 #define REG_AGC_RF_BANDWIDTH0   0x2d
     57 #define REG_AGC_RF_BANDWIDTH1   0x2e
     58 #define REG_AGC_RF_BANDWIDTH2   0x2f
     59 #define REG_AGC_LOOP_BANDWIDTH0 0x30
     60 #define REG_AGC_LOOP_BANDWIDTH1 0x31
     61 #define REG_AGC_FUNC_CTRL1      0x32
     62 #define REG_AGC_FUNC_CTRL2      0x33
     63 #define REG_AGC_FUNC_CTRL3      0x34
     64 #define REG_AGC_RFIF_ACC0       0x39
     65 #define REG_AGC_RFIF_ACC1       0x3a
     66 #define REG_AGC_RFIF_ACC2       0x3b
     67 #define REG_AGC_STATUS          0x3f
     68 #define REG_SYNC_STATUS_VSB     0x43
     69 #define REG_DEMUX_CONTROL       0x66
     70 #define REG_EQPH_ERR0           0x6e
     71 #define REG_EQ_ERR1             0x6f
     72 #define REG_EQ_ERR2             0x70
     73 #define REG_PH_ERR1             0x71
     74 #define REG_PH_ERR2             0x72
     75 #define REG_PACKET_ERR_COUNTER1 0x8b
     76 #define REG_PACKET_ERR_COUNTER2 0x8c
     77 
     78 #define LG3303_DEFAULT_DELAY 250000
     79 
     80 static int	lg3303_reset(struct lg3303 *);
     81 static int	lg3303_init(struct lg3303 *);
     82 
     83 struct lg3303 *
     84 lg3303_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr, int flags)
     85 {
     86 	struct lg3303 *lg;
     87 
     88 	lg = kmem_alloc(sizeof(*lg), KM_SLEEP);
     89 	if (lg == NULL)
     90 		return NULL;
     91 	lg->parent = parent;
     92 	lg->i2c = i2c;
     93 	lg->i2c_addr = addr;
     94 	lg->current_modulation = -1;
     95 	lg->flags = flags;
     96 
     97 	if (lg3303_init(lg) != 0) {
     98 		kmem_free(lg, sizeof(*lg));
     99 		return NULL;
    100 	}
    101 
    102 	device_printf(lg->parent, "lg3303: found @ 0x%02x\n", addr);
    103 
    104 	return lg;
    105 }
    106 
    107 void
    108 lg3303_close(struct lg3303 *lg)
    109 {
    110 	kmem_free(lg, sizeof(*lg));
    111 }
    112 
    113 static int
    114 lg3303_write(struct lg3303 *lg, uint8_t *buf, size_t len)
    115 {
    116 	unsigned int i;
    117 	uint8_t *p = buf;
    118 	int error;
    119 
    120 	for (i = 0; i < len - 1; i += 2) {
    121 		error = iic_exec(lg->i2c, I2C_OP_WRITE_WITH_STOP, lg->i2c_addr,
    122 		    p, 2, NULL, 0, 0);
    123 		if (error)
    124 			return error;
    125 		p += 2;
    126 	}
    127 
    128 	return 0;
    129 }
    130 
    131 static int
    132 lg3303_read(struct lg3303 *lg, uint8_t reg, uint8_t *buf, size_t len)
    133 {
    134 	int error;
    135 
    136 	error = iic_exec(lg->i2c, I2C_OP_WRITE, lg->i2c_addr,
    137 	    &reg, sizeof(reg), NULL, 0, 0);
    138 	if (error)
    139 		return error;
    140 	return iic_exec(lg->i2c, I2C_OP_READ, lg->i2c_addr,
    141 	    NULL, 0, buf, len, 0);
    142 }
    143 
    144 static int
    145 lg3303_reset(struct lg3303 *lg)
    146 {
    147 	uint8_t buffer[] = {REG_IRQ_STATUS, 0x00};
    148 	int error = lg3303_write(lg, buffer, 2);
    149 	if (error == 0) {
    150 		buffer[1] = 0x01;
    151 		error = lg3303_write(lg, buffer, 2);
    152 	}
    153 	return error;
    154 }
    155 
    156 static int
    157 lg3303_init(struct lg3303 *lg)
    158 {
    159 	//static uint8_t init_data[] = {0x4c, 0x14, 0x87, 0xf3};
    160 	static uint8_t init_data[] = {0x4c, 0x14};
    161 	size_t len;
    162 	int error;
    163 
    164 #if notyet
    165 	if (clock_polarity == DVB_IFC_POS_POL)
    166 		len = 4;
    167 	else
    168 #endif
    169 	len = 2;
    170 
    171 	error = lg3303_write(lg, init_data, len);
    172 	if (error == 0)
    173       		lg3303_reset(lg);
    174 
    175 	return error;
    176 }
    177 
    178 int
    179 lg3303_set_modulation(struct lg3303 *lg, fe_modulation_t modulation)
    180 {
    181 	int error;
    182 	static uint8_t vsb_data[] = {
    183 		0x04, 0x00,
    184 		0x0d, 0x40,
    185 		0x0e, 0x87,
    186 		0x0f, 0x8e,
    187 		0x10, 0x01,
    188 		0x47, 0x8b
    189 	};
    190 	static uint8_t qam_data[] = {
    191 		0x04, 0x00,
    192 		0x0d, 0x00,
    193 		0x0e, 0x00,
    194 		0x0f, 0x00,
    195 		0x10, 0x00,
    196 		0x51, 0x63,
    197 		0x47, 0x66,
    198 		0x48, 0x66,
    199 		0x4d, 0x1a,
    200 		0x49, 0x08,
    201 		0x4a, 0x9b
    202 	};
    203 	uint8_t top_ctrl[] = {REG_TOP_CONTROL, 0x00};
    204 
    205 	error = lg3303_reset(lg);
    206 	if (error)
    207 		return error;
    208 
    209 	if (lg->flags & LG3303_CFG_SERIAL_INPUT)
    210 		top_ctrl[1] = 0x40;
    211 
    212 	switch (modulation) {
    213 	case VSB_8:
    214 		top_ctrl[1] |= 0x03;
    215 		error = lg3303_write(lg, vsb_data, sizeof(vsb_data));
    216 		if (error)
    217 			return error;
    218 		break;
    219 	case QAM_256:
    220 		top_ctrl[1] |= 0x01;
    221 		/* FALLTHROUGH */
    222 	case QAM_64:
    223 		error = lg3303_write(lg, qam_data, sizeof(qam_data));
    224 		if (error)
    225 			return error;
    226 		break;
    227 	default:
    228 		device_printf(lg->parent,
    229 		    "lg3303: unsupported modulation type (%d)\n",
    230 		    modulation);
    231 		return EINVAL;
    232 	}
    233 	error = lg3303_write(lg, top_ctrl, sizeof(top_ctrl));
    234 	if (error)
    235 		return error;
    236 	lg->current_modulation = modulation;
    237 	lg3303_reset(lg);
    238 
    239 	return error;
    240 }
    241 
    242 fe_status_t
    243 lg3303_get_dtv_status(struct lg3303 *lg)
    244 {
    245 	uint8_t reg = 0, value = 0x00;
    246 	fe_status_t festatus = 0;
    247 	int error = 0;
    248 
    249 	error = lg3303_read(lg, 0x58, &value, sizeof(value));
    250 	if (error)
    251 		return 0;
    252 
    253 	if (value & 0x01)
    254 		festatus |= FE_HAS_SIGNAL;
    255 
    256 	error = lg3303_read(lg, REG_CARRIER_LOCK, &value, sizeof(value));
    257 	if (error)
    258 		return 0;
    259 
    260 	switch (lg->current_modulation) {
    261 	case VSB_8:
    262 		if (value & 0x80)
    263 			festatus |= FE_HAS_CARRIER;
    264 		reg = 0x38;
    265 		break;
    266 	case QAM_64:
    267 	case QAM_256:
    268 		if ((value & 0x07) == 0x07)
    269 			festatus |= FE_HAS_CARRIER;
    270 		reg = 0x8a;
    271 		break;
    272 	default:
    273 		device_printf(lg->parent,
    274 		    "lg3303: unsupported modulation type (%d)\n",
    275 		    lg->current_modulation);
    276 		return 0;
    277 	}
    278 
    279 	if ((festatus & FE_HAS_CARRIER) == 0)
    280 		return festatus;
    281 
    282 	error = lg3303_read(lg, reg, &value, sizeof(value));
    283 	if (!error && (value & 0x01))
    284 		festatus |= FE_HAS_LOCK;
    285 
    286 	if (festatus & FE_HAS_LOCK)
    287 		festatus |= (FE_HAS_SYNC | FE_HAS_VITERBI);
    288 
    289 	return festatus;
    290 }
    291 
    292 uint16_t
    293 lg3303_get_snr(struct lg3303 *lg)
    294 {
    295 	int64_t noise, snr_const;
    296 	uint8_t buffer[5];
    297 	int64_t snr;
    298 	int error;
    299 
    300 	switch (lg->current_modulation) {
    301 	case VSB_8:
    302 		error = lg3303_read(lg, REG_EQPH_ERR0, buffer, sizeof(buffer));
    303 		if (error)
    304 			return 0;
    305 		noise = ((buffer[0] & 7) << 16) | (buffer[3] << 8) | buffer[4];
    306 		snr_const = 73957994;	/* log10(2560) * pow(2,24) */
    307 		break;
    308 	case QAM_64:
    309 	case QAM_256:
    310 		error = lg3303_read(lg, REG_CARRIER_MSEQAM1, buffer, 2);
    311 		if (error)
    312 			return 0;
    313 		noise = (buffer[0] << 8) | buffer[1];
    314 		if (lg->current_modulation == QAM_64)
    315 			snr_const = 97939837;	/* log10(688128) * pow(2,24) */
    316 		else
    317 			snr_const = 98026066;	/* log10(696320) * pow(2,24) */
    318 		break;
    319 	default:
    320 		device_printf(lg->parent,
    321 		    "lg3303: unsupported modulation type (%d)\n",
    322 		    lg->current_modulation);
    323 		return 0;
    324 	}
    325 
    326 	if (noise == 0)
    327 		return 0;
    328 	snr = dtv_intlog10(noise);
    329 	if (snr > snr_const)
    330 		return 0;
    331 	return (10 * (snr_const - snr)) >> 16;
    332 }
    333 
    334 uint16_t
    335 lg3303_get_signal_strength(struct lg3303 *lg)
    336 {
    337 	return ((uint32_t)lg3303_get_snr(lg) << 16) / 8960;
    338 }
    339 
    340 uint32_t
    341 lg3303_get_ucblocks(struct lg3303 *lg)
    342 {
    343 	uint8_t buffer[2];
    344 	int error;
    345 
    346 	error = lg3303_read(lg, REG_PACKET_ERR_COUNTER1, buffer, sizeof(buffer));
    347 	if (error)
    348 		return 0;
    349 
    350 	return (buffer[0] << 8) | buffer[1];
    351 }
    352 
    353 MODULE(MODULE_CLASS_DRIVER, lg3303, NULL);
    354 
    355 static int
    356 lg3303_modcmd(modcmd_t cmd, void *opaque)
    357 {
    358 	if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI)
    359 		return 0;
    360 	return ENOTTY;
    361 }
    362