lg3303.c revision 1.3 1 /* $NetBSD: lg3303.c,v 1.3 2011/07/15 03:29:23 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.3 2011/07/15 03:29:23 jmcneill Exp $");
32
33 #include <sys/types.h>
34 #include <sys/kmem.h>
35 #include <sys/module.h>
36
37 #include <dev/i2c/i2cvar.h>
38 #include <dev/i2c/lg3303var.h>
39 #include <dev/dtv/dtvif.h>
40
41 #define REG_TOP_CONTROL 0x00
42 #define REG_IRQ_MASK 0x01
43 #define REG_IRQ_STATUS 0x02
44 #define REG_VSB_CARRIER_FREQ0 0x16
45 #define REG_VSB_CARRIER_FREQ1 0x17
46 #define REG_VSB_CARRIER_FREQ2 0x18
47 #define REG_VSB_CARRIER_FREQ3 0x19
48 #define REG_CARRIER_MSEQAM1 0x1a
49 #define REG_CARRIER_MSEQAM2 0x1b
50 #define REG_CARRIER_LOCK 0x1c
51 #define REG_TIMING_RECOVERY 0x1d
52 #define REG_AGC_DELAY0 0x2a
53 #define REG_AGC_DELAY1 0x2b
54 #define REG_AGC_DELAY2 0x2c
55 #define REG_AGC_RF_BANDWIDTH0 0x2d
56 #define REG_AGC_RF_BANDWIDTH1 0x2e
57 #define REG_AGC_RF_BANDWIDTH2 0x2f
58 #define REG_AGC_LOOP_BANDWIDTH0 0x30
59 #define REG_AGC_LOOP_BANDWIDTH1 0x31
60 #define REG_AGC_FUNC_CTRL1 0x32
61 #define REG_AGC_FUNC_CTRL2 0x33
62 #define REG_AGC_FUNC_CTRL3 0x34
63 #define REG_AGC_RFIF_ACC0 0x39
64 #define REG_AGC_RFIF_ACC1 0x3a
65 #define REG_AGC_RFIF_ACC2 0x3b
66 #define REG_AGC_STATUS 0x3f
67 #define REG_SYNC_STATUS_VSB 0x43
68 #define REG_DEMUX_CONTROL 0x66
69 #define REG_EQPH_ERR0 0x6e
70 #define REG_EQ_ERR1 0x6f
71 #define REG_EQ_ERR2 0x70
72 #define REG_PH_ERR1 0x71
73 #define REG_PH_ERR2 0x72
74 #define REG_PACKET_ERR_COUNTER1 0x8b
75 #define REG_PACKET_ERR_COUNTER2 0x8c
76
77 #define LG3303_DEFAULT_DELAY 250000
78
79 static int lg3303_reset(struct lg3303 *);
80 static int lg3303_init(struct lg3303 *);
81
82 struct lg3303 *
83 lg3303_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr, int flags)
84 {
85 struct lg3303 *lg;
86
87 lg = kmem_alloc(sizeof(*lg), KM_SLEEP);
88 if (lg == NULL)
89 return NULL;
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
203 error = lg3303_reset(lg);
204 if (error)
205 return error;
206
207 if (lg->current_modulation != modulation) {
208 uint8_t top_ctrl[] = {REG_TOP_CONTROL, 0x00};
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
241 return error;
242 }
243
244 fe_status_t
245 lg3303_get_dtv_status(struct lg3303 *lg)
246 {
247 uint8_t reg = 0, value = 0x00;
248 fe_status_t festatus = 0;
249 int error = 0;
250
251 error = lg3303_read(lg, 0x58, &value, sizeof(value));
252 if (error)
253 return 0;
254
255 if (value & 0x01)
256 festatus |= FE_HAS_SIGNAL;
257
258 error = lg3303_read(lg, REG_CARRIER_LOCK, &value, sizeof(value));
259 if (error)
260 return 0;
261
262 switch (lg->current_modulation) {
263 case VSB_8:
264 if (value & 0x80)
265 festatus |= FE_HAS_CARRIER;
266 reg = 0x38;
267 break;
268 case QAM_64:
269 case QAM_256:
270 if ((value & 0x07) == 0x07)
271 festatus |= FE_HAS_CARRIER;
272 reg = 0x8a;
273 break;
274 default:
275 device_printf(lg->parent,
276 "lg3303: unsupported modulation type (%d)\n",
277 lg->current_modulation);
278 return 0;
279 }
280
281 if ((festatus & FE_HAS_CARRIER) == 0)
282 return festatus;
283
284 error = lg3303_read(lg, reg, &value, sizeof(value));
285 if (!error && (value & 0x01))
286 festatus |= FE_HAS_LOCK;
287
288 if (festatus & FE_HAS_LOCK)
289 festatus |= (FE_HAS_SYNC | FE_HAS_VITERBI);
290
291 return festatus;
292 }
293
294 #if notyet
295 int lg3303::get_signal(dvb_signal &signal)
296 {
297 int error = check_for_lock(signal.locked);
298 uint32_t noise, snr_const;
299 uint8_t buffer[5];
300 uint8_t reg;
301 if (error || !signal.locked)
302 {
303 return error;
304 }
305 signal.ber = 0;
306 switch(m_modulation)
307 {
308 case DVB_MOD_VSB_8:
309 reg = REG_EQPH_ERR0;
310 if ((error = m_device.transact(®, sizeof(reg), buffer, sizeof(buffer))))
311 {
312 LIBTUNERERR << "LG3303: Unable to retrieve 8-VSB noise value" << endl;
313 return error;
314 }
315 noise = ((buffer[0] & 7) << 16) | (buffer[3] << 8) | buffer[4];
316 snr_const = 25600;
317 break;
318 case DVB_MOD_QAM_64:
319 case DVB_MOD_QAM_256:
320 reg = REG_CARRIER_MSEQAM1;
321 if ((error = m_device.transact(®, sizeof(reg), buffer, 2)))
322 {
323 LIBTUNERERR << "LG3303: Unable to retrieve QAM noise value" << endl;
324 return error;
325 }
326 noise = (buffer[0] << 8) | buffer[1];
327 if (m_modulation == DVB_MOD_QAM_64)
328 {
329 snr_const = 688128;
330 }
331 else
332 {
333 snr_const = 696320;
334 }
335 break;
336 default:
337 LIBTUNERERR << "LG3303: Unsupported modulation type" << endl;
338 return EINVAL;
339 }
340 signal.snr = 10.0 * log10((double)snr_const / noise);
341 signal.strength = (signal.snr / 35) * 100;
342 reg = REG_PACKET_ERR_COUNTER1;
343 if ((error = m_device.transact(®, sizeof(reg), buffer, 2)))
344 {
345 LIBTUNERERR << "LG3303: Unable to retrieve packet error count" << endl;
346 return error;
347 }
348 signal.uncorrected_blocks = (buffer[0] << 8) | buffer[1];
349 return 0;
350 }
351 #endif
352
353
354 MODULE(MODULE_CLASS_DRIVER, lg3303, NULL);
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