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