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 
1883afb32aSMauro Carvalho Chehab #include "au0828.h"
19f90c5d79SShuah Khan #include "au8522.h"
2083afb32aSMauro Carvalho Chehab 
210c0d06caSMauro Carvalho Chehab #include <linux/module.h>
220c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
230c0d06caSMauro Carvalho Chehab #include <linux/videodev2.h>
240c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
250c0d06caSMauro Carvalho Chehab #include <linux/mutex.h>
260c0d06caSMauro Carvalho Chehab 
27188d2d55SMauro Carvalho Chehab /* Due to enum tuner_pad_index */
28188d2d55SMauro Carvalho Chehab #include <media/tuner.h>
29188d2d55SMauro 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 
130bc5ccdbcSMauro Carvalho Chehab #ifdef CONFIG_MEDIA_CONTROLLER
131bc5ccdbcSMauro Carvalho Chehab static void au0828_media_graph_notify(struct media_entity *new,
132bc5ccdbcSMauro Carvalho Chehab 				      void *notify_data);
133bc5ccdbcSMauro Carvalho Chehab #endif
134bc5ccdbcSMauro Carvalho Chehab 
135bed69196SRafael Lourenço de Lima Chehab static void au0828_unregister_media_device(struct au0828_dev *dev)
136bed69196SRafael Lourenço de Lima Chehab {
137bed69196SRafael Lourenço de Lima Chehab #ifdef CONFIG_MEDIA_CONTROLLER
138bc5ccdbcSMauro Carvalho Chehab 	struct media_device *mdev = dev->media_dev;
139bc5ccdbcSMauro Carvalho Chehab 	struct media_entity_notify *notify, *nextp;
140bc5ccdbcSMauro Carvalho Chehab 
141a087ce70SMauro Carvalho Chehab 	if (!mdev || !media_devnode_is_registered(mdev->devnode))
142bc5ccdbcSMauro Carvalho Chehab 		return;
143bc5ccdbcSMauro Carvalho Chehab 
144bc5ccdbcSMauro Carvalho Chehab 	/* Remove au0828 entity_notify callbacks */
145bc5ccdbcSMauro Carvalho Chehab 	list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) {
146bc5ccdbcSMauro Carvalho Chehab 		if (notify->notify != au0828_media_graph_notify)
147bc5ccdbcSMauro Carvalho Chehab 			continue;
148bc5ccdbcSMauro Carvalho Chehab 		media_device_unregister_entity_notify(mdev, notify);
149bc5ccdbcSMauro Carvalho Chehab 	}
150bc5ccdbcSMauro Carvalho Chehab 
151ffa8576aSShuah Khan 	/* clear enable_source, disable_source */
152ffa8576aSShuah Khan 	dev->media_dev->source_priv = NULL;
153ffa8576aSShuah Khan 	dev->media_dev->enable_source = NULL;
154ffa8576aSShuah Khan 	dev->media_dev->disable_source = NULL;
155ffa8576aSShuah Khan 
156bed69196SRafael Lourenço de Lima Chehab 	media_device_unregister(dev->media_dev);
1579832e155SJavier Martinez Canillas 	media_device_cleanup(dev->media_dev);
158405ddbfaSMauro Carvalho Chehab 	kfree(dev->media_dev);
159bed69196SRafael Lourenço de Lima Chehab 	dev->media_dev = NULL;
160bed69196SRafael Lourenço de Lima Chehab #endif
161bed69196SRafael Lourenço de Lima Chehab }
162bed69196SRafael Lourenço de Lima Chehab 
1637b606ffdSMauro Carvalho Chehab void au0828_usb_release(struct au0828_dev *dev)
164823beb7eSHans Verkuil {
165bed69196SRafael Lourenço de Lima Chehab 	au0828_unregister_media_device(dev);
166bed69196SRafael Lourenço de Lima Chehab 
167823beb7eSHans Verkuil 	/* I2C */
168823beb7eSHans Verkuil 	au0828_i2c_unregister(dev);
169823beb7eSHans Verkuil 
170823beb7eSHans Verkuil 	kfree(dev);
171823beb7eSHans Verkuil }
172823beb7eSHans Verkuil 
1730c0d06caSMauro Carvalho Chehab static void au0828_usb_disconnect(struct usb_interface *interface)
1740c0d06caSMauro Carvalho Chehab {
1750c0d06caSMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
1760c0d06caSMauro Carvalho Chehab 
1770c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
1780c0d06caSMauro Carvalho Chehab 
179eb336eabSShuah Khan 	/* there is a small window after disconnect, before
180eb336eabSShuah Khan 	   dev->usbdev is NULL, for poll (e.g: IR) try to access
181eb336eabSShuah Khan 	   the device and fill the dmesg with error messages.
182eb336eabSShuah Khan 	   Set the status so poll routines can check and avoid
183eb336eabSShuah Khan 	   access after disconnect.
184eb336eabSShuah Khan 	*/
185e8e3039fSMauro Carvalho Chehab 	set_bit(DEV_DISCONNECTED, &dev->dev_state);
186eb336eabSShuah Khan 
1872fcfd317SMauro Carvalho Chehab 	au0828_rc_unregister(dev);
1880c0d06caSMauro Carvalho Chehab 	/* Digital TV */
1890c0d06caSMauro Carvalho Chehab 	au0828_dvb_unregister(dev);
1900c0d06caSMauro Carvalho Chehab 
1910c0d06caSMauro Carvalho Chehab 	usb_set_intfdata(interface, NULL);
1920c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->mutex);
1930c0d06caSMauro Carvalho Chehab 	dev->usbdev = NULL;
1940c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->mutex);
1957b606ffdSMauro Carvalho Chehab 	if (au0828_analog_unregister(dev)) {
1967e9a8ad5SMauro Carvalho Chehab 		/*
1977e9a8ad5SMauro Carvalho Chehab 		 * No need to call au0828_usb_release() if V4L2 is enabled,
1987e9a8ad5SMauro Carvalho Chehab 		 * as this is already called via au0828_usb_v4l2_release()
1997e9a8ad5SMauro Carvalho Chehab 		 */
200823beb7eSHans Verkuil 		return;
201823beb7eSHans Verkuil 	}
202823beb7eSHans Verkuil 	au0828_usb_release(dev);
2030c0d06caSMauro Carvalho Chehab }
2040c0d06caSMauro Carvalho Chehab 
2059f806795SMauro Carvalho Chehab static int au0828_media_device_init(struct au0828_dev *dev,
206bed69196SRafael Lourenço de Lima Chehab 				    struct usb_device *udev)
207bed69196SRafael Lourenço de Lima Chehab {
208bed69196SRafael Lourenço de Lima Chehab #ifdef CONFIG_MEDIA_CONTROLLER
209bed69196SRafael Lourenço de Lima Chehab 	struct media_device *mdev;
210bed69196SRafael Lourenço de Lima Chehab 
211405ddbfaSMauro Carvalho Chehab 	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
212bed69196SRafael Lourenço de Lima Chehab 	if (!mdev)
2139f806795SMauro Carvalho Chehab 		return -ENOMEM;
214bed69196SRafael Lourenço de Lima Chehab 
2157b12adf6SShuah Khan 	/* check if media device is already initialized */
2167b12adf6SShuah Khan 	if (!mdev->dev)
217182dde7cSShuah Khan 		media_device_usb_init(mdev, udev, udev->product);
2186cf5dad1SMauro Carvalho Chehab 
219bed69196SRafael Lourenço de Lima Chehab 	dev->media_dev = mdev;
220bed69196SRafael Lourenço de Lima Chehab #endif
2219f806795SMauro Carvalho Chehab 	return 0;
222bed69196SRafael Lourenço de Lima Chehab }
223bed69196SRafael Lourenço de Lima Chehab 
2240a82edd0SArnd Bergmann #ifdef CONFIG_MEDIA_CONTROLLER
225f90c5d79SShuah Khan static void au0828_media_graph_notify(struct media_entity *new,
226f90c5d79SShuah Khan 				      void *notify_data)
227f90c5d79SShuah Khan {
228f90c5d79SShuah Khan 	struct au0828_dev *dev = (struct au0828_dev *) notify_data;
229f90c5d79SShuah Khan 	int ret;
2309096cae1SShuah Khan 	struct media_entity *entity, *mixer = NULL, *decoder = NULL;
231f90c5d79SShuah Khan 
2329096cae1SShuah Khan 	if (!new) {
2339096cae1SShuah Khan 		/*
2349096cae1SShuah Khan 		 * Called during au0828 probe time to connect
2359096cae1SShuah Khan 		 * entites that were created prior to registering
2369096cae1SShuah Khan 		 * the notify handler. Find mixer and decoder.
2379096cae1SShuah Khan 		*/
2389096cae1SShuah Khan 		media_device_for_each_entity(entity, dev->media_dev) {
2399096cae1SShuah Khan 			if (entity->function == MEDIA_ENT_F_AUDIO_MIXER)
2409096cae1SShuah Khan 				mixer = entity;
2419096cae1SShuah Khan 			else if (entity->function == MEDIA_ENT_F_ATV_DECODER)
2429096cae1SShuah Khan 				decoder = entity;
2439096cae1SShuah Khan 		}
2449096cae1SShuah Khan 		goto create_link;
2459096cae1SShuah Khan 	}
246f90c5d79SShuah Khan 
247f90c5d79SShuah Khan 	switch (new->function) {
248f90c5d79SShuah Khan 	case MEDIA_ENT_F_AUDIO_MIXER:
2499096cae1SShuah Khan 		mixer = new;
2509096cae1SShuah Khan 		if (dev->decoder)
2519096cae1SShuah Khan 			decoder = dev->decoder;
2529096cae1SShuah Khan 		break;
2539096cae1SShuah Khan 	case MEDIA_ENT_F_ATV_DECODER:
2549096cae1SShuah Khan 		/* In case, Mixer is added first, find mixer and create link */
2559096cae1SShuah Khan 		media_device_for_each_entity(entity, dev->media_dev) {
2569096cae1SShuah Khan 			if (entity->function == MEDIA_ENT_F_AUDIO_MIXER)
2579096cae1SShuah Khan 				mixer = entity;
2589096cae1SShuah Khan 		}
2599096cae1SShuah Khan 		decoder = new;
260f90c5d79SShuah Khan 		break;
261f90c5d79SShuah Khan 	default:
262f90c5d79SShuah Khan 		break;
263f90c5d79SShuah Khan 	}
2649096cae1SShuah Khan 
2659096cae1SShuah Khan create_link:
2669096cae1SShuah Khan 	if (decoder && mixer) {
2679096cae1SShuah Khan 		ret = media_create_pad_link(decoder,
2689096cae1SShuah Khan 					    DEMOD_PAD_AUDIO_OUT,
2699096cae1SShuah Khan 					    mixer, 0,
2709096cae1SShuah Khan 					    MEDIA_LNK_FL_ENABLED);
2719096cae1SShuah Khan 		if (ret)
2729096cae1SShuah Khan 			dev_err(&dev->usbdev->dev,
2739096cae1SShuah Khan 				"Mixer Pad Link Create Error: %d\n", ret);
2749096cae1SShuah Khan 	}
275f90c5d79SShuah Khan }
276f90c5d79SShuah Khan 
277c94903f1SShuah Khan static int au0828_enable_source(struct media_entity *entity,
278c94903f1SShuah Khan 				struct media_pipeline *pipe)
279c94903f1SShuah Khan {
280c94903f1SShuah Khan 	struct media_entity  *source, *find_source;
281c94903f1SShuah Khan 	struct media_entity *sink;
282c94903f1SShuah Khan 	struct media_link *link, *found_link = NULL;
283c94903f1SShuah Khan 	int ret = 0;
284c94903f1SShuah Khan 	struct media_device *mdev = entity->graph_obj.mdev;
285c94903f1SShuah Khan 	struct au0828_dev *dev;
286c94903f1SShuah Khan 
287c94903f1SShuah Khan 	if (!mdev)
288c94903f1SShuah Khan 		return -ENODEV;
289c94903f1SShuah Khan 
290c94903f1SShuah Khan 	mutex_lock(&mdev->graph_mutex);
291c94903f1SShuah Khan 
292c94903f1SShuah Khan 	dev = mdev->source_priv;
293c94903f1SShuah Khan 
294c94903f1SShuah Khan 	/*
295c94903f1SShuah Khan 	 * For Audio and V4L2 entity, find the link to which decoder
296c94903f1SShuah Khan 	 * is the sink. Look for an active link between decoder and
297c94903f1SShuah Khan 	 * source (tuner/s-video/Composite), if one exists, nothing
298c94903f1SShuah Khan 	 * to do. If not, look for any  active links between source
299c94903f1SShuah Khan 	 * and any other entity. If one exists, source is busy. If
300c94903f1SShuah Khan 	 * source is free, setup link and start pipeline from source.
301c94903f1SShuah Khan 	 * For DVB FE entity, the source for the link is the tuner.
302c94903f1SShuah Khan 	 * Check if tuner is available and setup link and start
303c94903f1SShuah Khan 	 * pipeline.
304c94903f1SShuah Khan 	*/
305c94903f1SShuah Khan 	if (entity->function == MEDIA_ENT_F_DTV_DEMOD) {
306c94903f1SShuah Khan 		sink = entity;
307c94903f1SShuah Khan 		find_source = dev->tuner;
308c94903f1SShuah Khan 	} else {
309c94903f1SShuah Khan 		/* Analog isn't configured or register failed */
310c94903f1SShuah Khan 		if (!dev->decoder) {
311c94903f1SShuah Khan 			ret = -ENODEV;
312c94903f1SShuah Khan 			goto end;
313c94903f1SShuah Khan 		}
314c94903f1SShuah Khan 
315c94903f1SShuah Khan 		sink = dev->decoder;
316c94903f1SShuah Khan 
317c94903f1SShuah Khan 		/*
318c94903f1SShuah Khan 		 * Default input is tuner and default input_type
319c94903f1SShuah Khan 		 * is AU0828_VMUX_TELEVISION.
320c94903f1SShuah Khan 		 * FIXME:
321c94903f1SShuah Khan 		 * There is a problem when s_input is called to
322c94903f1SShuah Khan 		 * change the default input. s_input will try to
323c94903f1SShuah Khan 		 * enable_source before attempting to change the
324c94903f1SShuah Khan 		 * input on the device, and will end up enabling
325c94903f1SShuah Khan 		 * default source which is tuner.
326c94903f1SShuah Khan 		 *
327c94903f1SShuah Khan 		 * Additional logic is necessary in au0828
328c94903f1SShuah Khan 		 * to detect that the input has changed and
329c94903f1SShuah Khan 		 * enable the right source.
330c94903f1SShuah Khan 		*/
331c94903f1SShuah Khan 
332c94903f1SShuah Khan 		if (dev->input_type == AU0828_VMUX_TELEVISION)
333c94903f1SShuah Khan 			find_source = dev->tuner;
334c94903f1SShuah Khan 		else if (dev->input_type == AU0828_VMUX_SVIDEO ||
335c94903f1SShuah Khan 			 dev->input_type == AU0828_VMUX_COMPOSITE)
336c94903f1SShuah Khan 			find_source = &dev->input_ent[dev->input_type];
337c94903f1SShuah Khan 		else {
338c94903f1SShuah Khan 			/* unknown input - let user select input */
339c94903f1SShuah Khan 			ret = 0;
340c94903f1SShuah Khan 			goto end;
341c94903f1SShuah Khan 		}
342c94903f1SShuah Khan 	}
343c94903f1SShuah Khan 
344c94903f1SShuah Khan 	/* Is an active link between sink and source */
345c94903f1SShuah Khan 	if (dev->active_link) {
346c94903f1SShuah Khan 		/*
347c94903f1SShuah Khan 		 * If DVB is using the tuner and calling entity is
348c94903f1SShuah Khan 		 * audio/video, the following check will be false,
349c94903f1SShuah Khan 		 * since sink is different. Result is Busy.
350c94903f1SShuah Khan 		 */
351c94903f1SShuah Khan 		if (dev->active_link->sink->entity == sink &&
352c94903f1SShuah Khan 		    dev->active_link->source->entity == find_source) {
353c94903f1SShuah Khan 			/*
354c94903f1SShuah Khan 			 * Either ALSA or Video own tuner. sink is
355c94903f1SShuah Khan 			 * the same for both. Prevent Video stepping
356c94903f1SShuah Khan 			 * on ALSA when ALSA owns the source.
357c94903f1SShuah Khan 			*/
358c94903f1SShuah Khan 			if (dev->active_link_owner != entity &&
359c94903f1SShuah Khan 			    dev->active_link_owner->function ==
360c94903f1SShuah Khan 						MEDIA_ENT_F_AUDIO_CAPTURE) {
361c94903f1SShuah Khan 				pr_debug("ALSA has the tuner\n");
362c94903f1SShuah Khan 				ret = -EBUSY;
363c94903f1SShuah Khan 				goto end;
364c94903f1SShuah Khan 			}
365c94903f1SShuah Khan 			ret = 0;
366c94903f1SShuah Khan 			goto end;
367c94903f1SShuah Khan 		} else {
368c94903f1SShuah Khan 			ret = -EBUSY;
369c94903f1SShuah Khan 			goto end;
370c94903f1SShuah Khan 		}
371c94903f1SShuah Khan 	}
372c94903f1SShuah Khan 
373c94903f1SShuah Khan 	list_for_each_entry(link, &sink->links, list) {
374c94903f1SShuah Khan 		/* Check sink, and source */
375c94903f1SShuah Khan 		if (link->sink->entity == sink &&
376c94903f1SShuah Khan 		    link->source->entity == find_source) {
377c94903f1SShuah Khan 			found_link = link;
378c94903f1SShuah Khan 			break;
379c94903f1SShuah Khan 		}
380c94903f1SShuah Khan 	}
381c94903f1SShuah Khan 
382c94903f1SShuah Khan 	if (!found_link) {
383c94903f1SShuah Khan 		ret = -ENODEV;
384c94903f1SShuah Khan 		goto end;
385c94903f1SShuah Khan 	}
386c94903f1SShuah Khan 
387c94903f1SShuah Khan 	/* activate link between source and sink and start pipeline */
388c94903f1SShuah Khan 	source = found_link->source->entity;
389c94903f1SShuah Khan 	ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED);
390c94903f1SShuah Khan 	if (ret) {
391c94903f1SShuah Khan 		pr_err("Activate tuner link %s->%s. Error %d\n",
392c94903f1SShuah Khan 			source->name, sink->name, ret);
393c94903f1SShuah Khan 		goto end;
394c94903f1SShuah Khan 	}
395c94903f1SShuah Khan 
39620b85227SSakari Ailus 	ret = __media_pipeline_start(entity, pipe);
397c94903f1SShuah Khan 	if (ret) {
398c94903f1SShuah Khan 		pr_err("Start Pipeline: %s->%s Error %d\n",
399c94903f1SShuah Khan 			source->name, entity->name, ret);
400c94903f1SShuah Khan 		ret = __media_entity_setup_link(found_link, 0);
401c94903f1SShuah Khan 		pr_err("Deactivate link Error %d\n", ret);
402c94903f1SShuah Khan 		goto end;
403c94903f1SShuah Khan 	}
404c94903f1SShuah Khan 	/*
405c94903f1SShuah Khan 	 * save active link and active link owner to avoid audio
406c94903f1SShuah Khan 	 * deactivating video owned link from disable_source and
407c94903f1SShuah Khan 	 * vice versa
408c94903f1SShuah Khan 	*/
409c94903f1SShuah Khan 	dev->active_link = found_link;
410c94903f1SShuah Khan 	dev->active_link_owner = entity;
411c94903f1SShuah Khan 	dev->active_source = source;
412c94903f1SShuah Khan 	dev->active_sink = sink;
413c94903f1SShuah Khan 
414c94903f1SShuah Khan 	pr_debug("Enabled Source: %s->%s->%s Ret %d\n",
415c94903f1SShuah Khan 		 dev->active_source->name, dev->active_sink->name,
416c94903f1SShuah Khan 		 dev->active_link_owner->name, ret);
417c94903f1SShuah Khan end:
418c94903f1SShuah Khan 	mutex_unlock(&mdev->graph_mutex);
419c94903f1SShuah Khan 	pr_debug("au0828_enable_source() end %s %d %d\n",
420c94903f1SShuah Khan 		 entity->name, entity->function, ret);
421c94903f1SShuah Khan 	return ret;
422c94903f1SShuah Khan }
423c94903f1SShuah Khan 
424c94903f1SShuah Khan static void au0828_disable_source(struct media_entity *entity)
425c94903f1SShuah Khan {
426c94903f1SShuah Khan 	int ret = 0;
427c94903f1SShuah Khan 	struct media_device *mdev = entity->graph_obj.mdev;
428c94903f1SShuah Khan 	struct au0828_dev *dev;
429c94903f1SShuah Khan 
430c94903f1SShuah Khan 	if (!mdev)
431c94903f1SShuah Khan 		return;
432c94903f1SShuah Khan 
433c94903f1SShuah Khan 	mutex_lock(&mdev->graph_mutex);
434c94903f1SShuah Khan 	dev = mdev->source_priv;
435c94903f1SShuah Khan 
436c94903f1SShuah Khan 	if (!dev->active_link) {
437c94903f1SShuah Khan 		ret = -ENODEV;
438c94903f1SShuah Khan 		goto end;
439c94903f1SShuah Khan 	}
440c94903f1SShuah Khan 
441c94903f1SShuah Khan 	/* link is active - stop pipeline from source (tuner) */
442c94903f1SShuah Khan 	if (dev->active_link->sink->entity == dev->active_sink &&
443c94903f1SShuah Khan 	    dev->active_link->source->entity == dev->active_source) {
444c94903f1SShuah Khan 		/*
445c94903f1SShuah Khan 		 * prevent video from deactivating link when audio
446c94903f1SShuah Khan 		 * has active pipeline
447c94903f1SShuah Khan 		*/
448c94903f1SShuah Khan 		if (dev->active_link_owner != entity)
449c94903f1SShuah Khan 			goto end;
45020b85227SSakari Ailus 		__media_pipeline_stop(entity);
451c94903f1SShuah Khan 		ret = __media_entity_setup_link(dev->active_link, 0);
452c94903f1SShuah Khan 		if (ret)
453c94903f1SShuah Khan 			pr_err("Deactivate link Error %d\n", ret);
454c94903f1SShuah Khan 
455c94903f1SShuah Khan 		pr_debug("Disabled Source: %s->%s->%s Ret %d\n",
456c94903f1SShuah Khan 			 dev->active_source->name, dev->active_sink->name,
457c94903f1SShuah Khan 			 dev->active_link_owner->name, ret);
458c94903f1SShuah Khan 
459c94903f1SShuah Khan 		dev->active_link = NULL;
460c94903f1SShuah Khan 		dev->active_link_owner = NULL;
461c94903f1SShuah Khan 		dev->active_source = NULL;
462c94903f1SShuah Khan 		dev->active_sink = NULL;
463c94903f1SShuah Khan 	}
464c94903f1SShuah Khan 
465c94903f1SShuah Khan end:
466c94903f1SShuah Khan 	mutex_unlock(&mdev->graph_mutex);
467c94903f1SShuah Khan }
4680a82edd0SArnd Bergmann #endif
469c94903f1SShuah Khan 
4707b12adf6SShuah Khan static int au0828_media_device_register(struct au0828_dev *dev,
4717b12adf6SShuah Khan 					struct usb_device *udev)
4727b12adf6SShuah Khan {
4737b12adf6SShuah Khan #ifdef CONFIG_MEDIA_CONTROLLER
4747b12adf6SShuah Khan 	int ret;
4752e208c64SMauro Carvalho Chehab 	struct media_entity *entity, *demod = NULL;
4762e208c64SMauro Carvalho Chehab 	struct media_link *link;
4777b12adf6SShuah Khan 
478f90c5d79SShuah Khan 	if (!dev->media_dev)
479f90c5d79SShuah Khan 		return 0;
480f90c5d79SShuah Khan 
481a087ce70SMauro Carvalho Chehab 	if (!media_devnode_is_registered(dev->media_dev->devnode)) {
4827b12adf6SShuah Khan 
4837b12adf6SShuah Khan 		/* register media device */
4847b12adf6SShuah Khan 		ret = media_device_register(dev->media_dev);
4857b12adf6SShuah Khan 		if (ret) {
4867b12adf6SShuah Khan 			dev_err(&udev->dev,
4877b12adf6SShuah Khan 				"Media Device Register Error: %d\n", ret);
4887b12adf6SShuah Khan 			return ret;
4897b12adf6SShuah Khan 		}
4909096cae1SShuah Khan 	} else {
4919096cae1SShuah Khan 		/*
4929096cae1SShuah Khan 		 * Call au0828_media_graph_notify() to connect
4939096cae1SShuah Khan 		 * audio graph to our graph. In this case, audio
4949096cae1SShuah Khan 		 * driver registered the device and there is no
4959096cae1SShuah Khan 		 * entity_notify to be called when new entities
4969096cae1SShuah Khan 		 * are added. Invoke it now.
4979096cae1SShuah Khan 		*/
4989096cae1SShuah Khan 		au0828_media_graph_notify(NULL, (void *) dev);
4997b12adf6SShuah Khan 	}
500840f5b05SShuah Khan 
501840f5b05SShuah Khan 	/*
5022e208c64SMauro Carvalho Chehab 	 * Find tuner, decoder and demod.
5032e208c64SMauro Carvalho Chehab 	 *
5042e208c64SMauro Carvalho Chehab 	 * The tuner and decoder should be cached, as they'll be used by
5052e208c64SMauro Carvalho Chehab 	 *	au0828_enable_source.
5062e208c64SMauro Carvalho Chehab 	 *
5072e208c64SMauro Carvalho Chehab 	 * It also needs to disable the link between tuner and
5082e208c64SMauro Carvalho Chehab 	 * decoder/demod, to avoid disable step when tuner is requested
5092e208c64SMauro Carvalho Chehab 	 * by video or audio. Note that this step can't be done until dvb
5102e208c64SMauro Carvalho Chehab 	 * graph is created during dvb register.
511840f5b05SShuah Khan 	*/
512840f5b05SShuah Khan 	media_device_for_each_entity(entity, dev->media_dev) {
5132e208c64SMauro Carvalho Chehab 		switch (entity->function) {
5142e208c64SMauro Carvalho Chehab 		case MEDIA_ENT_F_TUNER:
5152e208c64SMauro Carvalho Chehab 			dev->tuner = entity;
5162e208c64SMauro Carvalho Chehab 			break;
5172e208c64SMauro Carvalho Chehab 		case MEDIA_ENT_F_ATV_DECODER:
5182e208c64SMauro Carvalho Chehab 			dev->decoder = entity;
5192e208c64SMauro Carvalho Chehab 			break;
5202e208c64SMauro Carvalho Chehab 		case MEDIA_ENT_F_DTV_DEMOD:
521840f5b05SShuah Khan 			demod = entity;
5222e208c64SMauro Carvalho Chehab 			break;
523840f5b05SShuah Khan 		}
5242e208c64SMauro Carvalho Chehab 	}
525840f5b05SShuah Khan 
5262e208c64SMauro Carvalho Chehab 	/* Disable link between tuner->demod and/or tuner->decoder */
5272e208c64SMauro Carvalho Chehab 	if (dev->tuner) {
5282e208c64SMauro Carvalho Chehab 		list_for_each_entry(link, &dev->tuner->links, list) {
5292e208c64SMauro Carvalho Chehab 			if (demod && link->sink->entity == demod)
530840f5b05SShuah Khan 				media_entity_setup_link(link, 0);
5312e208c64SMauro Carvalho Chehab 			if (dev->decoder && link->sink->entity == dev->decoder)
5322e208c64SMauro Carvalho Chehab 				media_entity_setup_link(link, 0);
533840f5b05SShuah Khan 		}
534840f5b05SShuah Khan 	}
535840f5b05SShuah Khan 
536f90c5d79SShuah Khan 	/* register entity_notify callback */
537f90c5d79SShuah Khan 	dev->entity_notify.notify_data = (void *) dev;
538f90c5d79SShuah Khan 	dev->entity_notify.notify = (void *) au0828_media_graph_notify;
539f90c5d79SShuah Khan 	ret = media_device_register_entity_notify(dev->media_dev,
540f90c5d79SShuah Khan 						  &dev->entity_notify);
541f90c5d79SShuah Khan 	if (ret) {
542f90c5d79SShuah Khan 		dev_err(&udev->dev,
543f90c5d79SShuah Khan 			"Media Device register entity_notify Error: %d\n",
544f90c5d79SShuah Khan 			ret);
545f90c5d79SShuah Khan 		return ret;
546f90c5d79SShuah Khan 	}
547c94903f1SShuah Khan 	/* set enable_source */
548c94903f1SShuah Khan 	dev->media_dev->source_priv = (void *) dev;
549c94903f1SShuah Khan 	dev->media_dev->enable_source = au0828_enable_source;
550c94903f1SShuah Khan 	dev->media_dev->disable_source = au0828_disable_source;
5517b12adf6SShuah Khan #endif
5527b12adf6SShuah Khan 	return 0;
5537b12adf6SShuah Khan }
554bed69196SRafael Lourenço de Lima Chehab 
5550c0d06caSMauro Carvalho Chehab static int au0828_usb_probe(struct usb_interface *interface,
5560c0d06caSMauro Carvalho Chehab 	const struct usb_device_id *id)
5570c0d06caSMauro Carvalho Chehab {
5588a4e7866SMichael Krufky 	int ifnum;
559f251b3e7STim Mester 	int retval = 0;
560f251b3e7STim Mester 
5610c0d06caSMauro Carvalho Chehab 	struct au0828_dev *dev;
5620c0d06caSMauro Carvalho Chehab 	struct usb_device *usbdev = interface_to_usbdev(interface);
5630c0d06caSMauro Carvalho Chehab 
5640c0d06caSMauro Carvalho Chehab 	ifnum = interface->altsetting->desc.bInterfaceNumber;
5650c0d06caSMauro Carvalho Chehab 
5660c0d06caSMauro Carvalho Chehab 	if (ifnum != 0)
5670c0d06caSMauro Carvalho Chehab 		return -ENODEV;
5680c0d06caSMauro Carvalho Chehab 
5690c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
5700c0d06caSMauro Carvalho Chehab 		le16_to_cpu(usbdev->descriptor.idVendor),
5710c0d06caSMauro Carvalho Chehab 		le16_to_cpu(usbdev->descriptor.idProduct),
5720c0d06caSMauro Carvalho Chehab 		ifnum);
5730c0d06caSMauro Carvalho Chehab 
5740c0d06caSMauro Carvalho Chehab 	/*
5750c0d06caSMauro Carvalho Chehab 	 * Make sure we have 480 Mbps of bandwidth, otherwise things like
5760c0d06caSMauro Carvalho Chehab 	 * video stream wouldn't likely work, since 12 Mbps is generally
5770c0d06caSMauro Carvalho Chehab 	 * not enough even for most Digital TV streams.
5780c0d06caSMauro Carvalho Chehab 	 */
5790c0d06caSMauro Carvalho Chehab 	if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
58083afb32aSMauro Carvalho Chehab 		pr_err("au0828: Device initialization failed.\n");
58183afb32aSMauro Carvalho Chehab 		pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
5820c0d06caSMauro Carvalho Chehab 		return -ENODEV;
5830c0d06caSMauro Carvalho Chehab 	}
5840c0d06caSMauro Carvalho Chehab 
5850c0d06caSMauro Carvalho Chehab 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
5860c0d06caSMauro Carvalho Chehab 	if (dev == NULL) {
58783afb32aSMauro Carvalho Chehab 		pr_err("%s() Unable to allocate memory\n", __func__);
5880c0d06caSMauro Carvalho Chehab 		return -ENOMEM;
5890c0d06caSMauro Carvalho Chehab 	}
5900c0d06caSMauro Carvalho Chehab 
5910c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->lock);
5920c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->lock);
5930c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->mutex);
5940c0d06caSMauro Carvalho Chehab 	mutex_init(&dev->dvb.lock);
5950c0d06caSMauro Carvalho Chehab 	dev->usbdev = usbdev;
5960c0d06caSMauro Carvalho Chehab 	dev->boardnr = id->driver_info;
597e42c8c6eSRafael Lourenço de Lima Chehab 	dev->board = au0828_boards[dev->boardnr];
598e42c8c6eSRafael Lourenço de Lima Chehab 
5999832e155SJavier Martinez Canillas 	/* Initialize the media controller */
6009f806795SMauro Carvalho Chehab 	retval = au0828_media_device_init(dev, usbdev);
6019f806795SMauro Carvalho Chehab 	if (retval) {
6029f806795SMauro Carvalho Chehab 		pr_err("%s() au0828_media_device_init failed\n",
6039f806795SMauro Carvalho Chehab 		       __func__);
6049f806795SMauro Carvalho Chehab 		mutex_unlock(&dev->lock);
6059f806795SMauro Carvalho Chehab 		kfree(dev);
6069f806795SMauro Carvalho Chehab 		return retval;
6079f806795SMauro Carvalho Chehab 	}
6080c0d06caSMauro Carvalho Chehab 
6097b606ffdSMauro Carvalho Chehab 	retval = au0828_v4l2_device_register(interface, dev);
6100c0d06caSMauro Carvalho Chehab 	if (retval) {
6117b606ffdSMauro Carvalho Chehab 		au0828_usb_v4l2_media_release(dev);
6120c0d06caSMauro Carvalho Chehab 		mutex_unlock(&dev->lock);
6130c0d06caSMauro Carvalho Chehab 		kfree(dev);
614e8c26f45SHans Verkuil 		return retval;
6150c0d06caSMauro Carvalho Chehab 	}
6160c0d06caSMauro Carvalho Chehab 
6170c0d06caSMauro Carvalho Chehab 	/* Power Up the bridge */
6180c0d06caSMauro Carvalho Chehab 	au0828_write(dev, REG_600, 1 << 4);
6190c0d06caSMauro Carvalho Chehab 
6200c0d06caSMauro Carvalho Chehab 	/* Bring up the GPIO's and supporting devices */
6210c0d06caSMauro Carvalho Chehab 	au0828_gpio_setup(dev);
6220c0d06caSMauro Carvalho Chehab 
6230c0d06caSMauro Carvalho Chehab 	/* I2C */
6240c0d06caSMauro Carvalho Chehab 	au0828_i2c_register(dev);
6250c0d06caSMauro Carvalho Chehab 
6260c0d06caSMauro Carvalho Chehab 	/* Setup */
6270c0d06caSMauro Carvalho Chehab 	au0828_card_setup(dev);
6280c0d06caSMauro Carvalho Chehab 
6290c0d06caSMauro Carvalho Chehab 	/* Analog TV */
63082e92f4cSMauro Carvalho Chehab 	retval = au0828_analog_register(dev, interface);
63182e92f4cSMauro Carvalho Chehab 	if (retval) {
63282e92f4cSMauro Carvalho Chehab 		pr_err("%s() au0282_dev_register failed to register on V4L2\n",
63382e92f4cSMauro Carvalho Chehab 			__func__);
63482e92f4cSMauro Carvalho Chehab 		goto done;
63582e92f4cSMauro Carvalho Chehab 	}
63682e92f4cSMauro Carvalho Chehab 
6370c0d06caSMauro Carvalho Chehab 	/* Digital TV */
638f251b3e7STim Mester 	retval = au0828_dvb_register(dev);
639f251b3e7STim Mester 	if (retval)
640f251b3e7STim Mester 		pr_err("%s() au0282_dev_register failed\n",
641f251b3e7STim Mester 		       __func__);
642f251b3e7STim Mester 
6432fcfd317SMauro Carvalho Chehab 	/* Remote controller */
6442fcfd317SMauro Carvalho Chehab 	au0828_rc_register(dev);
6450c0d06caSMauro Carvalho Chehab 
6462fcfd317SMauro Carvalho Chehab 	/*
6472fcfd317SMauro Carvalho Chehab 	 * Store the pointer to the au0828_dev so it can be accessed in
6482fcfd317SMauro Carvalho Chehab 	 * au0828_usb_disconnect
6492fcfd317SMauro Carvalho Chehab 	 */
6500c0d06caSMauro Carvalho Chehab 	usb_set_intfdata(interface, dev);
6510c0d06caSMauro Carvalho Chehab 
65283afb32aSMauro Carvalho Chehab 	pr_info("Registered device AU0828 [%s]\n",
6530c0d06caSMauro Carvalho Chehab 		dev->board.name == NULL ? "Unset" : dev->board.name);
6540c0d06caSMauro Carvalho Chehab 
6550c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
6560c0d06caSMauro Carvalho Chehab 
6577b12adf6SShuah Khan 	retval = au0828_media_device_register(dev, usbdev);
6589832e155SJavier Martinez Canillas 
6599832e155SJavier Martinez Canillas done:
6609832e155SJavier Martinez Canillas 	if (retval < 0)
6619832e155SJavier Martinez Canillas 		au0828_usb_disconnect(interface);
6629832e155SJavier Martinez Canillas 
663f251b3e7STim Mester 	return retval;
6640c0d06caSMauro Carvalho Chehab }
6650c0d06caSMauro Carvalho Chehab 
666aaeac199SMauro Carvalho Chehab static int au0828_suspend(struct usb_interface *interface,
667aaeac199SMauro Carvalho Chehab 				pm_message_t message)
668aaeac199SMauro Carvalho Chehab {
669aaeac199SMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
670aaeac199SMauro Carvalho Chehab 
671aaeac199SMauro Carvalho Chehab 	if (!dev)
672aaeac199SMauro Carvalho Chehab 		return 0;
673aaeac199SMauro Carvalho Chehab 
67481187240SMauro Carvalho Chehab 	pr_info("Suspend\n");
67581187240SMauro Carvalho Chehab 
676aaeac199SMauro Carvalho Chehab 	au0828_rc_suspend(dev);
6771a1ba95eSMauro Carvalho Chehab 	au0828_v4l2_suspend(dev);
678b799de75SMauro Carvalho Chehab 	au0828_dvb_suspend(dev);
679aaeac199SMauro Carvalho Chehab 
680aaeac199SMauro Carvalho Chehab 	/* FIXME: should suspend also ATV/DTV */
681aaeac199SMauro Carvalho Chehab 
682aaeac199SMauro Carvalho Chehab 	return 0;
683aaeac199SMauro Carvalho Chehab }
684aaeac199SMauro Carvalho Chehab 
685aaeac199SMauro Carvalho Chehab static int au0828_resume(struct usb_interface *interface)
686aaeac199SMauro Carvalho Chehab {
687aaeac199SMauro Carvalho Chehab 	struct au0828_dev *dev = usb_get_intfdata(interface);
688aaeac199SMauro Carvalho Chehab 	if (!dev)
689aaeac199SMauro Carvalho Chehab 		return 0;
690aaeac199SMauro Carvalho Chehab 
69181187240SMauro Carvalho Chehab 	pr_info("Resume\n");
69281187240SMauro Carvalho Chehab 
693fa500461SMauro Carvalho Chehab 	/* Power Up the bridge */
694fa500461SMauro Carvalho Chehab 	au0828_write(dev, REG_600, 1 << 4);
695fa500461SMauro Carvalho Chehab 
696fa500461SMauro Carvalho Chehab 	/* Bring up the GPIO's and supporting devices */
697fa500461SMauro Carvalho Chehab 	au0828_gpio_setup(dev);
698fa500461SMauro Carvalho Chehab 
699aaeac199SMauro Carvalho Chehab 	au0828_rc_resume(dev);
7001a1ba95eSMauro Carvalho Chehab 	au0828_v4l2_resume(dev);
701b799de75SMauro Carvalho Chehab 	au0828_dvb_resume(dev);
702aaeac199SMauro Carvalho Chehab 
703aaeac199SMauro Carvalho Chehab 	/* FIXME: should resume also ATV/DTV */
704aaeac199SMauro Carvalho Chehab 
705aaeac199SMauro Carvalho Chehab 	return 0;
706aaeac199SMauro Carvalho Chehab }
707aaeac199SMauro Carvalho Chehab 
7080c0d06caSMauro Carvalho Chehab static struct usb_driver au0828_usb_driver = {
70983afb32aSMauro Carvalho Chehab 	.name		= KBUILD_MODNAME,
7100c0d06caSMauro Carvalho Chehab 	.probe		= au0828_usb_probe,
7110c0d06caSMauro Carvalho Chehab 	.disconnect	= au0828_usb_disconnect,
7120c0d06caSMauro Carvalho Chehab 	.id_table	= au0828_usb_id_table,
713aaeac199SMauro Carvalho Chehab 	.suspend	= au0828_suspend,
714aaeac199SMauro Carvalho Chehab 	.resume		= au0828_resume,
715aaeac199SMauro Carvalho Chehab 	.reset_resume	= au0828_resume,
7160c0d06caSMauro Carvalho Chehab };
7170c0d06caSMauro Carvalho Chehab 
7180c0d06caSMauro Carvalho Chehab static int __init au0828_init(void)
7190c0d06caSMauro Carvalho Chehab {
7200c0d06caSMauro Carvalho Chehab 	int ret;
7210c0d06caSMauro Carvalho Chehab 
7220c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 1)
72383afb32aSMauro Carvalho Chehab 		pr_info("%s() Debugging is enabled\n", __func__);
7240c0d06caSMauro Carvalho Chehab 
7250c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 2)
72683afb32aSMauro Carvalho Chehab 		pr_info("%s() USB Debugging is enabled\n", __func__);
7270c0d06caSMauro Carvalho Chehab 
7280c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 4)
72983afb32aSMauro Carvalho Chehab 		pr_info("%s() I2C Debugging is enabled\n", __func__);
7300c0d06caSMauro Carvalho Chehab 
7310c0d06caSMauro Carvalho Chehab 	if (au0828_debug & 8)
73283afb32aSMauro Carvalho Chehab 		pr_info("%s() Bridge Debugging is enabled\n",
7330c0d06caSMauro Carvalho Chehab 		       __func__);
7340c0d06caSMauro Carvalho Chehab 
7352fcfd317SMauro Carvalho Chehab 	if (au0828_debug & 16)
73683afb32aSMauro Carvalho Chehab 		pr_info("%s() IR Debugging is enabled\n",
7372fcfd317SMauro Carvalho Chehab 		       __func__);
7382fcfd317SMauro Carvalho Chehab 
73983afb32aSMauro Carvalho Chehab 	pr_info("au0828 driver loaded\n");
7400c0d06caSMauro Carvalho Chehab 
7410c0d06caSMauro Carvalho Chehab 	ret = usb_register(&au0828_usb_driver);
7420c0d06caSMauro Carvalho Chehab 	if (ret)
74383afb32aSMauro Carvalho Chehab 		pr_err("usb_register failed, error = %d\n", ret);
7440c0d06caSMauro Carvalho Chehab 
7450c0d06caSMauro Carvalho Chehab 	return ret;
7460c0d06caSMauro Carvalho Chehab }
7470c0d06caSMauro Carvalho Chehab 
7480c0d06caSMauro Carvalho Chehab static void __exit au0828_exit(void)
7490c0d06caSMauro Carvalho Chehab {
7500c0d06caSMauro Carvalho Chehab 	usb_deregister(&au0828_usb_driver);
7510c0d06caSMauro Carvalho Chehab }
7520c0d06caSMauro Carvalho Chehab 
7530c0d06caSMauro Carvalho Chehab module_init(au0828_init);
7540c0d06caSMauro Carvalho Chehab module_exit(au0828_exit);
7550c0d06caSMauro Carvalho Chehab 
7560c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
7570c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
7580c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL");
7592fcfd317SMauro Carvalho Chehab MODULE_VERSION("0.0.3");
760