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 
30188d2d55SMauro Carvalho Chehab /* Due to enum tuner_pad_index */
31188d2d55SMauro Carvalho Chehab #include <media/tuner.h>
32188d2d55SMauro Carvalho Chehab 
330c0d06caSMauro Carvalho Chehab /*
340c0d06caSMauro Carvalho Chehab  * 1 = General debug messages
350c0d06caSMauro Carvalho Chehab  * 2 = USB handling
360c0d06caSMauro Carvalho Chehab  * 4 = I2C related
370c0d06caSMauro Carvalho Chehab  * 8 = Bridge related
382fcfd317SMauro Carvalho Chehab  * 16 = IR related
390c0d06caSMauro Carvalho Chehab  */
400c0d06caSMauro Carvalho Chehab int au0828_debug;
410c0d06caSMauro Carvalho Chehab module_param_named(debug, au0828_debug, int, 0644);
422fcfd317SMauro Carvalho Chehab MODULE_PARM_DESC(debug,
432fcfd317SMauro Carvalho Chehab 		 "set debug bitmask: 1=general, 2=USB, 4=I2C, 8=bridge, 16=IR");
440c0d06caSMauro Carvalho Chehab 
450c0d06caSMauro Carvalho Chehab static unsigned int disable_usb_speed_check;
460c0d06caSMauro Carvalho Chehab module_param(disable_usb_speed_check, int, 0444);
470c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(disable_usb_speed_check,
480c0d06caSMauro Carvalho Chehab 		 "override min bandwidth requirement of 480M bps");
490c0d06caSMauro Carvalho Chehab 
500c0d06caSMauro Carvalho Chehab #define _AU0828_BULKPIPE 0x03
510c0d06caSMauro Carvalho Chehab #define _BULKPIPESIZE 0xffff
520c0d06caSMauro Carvalho Chehab 
530c0d06caSMauro Carvalho Chehab static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
540c0d06caSMauro Carvalho Chehab 			    u16 index);
550c0d06caSMauro Carvalho Chehab static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
560c0d06caSMauro Carvalho Chehab 	u16 index, unsigned char *cp, u16 size);
570c0d06caSMauro Carvalho Chehab 
580c0d06caSMauro Carvalho Chehab /* USB Direction */
590c0d06caSMauro Carvalho Chehab #define CMD_REQUEST_IN		0x00
600c0d06caSMauro Carvalho Chehab #define CMD_REQUEST_OUT		0x01
610c0d06caSMauro Carvalho Chehab 
620c0d06caSMauro Carvalho Chehab u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
630c0d06caSMauro Carvalho Chehab {
640c0d06caSMauro Carvalho Chehab 	u8 result = 0;
650c0d06caSMauro Carvalho Chehab 
660c0d06caSMauro Carvalho Chehab 	recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, &result, 1);
670c0d06caSMauro Carvalho Chehab 	dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, result);
680c0d06caSMauro Carvalho Chehab 
690c0d06caSMauro Carvalho Chehab 	return result;
700c0d06caSMauro Carvalho Chehab }
710c0d06caSMauro Carvalho Chehab 
720c0d06caSMauro Carvalho Chehab u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
730c0d06caSMauro Carvalho Chehab {
740c0d06caSMauro Carvalho Chehab 	dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
750c0d06caSMauro Carvalho Chehab 	return send_control_msg(dev, CMD_REQUEST_OUT, val, reg);
760c0d06caSMauro Carvalho Chehab }
770c0d06caSMauro Carvalho Chehab 
780c0d06caSMauro Carvalho Chehab static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
790c0d06caSMauro Carvalho Chehab 	u16 index)
800c0d06caSMauro Carvalho Chehab {
810c0d06caSMauro Carvalho Chehab 	int status = -ENODEV;
820c0d06caSMauro Carvalho Chehab 
830c0d06caSMauro Carvalho Chehab 	if (dev->usbdev) {
840c0d06caSMauro Carvalho Chehab 
850c0d06caSMauro Carvalho Chehab 		/* cp must be memory that has been allocated by kmalloc */
860c0d06caSMauro Carvalho Chehab 		status = usb_control_msg(dev->usbdev,
870c0d06caSMauro Carvalho Chehab 				usb_sndctrlpipe(dev->usbdev, 0),
880c0d06caSMauro Carvalho Chehab 				request,
890c0d06caSMauro Carvalho Chehab 				USB_DIR_OUT | USB_TYPE_VENDOR |
900c0d06caSMauro Carvalho Chehab 					USB_RECIP_DEVICE,
910c0d06caSMauro Carvalho Chehab 				value, index, NULL, 0, 1000);
920c0d06caSMauro Carvalho Chehab 
930c0d06caSMauro Carvalho Chehab 		status = min(status, 0);
940c0d06caSMauro Carvalho Chehab 
950c0d06caSMauro Carvalho Chehab 		if (status < 0) {
9683afb32aSMauro Carvalho Chehab 			pr_err("%s() Failed sending control message, error %d.\n",
970c0d06caSMauro Carvalho Chehab 				__func__, status);
980c0d06caSMauro Carvalho Chehab 		}
990c0d06caSMauro Carvalho Chehab 
1000c0d06caSMauro Carvalho Chehab 	}
1010c0d06caSMauro Carvalho Chehab 
1020c0d06caSMauro Carvalho Chehab 	return status;
1030c0d06caSMauro Carvalho Chehab }
1040c0d06caSMauro Carvalho Chehab 
1050c0d06caSMauro Carvalho Chehab static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
1060c0d06caSMauro Carvalho Chehab 	u16 index, unsigned char *cp, u16 size)
1070c0d06caSMauro Carvalho Chehab {
1080c0d06caSMauro Carvalho Chehab 	int status = -ENODEV;
1090c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->mutex);
1100c0d06caSMauro Carvalho Chehab 	if (dev->usbdev) {
1110c0d06caSMauro Carvalho Chehab 		status = usb_control_msg(dev->usbdev,
1120c0d06caSMauro Carvalho Chehab 				usb_rcvctrlpipe(dev->usbdev, 0),
1130c0d06caSMauro Carvalho Chehab 				request,
1140c0d06caSMauro Carvalho Chehab 				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1150c0d06caSMauro Carvalho Chehab 				value, index,
1160c0d06caSMauro Carvalho Chehab 				dev->ctrlmsg, size, 1000);
1170c0d06caSMauro Carvalho Chehab 
1180c0d06caSMauro Carvalho Chehab 		status = min(status, 0);
1190c0d06caSMauro Carvalho Chehab 
1200c0d06caSMauro Carvalho Chehab 		if (status < 0) {
12183afb32aSMauro Carvalho Chehab 			pr_err("%s() Failed receiving control message, error %d.\n",
1220c0d06caSMauro Carvalho Chehab 				__func__, status);
1230c0d06caSMauro Carvalho Chehab 		}
1240c0d06caSMauro Carvalho Chehab 
1250c0d06caSMauro Carvalho Chehab 		/* the host controller requires heap allocated memory, which
1260c0d06caSMauro Carvalho Chehab 		   is why we didn't just pass "cp" into usb_control_msg */
1270c0d06caSMauro Carvalho Chehab 		memcpy(cp, dev->ctrlmsg, size);
1280c0d06caSMauro Carvalho Chehab 	}
1290c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->mutex);
1300c0d06caSMauro Carvalho Chehab 	return status;
1310c0d06caSMauro Carvalho Chehab }
1320c0d06caSMauro Carvalho Chehab 
133bed69196SRafael Lourenço de Lima Chehab static void au0828_unregister_media_device(struct au0828_dev *dev)
134bed69196SRafael Lourenço de Lima Chehab {
135bed69196SRafael Lourenço de Lima Chehab 
136bed69196SRafael Lourenço de Lima Chehab #ifdef CONFIG_MEDIA_CONTROLLER
137bed69196SRafael Lourenço de Lima Chehab 	if (dev->media_dev) {
138bed69196SRafael Lourenço de Lima Chehab 		media_device_unregister(dev->media_dev);
1399832e155SJavier Martinez Canillas 		media_device_cleanup(dev->media_dev);
140bed69196SRafael Lourenço de Lima Chehab 		kfree(dev->media_dev);
141bed69196SRafael Lourenço de Lima Chehab 		dev->media_dev = NULL;
142bed69196SRafael Lourenço de Lima Chehab 	}
143bed69196SRafael Lourenço de Lima Chehab #endif
144bed69196SRafael Lourenço de Lima Chehab }
145bed69196SRafael Lourenço de Lima Chehab 
1467b606ffdSMauro Carvalho Chehab void au0828_usb_release(struct au0828_dev *dev)
147823beb7eSHans Verkuil {
148bed69196SRafael Lourenço de Lima Chehab 	au0828_unregister_media_device(dev);
149bed69196SRafael Lourenço de Lima Chehab 
150823beb7eSHans Verkuil 	/* I2C */
151823beb7eSHans Verkuil 	au0828_i2c_unregister(dev);
152823beb7eSHans Verkuil 
153823beb7eSHans Verkuil 	kfree(dev);
154823beb7eSHans Verkuil }
155823beb7eSHans Verkuil 
1560c0d06caSMauro Carvalho Chehab static void au0828_usb_disconnect(struct usb_interface *interface)
1570c0d06caSMauro Carvalho Chehab {
1580c0d06caSMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
1590c0d06caSMauro Carvalho Chehab 
1600c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
1610c0d06caSMauro Carvalho Chehab 
162eb336eabSShuah Khan 	/* there is a small window after disconnect, before
163eb336eabSShuah Khan 	   dev->usbdev is NULL, for poll (e.g: IR) try to access
164eb336eabSShuah Khan 	   the device and fill the dmesg with error messages.
165eb336eabSShuah Khan 	   Set the status so poll routines can check and avoid
166eb336eabSShuah Khan 	   access after disconnect.
167eb336eabSShuah Khan 	*/
168eb336eabSShuah Khan 	dev->dev_state = DEV_DISCONNECTED;
169eb336eabSShuah Khan 
1702fcfd317SMauro Carvalho Chehab 	au0828_rc_unregister(dev);
1710c0d06caSMauro Carvalho Chehab 	/* Digital TV */
1720c0d06caSMauro Carvalho Chehab 	au0828_dvb_unregister(dev);
1730c0d06caSMauro Carvalho Chehab 
1740c0d06caSMauro Carvalho Chehab 	usb_set_intfdata(interface, NULL);
1750c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->mutex);
1760c0d06caSMauro Carvalho Chehab 	dev->usbdev = NULL;
1770c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->mutex);
1787b606ffdSMauro Carvalho Chehab 	if (au0828_analog_unregister(dev)) {
1797e9a8ad5SMauro Carvalho Chehab 		/*
1807e9a8ad5SMauro Carvalho Chehab 		 * No need to call au0828_usb_release() if V4L2 is enabled,
1817e9a8ad5SMauro Carvalho Chehab 		 * as this is already called via au0828_usb_v4l2_release()
1827e9a8ad5SMauro Carvalho Chehab 		 */
183823beb7eSHans Verkuil 		return;
184823beb7eSHans Verkuil 	}
185823beb7eSHans Verkuil 	au0828_usb_release(dev);
1860c0d06caSMauro Carvalho Chehab }
1870c0d06caSMauro Carvalho Chehab 
1889f806795SMauro Carvalho Chehab static int au0828_media_device_init(struct au0828_dev *dev,
189bed69196SRafael Lourenço de Lima Chehab 				    struct usb_device *udev)
190bed69196SRafael Lourenço de Lima Chehab {
191bed69196SRafael Lourenço de Lima Chehab #ifdef CONFIG_MEDIA_CONTROLLER
192bed69196SRafael Lourenço de Lima Chehab 	struct media_device *mdev;
193bed69196SRafael Lourenço de Lima Chehab 
194bed69196SRafael Lourenço de Lima Chehab 	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
195bed69196SRafael Lourenço de Lima Chehab 	if (!mdev)
1969f806795SMauro Carvalho Chehab 		return -ENOMEM;
197bed69196SRafael Lourenço de Lima Chehab 
198bed69196SRafael Lourenço de Lima Chehab 	mdev->dev = &udev->dev;
199bed69196SRafael Lourenço de Lima Chehab 
200bed69196SRafael Lourenço de Lima Chehab 	if (!dev->board.name)
201bed69196SRafael Lourenço de Lima Chehab 		strlcpy(mdev->model, "unknown au0828", sizeof(mdev->model));
202bed69196SRafael Lourenço de Lima Chehab 	else
203bed69196SRafael Lourenço de Lima Chehab 		strlcpy(mdev->model, dev->board.name, sizeof(mdev->model));
204bed69196SRafael Lourenço de Lima Chehab 	if (udev->serial)
205bed69196SRafael Lourenço de Lima Chehab 		strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
206bed69196SRafael Lourenço de Lima Chehab 	strcpy(mdev->bus_info, udev->devpath);
207bed69196SRafael Lourenço de Lima Chehab 	mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
208bed69196SRafael Lourenço de Lima Chehab 	mdev->driver_version = LINUX_VERSION_CODE;
209bed69196SRafael Lourenço de Lima Chehab 
2109832e155SJavier Martinez Canillas 	media_device_init(mdev);
211bed69196SRafael Lourenço de Lima Chehab 
212bed69196SRafael Lourenço de Lima Chehab 	dev->media_dev = mdev;
213bed69196SRafael Lourenço de Lima Chehab #endif
2149f806795SMauro Carvalho Chehab 	return 0;
215bed69196SRafael Lourenço de Lima Chehab }
216bed69196SRafael Lourenço de Lima Chehab 
217bed69196SRafael Lourenço de Lima Chehab 
2180c0d06caSMauro Carvalho Chehab static int au0828_usb_probe(struct usb_interface *interface,
2190c0d06caSMauro Carvalho Chehab 	const struct usb_device_id *id)
2200c0d06caSMauro Carvalho Chehab {
2218a4e7866SMichael Krufky 	int ifnum;
222f251b3e7STim Mester 	int retval = 0;
223f251b3e7STim Mester 
2240c0d06caSMauro Carvalho Chehab 	struct au0828_dev *dev;
2250c0d06caSMauro Carvalho Chehab 	struct usb_device *usbdev = interface_to_usbdev(interface);
2260c0d06caSMauro Carvalho Chehab 
2270c0d06caSMauro Carvalho Chehab 	ifnum = interface->altsetting->desc.bInterfaceNumber;
2280c0d06caSMauro Carvalho Chehab 
2290c0d06caSMauro Carvalho Chehab 	if (ifnum != 0)
2300c0d06caSMauro Carvalho Chehab 		return -ENODEV;
2310c0d06caSMauro Carvalho Chehab 
2320c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
2330c0d06caSMauro Carvalho Chehab 		le16_to_cpu(usbdev->descriptor.idVendor),
2340c0d06caSMauro Carvalho Chehab 		le16_to_cpu(usbdev->descriptor.idProduct),
2350c0d06caSMauro Carvalho Chehab 		ifnum);
2360c0d06caSMauro Carvalho Chehab 
2370c0d06caSMauro Carvalho Chehab 	/*
2380c0d06caSMauro Carvalho Chehab 	 * Make sure we have 480 Mbps of bandwidth, otherwise things like
2390c0d06caSMauro Carvalho Chehab 	 * video stream wouldn't likely work, since 12 Mbps is generally
2400c0d06caSMauro Carvalho Chehab 	 * not enough even for most Digital TV streams.
2410c0d06caSMauro Carvalho Chehab 	 */
2420c0d06caSMauro Carvalho Chehab 	if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
24383afb32aSMauro Carvalho Chehab 		pr_err("au0828: Device initialization failed.\n");
24483afb32aSMauro Carvalho Chehab 		pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
2450c0d06caSMauro Carvalho Chehab 		return -ENODEV;
2460c0d06caSMauro Carvalho Chehab 	}
2470c0d06caSMauro Carvalho Chehab 
2480c0d06caSMauro Carvalho Chehab 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2490c0d06caSMauro Carvalho Chehab 	if (dev == NULL) {
25083afb32aSMauro Carvalho Chehab 		pr_err("%s() Unable to allocate memory\n", __func__);
2510c0d06caSMauro Carvalho Chehab 		return -ENOMEM;
2520c0d06caSMauro Carvalho Chehab 	}
2530c0d06caSMauro Carvalho Chehab 
2540c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->lock);
2550c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->lock);
2560c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->mutex);
2570c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->dvb.lock);
2580c0d06caSMauro Carvalho Chehab 	dev->usbdev = usbdev;
2590c0d06caSMauro Carvalho Chehab 	dev->boardnr = id->driver_info;
260e42c8c6eSRafael Lourenço de Lima Chehab 	dev->board = au0828_boards[dev->boardnr];
261e42c8c6eSRafael Lourenço de Lima Chehab 
2629832e155SJavier Martinez Canillas 	/* Initialize the media controller */
2639f806795SMauro Carvalho Chehab 	retval = au0828_media_device_init(dev, usbdev);
2649f806795SMauro Carvalho Chehab 	if (retval) {
2659f806795SMauro Carvalho Chehab 		pr_err("%s() au0828_media_device_init failed\n",
2669f806795SMauro Carvalho Chehab 		       __func__);
2679f806795SMauro Carvalho Chehab 		mutex_unlock(&dev->lock);
2689f806795SMauro Carvalho Chehab 		kfree(dev);
2699f806795SMauro Carvalho Chehab 		return retval;
2709f806795SMauro Carvalho Chehab 	}
2710c0d06caSMauro Carvalho Chehab 
2727b606ffdSMauro Carvalho Chehab 	retval = au0828_v4l2_device_register(interface, dev);
2730c0d06caSMauro Carvalho Chehab 	if (retval) {
2747b606ffdSMauro Carvalho Chehab 		au0828_usb_v4l2_media_release(dev);
2750c0d06caSMauro Carvalho Chehab 		mutex_unlock(&dev->lock);
2760c0d06caSMauro Carvalho Chehab 		kfree(dev);
277e8c26f45SHans Verkuil 		return retval;
2780c0d06caSMauro Carvalho Chehab 	}
2790c0d06caSMauro Carvalho Chehab 
2800c0d06caSMauro Carvalho Chehab 	/* Power Up the bridge */
2810c0d06caSMauro Carvalho Chehab 	au0828_write(dev, REG_600, 1 << 4);
2820c0d06caSMauro Carvalho Chehab 
2830c0d06caSMauro Carvalho Chehab 	/* Bring up the GPIO's and supporting devices */
2840c0d06caSMauro Carvalho Chehab 	au0828_gpio_setup(dev);
2850c0d06caSMauro Carvalho Chehab 
2860c0d06caSMauro Carvalho Chehab 	/* I2C */
2870c0d06caSMauro Carvalho Chehab 	au0828_i2c_register(dev);
2880c0d06caSMauro Carvalho Chehab 
2890c0d06caSMauro Carvalho Chehab 	/* Setup */
2900c0d06caSMauro Carvalho Chehab 	au0828_card_setup(dev);
2910c0d06caSMauro Carvalho Chehab 
2920c0d06caSMauro Carvalho Chehab 	/* Analog TV */
29382e92f4cSMauro Carvalho Chehab 	retval = au0828_analog_register(dev, interface);
29482e92f4cSMauro Carvalho Chehab 	if (retval) {
29582e92f4cSMauro Carvalho Chehab 		pr_err("%s() au0282_dev_register failed to register on V4L2\n",
29682e92f4cSMauro Carvalho Chehab 			__func__);
29782e92f4cSMauro Carvalho Chehab 		goto done;
29882e92f4cSMauro Carvalho Chehab 	}
29982e92f4cSMauro Carvalho Chehab 
3000c0d06caSMauro Carvalho Chehab 	/* Digital TV */
301f251b3e7STim Mester 	retval = au0828_dvb_register(dev);
302f251b3e7STim Mester 	if (retval)
303f251b3e7STim Mester 		pr_err("%s() au0282_dev_register failed\n",
304f251b3e7STim Mester 		       __func__);
305f251b3e7STim Mester 
3062fcfd317SMauro Carvalho Chehab 	/* Remote controller */
3072fcfd317SMauro Carvalho Chehab 	au0828_rc_register(dev);
3080c0d06caSMauro Carvalho Chehab 
3092fcfd317SMauro Carvalho Chehab 	/*
3102fcfd317SMauro Carvalho Chehab 	 * Store the pointer to the au0828_dev so it can be accessed in
3112fcfd317SMauro Carvalho Chehab 	 * au0828_usb_disconnect
3122fcfd317SMauro Carvalho Chehab 	 */
3130c0d06caSMauro Carvalho Chehab 	usb_set_intfdata(interface, dev);
3140c0d06caSMauro Carvalho Chehab 
31583afb32aSMauro Carvalho Chehab 	pr_info("Registered device AU0828 [%s]\n",
3160c0d06caSMauro Carvalho Chehab 		dev->board.name == NULL ? "Unset" : dev->board.name);
3170c0d06caSMauro Carvalho Chehab 
3180c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
3190c0d06caSMauro Carvalho Chehab 
3209832e155SJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER
3219832e155SJavier Martinez Canillas 	retval = media_device_register(dev->media_dev);
3229832e155SJavier Martinez Canillas #endif
3239832e155SJavier Martinez Canillas 
3249832e155SJavier Martinez Canillas done:
3259832e155SJavier Martinez Canillas 	if (retval < 0)
3269832e155SJavier Martinez Canillas 		au0828_usb_disconnect(interface);
3279832e155SJavier Martinez Canillas 
328f251b3e7STim Mester 	return retval;
3290c0d06caSMauro Carvalho Chehab }
3300c0d06caSMauro Carvalho Chehab 
331aaeac199SMauro Carvalho Chehab static int au0828_suspend(struct usb_interface *interface,
332aaeac199SMauro Carvalho Chehab 				pm_message_t message)
333aaeac199SMauro Carvalho Chehab {
334aaeac199SMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
335aaeac199SMauro Carvalho Chehab 
336aaeac199SMauro Carvalho Chehab 	if (!dev)
337aaeac199SMauro Carvalho Chehab 		return 0;
338aaeac199SMauro Carvalho Chehab 
33981187240SMauro Carvalho Chehab 	pr_info("Suspend\n");
34081187240SMauro Carvalho Chehab 
341aaeac199SMauro Carvalho Chehab 	au0828_rc_suspend(dev);
3421a1ba95eSMauro Carvalho Chehab 	au0828_v4l2_suspend(dev);
343b799de75SMauro Carvalho Chehab 	au0828_dvb_suspend(dev);
344aaeac199SMauro Carvalho Chehab 
345aaeac199SMauro Carvalho Chehab 	/* FIXME: should suspend also ATV/DTV */
346aaeac199SMauro Carvalho Chehab 
347aaeac199SMauro Carvalho Chehab 	return 0;
348aaeac199SMauro Carvalho Chehab }
349aaeac199SMauro Carvalho Chehab 
350aaeac199SMauro Carvalho Chehab static int au0828_resume(struct usb_interface *interface)
351aaeac199SMauro Carvalho Chehab {
352aaeac199SMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
353aaeac199SMauro Carvalho Chehab 	if (!dev)
354aaeac199SMauro Carvalho Chehab 		return 0;
355aaeac199SMauro Carvalho Chehab 
35681187240SMauro Carvalho Chehab 	pr_info("Resume\n");
35781187240SMauro Carvalho Chehab 
358fa500461SMauro Carvalho Chehab 	/* Power Up the bridge */
359fa500461SMauro Carvalho Chehab 	au0828_write(dev, REG_600, 1 << 4);
360fa500461SMauro Carvalho Chehab 
361fa500461SMauro Carvalho Chehab 	/* Bring up the GPIO's and supporting devices */
362fa500461SMauro Carvalho Chehab 	au0828_gpio_setup(dev);
363fa500461SMauro Carvalho Chehab 
364aaeac199SMauro Carvalho Chehab 	au0828_rc_resume(dev);
3651a1ba95eSMauro Carvalho Chehab 	au0828_v4l2_resume(dev);
366b799de75SMauro Carvalho Chehab 	au0828_dvb_resume(dev);
367aaeac199SMauro Carvalho Chehab 
368aaeac199SMauro Carvalho Chehab 	/* FIXME: should resume also ATV/DTV */
369aaeac199SMauro Carvalho Chehab 
370aaeac199SMauro Carvalho Chehab 	return 0;
371aaeac199SMauro Carvalho Chehab }
372aaeac199SMauro Carvalho Chehab 
3730c0d06caSMauro Carvalho Chehab static struct usb_driver au0828_usb_driver = {
37483afb32aSMauro Carvalho Chehab 	.name		= KBUILD_MODNAME,
3750c0d06caSMauro Carvalho Chehab 	.probe		= au0828_usb_probe,
3760c0d06caSMauro Carvalho Chehab 	.disconnect	= au0828_usb_disconnect,
3770c0d06caSMauro Carvalho Chehab 	.id_table	= au0828_usb_id_table,
378aaeac199SMauro Carvalho Chehab 	.suspend	= au0828_suspend,
379aaeac199SMauro Carvalho Chehab 	.resume		= au0828_resume,
380aaeac199SMauro Carvalho Chehab 	.reset_resume	= au0828_resume,
3810c0d06caSMauro Carvalho Chehab };
3820c0d06caSMauro Carvalho Chehab 
3830c0d06caSMauro Carvalho Chehab static int __init au0828_init(void)
3840c0d06caSMauro Carvalho Chehab {
3850c0d06caSMauro Carvalho Chehab 	int ret;
3860c0d06caSMauro Carvalho Chehab 
3870c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 1)
38883afb32aSMauro Carvalho Chehab 		pr_info("%s() Debugging is enabled\n", __func__);
3890c0d06caSMauro Carvalho Chehab 
3900c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 2)
39183afb32aSMauro Carvalho Chehab 		pr_info("%s() USB Debugging is enabled\n", __func__);
3920c0d06caSMauro Carvalho Chehab 
3930c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 4)
39483afb32aSMauro Carvalho Chehab 		pr_info("%s() I2C Debugging is enabled\n", __func__);
3950c0d06caSMauro Carvalho Chehab 
3960c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 8)
39783afb32aSMauro Carvalho Chehab 		pr_info("%s() Bridge Debugging is enabled\n",
3980c0d06caSMauro Carvalho Chehab 		       __func__);
3990c0d06caSMauro Carvalho Chehab 
4002fcfd317SMauro Carvalho Chehab 	if (au0828_debug & 16)
40183afb32aSMauro Carvalho Chehab 		pr_info("%s() IR Debugging is enabled\n",
4022fcfd317SMauro Carvalho Chehab 		       __func__);
4032fcfd317SMauro Carvalho Chehab 
40483afb32aSMauro Carvalho Chehab 	pr_info("au0828 driver loaded\n");
4050c0d06caSMauro Carvalho Chehab 
4060c0d06caSMauro Carvalho Chehab 	ret = usb_register(&au0828_usb_driver);
4070c0d06caSMauro Carvalho Chehab 	if (ret)
40883afb32aSMauro Carvalho Chehab 		pr_err("usb_register failed, error = %d\n", ret);
4090c0d06caSMauro Carvalho Chehab 
4100c0d06caSMauro Carvalho Chehab 	return ret;
4110c0d06caSMauro Carvalho Chehab }
4120c0d06caSMauro Carvalho Chehab 
4130c0d06caSMauro Carvalho Chehab static void __exit au0828_exit(void)
4140c0d06caSMauro Carvalho Chehab {
4150c0d06caSMauro Carvalho Chehab 	usb_deregister(&au0828_usb_driver);
4160c0d06caSMauro Carvalho Chehab }
4170c0d06caSMauro Carvalho Chehab 
4180c0d06caSMauro Carvalho Chehab module_init(au0828_init);
4190c0d06caSMauro Carvalho Chehab module_exit(au0828_exit);
4200c0d06caSMauro Carvalho Chehab 
4210c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
4220c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
4230c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL");
4242fcfd317SMauro Carvalho Chehab MODULE_VERSION("0.0.3");
425