10c0d06caSMauro Carvalho Chehab /*
20c0d06caSMauro Carvalho Chehab  *  Driver for the Auvitek USB bridge
30c0d06caSMauro Carvalho Chehab  *
40c0d06caSMauro Carvalho Chehab  *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
50c0d06caSMauro Carvalho Chehab  *
60c0d06caSMauro Carvalho Chehab  *  This program is free software; you can redistribute it and/or modify
70c0d06caSMauro Carvalho Chehab  *  it under the terms of the GNU General Public License as published by
80c0d06caSMauro Carvalho Chehab  *  the Free Software Foundation; either version 2 of the License, or
90c0d06caSMauro Carvalho Chehab  *  (at your option) any later version.
100c0d06caSMauro Carvalho Chehab  *
110c0d06caSMauro Carvalho Chehab  *  This program is distributed in the hope that it will be useful,
120c0d06caSMauro Carvalho Chehab  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
130c0d06caSMauro Carvalho Chehab  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
140c0d06caSMauro Carvalho Chehab  *
150c0d06caSMauro Carvalho Chehab  *  GNU General Public License for more details.
160c0d06caSMauro Carvalho Chehab  *
170c0d06caSMauro Carvalho Chehab  *  You should have received a copy of the GNU General Public License
180c0d06caSMauro Carvalho Chehab  *  along with this program; if not, write to the Free Software
190c0d06caSMauro Carvalho Chehab  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
200c0d06caSMauro Carvalho Chehab  */
210c0d06caSMauro Carvalho Chehab 
2283afb32aSMauro Carvalho Chehab #include "au0828.h"
2383afb32aSMauro Carvalho Chehab 
240c0d06caSMauro Carvalho Chehab #include <linux/module.h>
250c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
260c0d06caSMauro Carvalho Chehab #include <linux/videodev2.h>
270c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
280c0d06caSMauro Carvalho Chehab #include <linux/mutex.h>
290c0d06caSMauro Carvalho Chehab 
300c0d06caSMauro Carvalho Chehab /*
310c0d06caSMauro Carvalho Chehab  * 1 = General debug messages
320c0d06caSMauro Carvalho Chehab  * 2 = USB handling
330c0d06caSMauro Carvalho Chehab  * 4 = I2C related
340c0d06caSMauro Carvalho Chehab  * 8 = Bridge related
352fcfd317SMauro Carvalho Chehab  * 16 = IR related
360c0d06caSMauro Carvalho Chehab  */
370c0d06caSMauro Carvalho Chehab int au0828_debug;
380c0d06caSMauro Carvalho Chehab module_param_named(debug, au0828_debug, int, 0644);
392fcfd317SMauro Carvalho Chehab MODULE_PARM_DESC(debug,
402fcfd317SMauro Carvalho Chehab 		 "set debug bitmask: 1=general, 2=USB, 4=I2C, 8=bridge, 16=IR");
410c0d06caSMauro Carvalho Chehab 
420c0d06caSMauro Carvalho Chehab static unsigned int disable_usb_speed_check;
430c0d06caSMauro Carvalho Chehab module_param(disable_usb_speed_check, int, 0444);
440c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(disable_usb_speed_check,
450c0d06caSMauro Carvalho Chehab 		 "override min bandwidth requirement of 480M bps");
460c0d06caSMauro Carvalho Chehab 
470c0d06caSMauro Carvalho Chehab #define _AU0828_BULKPIPE 0x03
480c0d06caSMauro Carvalho Chehab #define _BULKPIPESIZE 0xffff
490c0d06caSMauro Carvalho Chehab 
500c0d06caSMauro Carvalho Chehab static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
510c0d06caSMauro Carvalho Chehab 			    u16 index);
520c0d06caSMauro Carvalho Chehab static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
530c0d06caSMauro Carvalho Chehab 	u16 index, unsigned char *cp, u16 size);
540c0d06caSMauro Carvalho Chehab 
550c0d06caSMauro Carvalho Chehab /* USB Direction */
560c0d06caSMauro Carvalho Chehab #define CMD_REQUEST_IN		0x00
570c0d06caSMauro Carvalho Chehab #define CMD_REQUEST_OUT		0x01
580c0d06caSMauro Carvalho Chehab 
590c0d06caSMauro Carvalho Chehab u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
600c0d06caSMauro Carvalho Chehab {
610c0d06caSMauro Carvalho Chehab 	u8 result = 0;
620c0d06caSMauro Carvalho Chehab 
630c0d06caSMauro Carvalho Chehab 	recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, &result, 1);
640c0d06caSMauro Carvalho Chehab 	dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, result);
650c0d06caSMauro Carvalho Chehab 
660c0d06caSMauro Carvalho Chehab 	return result;
670c0d06caSMauro Carvalho Chehab }
680c0d06caSMauro Carvalho Chehab 
690c0d06caSMauro Carvalho Chehab u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
700c0d06caSMauro Carvalho Chehab {
710c0d06caSMauro Carvalho Chehab 	dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
720c0d06caSMauro Carvalho Chehab 	return send_control_msg(dev, CMD_REQUEST_OUT, val, reg);
730c0d06caSMauro Carvalho Chehab }
740c0d06caSMauro Carvalho Chehab 
750c0d06caSMauro Carvalho Chehab static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
760c0d06caSMauro Carvalho Chehab 	u16 index)
770c0d06caSMauro Carvalho Chehab {
780c0d06caSMauro Carvalho Chehab 	int status = -ENODEV;
790c0d06caSMauro Carvalho Chehab 
800c0d06caSMauro Carvalho Chehab 	if (dev->usbdev) {
810c0d06caSMauro Carvalho Chehab 
820c0d06caSMauro Carvalho Chehab 		/* cp must be memory that has been allocated by kmalloc */
830c0d06caSMauro Carvalho Chehab 		status = usb_control_msg(dev->usbdev,
840c0d06caSMauro Carvalho Chehab 				usb_sndctrlpipe(dev->usbdev, 0),
850c0d06caSMauro Carvalho Chehab 				request,
860c0d06caSMauro Carvalho Chehab 				USB_DIR_OUT | USB_TYPE_VENDOR |
870c0d06caSMauro Carvalho Chehab 					USB_RECIP_DEVICE,
880c0d06caSMauro Carvalho Chehab 				value, index, NULL, 0, 1000);
890c0d06caSMauro Carvalho Chehab 
900c0d06caSMauro Carvalho Chehab 		status = min(status, 0);
910c0d06caSMauro Carvalho Chehab 
920c0d06caSMauro Carvalho Chehab 		if (status < 0) {
9383afb32aSMauro Carvalho Chehab 			pr_err("%s() Failed sending control message, error %d.\n",
940c0d06caSMauro Carvalho Chehab 				__func__, status);
950c0d06caSMauro Carvalho Chehab 		}
960c0d06caSMauro Carvalho Chehab 
970c0d06caSMauro Carvalho Chehab 	}
980c0d06caSMauro Carvalho Chehab 
990c0d06caSMauro Carvalho Chehab 	return status;
1000c0d06caSMauro Carvalho Chehab }
1010c0d06caSMauro Carvalho Chehab 
1020c0d06caSMauro Carvalho Chehab static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
1030c0d06caSMauro Carvalho Chehab 	u16 index, unsigned char *cp, u16 size)
1040c0d06caSMauro Carvalho Chehab {
1050c0d06caSMauro Carvalho Chehab 	int status = -ENODEV;
1060c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->mutex);
1070c0d06caSMauro Carvalho Chehab 	if (dev->usbdev) {
1080c0d06caSMauro Carvalho Chehab 		status = usb_control_msg(dev->usbdev,
1090c0d06caSMauro Carvalho Chehab 				usb_rcvctrlpipe(dev->usbdev, 0),
1100c0d06caSMauro Carvalho Chehab 				request,
1110c0d06caSMauro Carvalho Chehab 				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1120c0d06caSMauro Carvalho Chehab 				value, index,
1130c0d06caSMauro Carvalho Chehab 				dev->ctrlmsg, size, 1000);
1140c0d06caSMauro Carvalho Chehab 
1150c0d06caSMauro Carvalho Chehab 		status = min(status, 0);
1160c0d06caSMauro Carvalho Chehab 
1170c0d06caSMauro Carvalho Chehab 		if (status < 0) {
11883afb32aSMauro Carvalho Chehab 			pr_err("%s() Failed receiving control message, error %d.\n",
1190c0d06caSMauro Carvalho Chehab 				__func__, status);
1200c0d06caSMauro Carvalho Chehab 		}
1210c0d06caSMauro Carvalho Chehab 
1220c0d06caSMauro Carvalho Chehab 		/* the host controller requires heap allocated memory, which
1230c0d06caSMauro Carvalho Chehab 		   is why we didn't just pass "cp" into usb_control_msg */
1240c0d06caSMauro Carvalho Chehab 		memcpy(cp, dev->ctrlmsg, size);
1250c0d06caSMauro Carvalho Chehab 	}
1260c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->mutex);
1270c0d06caSMauro Carvalho Chehab 	return status;
1280c0d06caSMauro Carvalho Chehab }
1290c0d06caSMauro Carvalho Chehab 
130823beb7eSHans Verkuil static void au0828_usb_release(struct au0828_dev *dev)
131823beb7eSHans Verkuil {
132823beb7eSHans Verkuil 	/* I2C */
133823beb7eSHans Verkuil 	au0828_i2c_unregister(dev);
134823beb7eSHans Verkuil 
135823beb7eSHans Verkuil 	kfree(dev);
136823beb7eSHans Verkuil }
137823beb7eSHans Verkuil 
138823beb7eSHans Verkuil #ifdef CONFIG_VIDEO_AU0828_V4L2
139823beb7eSHans Verkuil static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
140823beb7eSHans Verkuil {
141823beb7eSHans Verkuil 	struct au0828_dev *dev =
142823beb7eSHans Verkuil 		container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
143823beb7eSHans Verkuil 
144823beb7eSHans Verkuil 	v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
145823beb7eSHans Verkuil 	v4l2_device_unregister(&dev->v4l2_dev);
146823beb7eSHans Verkuil 	au0828_usb_release(dev);
147823beb7eSHans Verkuil }
148823beb7eSHans Verkuil #endif
149823beb7eSHans Verkuil 
1500c0d06caSMauro Carvalho Chehab static void au0828_usb_disconnect(struct usb_interface *interface)
1510c0d06caSMauro Carvalho Chehab {
1520c0d06caSMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
1530c0d06caSMauro Carvalho Chehab 
1540c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
1550c0d06caSMauro Carvalho Chehab 
156eb336eabSShuah Khan 	/* there is a small window after disconnect, before
157eb336eabSShuah Khan 	   dev->usbdev is NULL, for poll (e.g: IR) try to access
158eb336eabSShuah Khan 	   the device and fill the dmesg with error messages.
159eb336eabSShuah Khan 	   Set the status so poll routines can check and avoid
160eb336eabSShuah Khan 	   access after disconnect.
161eb336eabSShuah Khan 	*/
162eb336eabSShuah Khan 	dev->dev_state = DEV_DISCONNECTED;
163eb336eabSShuah Khan 
1642fcfd317SMauro Carvalho Chehab 	au0828_rc_unregister(dev);
1650c0d06caSMauro Carvalho Chehab 	/* Digital TV */
1660c0d06caSMauro Carvalho Chehab 	au0828_dvb_unregister(dev);
1670c0d06caSMauro Carvalho Chehab 
1680c0d06caSMauro Carvalho Chehab 	usb_set_intfdata(interface, NULL);
1690c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->mutex);
1700c0d06caSMauro Carvalho Chehab 	dev->usbdev = NULL;
1710c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->mutex);
172823beb7eSHans Verkuil #ifdef CONFIG_VIDEO_AU0828_V4L2
173823beb7eSHans Verkuil 	if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
174823beb7eSHans Verkuil 		au0828_analog_unregister(dev);
175823beb7eSHans Verkuil 		v4l2_device_disconnect(&dev->v4l2_dev);
176823beb7eSHans Verkuil 		v4l2_device_put(&dev->v4l2_dev);
177823beb7eSHans Verkuil 		return;
178823beb7eSHans Verkuil 	}
179823beb7eSHans Verkuil #endif
180823beb7eSHans Verkuil 	au0828_usb_release(dev);
1810c0d06caSMauro Carvalho Chehab }
1820c0d06caSMauro Carvalho Chehab 
1830c0d06caSMauro Carvalho Chehab static int au0828_usb_probe(struct usb_interface *interface,
1840c0d06caSMauro Carvalho Chehab 	const struct usb_device_id *id)
1850c0d06caSMauro Carvalho Chehab {
1868a4e7866SMichael Krufky 	int ifnum;
187f251b3e7STim Mester 	int retval = 0;
188f251b3e7STim Mester 
1890c0d06caSMauro Carvalho Chehab 	struct au0828_dev *dev;
1900c0d06caSMauro Carvalho Chehab 	struct usb_device *usbdev = interface_to_usbdev(interface);
1910c0d06caSMauro Carvalho Chehab 
1920c0d06caSMauro Carvalho Chehab 	ifnum = interface->altsetting->desc.bInterfaceNumber;
1930c0d06caSMauro Carvalho Chehab 
1940c0d06caSMauro Carvalho Chehab 	if (ifnum != 0)
1950c0d06caSMauro Carvalho Chehab 		return -ENODEV;
1960c0d06caSMauro Carvalho Chehab 
1970c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
1980c0d06caSMauro Carvalho Chehab 		le16_to_cpu(usbdev->descriptor.idVendor),
1990c0d06caSMauro Carvalho Chehab 		le16_to_cpu(usbdev->descriptor.idProduct),
2000c0d06caSMauro Carvalho Chehab 		ifnum);
2010c0d06caSMauro Carvalho Chehab 
2020c0d06caSMauro Carvalho Chehab 	/*
2030c0d06caSMauro Carvalho Chehab 	 * Make sure we have 480 Mbps of bandwidth, otherwise things like
2040c0d06caSMauro Carvalho Chehab 	 * video stream wouldn't likely work, since 12 Mbps is generally
2050c0d06caSMauro Carvalho Chehab 	 * not enough even for most Digital TV streams.
2060c0d06caSMauro Carvalho Chehab 	 */
2070c0d06caSMauro Carvalho Chehab 	if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
20883afb32aSMauro Carvalho Chehab 		pr_err("au0828: Device initialization failed.\n");
20983afb32aSMauro Carvalho Chehab 		pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
2100c0d06caSMauro Carvalho Chehab 		return -ENODEV;
2110c0d06caSMauro Carvalho Chehab 	}
2120c0d06caSMauro Carvalho Chehab 
2130c0d06caSMauro Carvalho Chehab 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2140c0d06caSMauro Carvalho Chehab 	if (dev == NULL) {
21583afb32aSMauro Carvalho Chehab 		pr_err("%s() Unable to allocate memory\n", __func__);
2160c0d06caSMauro Carvalho Chehab 		return -ENOMEM;
2170c0d06caSMauro Carvalho Chehab 	}
2180c0d06caSMauro Carvalho Chehab 
2190c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->lock);
2200c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->lock);
2210c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->mutex);
2220c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->dvb.lock);
2230c0d06caSMauro Carvalho Chehab 	dev->usbdev = usbdev;
2240c0d06caSMauro Carvalho Chehab 	dev->boardnr = id->driver_info;
225e42c8c6eSRafael Lourenço de Lima Chehab 	dev->board = au0828_boards[dev->boardnr];
226e42c8c6eSRafael Lourenço de Lima Chehab 
2270c0d06caSMauro Carvalho Chehab 
2288a4e7866SMichael Krufky #ifdef CONFIG_VIDEO_AU0828_V4L2
229823beb7eSHans Verkuil 	dev->v4l2_dev.release = au0828_usb_v4l2_release;
230823beb7eSHans Verkuil 
2310c0d06caSMauro Carvalho Chehab 	/* Create the v4l2_device */
2320c0d06caSMauro Carvalho Chehab 	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
2330c0d06caSMauro Carvalho Chehab 	if (retval) {
234e8c26f45SHans Verkuil 		pr_err("%s() v4l2_device_register failed\n",
2350c0d06caSMauro Carvalho Chehab 		       __func__);
2360c0d06caSMauro Carvalho Chehab 		mutex_unlock(&dev->lock);
2370c0d06caSMauro Carvalho Chehab 		kfree(dev);
238e8c26f45SHans Verkuil 		return retval;
2390c0d06caSMauro Carvalho Chehab 	}
240e8c26f45SHans Verkuil 	/* This control handler will inherit the controls from au8522 */
241e8c26f45SHans Verkuil 	retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4);
242e8c26f45SHans Verkuil 	if (retval) {
243e8c26f45SHans Verkuil 		pr_err("%s() v4l2_ctrl_handler_init failed\n",
244e8c26f45SHans Verkuil 		       __func__);
245e8c26f45SHans Verkuil 		mutex_unlock(&dev->lock);
246e8c26f45SHans Verkuil 		kfree(dev);
247e8c26f45SHans Verkuil 		return retval;
248e8c26f45SHans Verkuil 	}
249e8c26f45SHans Verkuil 	dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
2508a4e7866SMichael Krufky #endif
2510c0d06caSMauro Carvalho Chehab 
2520c0d06caSMauro Carvalho Chehab 	/* Power Up the bridge */
2530c0d06caSMauro Carvalho Chehab 	au0828_write(dev, REG_600, 1 << 4);
2540c0d06caSMauro Carvalho Chehab 
2550c0d06caSMauro Carvalho Chehab 	/* Bring up the GPIO's and supporting devices */
2560c0d06caSMauro Carvalho Chehab 	au0828_gpio_setup(dev);
2570c0d06caSMauro Carvalho Chehab 
2580c0d06caSMauro Carvalho Chehab 	/* I2C */
2590c0d06caSMauro Carvalho Chehab 	au0828_i2c_register(dev);
2600c0d06caSMauro Carvalho Chehab 
2610c0d06caSMauro Carvalho Chehab 	/* Setup */
2620c0d06caSMauro Carvalho Chehab 	au0828_card_setup(dev);
2630c0d06caSMauro Carvalho Chehab 
2648a4e7866SMichael Krufky #ifdef CONFIG_VIDEO_AU0828_V4L2
2650c0d06caSMauro Carvalho Chehab 	/* Analog TV */
2660c0d06caSMauro Carvalho Chehab 	if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
2670c0d06caSMauro Carvalho Chehab 		au0828_analog_register(dev, interface);
2688a4e7866SMichael Krufky #endif
2690c0d06caSMauro Carvalho Chehab 
2700c0d06caSMauro Carvalho Chehab 	/* Digital TV */
271f251b3e7STim Mester 	retval = au0828_dvb_register(dev);
272f251b3e7STim Mester 	if (retval)
273f251b3e7STim Mester 		pr_err("%s() au0282_dev_register failed\n",
274f251b3e7STim Mester 		       __func__);
275f251b3e7STim Mester 
2762fcfd317SMauro Carvalho Chehab 	/* Remote controller */
2772fcfd317SMauro Carvalho Chehab 	au0828_rc_register(dev);
2780c0d06caSMauro Carvalho Chehab 
2792fcfd317SMauro Carvalho Chehab 	/*
2802fcfd317SMauro Carvalho Chehab 	 * Store the pointer to the au0828_dev so it can be accessed in
2812fcfd317SMauro Carvalho Chehab 	 * au0828_usb_disconnect
2822fcfd317SMauro Carvalho Chehab 	 */
2830c0d06caSMauro Carvalho Chehab 	usb_set_intfdata(interface, dev);
2840c0d06caSMauro Carvalho Chehab 
28583afb32aSMauro Carvalho Chehab 	pr_info("Registered device AU0828 [%s]\n",
2860c0d06caSMauro Carvalho Chehab 		dev->board.name == NULL ? "Unset" : dev->board.name);
2870c0d06caSMauro Carvalho Chehab 
2880c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
2890c0d06caSMauro Carvalho Chehab 
290f251b3e7STim Mester 	return retval;
2910c0d06caSMauro Carvalho Chehab }
2920c0d06caSMauro Carvalho Chehab 
293aaeac199SMauro Carvalho Chehab static int au0828_suspend(struct usb_interface *interface,
294aaeac199SMauro Carvalho Chehab 				pm_message_t message)
295aaeac199SMauro Carvalho Chehab {
296aaeac199SMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
297aaeac199SMauro Carvalho Chehab 
298aaeac199SMauro Carvalho Chehab 	if (!dev)
299aaeac199SMauro Carvalho Chehab 		return 0;
300aaeac199SMauro Carvalho Chehab 
30181187240SMauro Carvalho Chehab 	pr_info("Suspend\n");
30281187240SMauro Carvalho Chehab 
303aaeac199SMauro Carvalho Chehab 	au0828_rc_suspend(dev);
3041a1ba95eSMauro Carvalho Chehab 	au0828_v4l2_suspend(dev);
305b799de75SMauro Carvalho Chehab 	au0828_dvb_suspend(dev);
306aaeac199SMauro Carvalho Chehab 
307aaeac199SMauro Carvalho Chehab 	/* FIXME: should suspend also ATV/DTV */
308aaeac199SMauro Carvalho Chehab 
309aaeac199SMauro Carvalho Chehab 	return 0;
310aaeac199SMauro Carvalho Chehab }
311aaeac199SMauro Carvalho Chehab 
312aaeac199SMauro Carvalho Chehab static int au0828_resume(struct usb_interface *interface)
313aaeac199SMauro Carvalho Chehab {
314aaeac199SMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
315aaeac199SMauro Carvalho Chehab 	if (!dev)
316aaeac199SMauro Carvalho Chehab 		return 0;
317aaeac199SMauro Carvalho Chehab 
31881187240SMauro Carvalho Chehab 	pr_info("Resume\n");
31981187240SMauro Carvalho Chehab 
320fa500461SMauro Carvalho Chehab 	/* Power Up the bridge */
321fa500461SMauro Carvalho Chehab 	au0828_write(dev, REG_600, 1 << 4);
322fa500461SMauro Carvalho Chehab 
323fa500461SMauro Carvalho Chehab 	/* Bring up the GPIO's and supporting devices */
324fa500461SMauro Carvalho Chehab 	au0828_gpio_setup(dev);
325fa500461SMauro Carvalho Chehab 
326aaeac199SMauro Carvalho Chehab 	au0828_rc_resume(dev);
3271a1ba95eSMauro Carvalho Chehab 	au0828_v4l2_resume(dev);
328b799de75SMauro Carvalho Chehab 	au0828_dvb_resume(dev);
329aaeac199SMauro Carvalho Chehab 
330aaeac199SMauro Carvalho Chehab 	/* FIXME: should resume also ATV/DTV */
331aaeac199SMauro Carvalho Chehab 
332aaeac199SMauro Carvalho Chehab 	return 0;
333aaeac199SMauro Carvalho Chehab }
334aaeac199SMauro Carvalho Chehab 
3350c0d06caSMauro Carvalho Chehab static struct usb_driver au0828_usb_driver = {
33683afb32aSMauro Carvalho Chehab 	.name		= KBUILD_MODNAME,
3370c0d06caSMauro Carvalho Chehab 	.probe		= au0828_usb_probe,
3380c0d06caSMauro Carvalho Chehab 	.disconnect	= au0828_usb_disconnect,
3390c0d06caSMauro Carvalho Chehab 	.id_table	= au0828_usb_id_table,
340aaeac199SMauro Carvalho Chehab 	.suspend	= au0828_suspend,
341aaeac199SMauro Carvalho Chehab 	.resume		= au0828_resume,
342aaeac199SMauro Carvalho Chehab 	.reset_resume	= au0828_resume,
3430c0d06caSMauro Carvalho Chehab };
3440c0d06caSMauro Carvalho Chehab 
3450c0d06caSMauro Carvalho Chehab static int __init au0828_init(void)
3460c0d06caSMauro Carvalho Chehab {
3470c0d06caSMauro Carvalho Chehab 	int ret;
3480c0d06caSMauro Carvalho Chehab 
3490c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 1)
35083afb32aSMauro Carvalho Chehab 		pr_info("%s() Debugging is enabled\n", __func__);
3510c0d06caSMauro Carvalho Chehab 
3520c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 2)
35383afb32aSMauro Carvalho Chehab 		pr_info("%s() USB Debugging is enabled\n", __func__);
3540c0d06caSMauro Carvalho Chehab 
3550c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 4)
35683afb32aSMauro Carvalho Chehab 		pr_info("%s() I2C Debugging is enabled\n", __func__);
3570c0d06caSMauro Carvalho Chehab 
3580c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 8)
35983afb32aSMauro Carvalho Chehab 		pr_info("%s() Bridge Debugging is enabled\n",
3600c0d06caSMauro Carvalho Chehab 		       __func__);
3610c0d06caSMauro Carvalho Chehab 
3622fcfd317SMauro Carvalho Chehab 	if (au0828_debug & 16)
36383afb32aSMauro Carvalho Chehab 		pr_info("%s() IR Debugging is enabled\n",
3642fcfd317SMauro Carvalho Chehab 		       __func__);
3652fcfd317SMauro Carvalho Chehab 
36683afb32aSMauro Carvalho Chehab 	pr_info("au0828 driver loaded\n");
3670c0d06caSMauro Carvalho Chehab 
3680c0d06caSMauro Carvalho Chehab 	ret = usb_register(&au0828_usb_driver);
3690c0d06caSMauro Carvalho Chehab 	if (ret)
37083afb32aSMauro Carvalho Chehab 		pr_err("usb_register failed, error = %d\n", ret);
3710c0d06caSMauro Carvalho Chehab 
3720c0d06caSMauro Carvalho Chehab 	return ret;
3730c0d06caSMauro Carvalho Chehab }
3740c0d06caSMauro Carvalho Chehab 
3750c0d06caSMauro Carvalho Chehab static void __exit au0828_exit(void)
3760c0d06caSMauro Carvalho Chehab {
3770c0d06caSMauro Carvalho Chehab 	usb_deregister(&au0828_usb_driver);
3780c0d06caSMauro Carvalho Chehab }
3790c0d06caSMauro Carvalho Chehab 
3800c0d06caSMauro Carvalho Chehab module_init(au0828_init);
3810c0d06caSMauro Carvalho Chehab module_exit(au0828_exit);
3820c0d06caSMauro Carvalho Chehab 
3830c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
3840c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
3850c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL");
3862fcfd317SMauro Carvalho Chehab MODULE_VERSION("0.0.3");
387