Home | History | Annotate | Line # | Download | only in i2c
      1 /* $NetBSD: lg3303.c,v 1.10 2017/06/01 02:45:10 chs 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.10 2017/06/01 02:45:10 chs 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 	lg->parent = parent;
     91 	lg->i2c = i2c;
     92 	lg->i2c_addr = addr;
     93 	lg->current_modulation = -1;
     94 	lg->flags = flags;
     95 
     96 	if (lg3303_init(lg) != 0) {
     97 		kmem_free(lg, sizeof(*lg));
     98 		return NULL;
     99 	}
    100 
    101 	device_printf(lg->parent, "lg3303: found @ 0x%02x\n", addr);
    102 
    103 	return lg;
    104 }
    105 
    106 void
    107 lg3303_close(struct lg3303 *lg)
    108 {
    109 	kmem_free(lg, sizeof(*lg));
    110 }
    111 
    112 static int
    113 lg3303_write(struct lg3303 *lg, uint8_t *buf, size_t len)
    114 {
    115 	unsigned int i;
    116 	uint8_t *p = buf;
    117 	int error;
    118 
    119 	for (i = 0; i < len - 1; i += 2) {
    120 		error = iic_exec(lg->i2c, I2C_OP_WRITE_WITH_STOP, lg->i2c_addr,
    121 		    p, 2, NULL, 0, 0);
    122 		if (error)
    123 			return error;
    124 		p += 2;
    125 	}
    126 
    127 	return 0;
    128 }
    129 
    130 static int
    131 lg3303_read(struct lg3303 *lg, uint8_t reg, uint8_t *buf, size_t len)
    132 {
    133 	int error;
    134 
    135 	error = iic_exec(lg->i2c, I2C_OP_WRITE, lg->i2c_addr,
    136 	    &reg, sizeof(reg), NULL, 0, 0);
    137 	if (error)
    138 		return error;
    139 	return iic_exec(lg->i2c, I2C_OP_READ, lg->i2c_addr,
    140 	    NULL, 0, buf, len, 0);
    141 }
    142 
    143 static int
    144 lg3303_reset(struct lg3303 *lg)
    145 {
    146 	uint8_t buffer[] = {REG_IRQ_STATUS, 0x00};
    147 	int error = lg3303_write(lg, buffer, 2);
    148 	if (error == 0) {
    149 		buffer[1] = 0x01;
    150 		error = lg3303_write(lg, buffer, 2);
    151 	}
    152 	return error;
    153 }
    154 
    155 static int
    156 lg3303_init(struct lg3303 *lg)
    157 {
    158 	//static uint8_t init_data[] = {0x4c, 0x14, 0x87, 0xf3};
    159 	static uint8_t init_data[] = {0x4c, 0x14};
    160 	size_t len;
    161 	int error;
    162 
    163 #if notyet
    164 	if (clock_polarity == DVB_IFC_POS_POL)
    165 		len = 4;
    166 	else
    167 #endif
    168 	len = 2;
    169 
    170 	error = lg3303_write(lg, init_data, len);
    171 	if (error == 0)
    172       		lg3303_reset(lg);
    173 
    174 	return error;
    175 }
    176 
    177 int
    178 lg3303_set_modulation(struct lg3303 *lg, fe_modulation_t modulation)
    179 {
    180 	int error;
    181 	static uint8_t vsb_data[] = {
    182 		0x04, 0x00,
    183 		0x0d, 0x40,
    184 		0x0e, 0x87,
    185 		0x0f, 0x8e,
    186 		0x10, 0x01,
    187 		0x47, 0x8b
    188 	};
    189 	static uint8_t qam_data[] = {
    190 		0x04, 0x00,
    191 		0x0d, 0x00,
    192 		0x0e, 0x00,
    193 		0x0f, 0x00,
    194 		0x10, 0x00,
    195 		0x51, 0x63,
    196 		0x47, 0x66,
    197 		0x48, 0x66,
    198 		0x4d, 0x1a,
    199 		0x49, 0x08,
    200 		0x4a, 0x9b
    201 	};
    202 	uint8_t top_ctrl[] = {REG_TOP_CONTROL, 0x00};
    203 
    204 	error = lg3303_reset(lg);
    205 	if (error)
    206 		return error;
    207 
    208 	if (lg->flags & LG3303_CFG_SERIAL_INPUT)
    209 		top_ctrl[1] = 0x40;
    210 
    211 	switch (modulation) {
    212 	case VSB_8:
    213 		top_ctrl[1] |= 0x03;
    214 		error = lg3303_write(lg, vsb_data, sizeof(vsb_data));
    215 		if (error)
    216 			return error;
    217 		break;
    218 	case QAM_256:
    219 		top_ctrl[1] |= 0x01;
    220 		/* FALLTHROUGH */
    221 	case QAM_64:
    222 		error = lg3303_write(lg, qam_data, sizeof(qam_data));
    223 		if (error)
    224 			return error;
    225 		break;
    226 	default:
    227 		device_printf(lg->parent,
    228 		    "lg3303: unsupported modulation type (%d)\n",
    229 		    modulation);
    230 		return EINVAL;
    231 	}
    232 	error = lg3303_write(lg, top_ctrl, sizeof(top_ctrl));
    233 	if (error)
    234 		return error;
    235 	lg->current_modulation = modulation;
    236 	lg3303_reset(lg);
    237 
    238 	return error;
    239 }
    240 
    241 fe_status_t
    242 lg3303_get_dtv_status(struct lg3303 *lg)
    243 {
    244 	uint8_t reg = 0, value = 0x00;
    245 	fe_status_t festatus = 0;
    246 	int error = 0;
    247 
    248 	error = lg3303_read(lg, 0x58, &value, sizeof(value));
    249 	if (error)
    250 		return 0;
    251 
    252 	if (value & 0x01)
    253 		festatus |= FE_HAS_SIGNAL;
    254 
    255 	error = lg3303_read(lg, REG_CARRIER_LOCK, &value, sizeof(value));
    256 	if (error)
    257 		return 0;
    258 
    259 	switch (lg->current_modulation) {
    260 	case VSB_8:
    261 		if (value & 0x80)
    262 			festatus |= FE_HAS_CARRIER;
    263 		reg = 0x38;
    264 		break;
    265 	case QAM_64:
    266 	case QAM_256:
    267 		if ((value & 0x07) == 0x07)
    268 			festatus |= FE_HAS_CARRIER;
    269 		reg = 0x8a;
    270 		break;
    271 	default:
    272 		device_printf(lg->parent,
    273 		    "lg3303: unsupported modulation type (%d)\n",
    274 		    lg->current_modulation);
    275 		return 0;
    276 	}
    277 
    278 	if ((festatus & FE_HAS_CARRIER) == 0)
    279 		return festatus;
    280 
    281 	error = lg3303_read(lg, reg, &value, sizeof(value));
    282 	if (!error && (value & 0x01))
    283 		festatus |= FE_HAS_LOCK;
    284 
    285 	if (festatus & FE_HAS_LOCK)
    286 		festatus |= (FE_HAS_SYNC | FE_HAS_VITERBI);
    287 
    288 	return festatus;
    289 }
    290 
    291 uint16_t
    292 lg3303_get_snr(struct lg3303 *lg)
    293 {
    294 	int64_t noise, snr_const;
    295 	uint8_t buffer[5];
    296 	int64_t snr;
    297 	int error;
    298 
    299 	switch (lg->current_modulation) {
    300 	case VSB_8:
    301 		error = lg3303_read(lg, REG_EQPH_ERR0, buffer, sizeof(buffer));
    302 		if (error)
    303 			return 0;
    304 		noise = ((buffer[0] & 7) << 16) | (buffer[3] << 8) | buffer[4];
    305 		snr_const = 73957994;	/* log10(2560) * pow(2,24) */
    306 		break;
    307 	case QAM_64:
    308 	case QAM_256:
    309 		error = lg3303_read(lg, REG_CARRIER_MSEQAM1, buffer, 2);
    310 		if (error)
    311 			return 0;
    312 		noise = (buffer[0] << 8) | buffer[1];
    313 		if (lg->current_modulation == QAM_64)
    314 			snr_const = 97939837;	/* log10(688128) * pow(2,24) */
    315 		else
    316 			snr_const = 98026066;	/* log10(696320) * pow(2,24) */
    317 		break;
    318 	default:
    319 		device_printf(lg->parent,
    320 		    "lg3303: unsupported modulation type (%d)\n",
    321 		    lg->current_modulation);
    322 		return 0;
    323 	}
    324 
    325 	if (noise == 0)
    326 		return 0;
    327 	snr = dtv_intlog10(noise);
    328 	if (snr > snr_const)
    329 		return 0;
    330 	return (10 * (snr_const - snr)) >> 16;
    331 }
    332 
    333 uint16_t
    334 lg3303_get_signal_strength(struct lg3303 *lg)
    335 {
    336 	return ((uint32_t)lg3303_get_snr(lg) << 16) / 8960;
    337 }
    338 
    339 uint32_t
    340 lg3303_get_ucblocks(struct lg3303 *lg)
    341 {
    342 	uint8_t buffer[2];
    343 	int error;
    344 
    345 	error = lg3303_read(lg, REG_PACKET_ERR_COUNTER1, buffer, sizeof(buffer));
    346 	if (error)
    347 		return 0;
    348 
    349 	return (buffer[0] << 8) | buffer[1];
    350 }
    351 
    352 MODULE(MODULE_CLASS_DRIVER, lg3303, "i2cexec,dtv_math");
    353 
    354 static int
    355 lg3303_modcmd(modcmd_t cmd, void *opaque)
    356 {
    357 	if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI)
    358 		return 0;
    359 	return ENOTTY;
    360 }
    361