Home | History | Annotate | Line # | Download | only in i2c
lg3303.c revision 1.5
      1  1.5  jmcneill /* $NetBSD: lg3303.c,v 1.5 2011/07/15 20:28:38 jmcneill Exp $ */
      2  1.1  jmcneill 
      3  1.1  jmcneill /*-
      4  1.1  jmcneill  * Copyright 2007 Jason Harmening
      5  1.1  jmcneill  * All rights reserved.
      6  1.1  jmcneill  *
      7  1.1  jmcneill  * Redistribution and use in source and binary forms, with or without
      8  1.1  jmcneill  * modification, are permitted provided that the following conditions
      9  1.1  jmcneill  * are met:
     10  1.1  jmcneill  * 1. Redistributions of source code must retain the above copyright
     11  1.1  jmcneill  *    notice, this list of conditions and the following disclaimer.
     12  1.1  jmcneill  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  jmcneill  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  jmcneill  *    documentation and/or other materials provided with the distribution.
     15  1.1  jmcneill  *
     16  1.1  jmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  1.1  jmcneill  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  1.1  jmcneill  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  1.1  jmcneill  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  1.1  jmcneill  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  1.1  jmcneill  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  1.1  jmcneill  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  1.1  jmcneill  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  1.1  jmcneill  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  1.1  jmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  1.1  jmcneill  * SUCH DAMAGE.
     27  1.1  jmcneill  *
     28  1.1  jmcneill  */
     29  1.1  jmcneill 
     30  1.1  jmcneill #include <sys/param.h>
     31  1.5  jmcneill __KERNEL_RCSID(0, "$NetBSD: lg3303.c,v 1.5 2011/07/15 20:28:38 jmcneill Exp $");
     32  1.1  jmcneill 
     33  1.1  jmcneill #include <sys/types.h>
     34  1.1  jmcneill #include <sys/kmem.h>
     35  1.1  jmcneill #include <sys/module.h>
     36  1.5  jmcneill #include <sys/bitops.h>
     37  1.1  jmcneill 
     38  1.1  jmcneill #include <dev/i2c/i2cvar.h>
     39  1.1  jmcneill #include <dev/i2c/lg3303var.h>
     40  1.1  jmcneill #include <dev/dtv/dtvif.h>
     41  1.1  jmcneill 
     42  1.1  jmcneill #define REG_TOP_CONTROL         0x00
     43  1.1  jmcneill #define REG_IRQ_MASK            0x01
     44  1.1  jmcneill #define REG_IRQ_STATUS          0x02
     45  1.1  jmcneill #define REG_VSB_CARRIER_FREQ0   0x16
     46  1.1  jmcneill #define REG_VSB_CARRIER_FREQ1   0x17
     47  1.1  jmcneill #define REG_VSB_CARRIER_FREQ2   0x18
     48  1.1  jmcneill #define REG_VSB_CARRIER_FREQ3   0x19
     49  1.1  jmcneill #define REG_CARRIER_MSEQAM1     0x1a
     50  1.1  jmcneill #define REG_CARRIER_MSEQAM2     0x1b
     51  1.1  jmcneill #define REG_CARRIER_LOCK        0x1c
     52  1.1  jmcneill #define REG_TIMING_RECOVERY     0x1d
     53  1.1  jmcneill #define REG_AGC_DELAY0          0x2a
     54  1.1  jmcneill #define REG_AGC_DELAY1          0x2b
     55  1.1  jmcneill #define REG_AGC_DELAY2          0x2c
     56  1.1  jmcneill #define REG_AGC_RF_BANDWIDTH0   0x2d
     57  1.1  jmcneill #define REG_AGC_RF_BANDWIDTH1   0x2e
     58  1.1  jmcneill #define REG_AGC_RF_BANDWIDTH2   0x2f
     59  1.1  jmcneill #define REG_AGC_LOOP_BANDWIDTH0 0x30
     60  1.1  jmcneill #define REG_AGC_LOOP_BANDWIDTH1 0x31
     61  1.1  jmcneill #define REG_AGC_FUNC_CTRL1      0x32
     62  1.1  jmcneill #define REG_AGC_FUNC_CTRL2      0x33
     63  1.1  jmcneill #define REG_AGC_FUNC_CTRL3      0x34
     64  1.1  jmcneill #define REG_AGC_RFIF_ACC0       0x39
     65  1.1  jmcneill #define REG_AGC_RFIF_ACC1       0x3a
     66  1.1  jmcneill #define REG_AGC_RFIF_ACC2       0x3b
     67  1.1  jmcneill #define REG_AGC_STATUS          0x3f
     68  1.1  jmcneill #define REG_SYNC_STATUS_VSB     0x43
     69  1.1  jmcneill #define REG_DEMUX_CONTROL       0x66
     70  1.1  jmcneill #define REG_EQPH_ERR0           0x6e
     71  1.1  jmcneill #define REG_EQ_ERR1             0x6f
     72  1.1  jmcneill #define REG_EQ_ERR2             0x70
     73  1.1  jmcneill #define REG_PH_ERR1             0x71
     74  1.1  jmcneill #define REG_PH_ERR2             0x72
     75  1.1  jmcneill #define REG_PACKET_ERR_COUNTER1 0x8b
     76  1.1  jmcneill #define REG_PACKET_ERR_COUNTER2 0x8c
     77  1.1  jmcneill 
     78  1.1  jmcneill #define LG3303_DEFAULT_DELAY 250000
     79  1.1  jmcneill 
     80  1.1  jmcneill static int	lg3303_reset(struct lg3303 *);
     81  1.1  jmcneill static int	lg3303_init(struct lg3303 *);
     82  1.1  jmcneill 
     83  1.1  jmcneill struct lg3303 *
     84  1.2  jmcneill lg3303_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr, int flags)
     85  1.1  jmcneill {
     86  1.1  jmcneill 	struct lg3303 *lg;
     87  1.1  jmcneill 
     88  1.1  jmcneill 	lg = kmem_alloc(sizeof(*lg), KM_SLEEP);
     89  1.1  jmcneill 	if (lg == NULL)
     90  1.1  jmcneill 		return NULL;
     91  1.1  jmcneill 	lg->parent = parent;
     92  1.1  jmcneill 	lg->i2c = i2c;
     93  1.1  jmcneill 	lg->i2c_addr = addr;
     94  1.1  jmcneill 	lg->current_modulation = -1;
     95  1.2  jmcneill 	lg->flags = flags;
     96  1.1  jmcneill 
     97  1.1  jmcneill 	if (lg3303_init(lg) != 0) {
     98  1.1  jmcneill 		kmem_free(lg, sizeof(*lg));
     99  1.1  jmcneill 		return NULL;
    100  1.1  jmcneill 	}
    101  1.1  jmcneill 
    102  1.1  jmcneill 	device_printf(lg->parent, "lg3303: found @ 0x%02x\n", addr);
    103  1.1  jmcneill 
    104  1.1  jmcneill 	return lg;
    105  1.1  jmcneill }
    106  1.1  jmcneill 
    107  1.1  jmcneill void
    108  1.1  jmcneill lg3303_close(struct lg3303 *lg)
    109  1.1  jmcneill {
    110  1.1  jmcneill 	kmem_free(lg, sizeof(*lg));
    111  1.1  jmcneill }
    112  1.1  jmcneill 
    113  1.1  jmcneill static int
    114  1.1  jmcneill lg3303_write(struct lg3303 *lg, uint8_t *buf, size_t len)
    115  1.1  jmcneill {
    116  1.1  jmcneill 	unsigned int i;
    117  1.1  jmcneill 	uint8_t *p = buf;
    118  1.1  jmcneill 	int error;
    119  1.1  jmcneill 
    120  1.1  jmcneill 	for (i = 0; i < len - 1; i += 2) {
    121  1.1  jmcneill 		error = iic_exec(lg->i2c, I2C_OP_WRITE_WITH_STOP, lg->i2c_addr,
    122  1.1  jmcneill 		    p, 2, NULL, 0, 0);
    123  1.1  jmcneill 		if (error)
    124  1.1  jmcneill 			return error;
    125  1.1  jmcneill 		p += 2;
    126  1.1  jmcneill 	}
    127  1.1  jmcneill 
    128  1.1  jmcneill 	return 0;
    129  1.1  jmcneill }
    130  1.1  jmcneill 
    131  1.1  jmcneill static int
    132  1.1  jmcneill lg3303_read(struct lg3303 *lg, uint8_t reg, uint8_t *buf, size_t len)
    133  1.1  jmcneill {
    134  1.1  jmcneill 	int error;
    135  1.1  jmcneill 
    136  1.1  jmcneill 	error = iic_exec(lg->i2c, I2C_OP_WRITE, lg->i2c_addr,
    137  1.1  jmcneill 	    &reg, sizeof(reg), NULL, 0, 0);
    138  1.1  jmcneill 	if (error)
    139  1.1  jmcneill 		return error;
    140  1.1  jmcneill 	return iic_exec(lg->i2c, I2C_OP_READ, lg->i2c_addr,
    141  1.1  jmcneill 	    NULL, 0, buf, len, 0);
    142  1.1  jmcneill }
    143  1.1  jmcneill 
    144  1.1  jmcneill static int
    145  1.1  jmcneill lg3303_reset(struct lg3303 *lg)
    146  1.1  jmcneill {
    147  1.1  jmcneill 	uint8_t buffer[] = {REG_IRQ_STATUS, 0x00};
    148  1.1  jmcneill 	int error = lg3303_write(lg, buffer, 2);
    149  1.1  jmcneill 	if (error == 0) {
    150  1.1  jmcneill 		buffer[1] = 0x01;
    151  1.1  jmcneill 		error = lg3303_write(lg, buffer, 2);
    152  1.1  jmcneill 	}
    153  1.1  jmcneill 	return error;
    154  1.1  jmcneill }
    155  1.1  jmcneill 
    156  1.1  jmcneill static int
    157  1.1  jmcneill lg3303_init(struct lg3303 *lg)
    158  1.1  jmcneill {
    159  1.1  jmcneill 	//static uint8_t init_data[] = {0x4c, 0x14, 0x87, 0xf3};
    160  1.1  jmcneill 	static uint8_t init_data[] = {0x4c, 0x14};
    161  1.1  jmcneill 	size_t len;
    162  1.1  jmcneill 	int error;
    163  1.1  jmcneill 
    164  1.1  jmcneill #if notyet
    165  1.1  jmcneill 	if (clock_polarity == DVB_IFC_POS_POL)
    166  1.1  jmcneill 		len = 4;
    167  1.1  jmcneill 	else
    168  1.1  jmcneill #endif
    169  1.1  jmcneill 	len = 2;
    170  1.1  jmcneill 
    171  1.1  jmcneill 	error = lg3303_write(lg, init_data, len);
    172  1.1  jmcneill 	if (error == 0)
    173  1.1  jmcneill       		lg3303_reset(lg);
    174  1.1  jmcneill 
    175  1.1  jmcneill 	return error;
    176  1.1  jmcneill }
    177  1.1  jmcneill 
    178  1.1  jmcneill int
    179  1.1  jmcneill lg3303_set_modulation(struct lg3303 *lg, fe_modulation_t modulation)
    180  1.1  jmcneill {
    181  1.1  jmcneill 	int error;
    182  1.1  jmcneill 	static uint8_t vsb_data[] = {
    183  1.1  jmcneill 		0x04, 0x00,
    184  1.1  jmcneill 		0x0d, 0x40,
    185  1.1  jmcneill 		0x0e, 0x87,
    186  1.1  jmcneill 		0x0f, 0x8e,
    187  1.1  jmcneill 		0x10, 0x01,
    188  1.1  jmcneill 		0x47, 0x8b
    189  1.1  jmcneill 	};
    190  1.1  jmcneill 	static uint8_t qam_data[] = {
    191  1.1  jmcneill 		0x04, 0x00,
    192  1.1  jmcneill 		0x0d, 0x00,
    193  1.1  jmcneill 		0x0e, 0x00,
    194  1.1  jmcneill 		0x0f, 0x00,
    195  1.1  jmcneill 		0x10, 0x00,
    196  1.1  jmcneill 		0x51, 0x63,
    197  1.1  jmcneill 		0x47, 0x66,
    198  1.1  jmcneill 		0x48, 0x66,
    199  1.1  jmcneill 		0x4d, 0x1a,
    200  1.1  jmcneill 		0x49, 0x08,
    201  1.1  jmcneill 		0x4a, 0x9b
    202  1.1  jmcneill 	};
    203  1.4  jmcneill 	uint8_t top_ctrl[] = {REG_TOP_CONTROL, 0x00};
    204  1.1  jmcneill 
    205  1.1  jmcneill 	error = lg3303_reset(lg);
    206  1.1  jmcneill 	if (error)
    207  1.1  jmcneill 		return error;
    208  1.1  jmcneill 
    209  1.4  jmcneill 	if (lg->flags & LG3303_CFG_SERIAL_INPUT)
    210  1.4  jmcneill 		top_ctrl[1] = 0x40;
    211  1.2  jmcneill 
    212  1.4  jmcneill 	switch (modulation) {
    213  1.4  jmcneill 	case VSB_8:
    214  1.4  jmcneill 		top_ctrl[1] |= 0x03;
    215  1.4  jmcneill 		error = lg3303_write(lg, vsb_data, sizeof(vsb_data));
    216  1.4  jmcneill 		if (error)
    217  1.4  jmcneill 			return error;
    218  1.4  jmcneill 		break;
    219  1.4  jmcneill 	case QAM_256:
    220  1.4  jmcneill 		top_ctrl[1] |= 0x01;
    221  1.4  jmcneill 		/* FALLTHROUGH */
    222  1.4  jmcneill 	case QAM_64:
    223  1.4  jmcneill 		error = lg3303_write(lg, qam_data, sizeof(qam_data));
    224  1.1  jmcneill 		if (error)
    225  1.1  jmcneill 			return error;
    226  1.4  jmcneill 		break;
    227  1.4  jmcneill 	default:
    228  1.4  jmcneill 		device_printf(lg->parent,
    229  1.4  jmcneill 		    "lg3303: unsupported modulation type (%d)\n",
    230  1.4  jmcneill 		    modulation);
    231  1.4  jmcneill 		return EINVAL;
    232  1.1  jmcneill 	}
    233  1.4  jmcneill 	error = lg3303_write(lg, top_ctrl, sizeof(top_ctrl));
    234  1.4  jmcneill 	if (error)
    235  1.4  jmcneill 		return error;
    236  1.4  jmcneill 	lg->current_modulation = modulation;
    237  1.4  jmcneill 	lg3303_reset(lg);
    238  1.1  jmcneill 
    239  1.1  jmcneill 	return error;
    240  1.1  jmcneill }
    241  1.1  jmcneill 
    242  1.1  jmcneill fe_status_t
    243  1.1  jmcneill lg3303_get_dtv_status(struct lg3303 *lg)
    244  1.1  jmcneill {
    245  1.1  jmcneill 	uint8_t reg = 0, value = 0x00;
    246  1.1  jmcneill 	fe_status_t festatus = 0;
    247  1.1  jmcneill 	int error = 0;
    248  1.1  jmcneill 
    249  1.1  jmcneill 	error = lg3303_read(lg, 0x58, &value, sizeof(value));
    250  1.1  jmcneill 	if (error)
    251  1.1  jmcneill 		return 0;
    252  1.1  jmcneill 
    253  1.1  jmcneill 	if (value & 0x01)
    254  1.1  jmcneill 		festatus |= FE_HAS_SIGNAL;
    255  1.1  jmcneill 
    256  1.1  jmcneill 	error = lg3303_read(lg, REG_CARRIER_LOCK, &value, sizeof(value));
    257  1.1  jmcneill 	if (error)
    258  1.1  jmcneill 		return 0;
    259  1.1  jmcneill 
    260  1.1  jmcneill 	switch (lg->current_modulation) {
    261  1.1  jmcneill 	case VSB_8:
    262  1.1  jmcneill 		if (value & 0x80)
    263  1.1  jmcneill 			festatus |= FE_HAS_CARRIER;
    264  1.1  jmcneill 		reg = 0x38;
    265  1.1  jmcneill 		break;
    266  1.1  jmcneill 	case QAM_64:
    267  1.1  jmcneill 	case QAM_256:
    268  1.1  jmcneill 		if ((value & 0x07) == 0x07)
    269  1.1  jmcneill 			festatus |= FE_HAS_CARRIER;
    270  1.1  jmcneill 		reg = 0x8a;
    271  1.1  jmcneill 		break;
    272  1.1  jmcneill 	default:
    273  1.1  jmcneill 		device_printf(lg->parent,
    274  1.1  jmcneill 		    "lg3303: unsupported modulation type (%d)\n",
    275  1.1  jmcneill 		    lg->current_modulation);
    276  1.3  jmcneill 		return 0;
    277  1.1  jmcneill 	}
    278  1.1  jmcneill 
    279  1.3  jmcneill 	if ((festatus & FE_HAS_CARRIER) == 0)
    280  1.3  jmcneill 		return festatus;
    281  1.3  jmcneill 
    282  1.1  jmcneill 	error = lg3303_read(lg, reg, &value, sizeof(value));
    283  1.1  jmcneill 	if (!error && (value & 0x01))
    284  1.1  jmcneill 		festatus |= FE_HAS_LOCK;
    285  1.1  jmcneill 
    286  1.1  jmcneill 	if (festatus & FE_HAS_LOCK)
    287  1.1  jmcneill 		festatus |= (FE_HAS_SYNC | FE_HAS_VITERBI);
    288  1.1  jmcneill 
    289  1.1  jmcneill 	return festatus;
    290  1.1  jmcneill }
    291  1.1  jmcneill 
    292  1.5  jmcneill uint16_t
    293  1.5  jmcneill lg3303_get_snr(struct lg3303 *lg)
    294  1.5  jmcneill {
    295  1.5  jmcneill 	int64_t noise, snr_const;
    296  1.5  jmcneill 	uint8_t buffer[5];
    297  1.5  jmcneill 	int64_t snr;
    298  1.5  jmcneill 	int error;
    299  1.5  jmcneill 
    300  1.5  jmcneill 	switch (lg->current_modulation) {
    301  1.5  jmcneill 	case VSB_8:
    302  1.5  jmcneill 		error = lg3303_read(lg, REG_EQPH_ERR0, buffer, sizeof(buffer));
    303  1.5  jmcneill 		if (error)
    304  1.5  jmcneill 			return 0;
    305  1.5  jmcneill 		noise = ((buffer[0] & 7) << 16) | (buffer[3] << 8) | buffer[4];
    306  1.5  jmcneill 		snr_const = 73957994;	/* log10(2560) * pow(2,24) */
    307  1.5  jmcneill 		break;
    308  1.5  jmcneill 	case QAM_64:
    309  1.5  jmcneill 	case QAM_256:
    310  1.5  jmcneill 		error = lg3303_read(lg, REG_CARRIER_MSEQAM1, buffer, 2);
    311  1.5  jmcneill 		if (error)
    312  1.5  jmcneill 			return 0;
    313  1.5  jmcneill 		noise = (buffer[0] << 8) | buffer[1];
    314  1.5  jmcneill 		if (lg->current_modulation == QAM_64)
    315  1.5  jmcneill 			snr_const = 97939837;	/* log10(688128) * pow(2,24) */
    316  1.5  jmcneill 		else
    317  1.5  jmcneill 			snr_const = 98026066;	/* log10(696320) * pow(2,24) */
    318  1.5  jmcneill 		break;
    319  1.5  jmcneill 	default:
    320  1.5  jmcneill 		device_printf(lg->parent,
    321  1.5  jmcneill 		    "lg3303: unsupported modulation type (%d)\n",
    322  1.5  jmcneill 		    lg->current_modulation);
    323  1.5  jmcneill 		return 0;
    324  1.5  jmcneill 	}
    325  1.5  jmcneill 
    326  1.5  jmcneill 	if (noise == 0)
    327  1.5  jmcneill 		return 0;
    328  1.5  jmcneill 	snr = dtv_intlog10(noise);
    329  1.5  jmcneill 	if (snr > snr_const)
    330  1.5  jmcneill 		return 0;
    331  1.5  jmcneill 	return (10 * (snr_const - snr)) >> 16;
    332  1.5  jmcneill }
    333  1.5  jmcneill 
    334  1.5  jmcneill uint16_t
    335  1.5  jmcneill lg3303_get_signal_strength(struct lg3303 *lg)
    336  1.1  jmcneill {
    337  1.5  jmcneill 	return ((uint32_t)lg3303_get_snr(lg) << 16) / 8960;
    338  1.1  jmcneill }
    339  1.1  jmcneill 
    340  1.5  jmcneill uint32_t
    341  1.5  jmcneill lg3303_get_ucblocks(struct lg3303 *lg)
    342  1.5  jmcneill {
    343  1.5  jmcneill 	uint8_t buffer[2];
    344  1.5  jmcneill 	int error;
    345  1.5  jmcneill 
    346  1.5  jmcneill 	error = lg3303_read(lg, REG_PACKET_ERR_COUNTER1, buffer, sizeof(buffer));
    347  1.5  jmcneill 	if (error)
    348  1.5  jmcneill 		return 0;
    349  1.5  jmcneill 
    350  1.5  jmcneill 	return (buffer[0] << 8) | buffer[1];
    351  1.5  jmcneill }
    352  1.1  jmcneill 
    353  1.1  jmcneill MODULE(MODULE_CLASS_DRIVER, lg3303, NULL);
    354  1.1  jmcneill 
    355  1.1  jmcneill static int
    356  1.1  jmcneill lg3303_modcmd(modcmd_t cmd, void *opaque)
    357  1.1  jmcneill {
    358  1.1  jmcneill 	if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI)
    359  1.1  jmcneill 		return 0;
    360  1.1  jmcneill 	return ENOTTY;
    361  1.1  jmcneill }
    362