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