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 ®, 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