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 
220c0d06caSMauro Carvalho Chehab #include <linux/module.h>
230c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
240c0d06caSMauro Carvalho Chehab #include <linux/videodev2.h>
250c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
260c0d06caSMauro Carvalho Chehab #include <linux/mutex.h>
270c0d06caSMauro Carvalho Chehab 
280c0d06caSMauro Carvalho Chehab #include "au0828.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) {
930c0d06caSMauro Carvalho Chehab 			printk(KERN_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) {
1180c0d06caSMauro Carvalho Chehab 			printk(KERN_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 
1562fcfd317SMauro Carvalho Chehab 	au0828_rc_unregister(dev);
1570c0d06caSMauro Carvalho Chehab 	/* Digital TV */
1580c0d06caSMauro Carvalho Chehab 	au0828_dvb_unregister(dev);
1590c0d06caSMauro Carvalho Chehab 
1600c0d06caSMauro Carvalho Chehab 	usb_set_intfdata(interface, NULL);
1610c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->mutex);
1620c0d06caSMauro Carvalho Chehab 	dev->usbdev = NULL;
1630c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->mutex);
164823beb7eSHans Verkuil #ifdef CONFIG_VIDEO_AU0828_V4L2
165823beb7eSHans Verkuil 	if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
166823beb7eSHans Verkuil 		au0828_analog_unregister(dev);
167823beb7eSHans Verkuil 		v4l2_device_disconnect(&dev->v4l2_dev);
168823beb7eSHans Verkuil 		v4l2_device_put(&dev->v4l2_dev);
169823beb7eSHans Verkuil 		return;
170823beb7eSHans Verkuil 	}
171823beb7eSHans Verkuil #endif
172823beb7eSHans Verkuil 	au0828_usb_release(dev);
1730c0d06caSMauro Carvalho Chehab }
1740c0d06caSMauro Carvalho Chehab 
1750c0d06caSMauro Carvalho Chehab static int au0828_usb_probe(struct usb_interface *interface,
1760c0d06caSMauro Carvalho Chehab 	const struct usb_device_id *id)
1770c0d06caSMauro Carvalho Chehab {
1788a4e7866SMichael Krufky 	int ifnum;
179f251b3e7STim Mester 	int retval = 0;
180f251b3e7STim Mester 
1810c0d06caSMauro Carvalho Chehab 	struct au0828_dev *dev;
1820c0d06caSMauro Carvalho Chehab 	struct usb_device *usbdev = interface_to_usbdev(interface);
1830c0d06caSMauro Carvalho Chehab 
1840c0d06caSMauro Carvalho Chehab 	ifnum = interface->altsetting->desc.bInterfaceNumber;
1850c0d06caSMauro Carvalho Chehab 
1860c0d06caSMauro Carvalho Chehab 	if (ifnum != 0)
1870c0d06caSMauro Carvalho Chehab 		return -ENODEV;
1880c0d06caSMauro Carvalho Chehab 
1890c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
1900c0d06caSMauro Carvalho Chehab 		le16_to_cpu(usbdev->descriptor.idVendor),
1910c0d06caSMauro Carvalho Chehab 		le16_to_cpu(usbdev->descriptor.idProduct),
1920c0d06caSMauro Carvalho Chehab 		ifnum);
1930c0d06caSMauro Carvalho Chehab 
1940c0d06caSMauro Carvalho Chehab 	/*
1950c0d06caSMauro Carvalho Chehab 	 * Make sure we have 480 Mbps of bandwidth, otherwise things like
1960c0d06caSMauro Carvalho Chehab 	 * video stream wouldn't likely work, since 12 Mbps is generally
1970c0d06caSMauro Carvalho Chehab 	 * not enough even for most Digital TV streams.
1980c0d06caSMauro Carvalho Chehab 	 */
1990c0d06caSMauro Carvalho Chehab 	if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
2000c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR "au0828: Device initialization failed.\n");
2010c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR "au0828: Device must be connected to a "
2020c0d06caSMauro Carvalho Chehab 		       "high-speed USB 2.0 port.\n");
2030c0d06caSMauro Carvalho Chehab 		return -ENODEV;
2040c0d06caSMauro Carvalho Chehab 	}
2050c0d06caSMauro Carvalho Chehab 
2060c0d06caSMauro Carvalho Chehab 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2070c0d06caSMauro Carvalho Chehab 	if (dev == NULL) {
2080c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
2090c0d06caSMauro Carvalho Chehab 		return -ENOMEM;
2100c0d06caSMauro Carvalho Chehab 	}
2110c0d06caSMauro Carvalho Chehab 
2120c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->lock);
2130c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->lock);
2140c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->mutex);
2150c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->dvb.lock);
2160c0d06caSMauro Carvalho Chehab 	dev->usbdev = usbdev;
2170c0d06caSMauro Carvalho Chehab 	dev->boardnr = id->driver_info;
2180c0d06caSMauro Carvalho Chehab 
2198a4e7866SMichael Krufky #ifdef CONFIG_VIDEO_AU0828_V4L2
220823beb7eSHans Verkuil 	dev->v4l2_dev.release = au0828_usb_v4l2_release;
221823beb7eSHans Verkuil 
2220c0d06caSMauro Carvalho Chehab 	/* Create the v4l2_device */
2230c0d06caSMauro Carvalho Chehab 	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
2240c0d06caSMauro Carvalho Chehab 	if (retval) {
225e8c26f45SHans Verkuil 		pr_err("%s() v4l2_device_register failed\n",
2260c0d06caSMauro Carvalho Chehab 		       __func__);
2270c0d06caSMauro Carvalho Chehab 		mutex_unlock(&dev->lock);
2280c0d06caSMauro Carvalho Chehab 		kfree(dev);
229e8c26f45SHans Verkuil 		return retval;
2300c0d06caSMauro Carvalho Chehab 	}
231e8c26f45SHans Verkuil 	/* This control handler will inherit the controls from au8522 */
232e8c26f45SHans Verkuil 	retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4);
233e8c26f45SHans Verkuil 	if (retval) {
234e8c26f45SHans Verkuil 		pr_err("%s() v4l2_ctrl_handler_init failed\n",
235e8c26f45SHans Verkuil 		       __func__);
236e8c26f45SHans Verkuil 		mutex_unlock(&dev->lock);
237e8c26f45SHans Verkuil 		kfree(dev);
238e8c26f45SHans Verkuil 		return retval;
239e8c26f45SHans Verkuil 	}
240e8c26f45SHans Verkuil 	dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
2418a4e7866SMichael Krufky #endif
2420c0d06caSMauro Carvalho Chehab 
2430c0d06caSMauro Carvalho Chehab 	/* Power Up the bridge */
2440c0d06caSMauro Carvalho Chehab 	au0828_write(dev, REG_600, 1 << 4);
2450c0d06caSMauro Carvalho Chehab 
2460c0d06caSMauro Carvalho Chehab 	/* Bring up the GPIO's and supporting devices */
2470c0d06caSMauro Carvalho Chehab 	au0828_gpio_setup(dev);
2480c0d06caSMauro Carvalho Chehab 
2490c0d06caSMauro Carvalho Chehab 	/* I2C */
2500c0d06caSMauro Carvalho Chehab 	au0828_i2c_register(dev);
2510c0d06caSMauro Carvalho Chehab 
2520c0d06caSMauro Carvalho Chehab 	/* Setup */
2530c0d06caSMauro Carvalho Chehab 	au0828_card_setup(dev);
2540c0d06caSMauro Carvalho Chehab 
2558a4e7866SMichael Krufky #ifdef CONFIG_VIDEO_AU0828_V4L2
2560c0d06caSMauro Carvalho Chehab 	/* Analog TV */
2570c0d06caSMauro Carvalho Chehab 	if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
2580c0d06caSMauro Carvalho Chehab 		au0828_analog_register(dev, interface);
2598a4e7866SMichael Krufky #endif
2600c0d06caSMauro Carvalho Chehab 
2610c0d06caSMauro Carvalho Chehab 	/* Digital TV */
262f251b3e7STim Mester 	retval = au0828_dvb_register(dev);
263f251b3e7STim Mester 	if (retval)
264f251b3e7STim Mester 		pr_err("%s() au0282_dev_register failed\n",
265f251b3e7STim Mester 		       __func__);
266f251b3e7STim Mester 
2672fcfd317SMauro Carvalho Chehab 	/* Remote controller */
2682fcfd317SMauro Carvalho Chehab 	au0828_rc_register(dev);
2690c0d06caSMauro Carvalho Chehab 
2702fcfd317SMauro Carvalho Chehab 	/*
2712fcfd317SMauro Carvalho Chehab 	 * Store the pointer to the au0828_dev so it can be accessed in
2722fcfd317SMauro Carvalho Chehab 	 * au0828_usb_disconnect
2732fcfd317SMauro Carvalho Chehab 	 */
2740c0d06caSMauro Carvalho Chehab 	usb_set_intfdata(interface, dev);
2750c0d06caSMauro Carvalho Chehab 
2760c0d06caSMauro Carvalho Chehab 	printk(KERN_INFO "Registered device AU0828 [%s]\n",
2770c0d06caSMauro Carvalho Chehab 		dev->board.name == NULL ? "Unset" : dev->board.name);
2780c0d06caSMauro Carvalho Chehab 
2790c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
2800c0d06caSMauro Carvalho Chehab 
281f251b3e7STim Mester 	return retval;
2820c0d06caSMauro Carvalho Chehab }
2830c0d06caSMauro Carvalho Chehab 
284aaeac199SMauro Carvalho Chehab static int au0828_suspend(struct usb_interface *interface,
285aaeac199SMauro Carvalho Chehab 				pm_message_t message)
286aaeac199SMauro Carvalho Chehab {
287aaeac199SMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
288aaeac199SMauro Carvalho Chehab 
289aaeac199SMauro Carvalho Chehab 	if (!dev)
290aaeac199SMauro Carvalho Chehab 		return 0;
291aaeac199SMauro Carvalho Chehab 
292aaeac199SMauro Carvalho Chehab 	au0828_rc_suspend(dev);
293aaeac199SMauro Carvalho Chehab 
294aaeac199SMauro Carvalho Chehab 	/* FIXME: should suspend also ATV/DTV */
295aaeac199SMauro Carvalho Chehab 
296aaeac199SMauro Carvalho Chehab 	return 0;
297aaeac199SMauro Carvalho Chehab }
298aaeac199SMauro Carvalho Chehab 
299aaeac199SMauro Carvalho Chehab static int au0828_resume(struct usb_interface *interface)
300aaeac199SMauro Carvalho Chehab {
301aaeac199SMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
302aaeac199SMauro Carvalho Chehab 	if (!dev)
303aaeac199SMauro Carvalho Chehab 		return 0;
304aaeac199SMauro Carvalho Chehab 
305fa500461SMauro Carvalho Chehab 	/* Power Up the bridge */
306fa500461SMauro Carvalho Chehab 	au0828_write(dev, REG_600, 1 << 4);
307fa500461SMauro Carvalho Chehab 
308fa500461SMauro Carvalho Chehab 	/* Bring up the GPIO's and supporting devices */
309fa500461SMauro Carvalho Chehab 	au0828_gpio_setup(dev);
310fa500461SMauro Carvalho Chehab 
311aaeac199SMauro Carvalho Chehab 	au0828_rc_resume(dev);
312aaeac199SMauro Carvalho Chehab 
313aaeac199SMauro Carvalho Chehab 	/* FIXME: should resume also ATV/DTV */
314aaeac199SMauro Carvalho Chehab 
315aaeac199SMauro Carvalho Chehab 	return 0;
316aaeac199SMauro Carvalho Chehab }
317aaeac199SMauro Carvalho Chehab 
3180c0d06caSMauro Carvalho Chehab static struct usb_driver au0828_usb_driver = {
3190c0d06caSMauro Carvalho Chehab 	.name		= DRIVER_NAME,
3200c0d06caSMauro Carvalho Chehab 	.probe		= au0828_usb_probe,
3210c0d06caSMauro Carvalho Chehab 	.disconnect	= au0828_usb_disconnect,
3220c0d06caSMauro Carvalho Chehab 	.id_table	= au0828_usb_id_table,
323aaeac199SMauro Carvalho Chehab 	.suspend	= au0828_suspend,
324aaeac199SMauro Carvalho Chehab 	.resume		= au0828_resume,
325aaeac199SMauro Carvalho Chehab 	.reset_resume	= au0828_resume,
3260c0d06caSMauro Carvalho Chehab };
3270c0d06caSMauro Carvalho Chehab 
3280c0d06caSMauro Carvalho Chehab static int __init au0828_init(void)
3290c0d06caSMauro Carvalho Chehab {
3300c0d06caSMauro Carvalho Chehab 	int ret;
3310c0d06caSMauro Carvalho Chehab 
3320c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 1)
3330c0d06caSMauro Carvalho Chehab 		printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
3340c0d06caSMauro Carvalho Chehab 
3350c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 2)
3360c0d06caSMauro Carvalho Chehab 		printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
3370c0d06caSMauro Carvalho Chehab 
3380c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 4)
3390c0d06caSMauro Carvalho Chehab 		printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
3400c0d06caSMauro Carvalho Chehab 
3410c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 8)
3420c0d06caSMauro Carvalho Chehab 		printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
3430c0d06caSMauro Carvalho Chehab 		       __func__);
3440c0d06caSMauro Carvalho Chehab 
3452fcfd317SMauro Carvalho Chehab 	if (au0828_debug & 16)
3462fcfd317SMauro Carvalho Chehab 		printk(KERN_INFO "%s() IR Debugging is enabled\n",
3472fcfd317SMauro Carvalho Chehab 		       __func__);
3482fcfd317SMauro Carvalho Chehab 
3490c0d06caSMauro Carvalho Chehab 	printk(KERN_INFO "au0828 driver loaded\n");
3500c0d06caSMauro Carvalho Chehab 
3510c0d06caSMauro Carvalho Chehab 	ret = usb_register(&au0828_usb_driver);
3520c0d06caSMauro Carvalho Chehab 	if (ret)
3530c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR "usb_register failed, error = %d\n", ret);
3540c0d06caSMauro Carvalho Chehab 
3550c0d06caSMauro Carvalho Chehab 	return ret;
3560c0d06caSMauro Carvalho Chehab }
3570c0d06caSMauro Carvalho Chehab 
3580c0d06caSMauro Carvalho Chehab static void __exit au0828_exit(void)
3590c0d06caSMauro Carvalho Chehab {
3600c0d06caSMauro Carvalho Chehab 	usb_deregister(&au0828_usb_driver);
3610c0d06caSMauro Carvalho Chehab }
3620c0d06caSMauro Carvalho Chehab 
3630c0d06caSMauro Carvalho Chehab module_init(au0828_init);
3640c0d06caSMauro Carvalho Chehab module_exit(au0828_exit);
3650c0d06caSMauro Carvalho Chehab 
3660c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
3670c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
3680c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL");
3692fcfd317SMauro Carvalho Chehab MODULE_VERSION("0.0.3");
370