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 1946cf5dad1SMauro Carvalho 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 1986cf5dad1SMauro Carvalho Chehab if (!dev->board.name) 1996cf5dad1SMauro Carvalho Chehab media_device_usb_init(mdev, udev, "unknown au0828"); 2006cf5dad1SMauro Carvalho Chehab else 2016cf5dad1SMauro Carvalho Chehab media_device_usb_init(mdev, udev, dev->board.name); 2026cf5dad1SMauro Carvalho Chehab 203bed69196SRafael Lourenço de Lima Chehab dev->media_dev = mdev; 204bed69196SRafael Lourenço de Lima Chehab #endif 2059f806795SMauro Carvalho Chehab return 0; 206bed69196SRafael Lourenço de Lima Chehab } 207bed69196SRafael Lourenço de Lima Chehab 208bed69196SRafael Lourenço de Lima Chehab 2090c0d06caSMauro Carvalho Chehab static int au0828_usb_probe(struct usb_interface *interface, 2100c0d06caSMauro Carvalho Chehab const struct usb_device_id *id) 2110c0d06caSMauro Carvalho Chehab { 2128a4e7866SMichael Krufky int ifnum; 213f251b3e7STim Mester int retval = 0; 214f251b3e7STim Mester 2150c0d06caSMauro Carvalho Chehab struct au0828_dev *dev; 2160c0d06caSMauro Carvalho Chehab struct usb_device *usbdev = interface_to_usbdev(interface); 2170c0d06caSMauro Carvalho Chehab 2180c0d06caSMauro Carvalho Chehab ifnum = interface->altsetting->desc.bInterfaceNumber; 2190c0d06caSMauro Carvalho Chehab 2200c0d06caSMauro Carvalho Chehab if (ifnum != 0) 2210c0d06caSMauro Carvalho Chehab return -ENODEV; 2220c0d06caSMauro Carvalho Chehab 2230c0d06caSMauro Carvalho Chehab dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__, 2240c0d06caSMauro Carvalho Chehab le16_to_cpu(usbdev->descriptor.idVendor), 2250c0d06caSMauro Carvalho Chehab le16_to_cpu(usbdev->descriptor.idProduct), 2260c0d06caSMauro Carvalho Chehab ifnum); 2270c0d06caSMauro Carvalho Chehab 2280c0d06caSMauro Carvalho Chehab /* 2290c0d06caSMauro Carvalho Chehab * Make sure we have 480 Mbps of bandwidth, otherwise things like 2300c0d06caSMauro Carvalho Chehab * video stream wouldn't likely work, since 12 Mbps is generally 2310c0d06caSMauro Carvalho Chehab * not enough even for most Digital TV streams. 2320c0d06caSMauro Carvalho Chehab */ 2330c0d06caSMauro Carvalho Chehab if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { 23483afb32aSMauro Carvalho Chehab pr_err("au0828: Device initialization failed.\n"); 23583afb32aSMauro Carvalho Chehab pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n"); 2360c0d06caSMauro Carvalho Chehab return -ENODEV; 2370c0d06caSMauro Carvalho Chehab } 2380c0d06caSMauro Carvalho Chehab 2390c0d06caSMauro Carvalho Chehab dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2400c0d06caSMauro Carvalho Chehab if (dev == NULL) { 24183afb32aSMauro Carvalho Chehab pr_err("%s() Unable to allocate memory\n", __func__); 2420c0d06caSMauro Carvalho Chehab return -ENOMEM; 2430c0d06caSMauro Carvalho Chehab } 2440c0d06caSMauro Carvalho Chehab 2450c0d06caSMauro Carvalho Chehab mutex_init(&dev->lock); 2460c0d06caSMauro Carvalho Chehab mutex_lock(&dev->lock); 2470c0d06caSMauro Carvalho Chehab mutex_init(&dev->mutex); 2480c0d06caSMauro Carvalho Chehab mutex_init(&dev->dvb.lock); 2490c0d06caSMauro Carvalho Chehab dev->usbdev = usbdev; 2500c0d06caSMauro Carvalho Chehab dev->boardnr = id->driver_info; 251e42c8c6eSRafael Lourenço de Lima Chehab dev->board = au0828_boards[dev->boardnr]; 252e42c8c6eSRafael Lourenço de Lima Chehab 2539832e155SJavier Martinez Canillas /* Initialize the media controller */ 2549f806795SMauro Carvalho Chehab retval = au0828_media_device_init(dev, usbdev); 2559f806795SMauro Carvalho Chehab if (retval) { 2569f806795SMauro Carvalho Chehab pr_err("%s() au0828_media_device_init failed\n", 2579f806795SMauro Carvalho Chehab __func__); 2589f806795SMauro Carvalho Chehab mutex_unlock(&dev->lock); 2599f806795SMauro Carvalho Chehab kfree(dev); 2609f806795SMauro Carvalho Chehab return retval; 2619f806795SMauro Carvalho Chehab } 2620c0d06caSMauro Carvalho Chehab 2637b606ffdSMauro Carvalho Chehab retval = au0828_v4l2_device_register(interface, dev); 2640c0d06caSMauro Carvalho Chehab if (retval) { 2657b606ffdSMauro Carvalho Chehab au0828_usb_v4l2_media_release(dev); 2660c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock); 2670c0d06caSMauro Carvalho Chehab kfree(dev); 268e8c26f45SHans Verkuil return retval; 2690c0d06caSMauro Carvalho Chehab } 2700c0d06caSMauro Carvalho Chehab 2710c0d06caSMauro Carvalho Chehab /* Power Up the bridge */ 2720c0d06caSMauro Carvalho Chehab au0828_write(dev, REG_600, 1 << 4); 2730c0d06caSMauro Carvalho Chehab 2740c0d06caSMauro Carvalho Chehab /* Bring up the GPIO's and supporting devices */ 2750c0d06caSMauro Carvalho Chehab au0828_gpio_setup(dev); 2760c0d06caSMauro Carvalho Chehab 2770c0d06caSMauro Carvalho Chehab /* I2C */ 2780c0d06caSMauro Carvalho Chehab au0828_i2c_register(dev); 2790c0d06caSMauro Carvalho Chehab 2800c0d06caSMauro Carvalho Chehab /* Setup */ 2810c0d06caSMauro Carvalho Chehab au0828_card_setup(dev); 2820c0d06caSMauro Carvalho Chehab 2830c0d06caSMauro Carvalho Chehab /* Analog TV */ 28482e92f4cSMauro Carvalho Chehab retval = au0828_analog_register(dev, interface); 28582e92f4cSMauro Carvalho Chehab if (retval) { 28682e92f4cSMauro Carvalho Chehab pr_err("%s() au0282_dev_register failed to register on V4L2\n", 28782e92f4cSMauro Carvalho Chehab __func__); 28882e92f4cSMauro Carvalho Chehab goto done; 28982e92f4cSMauro Carvalho Chehab } 29082e92f4cSMauro Carvalho Chehab 2910c0d06caSMauro Carvalho Chehab /* Digital TV */ 292f251b3e7STim Mester retval = au0828_dvb_register(dev); 293f251b3e7STim Mester if (retval) 294f251b3e7STim Mester pr_err("%s() au0282_dev_register failed\n", 295f251b3e7STim Mester __func__); 296f251b3e7STim Mester 2972fcfd317SMauro Carvalho Chehab /* Remote controller */ 2982fcfd317SMauro Carvalho Chehab au0828_rc_register(dev); 2990c0d06caSMauro Carvalho Chehab 3002fcfd317SMauro Carvalho Chehab /* 3012fcfd317SMauro Carvalho Chehab * Store the pointer to the au0828_dev so it can be accessed in 3022fcfd317SMauro Carvalho Chehab * au0828_usb_disconnect 3032fcfd317SMauro Carvalho Chehab */ 3040c0d06caSMauro Carvalho Chehab usb_set_intfdata(interface, dev); 3050c0d06caSMauro Carvalho Chehab 30683afb32aSMauro Carvalho Chehab pr_info("Registered device AU0828 [%s]\n", 3070c0d06caSMauro Carvalho Chehab dev->board.name == NULL ? "Unset" : dev->board.name); 3080c0d06caSMauro Carvalho Chehab 3090c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock); 3100c0d06caSMauro Carvalho Chehab 3119832e155SJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 3129832e155SJavier Martinez Canillas retval = media_device_register(dev->media_dev); 3139832e155SJavier Martinez Canillas #endif 3149832e155SJavier Martinez Canillas 3159832e155SJavier Martinez Canillas done: 3169832e155SJavier Martinez Canillas if (retval < 0) 3179832e155SJavier Martinez Canillas au0828_usb_disconnect(interface); 3189832e155SJavier Martinez Canillas 319f251b3e7STim Mester return retval; 3200c0d06caSMauro Carvalho Chehab } 3210c0d06caSMauro Carvalho Chehab 322aaeac199SMauro Carvalho Chehab static int au0828_suspend(struct usb_interface *interface, 323aaeac199SMauro Carvalho Chehab pm_message_t message) 324aaeac199SMauro Carvalho Chehab { 325aaeac199SMauro Carvalho Chehab struct au0828_dev *dev = usb_get_intfdata(interface); 326aaeac199SMauro Carvalho Chehab 327aaeac199SMauro Carvalho Chehab if (!dev) 328aaeac199SMauro Carvalho Chehab return 0; 329aaeac199SMauro Carvalho Chehab 33081187240SMauro Carvalho Chehab pr_info("Suspend\n"); 33181187240SMauro Carvalho Chehab 332aaeac199SMauro Carvalho Chehab au0828_rc_suspend(dev); 3331a1ba95eSMauro Carvalho Chehab au0828_v4l2_suspend(dev); 334b799de75SMauro Carvalho Chehab au0828_dvb_suspend(dev); 335aaeac199SMauro Carvalho Chehab 336aaeac199SMauro Carvalho Chehab /* FIXME: should suspend also ATV/DTV */ 337aaeac199SMauro Carvalho Chehab 338aaeac199SMauro Carvalho Chehab return 0; 339aaeac199SMauro Carvalho Chehab } 340aaeac199SMauro Carvalho Chehab 341aaeac199SMauro Carvalho Chehab static int au0828_resume(struct usb_interface *interface) 342aaeac199SMauro Carvalho Chehab { 343aaeac199SMauro Carvalho Chehab struct au0828_dev *dev = usb_get_intfdata(interface); 344aaeac199SMauro Carvalho Chehab if (!dev) 345aaeac199SMauro Carvalho Chehab return 0; 346aaeac199SMauro Carvalho Chehab 34781187240SMauro Carvalho Chehab pr_info("Resume\n"); 34881187240SMauro Carvalho Chehab 349fa500461SMauro Carvalho Chehab /* Power Up the bridge */ 350fa500461SMauro Carvalho Chehab au0828_write(dev, REG_600, 1 << 4); 351fa500461SMauro Carvalho Chehab 352fa500461SMauro Carvalho Chehab /* Bring up the GPIO's and supporting devices */ 353fa500461SMauro Carvalho Chehab au0828_gpio_setup(dev); 354fa500461SMauro Carvalho Chehab 355aaeac199SMauro Carvalho Chehab au0828_rc_resume(dev); 3561a1ba95eSMauro Carvalho Chehab au0828_v4l2_resume(dev); 357b799de75SMauro Carvalho Chehab au0828_dvb_resume(dev); 358aaeac199SMauro Carvalho Chehab 359aaeac199SMauro Carvalho Chehab /* FIXME: should resume also ATV/DTV */ 360aaeac199SMauro Carvalho Chehab 361aaeac199SMauro Carvalho Chehab return 0; 362aaeac199SMauro Carvalho Chehab } 363aaeac199SMauro Carvalho Chehab 3640c0d06caSMauro Carvalho Chehab static struct usb_driver au0828_usb_driver = { 36583afb32aSMauro Carvalho Chehab .name = KBUILD_MODNAME, 3660c0d06caSMauro Carvalho Chehab .probe = au0828_usb_probe, 3670c0d06caSMauro Carvalho Chehab .disconnect = au0828_usb_disconnect, 3680c0d06caSMauro Carvalho Chehab .id_table = au0828_usb_id_table, 369aaeac199SMauro Carvalho Chehab .suspend = au0828_suspend, 370aaeac199SMauro Carvalho Chehab .resume = au0828_resume, 371aaeac199SMauro Carvalho Chehab .reset_resume = au0828_resume, 3720c0d06caSMauro Carvalho Chehab }; 3730c0d06caSMauro Carvalho Chehab 3740c0d06caSMauro Carvalho Chehab static int __init au0828_init(void) 3750c0d06caSMauro Carvalho Chehab { 3760c0d06caSMauro Carvalho Chehab int ret; 3770c0d06caSMauro Carvalho Chehab 3780c0d06caSMauro Carvalho Chehab if (au0828_debug & 1) 37983afb32aSMauro Carvalho Chehab pr_info("%s() Debugging is enabled\n", __func__); 3800c0d06caSMauro Carvalho Chehab 3810c0d06caSMauro Carvalho Chehab if (au0828_debug & 2) 38283afb32aSMauro Carvalho Chehab pr_info("%s() USB Debugging is enabled\n", __func__); 3830c0d06caSMauro Carvalho Chehab 3840c0d06caSMauro Carvalho Chehab if (au0828_debug & 4) 38583afb32aSMauro Carvalho Chehab pr_info("%s() I2C Debugging is enabled\n", __func__); 3860c0d06caSMauro Carvalho Chehab 3870c0d06caSMauro Carvalho Chehab if (au0828_debug & 8) 38883afb32aSMauro Carvalho Chehab pr_info("%s() Bridge Debugging is enabled\n", 3890c0d06caSMauro Carvalho Chehab __func__); 3900c0d06caSMauro Carvalho Chehab 3912fcfd317SMauro Carvalho Chehab if (au0828_debug & 16) 39283afb32aSMauro Carvalho Chehab pr_info("%s() IR Debugging is enabled\n", 3932fcfd317SMauro Carvalho Chehab __func__); 3942fcfd317SMauro Carvalho Chehab 39583afb32aSMauro Carvalho Chehab pr_info("au0828 driver loaded\n"); 3960c0d06caSMauro Carvalho Chehab 3970c0d06caSMauro Carvalho Chehab ret = usb_register(&au0828_usb_driver); 3980c0d06caSMauro Carvalho Chehab if (ret) 39983afb32aSMauro Carvalho Chehab pr_err("usb_register failed, error = %d\n", ret); 4000c0d06caSMauro Carvalho Chehab 4010c0d06caSMauro Carvalho Chehab return ret; 4020c0d06caSMauro Carvalho Chehab } 4030c0d06caSMauro Carvalho Chehab 4040c0d06caSMauro Carvalho Chehab static void __exit au0828_exit(void) 4050c0d06caSMauro Carvalho Chehab { 4060c0d06caSMauro Carvalho Chehab usb_deregister(&au0828_usb_driver); 4070c0d06caSMauro Carvalho Chehab } 4080c0d06caSMauro Carvalho Chehab 4090c0d06caSMauro Carvalho Chehab module_init(au0828_init); 4100c0d06caSMauro Carvalho Chehab module_exit(au0828_exit); 4110c0d06caSMauro Carvalho Chehab 4120c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); 4130c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); 4140c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 4152fcfd317SMauro Carvalho Chehab MODULE_VERSION("0.0.3"); 416