emdtv.c revision 1.4
1/* $NetBSD: emdtv.c,v 1.4 2011/08/09 01:42:24 jmcneill Exp $ */
2
3/*-
4 * Copyright (c) 2008, 2011 Jared D. McNeill <jmcneill@invisible.ca>
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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: emdtv.c,v 1.4 2011/08/09 01:42:24 jmcneill Exp $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/device.h>
35#include <sys/module.h>
36#include <sys/conf.h>
37
38#include <dev/usb/usb.h>
39#include <dev/usb/usbdi.h>
40#include <dev/usb/usbdi_util.h>
41#include <dev/usb/usbdevs.h>
42
43#include <dev/usb/emdtvvar.h>
44#include <dev/usb/emdtvreg.h>
45
46static int	emdtv_match(device_t, cfdata_t, void *);
47static void	emdtv_attach(device_t, device_t, void *);
48static int	emdtv_detach(device_t, int);
49static int	emdtv_rescan(device_t, const char *, const int *);
50static void	emdtv_childdet(device_t, device_t);
51static int	emdtv_activate(device_t, enum devact);
52
53static bool	emdtv_read_eeprom(struct emdtv_softc *);
54static void	emdtv_board_setup(struct emdtv_softc *);
55
56static void	emdtv_default_board_init(struct emdtv_softc *);
57
58CFATTACH_DECL2_NEW(emdtv, sizeof(struct emdtv_softc),
59    emdtv_match, emdtv_attach, emdtv_detach, emdtv_activate,
60    emdtv_rescan, emdtv_childdet);
61
62static const struct usb_devno emdtv_devices[] = {
63	{ USB_VENDOR_AMD,	USB_PRODUCT_AMD_TV_WONDER_600_USB },
64	{ USB_VENDOR_PINNACLE,	USB_PRODUCT_PINNACLE_PCTV800E },
65};
66
67int emdtv_debug_regs = 0;
68
69static int
70emdtv_match(device_t parent, cfdata_t match, void *opaque)
71{
72	struct usb_attach_arg *uaa = opaque;
73
74	return usb_lookup(emdtv_devices, uaa->vendor, uaa->product) != NULL ?
75	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
76}
77
78static void
79emdtv_attach(device_t parent, device_t self, void *opaque)
80{
81	struct emdtv_softc *sc = device_private(self);
82	struct usb_attach_arg *uaa = opaque;
83	usbd_device_handle dev = uaa->device;
84	usbd_status status;
85	char *devinfo;
86
87	devinfo = usbd_devinfo_alloc(dev, 0);
88	aprint_naive("\n");
89	aprint_normal(": %s\n", devinfo);
90	usbd_devinfo_free(devinfo);
91
92	sc->sc_dev = self;
93	sc->sc_udev = dev;
94
95	sc->sc_vendor = uaa->vendor;
96	sc->sc_product = uaa->product;
97
98	emdtv_i2c_attach(sc);
99
100	emdtv_read_eeprom(sc);
101
102	sc->sc_board = emdtv_board_lookup(sc->sc_vendor, sc->sc_product);
103	if (sc->sc_board == NULL) {
104		aprint_error_dev(sc->sc_dev,
105		    "unsupported board 0x%04x:0x%04x\n",
106		    sc->sc_vendor, sc->sc_product);
107		sc->sc_dying = true;
108		return;
109	}
110
111	emdtv_write_1(sc, 0x02, 0xa0, 0x23);
112	if (emdtv_read_1(sc, UR_GET_STATUS, 0x05) != 0) {
113		(void)emdtv_read_1(sc, 0x02, 0xa0);
114		if (emdtv_read_1(sc, 0x02, 0xa0) & 0x08)
115			aprint_debug_dev(sc->sc_dev,
116			    "board requires manual gpio configuration\n");
117	}
118
119	emdtv_board_setup(sc);
120
121	emdtv_gpio_ctl(sc, EMDTV_GPIO_ANALOG_ON, false);
122	emdtv_gpio_ctl(sc, EMDTV_GPIO_TS1_ON, false);
123	usbd_delay_ms(sc->sc_udev, 100);
124	emdtv_gpio_ctl(sc, EMDTV_GPIO_ANALOG_ON, true);
125	emdtv_gpio_ctl(sc, EMDTV_GPIO_TUNER1_ON, true);
126	usbd_delay_ms(sc->sc_udev, 100);
127
128	status = usbd_set_config_no(sc->sc_udev, 1, 1);
129        if (status != USBD_NORMAL_COMPLETION) {
130		aprint_error_dev(sc->sc_dev, "couldn't set config no\n");
131		return;
132	}
133
134	status = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface);
135	if (status != USBD_NORMAL_COMPLETION) {
136		aprint_error_dev(sc->sc_dev, "couldn't find iface handle\n");
137		return;
138	}
139
140	status = usbd_set_interface(sc->sc_iface, 1);
141	if (status != USBD_NORMAL_COMPLETION) {
142		aprint_error_dev(sc->sc_dev, "couldn't set interface\n");
143		return;
144	}
145
146	emdtv_dtv_attach(sc);
147	emdtv_ir_attach(sc);
148}
149
150static int
151emdtv_detach(device_t self, int flags)
152{
153	struct emdtv_softc *sc = device_private(self);
154	usbd_status status;
155
156	sc->sc_dying = true;
157
158	emdtv_ir_detach(sc, flags);
159	emdtv_dtv_detach(sc, flags);
160
161	if (sc->sc_iface != NULL) {
162        	status = usbd_set_interface(sc->sc_iface, 0);
163		if (status != USBD_NORMAL_COMPLETION)
164			aprint_error_dev(sc->sc_dev,
165			    "couldn't stop stream: %s\n", usbd_errstr(status));
166	}
167
168	emdtv_i2c_detach(sc, flags);
169
170	return 0;
171}
172
173int
174emdtv_activate(device_t self, enum devact act)
175{
176	struct emdtv_softc *sc = device_private(self);
177
178	switch (act) {
179	case DVACT_DEACTIVATE:
180		sc->sc_dying = true;
181		break;
182	}
183
184	return 0;
185}
186
187static int
188emdtv_rescan(device_t self, const char *ifattr, const int *locs)
189{
190	struct emdtv_softc *sc = device_private(self);
191
192	emdtv_dtv_rescan(sc, ifattr, locs);
193
194	return 0;
195}
196
197static void
198emdtv_childdet(device_t self, device_t child)
199{
200	struct emdtv_softc *sc = device_private(self);
201
202	if (child == sc->sc_cirdev)
203		sc->sc_cirdev = NULL;
204	if (child == sc->sc_dtvdev)
205		sc->sc_dtvdev = NULL;
206}
207
208static bool
209emdtv_read_eeprom(struct emdtv_softc *sc)
210{
211	i2c_addr_t ee = EM28XX_I2C_ADDR_EEPROM;
212	uint8_t buf, *p = sc->sc_eeprom;
213	struct emdtv_eeprom *eeprom = (struct emdtv_eeprom *)sc->sc_eeprom;
214	int block, size = sizeof(sc->sc_eeprom);
215
216	if (iic_exec(&sc->sc_i2c, I2C_OP_READ, ee, NULL, 0, NULL, 0, 0))
217		return false;
218	buf = 0;
219	if (iic_exec(&sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, ee, &buf, 1,
220	    NULL, 0, 0))
221		return false;
222	while (size > 0) {
223		block = min(size, 16);
224		if (iic_exec(&sc->sc_i2c, I2C_OP_READ, ee, NULL, 0,
225		    p, block, 0))
226			return false;
227		size -= block;
228		p += block;
229	}
230
231	aprint_normal_dev(sc->sc_dev,
232	    "id 0x%08x vendor 0x%04x product 0x%04x\n",
233	    eeprom->id, eeprom->vendor, eeprom->product);
234
235	sc->sc_vendor = eeprom->vendor;
236	sc->sc_product = eeprom->product;
237
238	return true;
239}
240
241static void
242emdtv_board_setup(struct emdtv_softc *sc)
243{
244	switch (sc->sc_vendor) {
245	case USB_VENDOR_EMPIA:
246		switch (sc->sc_product) {
247		case USB_PRODUCT_EMPIA_EM2883:
248			emdtv_write_1(sc, UR_GET_STATUS, EM28XX_XCLK_REG, 0x97);
249			emdtv_write_1(sc, UR_GET_STATUS, EM28XX_I2C_CLK_REG,
250			    0x40);
251			delay(10000);
252			emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x2d);
253			delay(10000);
254			break;
255		default:
256			aprint_normal_dev(sc->sc_dev,
257			    "unknown EMPIA board 0x%04x/0x%04x\n",
258			    sc->sc_vendor, sc->sc_product);
259			break;
260		}
261		break;
262	case USB_VENDOR_AMD:
263		switch (sc->sc_product) {
264		case USB_PRODUCT_AMD_TV_WONDER_600_USB:
265			emdtv_default_board_init(sc);
266			break;
267		default:
268			aprint_normal_dev(sc->sc_dev,
269			    "unknown AMD board 0x%04x/0x%04x\n",
270			    sc->sc_vendor, sc->sc_product);
271		}
272		break;
273	case USB_VENDOR_PINNACLE:
274		switch (sc->sc_product) {
275		case USB_PRODUCT_PINNACLE_PCTV800E:
276			emdtv_default_board_init(sc);
277			break;
278		default:
279			aprint_normal_dev(sc->sc_dev,
280			    "unknown Pinnacle board 0x%04x/0x%04x\n",
281			    sc->sc_vendor, sc->sc_product);
282		}
283		break;
284	default:
285		aprint_normal_dev(sc->sc_dev,
286		    "unknown board 0x%04x:0x%04x\n",
287		    sc->sc_vendor, sc->sc_product);
288		break;
289	}
290}
291
292/*
293 * Register read/write
294 */
295uint8_t
296emdtv_read_1(struct emdtv_softc *sc, uint8_t req, uint16_t index)
297{
298	uint8_t val;
299	emdtv_read_multi_1(sc, req, index, &val, 1);
300	return val;
301}
302
303void
304emdtv_write_1(struct emdtv_softc *sc, uint8_t req, uint16_t index, uint8_t val)
305{
306	emdtv_write_multi_1(sc, req, index, &val, 1);
307}
308
309void
310emdtv_read_multi_1(struct emdtv_softc *sc, uint8_t req, uint16_t index,
311    uint8_t *datap, uint16_t count)
312{
313	usb_device_request_t request;
314	usbd_status status;
315
316	request.bmRequestType = UT_READ_VENDOR_DEVICE;
317	request.bRequest = req;
318	USETW(request.wValue, 0x0000);
319	USETW(request.wIndex, index);
320	USETW(request.wLength, count);
321
322	status = usbd_do_request(sc->sc_udev, &request, datap);
323	if (status != USBD_NORMAL_COMPLETION)
324		aprint_error_dev(sc->sc_dev, "couldn't read %x/%x: %s\n",
325		    req, index, usbd_errstr(status));
326
327	if (emdtv_debug_regs) {
328		int i;
329		printf("%s [%s] c0 %02x 00 00 %02x 00 01 00 <<<",
330		    __func__, status == 0 ? " OK" : "NOK", req, index);
331		for (i = 0; status == 0 && i < count; i++)
332			printf(" %02x", datap[i]);
333		printf("\n");
334	}
335}
336
337void
338emdtv_write_multi_1(struct emdtv_softc *sc, uint8_t req, uint16_t index,
339    const uint8_t *datap, uint16_t count)
340{
341	usb_device_request_t request;
342	usbd_status status;
343
344	request.bmRequestType = UT_WRITE_VENDOR_DEVICE;
345	request.bRequest = req;
346	USETW(request.wValue, 0x0000);
347	USETW(request.wIndex, index);
348	USETW(request.wLength, count);
349
350	status = usbd_do_request(sc->sc_udev, &request, __UNCONST(datap));
351	if (status != USBD_NORMAL_COMPLETION)
352		aprint_error_dev(sc->sc_dev, "couldn't read %x/%x: %s\n",
353		    req, index, usbd_errstr(status));
354
355	if (emdtv_debug_regs) {
356		int i;
357		printf("%s [%s] 40 %02x 00 00 %02x 00 %02x 00 >>>",
358		    __func__, status == 0 ? " OK" : "NOK",
359		    req, index, count);
360		for (i = 0; i < count; ++i)
361			printf(" %02x", datap[i]);
362		printf("\n");
363	}
364}
365
366bool
367emdtv_gpio_ctl(struct emdtv_softc *sc, emdtv_gpio_reg_t gpioreg, bool onoff)
368{
369	const struct emdtv_board *eb = sc->sc_board;
370	uint16_t gpio_value, reg;
371	uint8_t gpio;
372	uint8_t eeprom_offset = 0x3c;
373	uint8_t val;
374
375	if (sc->sc_board->eb_manual_gpio == false) {
376		val = eeprom_offset + gpioreg;
377		emdtv_write_1(sc, 0x03, 0xa0, val);
378		gpio_value = emdtv_read_1(sc, 0x02, 0xa0);
379	} else {
380		const struct emdtv_gpio_regs *r = &eb->eb_gpio_regs;
381		switch (gpioreg) {
382		case EMDTV_GPIO_TS1_ON:
383			gpio_value = r->ts1_on;
384			break;
385		case EMDTV_GPIO_ANALOG_ON:
386			gpio_value = r->a_on;
387			break;
388		case EMDTV_GPIO_TUNER1_ON:
389			gpio_value = r->t1_on;
390			break;
391		case EMDTV_GPIO_TUNER1_RESET:
392			gpio_value = r->t1_reset;
393				break;
394		case EMDTV_GPIO_DEMOD1_RESET:
395			gpio_value = r->d1_reset;
396			break;
397		default:
398			aprint_error_dev(sc->sc_dev,
399			    "unknown gpio reg %d\n", gpioreg);
400			return false;
401		}
402	}
403
404	if ((gpio_value & 0x80) == 0) {
405		aprint_error_dev(sc->sc_dev,
406		    "gpio reg %d not enabled\n", gpioreg);
407		return false;
408	}
409
410	reg = gpio_value & 0x10 ? 0x04 : 0x08;
411	gpio = emdtv_read_1(sc, UR_GET_STATUS, reg);
412	if ((gpio_value & 0x40) == 0) {
413		gpio &= ~((uint8_t)(1 << (gpio_value & 7)));
414
415		if (onoff)
416			gpio |= ((gpio_value >> 5) & 1) << (gpio_value & 7);
417		else
418			gpio |= (((gpio_value >> 5) & 1) ^ 1) <<
419			    (gpio_value & 7);
420		emdtv_write_1(sc, UR_GET_STATUS, reg, gpio);
421	} else {
422		gpio &= ~((uint8_t)(1 << (gpio_value & 0xf)));
423
424		gpio |= ((gpio_value >> 5) & 1) << (gpio_value & 7);
425		emdtv_write_1(sc, UR_GET_STATUS, reg, gpio);
426		usbd_delay_ms(sc->sc_udev, 100);
427
428		gpio &= ~((uint8_t)(1 << (gpio_value & 0xf)));
429		gpio |= (((gpio_value >> 5) & 1) ^ 1) << (gpio_value & 7);
430		emdtv_write_1(sc, UR_GET_STATUS, reg, gpio);
431		usbd_delay_ms(sc->sc_udev, 100);
432	}
433
434	return true;
435}
436
437static void
438emdtv_default_board_init(struct emdtv_softc *sc)
439{
440	emdtv_write_1(sc, UR_GET_STATUS, EM28XX_XCLK_REG, 0x27);
441	emdtv_write_1(sc, UR_GET_STATUS, EM28XX_I2C_CLK_REG, 0x40);
442	emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0xff);
443	emdtv_write_1(sc, UR_GET_STATUS, 0x04, 0x00);
444	usbd_delay_ms(sc->sc_udev, 100);
445	emdtv_write_1(sc, UR_GET_STATUS, 0x04, 0x08);
446	usbd_delay_ms(sc->sc_udev, 100);
447	emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0xff);
448	usbd_delay_ms(sc->sc_udev, 50);
449	emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x2d);
450	usbd_delay_ms(sc->sc_udev, 50);
451	emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x3d);
452	//emdtv_write_1(sc, UR_GET_STATUS, 0x0f, 0xa7);
453	usbd_delay_ms(sc->sc_udev, 10);
454}
455
456MODULE(MODULE_CLASS_DRIVER, emdtv, "cir,lg3303,xc3028");
457
458#ifdef _MODULE
459#include "ioconf.c"
460#endif
461
462static int
463emdtv_modcmd(modcmd_t cmd, void *opaque)
464{
465	switch (cmd) {
466	case MODULE_CMD_INIT:
467#ifdef _MODULE
468		return config_init_component(cfdriver_ioconf_emdtv,
469		    cfattach_ioconf_emdtv, cfdata_ioconf_emdtv);
470#else
471		return 0;
472#endif
473	case MODULE_CMD_FINI:
474#ifdef _MODULE
475		return config_fini_component(cfdriver_ioconf_emdtv,
476		    cfattach_ioconf_emdtv, cfdata_ioconf_emdtv);
477#else
478		return 0;
479#endif
480	default:
481		return ENOTTY;
482	}
483}
484