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"
23f90c5d79SShuah Khan #include "au8522.h"
2483afb32aSMauro Carvalho Chehab 
250c0d06caSMauro Carvalho Chehab #include <linux/module.h>
260c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
270c0d06caSMauro Carvalho Chehab #include <linux/videodev2.h>
280c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
290c0d06caSMauro Carvalho Chehab #include <linux/mutex.h>
300c0d06caSMauro Carvalho Chehab 
31188d2d55SMauro Carvalho Chehab /* Due to enum tuner_pad_index */
32188d2d55SMauro Carvalho Chehab #include <media/tuner.h>
33188d2d55SMauro Carvalho Chehab 
340c0d06caSMauro Carvalho Chehab /*
350c0d06caSMauro Carvalho Chehab  * 1 = General debug messages
360c0d06caSMauro Carvalho Chehab  * 2 = USB handling
370c0d06caSMauro Carvalho Chehab  * 4 = I2C related
380c0d06caSMauro Carvalho Chehab  * 8 = Bridge related
392fcfd317SMauro Carvalho Chehab  * 16 = IR related
400c0d06caSMauro Carvalho Chehab  */
410c0d06caSMauro Carvalho Chehab int au0828_debug;
420c0d06caSMauro Carvalho Chehab module_param_named(debug, au0828_debug, int, 0644);
432fcfd317SMauro Carvalho Chehab MODULE_PARM_DESC(debug,
442fcfd317SMauro Carvalho Chehab 		 "set debug bitmask: 1=general, 2=USB, 4=I2C, 8=bridge, 16=IR");
450c0d06caSMauro Carvalho Chehab 
460c0d06caSMauro Carvalho Chehab static unsigned int disable_usb_speed_check;
470c0d06caSMauro Carvalho Chehab module_param(disable_usb_speed_check, int, 0444);
480c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(disable_usb_speed_check,
490c0d06caSMauro Carvalho Chehab 		 "override min bandwidth requirement of 480M bps");
500c0d06caSMauro Carvalho Chehab 
510c0d06caSMauro Carvalho Chehab #define _AU0828_BULKPIPE 0x03
520c0d06caSMauro Carvalho Chehab #define _BULKPIPESIZE 0xffff
530c0d06caSMauro Carvalho Chehab 
540c0d06caSMauro Carvalho Chehab static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
550c0d06caSMauro Carvalho Chehab 			    u16 index);
560c0d06caSMauro Carvalho Chehab static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
570c0d06caSMauro Carvalho Chehab 	u16 index, unsigned char *cp, u16 size);
580c0d06caSMauro Carvalho Chehab 
590c0d06caSMauro Carvalho Chehab /* USB Direction */
600c0d06caSMauro Carvalho Chehab #define CMD_REQUEST_IN		0x00
610c0d06caSMauro Carvalho Chehab #define CMD_REQUEST_OUT		0x01
620c0d06caSMauro Carvalho Chehab 
630c0d06caSMauro Carvalho Chehab u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
640c0d06caSMauro Carvalho Chehab {
650c0d06caSMauro Carvalho Chehab 	u8 result = 0;
660c0d06caSMauro Carvalho Chehab 
670c0d06caSMauro Carvalho Chehab 	recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, &result, 1);
680c0d06caSMauro Carvalho Chehab 	dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, result);
690c0d06caSMauro Carvalho Chehab 
700c0d06caSMauro Carvalho Chehab 	return result;
710c0d06caSMauro Carvalho Chehab }
720c0d06caSMauro Carvalho Chehab 
730c0d06caSMauro Carvalho Chehab u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
740c0d06caSMauro Carvalho Chehab {
750c0d06caSMauro Carvalho Chehab 	dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
760c0d06caSMauro Carvalho Chehab 	return send_control_msg(dev, CMD_REQUEST_OUT, val, reg);
770c0d06caSMauro Carvalho Chehab }
780c0d06caSMauro Carvalho Chehab 
790c0d06caSMauro Carvalho Chehab static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
800c0d06caSMauro Carvalho Chehab 	u16 index)
810c0d06caSMauro Carvalho Chehab {
820c0d06caSMauro Carvalho Chehab 	int status = -ENODEV;
830c0d06caSMauro Carvalho Chehab 
840c0d06caSMauro Carvalho Chehab 	if (dev->usbdev) {
850c0d06caSMauro Carvalho Chehab 
860c0d06caSMauro Carvalho Chehab 		/* cp must be memory that has been allocated by kmalloc */
870c0d06caSMauro Carvalho Chehab 		status = usb_control_msg(dev->usbdev,
880c0d06caSMauro Carvalho Chehab 				usb_sndctrlpipe(dev->usbdev, 0),
890c0d06caSMauro Carvalho Chehab 				request,
900c0d06caSMauro Carvalho Chehab 				USB_DIR_OUT | USB_TYPE_VENDOR |
910c0d06caSMauro Carvalho Chehab 					USB_RECIP_DEVICE,
920c0d06caSMauro Carvalho Chehab 				value, index, NULL, 0, 1000);
930c0d06caSMauro Carvalho Chehab 
940c0d06caSMauro Carvalho Chehab 		status = min(status, 0);
950c0d06caSMauro Carvalho Chehab 
960c0d06caSMauro Carvalho Chehab 		if (status < 0) {
9783afb32aSMauro Carvalho Chehab 			pr_err("%s() Failed sending control message, error %d.\n",
980c0d06caSMauro Carvalho Chehab 				__func__, status);
990c0d06caSMauro Carvalho Chehab 		}
1000c0d06caSMauro Carvalho Chehab 
1010c0d06caSMauro Carvalho Chehab 	}
1020c0d06caSMauro Carvalho Chehab 
1030c0d06caSMauro Carvalho Chehab 	return status;
1040c0d06caSMauro Carvalho Chehab }
1050c0d06caSMauro Carvalho Chehab 
1060c0d06caSMauro Carvalho Chehab static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
1070c0d06caSMauro Carvalho Chehab 	u16 index, unsigned char *cp, u16 size)
1080c0d06caSMauro Carvalho Chehab {
1090c0d06caSMauro Carvalho Chehab 	int status = -ENODEV;
1100c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->mutex);
1110c0d06caSMauro Carvalho Chehab 	if (dev->usbdev) {
1120c0d06caSMauro Carvalho Chehab 		status = usb_control_msg(dev->usbdev,
1130c0d06caSMauro Carvalho Chehab 				usb_rcvctrlpipe(dev->usbdev, 0),
1140c0d06caSMauro Carvalho Chehab 				request,
1150c0d06caSMauro Carvalho Chehab 				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1160c0d06caSMauro Carvalho Chehab 				value, index,
1170c0d06caSMauro Carvalho Chehab 				dev->ctrlmsg, size, 1000);
1180c0d06caSMauro Carvalho Chehab 
1190c0d06caSMauro Carvalho Chehab 		status = min(status, 0);
1200c0d06caSMauro Carvalho Chehab 
1210c0d06caSMauro Carvalho Chehab 		if (status < 0) {
12283afb32aSMauro Carvalho Chehab 			pr_err("%s() Failed receiving control message, error %d.\n",
1230c0d06caSMauro Carvalho Chehab 				__func__, status);
1240c0d06caSMauro Carvalho Chehab 		}
1250c0d06caSMauro Carvalho Chehab 
1260c0d06caSMauro Carvalho Chehab 		/* the host controller requires heap allocated memory, which
1270c0d06caSMauro Carvalho Chehab 		   is why we didn't just pass "cp" into usb_control_msg */
1280c0d06caSMauro Carvalho Chehab 		memcpy(cp, dev->ctrlmsg, size);
1290c0d06caSMauro Carvalho Chehab 	}
1300c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->mutex);
1310c0d06caSMauro Carvalho Chehab 	return status;
1320c0d06caSMauro Carvalho Chehab }
1330c0d06caSMauro Carvalho Chehab 
134bed69196SRafael Lourenço de Lima Chehab static void au0828_unregister_media_device(struct au0828_dev *dev)
135bed69196SRafael Lourenço de Lima Chehab {
136bed69196SRafael Lourenço de Lima Chehab 
137bed69196SRafael Lourenço de Lima Chehab #ifdef CONFIG_MEDIA_CONTROLLER
138182dde7cSShuah Khan 	if (dev->media_dev &&
139182dde7cSShuah Khan 		media_devnode_is_registered(&dev->media_dev->devnode)) {
140ffa8576aSShuah Khan 		/* clear enable_source, disable_source */
141ffa8576aSShuah Khan 		dev->media_dev->source_priv = NULL;
142ffa8576aSShuah Khan 		dev->media_dev->enable_source = NULL;
143ffa8576aSShuah Khan 		dev->media_dev->disable_source = NULL;
144ffa8576aSShuah Khan 
145bed69196SRafael Lourenço de Lima Chehab 		media_device_unregister(dev->media_dev);
1469832e155SJavier Martinez Canillas 		media_device_cleanup(dev->media_dev);
147bed69196SRafael Lourenço de Lima Chehab 		dev->media_dev = NULL;
148bed69196SRafael Lourenço de Lima Chehab 	}
149bed69196SRafael Lourenço de Lima Chehab #endif
150bed69196SRafael Lourenço de Lima Chehab }
151bed69196SRafael Lourenço de Lima Chehab 
1527b606ffdSMauro Carvalho Chehab void au0828_usb_release(struct au0828_dev *dev)
153823beb7eSHans Verkuil {
154bed69196SRafael Lourenço de Lima Chehab 	au0828_unregister_media_device(dev);
155bed69196SRafael Lourenço de Lima Chehab 
156823beb7eSHans Verkuil 	/* I2C */
157823beb7eSHans Verkuil 	au0828_i2c_unregister(dev);
158823beb7eSHans Verkuil 
159823beb7eSHans Verkuil 	kfree(dev);
160823beb7eSHans Verkuil }
161823beb7eSHans Verkuil 
1620c0d06caSMauro Carvalho Chehab static void au0828_usb_disconnect(struct usb_interface *interface)
1630c0d06caSMauro Carvalho Chehab {
1640c0d06caSMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
1650c0d06caSMauro Carvalho Chehab 
1660c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
1670c0d06caSMauro Carvalho Chehab 
168eb336eabSShuah Khan 	/* there is a small window after disconnect, before
169eb336eabSShuah Khan 	   dev->usbdev is NULL, for poll (e.g: IR) try to access
170eb336eabSShuah Khan 	   the device and fill the dmesg with error messages.
171eb336eabSShuah Khan 	   Set the status so poll routines can check and avoid
172eb336eabSShuah Khan 	   access after disconnect.
173eb336eabSShuah Khan 	*/
174e8e3039fSMauro Carvalho Chehab 	set_bit(DEV_DISCONNECTED, &dev->dev_state);
175eb336eabSShuah Khan 
1762fcfd317SMauro Carvalho Chehab 	au0828_rc_unregister(dev);
1770c0d06caSMauro Carvalho Chehab 	/* Digital TV */
1780c0d06caSMauro Carvalho Chehab 	au0828_dvb_unregister(dev);
1790c0d06caSMauro Carvalho Chehab 
1800c0d06caSMauro Carvalho Chehab 	usb_set_intfdata(interface, NULL);
1810c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->mutex);
1820c0d06caSMauro Carvalho Chehab 	dev->usbdev = NULL;
1830c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->mutex);
1847b606ffdSMauro Carvalho Chehab 	if (au0828_analog_unregister(dev)) {
1857e9a8ad5SMauro Carvalho Chehab 		/*
1867e9a8ad5SMauro Carvalho Chehab 		 * No need to call au0828_usb_release() if V4L2 is enabled,
1877e9a8ad5SMauro Carvalho Chehab 		 * as this is already called via au0828_usb_v4l2_release()
1887e9a8ad5SMauro Carvalho Chehab 		 */
189823beb7eSHans Verkuil 		return;
190823beb7eSHans Verkuil 	}
191823beb7eSHans Verkuil 	au0828_usb_release(dev);
1920c0d06caSMauro Carvalho Chehab }
1930c0d06caSMauro Carvalho Chehab 
1949f806795SMauro Carvalho Chehab static int au0828_media_device_init(struct au0828_dev *dev,
195bed69196SRafael Lourenço de Lima Chehab 				    struct usb_device *udev)
196bed69196SRafael Lourenço de Lima Chehab {
197bed69196SRafael Lourenço de Lima Chehab #ifdef CONFIG_MEDIA_CONTROLLER
198bed69196SRafael Lourenço de Lima Chehab 	struct media_device *mdev;
199bed69196SRafael Lourenço de Lima Chehab 
200182dde7cSShuah Khan 	mdev = media_device_get_devres(&udev->dev);
201bed69196SRafael Lourenço de Lima Chehab 	if (!mdev)
2029f806795SMauro Carvalho Chehab 		return -ENOMEM;
203bed69196SRafael Lourenço de Lima Chehab 
2047b12adf6SShuah Khan 	/* check if media device is already initialized */
2057b12adf6SShuah Khan 	if (!mdev->dev)
206182dde7cSShuah Khan 		media_device_usb_init(mdev, udev, udev->product);
2076cf5dad1SMauro Carvalho Chehab 
208bed69196SRafael Lourenço de Lima Chehab 	dev->media_dev = mdev;
209bed69196SRafael Lourenço de Lima Chehab #endif
2109f806795SMauro Carvalho Chehab 	return 0;
211bed69196SRafael Lourenço de Lima Chehab }
212bed69196SRafael Lourenço de Lima Chehab 
2130a82edd0SArnd Bergmann #ifdef CONFIG_MEDIA_CONTROLLER
214f90c5d79SShuah Khan static void au0828_media_graph_notify(struct media_entity *new,
215f90c5d79SShuah Khan 				      void *notify_data)
216f90c5d79SShuah Khan {
217f90c5d79SShuah Khan 	struct au0828_dev *dev = (struct au0828_dev *) notify_data;
218f90c5d79SShuah Khan 	int ret;
2199096cae1SShuah Khan 	struct media_entity *entity, *mixer = NULL, *decoder = NULL;
220f90c5d79SShuah Khan 
2219096cae1SShuah Khan 	if (!new) {
2229096cae1SShuah Khan 		/*
2239096cae1SShuah Khan 		 * Called during au0828 probe time to connect
2249096cae1SShuah Khan 		 * entites that were created prior to registering
2259096cae1SShuah Khan 		 * the notify handler. Find mixer and decoder.
2269096cae1SShuah Khan 		*/
2279096cae1SShuah Khan 		media_device_for_each_entity(entity, dev->media_dev) {
2289096cae1SShuah Khan 			if (entity->function == MEDIA_ENT_F_AUDIO_MIXER)
2299096cae1SShuah Khan 				mixer = entity;
2309096cae1SShuah Khan 			else if (entity->function == MEDIA_ENT_F_ATV_DECODER)
2319096cae1SShuah Khan 				decoder = entity;
2329096cae1SShuah Khan 		}
2339096cae1SShuah Khan 		goto create_link;
2349096cae1SShuah Khan 	}
235f90c5d79SShuah Khan 
236f90c5d79SShuah Khan 	switch (new->function) {
237f90c5d79SShuah Khan 	case MEDIA_ENT_F_AUDIO_MIXER:
2389096cae1SShuah Khan 		mixer = new;
2399096cae1SShuah Khan 		if (dev->decoder)
2409096cae1SShuah Khan 			decoder = dev->decoder;
2419096cae1SShuah Khan 		break;
2429096cae1SShuah Khan 	case MEDIA_ENT_F_ATV_DECODER:
2439096cae1SShuah Khan 		/* In case, Mixer is added first, find mixer and create link */
2449096cae1SShuah Khan 		media_device_for_each_entity(entity, dev->media_dev) {
2459096cae1SShuah Khan 			if (entity->function == MEDIA_ENT_F_AUDIO_MIXER)
2469096cae1SShuah Khan 				mixer = entity;
2479096cae1SShuah Khan 		}
2489096cae1SShuah Khan 		decoder = new;
249f90c5d79SShuah Khan 		break;
250f90c5d79SShuah Khan 	default:
251f90c5d79SShuah Khan 		break;
252f90c5d79SShuah Khan 	}
2539096cae1SShuah Khan 
2549096cae1SShuah Khan create_link:
2559096cae1SShuah Khan 	if (decoder && mixer) {
2569096cae1SShuah Khan 		ret = media_create_pad_link(decoder,
2579096cae1SShuah Khan 					    DEMOD_PAD_AUDIO_OUT,
2589096cae1SShuah Khan 					    mixer, 0,
2599096cae1SShuah Khan 					    MEDIA_LNK_FL_ENABLED);
2609096cae1SShuah Khan 		if (ret)
2619096cae1SShuah Khan 			dev_err(&dev->usbdev->dev,
2629096cae1SShuah Khan 				"Mixer Pad Link Create Error: %d\n", ret);
2639096cae1SShuah Khan 	}
264f90c5d79SShuah Khan }
265f90c5d79SShuah Khan 
266c94903f1SShuah Khan static int au0828_enable_source(struct media_entity *entity,
267c94903f1SShuah Khan 				struct media_pipeline *pipe)
268c94903f1SShuah Khan {
269c94903f1SShuah Khan 	struct media_entity  *source, *find_source;
270c94903f1SShuah Khan 	struct media_entity *sink;
271c94903f1SShuah Khan 	struct media_link *link, *found_link = NULL;
272c94903f1SShuah Khan 	int ret = 0;
273c94903f1SShuah Khan 	struct media_device *mdev = entity->graph_obj.mdev;
274c94903f1SShuah Khan 	struct au0828_dev *dev;
275c94903f1SShuah Khan 
276c94903f1SShuah Khan 	if (!mdev)
277c94903f1SShuah Khan 		return -ENODEV;
278c94903f1SShuah Khan 
279c94903f1SShuah Khan 	mutex_lock(&mdev->graph_mutex);
280c94903f1SShuah Khan 
281c94903f1SShuah Khan 	dev = mdev->source_priv;
282c94903f1SShuah Khan 
283c94903f1SShuah Khan 	/*
284c94903f1SShuah Khan 	 * For Audio and V4L2 entity, find the link to which decoder
285c94903f1SShuah Khan 	 * is the sink. Look for an active link between decoder and
286c94903f1SShuah Khan 	 * source (tuner/s-video/Composite), if one exists, nothing
287c94903f1SShuah Khan 	 * to do. If not, look for any  active links between source
288c94903f1SShuah Khan 	 * and any other entity. If one exists, source is busy. If
289c94903f1SShuah Khan 	 * source is free, setup link and start pipeline from source.
290c94903f1SShuah Khan 	 * For DVB FE entity, the source for the link is the tuner.
291c94903f1SShuah Khan 	 * Check if tuner is available and setup link and start
292c94903f1SShuah Khan 	 * pipeline.
293c94903f1SShuah Khan 	*/
294c94903f1SShuah Khan 	if (entity->function == MEDIA_ENT_F_DTV_DEMOD) {
295c94903f1SShuah Khan 		sink = entity;
296c94903f1SShuah Khan 		find_source = dev->tuner;
297c94903f1SShuah Khan 	} else {
298c94903f1SShuah Khan 		/* Analog isn't configured or register failed */
299c94903f1SShuah Khan 		if (!dev->decoder) {
300c94903f1SShuah Khan 			ret = -ENODEV;
301c94903f1SShuah Khan 			goto end;
302c94903f1SShuah Khan 		}
303c94903f1SShuah Khan 
304c94903f1SShuah Khan 		sink = dev->decoder;
305c94903f1SShuah Khan 
306c94903f1SShuah Khan 		/*
307c94903f1SShuah Khan 		 * Default input is tuner and default input_type
308c94903f1SShuah Khan 		 * is AU0828_VMUX_TELEVISION.
309c94903f1SShuah Khan 		 * FIXME:
310c94903f1SShuah Khan 		 * There is a problem when s_input is called to
311c94903f1SShuah Khan 		 * change the default input. s_input will try to
312c94903f1SShuah Khan 		 * enable_source before attempting to change the
313c94903f1SShuah Khan 		 * input on the device, and will end up enabling
314c94903f1SShuah Khan 		 * default source which is tuner.
315c94903f1SShuah Khan 		 *
316c94903f1SShuah Khan 		 * Additional logic is necessary in au0828
317c94903f1SShuah Khan 		 * to detect that the input has changed and
318c94903f1SShuah Khan 		 * enable the right source.
319c94903f1SShuah Khan 		*/
320c94903f1SShuah Khan 
321c94903f1SShuah Khan 		if (dev->input_type == AU0828_VMUX_TELEVISION)
322c94903f1SShuah Khan 			find_source = dev->tuner;
323c94903f1SShuah Khan 		else if (dev->input_type == AU0828_VMUX_SVIDEO ||
324c94903f1SShuah Khan 			 dev->input_type == AU0828_VMUX_COMPOSITE)
325c94903f1SShuah Khan 			find_source = &dev->input_ent[dev->input_type];
326c94903f1SShuah Khan 		else {
327c94903f1SShuah Khan 			/* unknown input - let user select input */
328c94903f1SShuah Khan 			ret = 0;
329c94903f1SShuah Khan 			goto end;
330c94903f1SShuah Khan 		}
331c94903f1SShuah Khan 	}
332c94903f1SShuah Khan 
333c94903f1SShuah Khan 	/* Is an active link between sink and source */
334c94903f1SShuah Khan 	if (dev->active_link) {
335c94903f1SShuah Khan 		/*
336c94903f1SShuah Khan 		 * If DVB is using the tuner and calling entity is
337c94903f1SShuah Khan 		 * audio/video, the following check will be false,
338c94903f1SShuah Khan 		 * since sink is different. Result is Busy.
339c94903f1SShuah Khan 		 */
340c94903f1SShuah Khan 		if (dev->active_link->sink->entity == sink &&
341c94903f1SShuah Khan 		    dev->active_link->source->entity == find_source) {
342c94903f1SShuah Khan 			/*
343c94903f1SShuah Khan 			 * Either ALSA or Video own tuner. sink is
344c94903f1SShuah Khan 			 * the same for both. Prevent Video stepping
345c94903f1SShuah Khan 			 * on ALSA when ALSA owns the source.
346c94903f1SShuah Khan 			*/
347c94903f1SShuah Khan 			if (dev->active_link_owner != entity &&
348c94903f1SShuah Khan 			    dev->active_link_owner->function ==
349c94903f1SShuah Khan 						MEDIA_ENT_F_AUDIO_CAPTURE) {
350c94903f1SShuah Khan 				pr_debug("ALSA has the tuner\n");
351c94903f1SShuah Khan 				ret = -EBUSY;
352c94903f1SShuah Khan 				goto end;
353c94903f1SShuah Khan 			}
354c94903f1SShuah Khan 			ret = 0;
355c94903f1SShuah Khan 			goto end;
356c94903f1SShuah Khan 		} else {
357c94903f1SShuah Khan 			ret = -EBUSY;
358c94903f1SShuah Khan 			goto end;
359c94903f1SShuah Khan 		}
360c94903f1SShuah Khan 	}
361c94903f1SShuah Khan 
362c94903f1SShuah Khan 	list_for_each_entry(link, &sink->links, list) {
363c94903f1SShuah Khan 		/* Check sink, and source */
364c94903f1SShuah Khan 		if (link->sink->entity == sink &&
365c94903f1SShuah Khan 		    link->source->entity == find_source) {
366c94903f1SShuah Khan 			found_link = link;
367c94903f1SShuah Khan 			break;
368c94903f1SShuah Khan 		}
369c94903f1SShuah Khan 	}
370c94903f1SShuah Khan 
371c94903f1SShuah Khan 	if (!found_link) {
372c94903f1SShuah Khan 		ret = -ENODEV;
373c94903f1SShuah Khan 		goto end;
374c94903f1SShuah Khan 	}
375c94903f1SShuah Khan 
376c94903f1SShuah Khan 	/* activate link between source and sink and start pipeline */
377c94903f1SShuah Khan 	source = found_link->source->entity;
378c94903f1SShuah Khan 	ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED);
379c94903f1SShuah Khan 	if (ret) {
380c94903f1SShuah Khan 		pr_err("Activate tuner link %s->%s. Error %d\n",
381c94903f1SShuah Khan 			source->name, sink->name, ret);
382c94903f1SShuah Khan 		goto end;
383c94903f1SShuah Khan 	}
384c94903f1SShuah Khan 
385c94903f1SShuah Khan 	ret = __media_entity_pipeline_start(entity, pipe);
386c94903f1SShuah Khan 	if (ret) {
387c94903f1SShuah Khan 		pr_err("Start Pipeline: %s->%s Error %d\n",
388c94903f1SShuah Khan 			source->name, entity->name, ret);
389c94903f1SShuah Khan 		ret = __media_entity_setup_link(found_link, 0);
390c94903f1SShuah Khan 		pr_err("Deactivate link Error %d\n", ret);
391c94903f1SShuah Khan 		goto end;
392c94903f1SShuah Khan 	}
393c94903f1SShuah Khan 	/*
394c94903f1SShuah Khan 	 * save active link and active link owner to avoid audio
395c94903f1SShuah Khan 	 * deactivating video owned link from disable_source and
396c94903f1SShuah Khan 	 * vice versa
397c94903f1SShuah Khan 	*/
398c94903f1SShuah Khan 	dev->active_link = found_link;
399c94903f1SShuah Khan 	dev->active_link_owner = entity;
400c94903f1SShuah Khan 	dev->active_source = source;
401c94903f1SShuah Khan 	dev->active_sink = sink;
402c94903f1SShuah Khan 
403c94903f1SShuah Khan 	pr_debug("Enabled Source: %s->%s->%s Ret %d\n",
404c94903f1SShuah Khan 		 dev->active_source->name, dev->active_sink->name,
405c94903f1SShuah Khan 		 dev->active_link_owner->name, ret);
406c94903f1SShuah Khan end:
407c94903f1SShuah Khan 	mutex_unlock(&mdev->graph_mutex);
408c94903f1SShuah Khan 	pr_debug("au0828_enable_source() end %s %d %d\n",
409c94903f1SShuah Khan 		 entity->name, entity->function, ret);
410c94903f1SShuah Khan 	return ret;
411c94903f1SShuah Khan }
412c94903f1SShuah Khan 
413c94903f1SShuah Khan static void au0828_disable_source(struct media_entity *entity)
414c94903f1SShuah Khan {
415c94903f1SShuah Khan 	int ret = 0;
416c94903f1SShuah Khan 	struct media_device *mdev = entity->graph_obj.mdev;
417c94903f1SShuah Khan 	struct au0828_dev *dev;
418c94903f1SShuah Khan 
419c94903f1SShuah Khan 	if (!mdev)
420c94903f1SShuah Khan 		return;
421c94903f1SShuah Khan 
422c94903f1SShuah Khan 	mutex_lock(&mdev->graph_mutex);
423c94903f1SShuah Khan 	dev = mdev->source_priv;
424c94903f1SShuah Khan 
425c94903f1SShuah Khan 	if (!dev->active_link) {
426c94903f1SShuah Khan 		ret = -ENODEV;
427c94903f1SShuah Khan 		goto end;
428c94903f1SShuah Khan 	}
429c94903f1SShuah Khan 
430c94903f1SShuah Khan 	/* link is active - stop pipeline from source (tuner) */
431c94903f1SShuah Khan 	if (dev->active_link->sink->entity == dev->active_sink &&
432c94903f1SShuah Khan 	    dev->active_link->source->entity == dev->active_source) {
433c94903f1SShuah Khan 		/*
434c94903f1SShuah Khan 		 * prevent video from deactivating link when audio
435c94903f1SShuah Khan 		 * has active pipeline
436c94903f1SShuah Khan 		*/
437c94903f1SShuah Khan 		if (dev->active_link_owner != entity)
438c94903f1SShuah Khan 			goto end;
439c94903f1SShuah Khan 		__media_entity_pipeline_stop(entity);
440c94903f1SShuah Khan 		ret = __media_entity_setup_link(dev->active_link, 0);
441c94903f1SShuah Khan 		if (ret)
442c94903f1SShuah Khan 			pr_err("Deactivate link Error %d\n", ret);
443c94903f1SShuah Khan 
444c94903f1SShuah Khan 		pr_debug("Disabled Source: %s->%s->%s Ret %d\n",
445c94903f1SShuah Khan 			 dev->active_source->name, dev->active_sink->name,
446c94903f1SShuah Khan 			 dev->active_link_owner->name, ret);
447c94903f1SShuah Khan 
448c94903f1SShuah Khan 		dev->active_link = NULL;
449c94903f1SShuah Khan 		dev->active_link_owner = NULL;
450c94903f1SShuah Khan 		dev->active_source = NULL;
451c94903f1SShuah Khan 		dev->active_sink = NULL;
452c94903f1SShuah Khan 	}
453c94903f1SShuah Khan 
454c94903f1SShuah Khan end:
455c94903f1SShuah Khan 	mutex_unlock(&mdev->graph_mutex);
456c94903f1SShuah Khan }
4570a82edd0SArnd Bergmann #endif
458c94903f1SShuah Khan 
4597b12adf6SShuah Khan static int au0828_media_device_register(struct au0828_dev *dev,
4607b12adf6SShuah Khan 					struct usb_device *udev)
4617b12adf6SShuah Khan {
4627b12adf6SShuah Khan #ifdef CONFIG_MEDIA_CONTROLLER
4637b12adf6SShuah Khan 	int ret;
4642e208c64SMauro Carvalho Chehab 	struct media_entity *entity, *demod = NULL;
4652e208c64SMauro Carvalho Chehab 	struct media_link *link;
4667b12adf6SShuah Khan 
467f90c5d79SShuah Khan 	if (!dev->media_dev)
468f90c5d79SShuah Khan 		return 0;
469f90c5d79SShuah Khan 
470f90c5d79SShuah Khan 	if (!media_devnode_is_registered(&dev->media_dev->devnode)) {
4717b12adf6SShuah Khan 
4727b12adf6SShuah Khan 		/* register media device */
4737b12adf6SShuah Khan 		ret = media_device_register(dev->media_dev);
4747b12adf6SShuah Khan 		if (ret) {
4757b12adf6SShuah Khan 			dev_err(&udev->dev,
4767b12adf6SShuah Khan 				"Media Device Register Error: %d\n", ret);
4777b12adf6SShuah Khan 			return ret;
4787b12adf6SShuah Khan 		}
4799096cae1SShuah Khan 	} else {
4809096cae1SShuah Khan 		/*
4819096cae1SShuah Khan 		 * Call au0828_media_graph_notify() to connect
4829096cae1SShuah Khan 		 * audio graph to our graph. In this case, audio
4839096cae1SShuah Khan 		 * driver registered the device and there is no
4849096cae1SShuah Khan 		 * entity_notify to be called when new entities
4859096cae1SShuah Khan 		 * are added. Invoke it now.
4869096cae1SShuah Khan 		*/
4879096cae1SShuah Khan 		au0828_media_graph_notify(NULL, (void *) dev);
4887b12adf6SShuah Khan 	}
489840f5b05SShuah Khan 
490840f5b05SShuah Khan 	/*
4912e208c64SMauro Carvalho Chehab 	 * Find tuner, decoder and demod.
4922e208c64SMauro Carvalho Chehab 	 *
4932e208c64SMauro Carvalho Chehab 	 * The tuner and decoder should be cached, as they'll be used by
4942e208c64SMauro Carvalho Chehab 	 *	au0828_enable_source.
4952e208c64SMauro Carvalho Chehab 	 *
4962e208c64SMauro Carvalho Chehab 	 * It also needs to disable the link between tuner and
4972e208c64SMauro Carvalho Chehab 	 * decoder/demod, to avoid disable step when tuner is requested
4982e208c64SMauro Carvalho Chehab 	 * by video or audio. Note that this step can't be done until dvb
4992e208c64SMauro Carvalho Chehab 	 * graph is created during dvb register.
500840f5b05SShuah Khan 	*/
501840f5b05SShuah Khan 	media_device_for_each_entity(entity, dev->media_dev) {
5022e208c64SMauro Carvalho Chehab 		switch (entity->function) {
5032e208c64SMauro Carvalho Chehab 		case MEDIA_ENT_F_TUNER:
5042e208c64SMauro Carvalho Chehab 			dev->tuner = entity;
5052e208c64SMauro Carvalho Chehab 			break;
5062e208c64SMauro Carvalho Chehab 		case MEDIA_ENT_F_ATV_DECODER:
5072e208c64SMauro Carvalho Chehab 			dev->decoder = entity;
5082e208c64SMauro Carvalho Chehab 			break;
5092e208c64SMauro Carvalho Chehab 		case MEDIA_ENT_F_DTV_DEMOD:
510840f5b05SShuah Khan 			demod = entity;
5112e208c64SMauro Carvalho Chehab 			break;
512840f5b05SShuah Khan 		}
5132e208c64SMauro Carvalho Chehab 	}
514840f5b05SShuah Khan 
5152e208c64SMauro Carvalho Chehab 	/* Disable link between tuner->demod and/or tuner->decoder */
5162e208c64SMauro Carvalho Chehab 	if (dev->tuner) {
5172e208c64SMauro Carvalho Chehab 		list_for_each_entry(link, &dev->tuner->links, list) {
5182e208c64SMauro Carvalho Chehab 			if (demod && link->sink->entity == demod)
519840f5b05SShuah Khan 				media_entity_setup_link(link, 0);
5202e208c64SMauro Carvalho Chehab 			if (dev->decoder && link->sink->entity == dev->decoder)
5212e208c64SMauro Carvalho Chehab 				media_entity_setup_link(link, 0);
522840f5b05SShuah Khan 		}
523840f5b05SShuah Khan 	}
524840f5b05SShuah Khan 
525f90c5d79SShuah Khan 	/* register entity_notify callback */
526f90c5d79SShuah Khan 	dev->entity_notify.notify_data = (void *) dev;
527f90c5d79SShuah Khan 	dev->entity_notify.notify = (void *) au0828_media_graph_notify;
528f90c5d79SShuah Khan 	ret = media_device_register_entity_notify(dev->media_dev,
529f90c5d79SShuah Khan 						  &dev->entity_notify);
530f90c5d79SShuah Khan 	if (ret) {
531f90c5d79SShuah Khan 		dev_err(&udev->dev,
532f90c5d79SShuah Khan 			"Media Device register entity_notify Error: %d\n",
533f90c5d79SShuah Khan 			ret);
534f90c5d79SShuah Khan 		return ret;
535f90c5d79SShuah Khan 	}
536c94903f1SShuah Khan 	/* set enable_source */
537c94903f1SShuah Khan 	dev->media_dev->source_priv = (void *) dev;
538c94903f1SShuah Khan 	dev->media_dev->enable_source = au0828_enable_source;
539c94903f1SShuah Khan 	dev->media_dev->disable_source = au0828_disable_source;
5407b12adf6SShuah Khan #endif
5417b12adf6SShuah Khan 	return 0;
5427b12adf6SShuah Khan }
543bed69196SRafael Lourenço de Lima Chehab 
5440c0d06caSMauro Carvalho Chehab static int au0828_usb_probe(struct usb_interface *interface,
5450c0d06caSMauro Carvalho Chehab 	const struct usb_device_id *id)
5460c0d06caSMauro Carvalho Chehab {
5478a4e7866SMichael Krufky 	int ifnum;
548f251b3e7STim Mester 	int retval = 0;
549f251b3e7STim Mester 
5500c0d06caSMauro Carvalho Chehab 	struct au0828_dev *dev;
5510c0d06caSMauro Carvalho Chehab 	struct usb_device *usbdev = interface_to_usbdev(interface);
5520c0d06caSMauro Carvalho Chehab 
5530c0d06caSMauro Carvalho Chehab 	ifnum = interface->altsetting->desc.bInterfaceNumber;
5540c0d06caSMauro Carvalho Chehab 
5550c0d06caSMauro Carvalho Chehab 	if (ifnum != 0)
5560c0d06caSMauro Carvalho Chehab 		return -ENODEV;
5570c0d06caSMauro Carvalho Chehab 
5580c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
5590c0d06caSMauro Carvalho Chehab 		le16_to_cpu(usbdev->descriptor.idVendor),
5600c0d06caSMauro Carvalho Chehab 		le16_to_cpu(usbdev->descriptor.idProduct),
5610c0d06caSMauro Carvalho Chehab 		ifnum);
5620c0d06caSMauro Carvalho Chehab 
5630c0d06caSMauro Carvalho Chehab 	/*
5640c0d06caSMauro Carvalho Chehab 	 * Make sure we have 480 Mbps of bandwidth, otherwise things like
5650c0d06caSMauro Carvalho Chehab 	 * video stream wouldn't likely work, since 12 Mbps is generally
5660c0d06caSMauro Carvalho Chehab 	 * not enough even for most Digital TV streams.
5670c0d06caSMauro Carvalho Chehab 	 */
5680c0d06caSMauro Carvalho Chehab 	if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
56983afb32aSMauro Carvalho Chehab 		pr_err("au0828: Device initialization failed.\n");
57083afb32aSMauro Carvalho Chehab 		pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
5710c0d06caSMauro Carvalho Chehab 		return -ENODEV;
5720c0d06caSMauro Carvalho Chehab 	}
5730c0d06caSMauro Carvalho Chehab 
5740c0d06caSMauro Carvalho Chehab 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
5750c0d06caSMauro Carvalho Chehab 	if (dev == NULL) {
57683afb32aSMauro Carvalho Chehab 		pr_err("%s() Unable to allocate memory\n", __func__);
5770c0d06caSMauro Carvalho Chehab 		return -ENOMEM;
5780c0d06caSMauro Carvalho Chehab 	}
5790c0d06caSMauro Carvalho Chehab 
5800c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->lock);
5810c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->lock);
5820c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->mutex);
5830c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->dvb.lock);
5840c0d06caSMauro Carvalho Chehab 	dev->usbdev = usbdev;
5850c0d06caSMauro Carvalho Chehab 	dev->boardnr = id->driver_info;
586e42c8c6eSRafael Lourenço de Lima Chehab 	dev->board = au0828_boards[dev->boardnr];
587e42c8c6eSRafael Lourenço de Lima Chehab 
5889832e155SJavier Martinez Canillas 	/* Initialize the media controller */
5899f806795SMauro Carvalho Chehab 	retval = au0828_media_device_init(dev, usbdev);
5909f806795SMauro Carvalho Chehab 	if (retval) {
5919f806795SMauro Carvalho Chehab 		pr_err("%s() au0828_media_device_init failed\n",
5929f806795SMauro Carvalho Chehab 		       __func__);
5939f806795SMauro Carvalho Chehab 		mutex_unlock(&dev->lock);
5949f806795SMauro Carvalho Chehab 		kfree(dev);
5959f806795SMauro Carvalho Chehab 		return retval;
5969f806795SMauro Carvalho Chehab 	}
5970c0d06caSMauro Carvalho Chehab 
5987b606ffdSMauro Carvalho Chehab 	retval = au0828_v4l2_device_register(interface, dev);
5990c0d06caSMauro Carvalho Chehab 	if (retval) {
6007b606ffdSMauro Carvalho Chehab 		au0828_usb_v4l2_media_release(dev);
6010c0d06caSMauro Carvalho Chehab 		mutex_unlock(&dev->lock);
6020c0d06caSMauro Carvalho Chehab 		kfree(dev);
603e8c26f45SHans Verkuil 		return retval;
6040c0d06caSMauro Carvalho Chehab 	}
6050c0d06caSMauro Carvalho Chehab 
6060c0d06caSMauro Carvalho Chehab 	/* Power Up the bridge */
6070c0d06caSMauro Carvalho Chehab 	au0828_write(dev, REG_600, 1 << 4);
6080c0d06caSMauro Carvalho Chehab 
6090c0d06caSMauro Carvalho Chehab 	/* Bring up the GPIO's and supporting devices */
6100c0d06caSMauro Carvalho Chehab 	au0828_gpio_setup(dev);
6110c0d06caSMauro Carvalho Chehab 
6120c0d06caSMauro Carvalho Chehab 	/* I2C */
6130c0d06caSMauro Carvalho Chehab 	au0828_i2c_register(dev);
6140c0d06caSMauro Carvalho Chehab 
6150c0d06caSMauro Carvalho Chehab 	/* Setup */
6160c0d06caSMauro Carvalho Chehab 	au0828_card_setup(dev);
6170c0d06caSMauro Carvalho Chehab 
6180c0d06caSMauro Carvalho Chehab 	/* Analog TV */
61982e92f4cSMauro Carvalho Chehab 	retval = au0828_analog_register(dev, interface);
62082e92f4cSMauro Carvalho Chehab 	if (retval) {
62182e92f4cSMauro Carvalho Chehab 		pr_err("%s() au0282_dev_register failed to register on V4L2\n",
62282e92f4cSMauro Carvalho Chehab 			__func__);
62382e92f4cSMauro Carvalho Chehab 		goto done;
62482e92f4cSMauro Carvalho Chehab 	}
62582e92f4cSMauro Carvalho Chehab 
6260c0d06caSMauro Carvalho Chehab 	/* Digital TV */
627f251b3e7STim Mester 	retval = au0828_dvb_register(dev);
628f251b3e7STim Mester 	if (retval)
629f251b3e7STim Mester 		pr_err("%s() au0282_dev_register failed\n",
630f251b3e7STim Mester 		       __func__);
631f251b3e7STim Mester 
6322fcfd317SMauro Carvalho Chehab 	/* Remote controller */
6332fcfd317SMauro Carvalho Chehab 	au0828_rc_register(dev);
6340c0d06caSMauro Carvalho Chehab 
6352fcfd317SMauro Carvalho Chehab 	/*
6362fcfd317SMauro Carvalho Chehab 	 * Store the pointer to the au0828_dev so it can be accessed in
6372fcfd317SMauro Carvalho Chehab 	 * au0828_usb_disconnect
6382fcfd317SMauro Carvalho Chehab 	 */
6390c0d06caSMauro Carvalho Chehab 	usb_set_intfdata(interface, dev);
6400c0d06caSMauro Carvalho Chehab 
64183afb32aSMauro Carvalho Chehab 	pr_info("Registered device AU0828 [%s]\n",
6420c0d06caSMauro Carvalho Chehab 		dev->board.name == NULL ? "Unset" : dev->board.name);
6430c0d06caSMauro Carvalho Chehab 
6440c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
6450c0d06caSMauro Carvalho Chehab 
6467b12adf6SShuah Khan 	retval = au0828_media_device_register(dev, usbdev);
6479832e155SJavier Martinez Canillas 
6489832e155SJavier Martinez Canillas done:
6499832e155SJavier Martinez Canillas 	if (retval < 0)
6509832e155SJavier Martinez Canillas 		au0828_usb_disconnect(interface);
6519832e155SJavier Martinez Canillas 
652f251b3e7STim Mester 	return retval;
6530c0d06caSMauro Carvalho Chehab }
6540c0d06caSMauro Carvalho Chehab 
655aaeac199SMauro Carvalho Chehab static int au0828_suspend(struct usb_interface *interface,
656aaeac199SMauro Carvalho Chehab 				pm_message_t message)
657aaeac199SMauro Carvalho Chehab {
658aaeac199SMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
659aaeac199SMauro Carvalho Chehab 
660aaeac199SMauro Carvalho Chehab 	if (!dev)
661aaeac199SMauro Carvalho Chehab 		return 0;
662aaeac199SMauro Carvalho Chehab 
66381187240SMauro Carvalho Chehab 	pr_info("Suspend\n");
66481187240SMauro Carvalho Chehab 
665aaeac199SMauro Carvalho Chehab 	au0828_rc_suspend(dev);
6661a1ba95eSMauro Carvalho Chehab 	au0828_v4l2_suspend(dev);
667b799de75SMauro Carvalho Chehab 	au0828_dvb_suspend(dev);
668aaeac199SMauro Carvalho Chehab 
669aaeac199SMauro Carvalho Chehab 	/* FIXME: should suspend also ATV/DTV */
670aaeac199SMauro Carvalho Chehab 
671aaeac199SMauro Carvalho Chehab 	return 0;
672aaeac199SMauro Carvalho Chehab }
673aaeac199SMauro Carvalho Chehab 
674aaeac199SMauro Carvalho Chehab static int au0828_resume(struct usb_interface *interface)
675aaeac199SMauro Carvalho Chehab {
676aaeac199SMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
677aaeac199SMauro Carvalho Chehab 	if (!dev)
678aaeac199SMauro Carvalho Chehab 		return 0;
679aaeac199SMauro Carvalho Chehab 
68081187240SMauro Carvalho Chehab 	pr_info("Resume\n");
68181187240SMauro Carvalho Chehab 
682fa500461SMauro Carvalho Chehab 	/* Power Up the bridge */
683fa500461SMauro Carvalho Chehab 	au0828_write(dev, REG_600, 1 << 4);
684fa500461SMauro Carvalho Chehab 
685fa500461SMauro Carvalho Chehab 	/* Bring up the GPIO's and supporting devices */
686fa500461SMauro Carvalho Chehab 	au0828_gpio_setup(dev);
687fa500461SMauro Carvalho Chehab 
688aaeac199SMauro Carvalho Chehab 	au0828_rc_resume(dev);
6891a1ba95eSMauro Carvalho Chehab 	au0828_v4l2_resume(dev);
690b799de75SMauro Carvalho Chehab 	au0828_dvb_resume(dev);
691aaeac199SMauro Carvalho Chehab 
692aaeac199SMauro Carvalho Chehab 	/* FIXME: should resume also ATV/DTV */
693aaeac199SMauro Carvalho Chehab 
694aaeac199SMauro Carvalho Chehab 	return 0;
695aaeac199SMauro Carvalho Chehab }
696aaeac199SMauro Carvalho Chehab 
6970c0d06caSMauro Carvalho Chehab static struct usb_driver au0828_usb_driver = {
69883afb32aSMauro Carvalho Chehab 	.name		= KBUILD_MODNAME,
6990c0d06caSMauro Carvalho Chehab 	.probe		= au0828_usb_probe,
7000c0d06caSMauro Carvalho Chehab 	.disconnect	= au0828_usb_disconnect,
7010c0d06caSMauro Carvalho Chehab 	.id_table	= au0828_usb_id_table,
702aaeac199SMauro Carvalho Chehab 	.suspend	= au0828_suspend,
703aaeac199SMauro Carvalho Chehab 	.resume		= au0828_resume,
704aaeac199SMauro Carvalho Chehab 	.reset_resume	= au0828_resume,
7050c0d06caSMauro Carvalho Chehab };
7060c0d06caSMauro Carvalho Chehab 
7070c0d06caSMauro Carvalho Chehab static int __init au0828_init(void)
7080c0d06caSMauro Carvalho Chehab {
7090c0d06caSMauro Carvalho Chehab 	int ret;
7100c0d06caSMauro Carvalho Chehab 
7110c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 1)
71283afb32aSMauro Carvalho Chehab 		pr_info("%s() Debugging is enabled\n", __func__);
7130c0d06caSMauro Carvalho Chehab 
7140c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 2)
71583afb32aSMauro Carvalho Chehab 		pr_info("%s() USB Debugging is enabled\n", __func__);
7160c0d06caSMauro Carvalho Chehab 
7170c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 4)
71883afb32aSMauro Carvalho Chehab 		pr_info("%s() I2C Debugging is enabled\n", __func__);
7190c0d06caSMauro Carvalho Chehab 
7200c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 8)
72183afb32aSMauro Carvalho Chehab 		pr_info("%s() Bridge Debugging is enabled\n",
7220c0d06caSMauro Carvalho Chehab 		       __func__);
7230c0d06caSMauro Carvalho Chehab 
7242fcfd317SMauro Carvalho Chehab 	if (au0828_debug & 16)
72583afb32aSMauro Carvalho Chehab 		pr_info("%s() IR Debugging is enabled\n",
7262fcfd317SMauro Carvalho Chehab 		       __func__);
7272fcfd317SMauro Carvalho Chehab 
72883afb32aSMauro Carvalho Chehab 	pr_info("au0828 driver loaded\n");
7290c0d06caSMauro Carvalho Chehab 
7300c0d06caSMauro Carvalho Chehab 	ret = usb_register(&au0828_usb_driver);
7310c0d06caSMauro Carvalho Chehab 	if (ret)
73283afb32aSMauro Carvalho Chehab 		pr_err("usb_register failed, error = %d\n", ret);
7330c0d06caSMauro Carvalho Chehab 
7340c0d06caSMauro Carvalho Chehab 	return ret;
7350c0d06caSMauro Carvalho Chehab }
7360c0d06caSMauro Carvalho Chehab 
7370c0d06caSMauro Carvalho Chehab static void __exit au0828_exit(void)
7380c0d06caSMauro Carvalho Chehab {
7390c0d06caSMauro Carvalho Chehab 	usb_deregister(&au0828_usb_driver);
7400c0d06caSMauro Carvalho Chehab }
7410c0d06caSMauro Carvalho Chehab 
7420c0d06caSMauro Carvalho Chehab module_init(au0828_init);
7430c0d06caSMauro Carvalho Chehab module_exit(au0828_exit);
7440c0d06caSMauro Carvalho Chehab 
7450c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
7460c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
7470c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL");
7482fcfd317SMauro Carvalho Chehab MODULE_VERSION("0.0.3");
749