Home | History | Annotate | Line # | Download | only in i2c
lg3303.c revision 1.3
      1 /* $NetBSD: lg3303.c,v 1.3 2011/07/15 03:29:23 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.3 2011/07/15 03:29:23 jmcneill Exp $");
     32 
     33 #include <sys/types.h>
     34 #include <sys/kmem.h>
     35 #include <sys/module.h>
     36 
     37 #include <dev/i2c/i2cvar.h>
     38 #include <dev/i2c/lg3303var.h>
     39 #include <dev/dtv/dtvif.h>
     40 
     41 #define REG_TOP_CONTROL         0x00
     42 #define REG_IRQ_MASK            0x01
     43 #define REG_IRQ_STATUS          0x02
     44 #define REG_VSB_CARRIER_FREQ0   0x16
     45 #define REG_VSB_CARRIER_FREQ1   0x17
     46 #define REG_VSB_CARRIER_FREQ2   0x18
     47 #define REG_VSB_CARRIER_FREQ3   0x19
     48 #define REG_CARRIER_MSEQAM1     0x1a
     49 #define REG_CARRIER_MSEQAM2     0x1b
     50 #define REG_CARRIER_LOCK        0x1c
     51 #define REG_TIMING_RECOVERY     0x1d
     52 #define REG_AGC_DELAY0          0x2a
     53 #define REG_AGC_DELAY1          0x2b
     54 #define REG_AGC_DELAY2          0x2c
     55 #define REG_AGC_RF_BANDWIDTH0   0x2d
     56 #define REG_AGC_RF_BANDWIDTH1   0x2e
     57 #define REG_AGC_RF_BANDWIDTH2   0x2f
     58 #define REG_AGC_LOOP_BANDWIDTH0 0x30
     59 #define REG_AGC_LOOP_BANDWIDTH1 0x31
     60 #define REG_AGC_FUNC_CTRL1      0x32
     61 #define REG_AGC_FUNC_CTRL2      0x33
     62 #define REG_AGC_FUNC_CTRL3      0x34
     63 #define REG_AGC_RFIF_ACC0       0x39
     64 #define REG_AGC_RFIF_ACC1       0x3a
     65 #define REG_AGC_RFIF_ACC2       0x3b
     66 #define REG_AGC_STATUS          0x3f
     67 #define REG_SYNC_STATUS_VSB     0x43
     68 #define REG_DEMUX_CONTROL       0x66
     69 #define REG_EQPH_ERR0           0x6e
     70 #define REG_EQ_ERR1             0x6f
     71 #define REG_EQ_ERR2             0x70
     72 #define REG_PH_ERR1             0x71
     73 #define REG_PH_ERR2             0x72
     74 #define REG_PACKET_ERR_COUNTER1 0x8b
     75 #define REG_PACKET_ERR_COUNTER2 0x8c
     76 
     77 #define LG3303_DEFAULT_DELAY 250000
     78 
     79 static int	lg3303_reset(struct lg3303 *);
     80 static int	lg3303_init(struct lg3303 *);
     81 
     82 struct lg3303 *
     83 lg3303_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr, int flags)
     84 {
     85 	struct lg3303 *lg;
     86 
     87 	lg = kmem_alloc(sizeof(*lg), KM_SLEEP);
     88 	if (lg == NULL)
     89 		return NULL;
     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 
    203 	error = lg3303_reset(lg);
    204 	if (error)
    205 		return error;
    206 
    207 	if (lg->current_modulation != modulation) {
    208 		uint8_t top_ctrl[] = {REG_TOP_CONTROL, 0x00};
    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 
    241 	return error;
    242 }
    243 
    244 fe_status_t
    245 lg3303_get_dtv_status(struct lg3303 *lg)
    246 {
    247 	uint8_t reg = 0, value = 0x00;
    248 	fe_status_t festatus = 0;
    249 	int error = 0;
    250 
    251 	error = lg3303_read(lg, 0x58, &value, sizeof(value));
    252 	if (error)
    253 		return 0;
    254 
    255 	if (value & 0x01)
    256 		festatus |= FE_HAS_SIGNAL;
    257 
    258 	error = lg3303_read(lg, REG_CARRIER_LOCK, &value, sizeof(value));
    259 	if (error)
    260 		return 0;
    261 
    262 	switch (lg->current_modulation) {
    263 	case VSB_8:
    264 		if (value & 0x80)
    265 			festatus |= FE_HAS_CARRIER;
    266 		reg = 0x38;
    267 		break;
    268 	case QAM_64:
    269 	case QAM_256:
    270 		if ((value & 0x07) == 0x07)
    271 			festatus |= FE_HAS_CARRIER;
    272 		reg = 0x8a;
    273 		break;
    274 	default:
    275 		device_printf(lg->parent,
    276 		    "lg3303: unsupported modulation type (%d)\n",
    277 		    lg->current_modulation);
    278 		return 0;
    279 	}
    280 
    281 	if ((festatus & FE_HAS_CARRIER) == 0)
    282 		return festatus;
    283 
    284 	error = lg3303_read(lg, reg, &value, sizeof(value));
    285 	if (!error && (value & 0x01))
    286 		festatus |= FE_HAS_LOCK;
    287 
    288 	if (festatus & FE_HAS_LOCK)
    289 		festatus |= (FE_HAS_SYNC | FE_HAS_VITERBI);
    290 
    291 	return festatus;
    292 }
    293 
    294 #if notyet
    295 int lg3303::get_signal(dvb_signal &signal)
    296 {
    297    int error = check_for_lock(signal.locked);
    298    uint32_t noise, snr_const;
    299    uint8_t buffer[5];
    300    uint8_t reg;
    301    if (error || !signal.locked)
    302    {
    303       return error;
    304    }
    305    signal.ber = 0;
    306    switch(m_modulation)
    307    {
    308       case DVB_MOD_VSB_8:
    309          reg = REG_EQPH_ERR0;
    310          if ((error = m_device.transact(&reg, sizeof(reg), buffer, sizeof(buffer))))
    311          {
    312             LIBTUNERERR << "LG3303: Unable to retrieve 8-VSB noise value" << endl;
    313             return error;
    314          }
    315          noise = ((buffer[0] & 7) << 16) | (buffer[3] << 8) | buffer[4];
    316          snr_const = 25600;
    317          break;
    318       case DVB_MOD_QAM_64:
    319       case DVB_MOD_QAM_256:
    320          reg = REG_CARRIER_MSEQAM1;
    321          if ((error = m_device.transact(&reg, sizeof(reg), buffer, 2)))
    322          {
    323             LIBTUNERERR << "LG3303: Unable to retrieve QAM noise value" << endl;
    324             return error;
    325          }
    326          noise = (buffer[0] << 8) | buffer[1];
    327          if (m_modulation == DVB_MOD_QAM_64)
    328          {
    329             snr_const = 688128;
    330          }
    331          else
    332          {
    333             snr_const = 696320;
    334          }
    335          break;
    336       default:
    337          LIBTUNERERR << "LG3303: Unsupported modulation type" << endl;
    338          return EINVAL;
    339    }
    340    signal.snr = 10.0 * log10((double)snr_const / noise);
    341    signal.strength = (signal.snr / 35) * 100;
    342    reg = REG_PACKET_ERR_COUNTER1;
    343    if ((error = m_device.transact(&reg, sizeof(reg), buffer, 2)))
    344    {
    345       LIBTUNERERR << "LG3303: Unable to retrieve packet error count" << endl;
    346       return error;
    347    }
    348    signal.uncorrected_blocks = (buffer[0] << 8) | buffer[1];
    349    return 0;
    350 }
    351 #endif
    352 
    353 
    354 MODULE(MODULE_CLASS_DRIVER, lg3303, NULL);
    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