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