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