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