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)) { 140bed69196SRafael Lourenço de Lima Chehab media_device_unregister(dev->media_dev); 1419832e155SJavier Martinez Canillas media_device_cleanup(dev->media_dev); 142bed69196SRafael Lourenço de Lima Chehab dev->media_dev = NULL; 143bed69196SRafael Lourenço de Lima Chehab } 144bed69196SRafael Lourenço de Lima Chehab #endif 145bed69196SRafael Lourenço de Lima Chehab } 146bed69196SRafael Lourenço de Lima Chehab 1477b606ffdSMauro Carvalho Chehab void au0828_usb_release(struct au0828_dev *dev) 148823beb7eSHans Verkuil { 149bed69196SRafael Lourenço de Lima Chehab au0828_unregister_media_device(dev); 150bed69196SRafael Lourenço de Lima Chehab 151823beb7eSHans Verkuil /* I2C */ 152823beb7eSHans Verkuil au0828_i2c_unregister(dev); 153823beb7eSHans Verkuil 154823beb7eSHans Verkuil kfree(dev); 155823beb7eSHans Verkuil } 156823beb7eSHans Verkuil 1570c0d06caSMauro Carvalho Chehab static void au0828_usb_disconnect(struct usb_interface *interface) 1580c0d06caSMauro Carvalho Chehab { 1590c0d06caSMauro Carvalho Chehab struct au0828_dev *dev = usb_get_intfdata(interface); 1600c0d06caSMauro Carvalho Chehab 1610c0d06caSMauro Carvalho Chehab dprintk(1, "%s()\n", __func__); 1620c0d06caSMauro Carvalho Chehab 163eb336eabSShuah Khan /* there is a small window after disconnect, before 164eb336eabSShuah Khan dev->usbdev is NULL, for poll (e.g: IR) try to access 165eb336eabSShuah Khan the device and fill the dmesg with error messages. 166eb336eabSShuah Khan Set the status so poll routines can check and avoid 167eb336eabSShuah Khan access after disconnect. 168eb336eabSShuah Khan */ 169eb336eabSShuah Khan dev->dev_state = DEV_DISCONNECTED; 170eb336eabSShuah Khan 1712fcfd317SMauro Carvalho Chehab au0828_rc_unregister(dev); 1720c0d06caSMauro Carvalho Chehab /* Digital TV */ 1730c0d06caSMauro Carvalho Chehab au0828_dvb_unregister(dev); 1740c0d06caSMauro Carvalho Chehab 1750c0d06caSMauro Carvalho Chehab usb_set_intfdata(interface, NULL); 1760c0d06caSMauro Carvalho Chehab mutex_lock(&dev->mutex); 1770c0d06caSMauro Carvalho Chehab dev->usbdev = NULL; 1780c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->mutex); 1797b606ffdSMauro Carvalho Chehab if (au0828_analog_unregister(dev)) { 1807e9a8ad5SMauro Carvalho Chehab /* 1817e9a8ad5SMauro Carvalho Chehab * No need to call au0828_usb_release() if V4L2 is enabled, 1827e9a8ad5SMauro Carvalho Chehab * as this is already called via au0828_usb_v4l2_release() 1837e9a8ad5SMauro Carvalho Chehab */ 184823beb7eSHans Verkuil return; 185823beb7eSHans Verkuil } 186823beb7eSHans Verkuil au0828_usb_release(dev); 1870c0d06caSMauro Carvalho Chehab } 1880c0d06caSMauro Carvalho Chehab 1899f806795SMauro Carvalho Chehab static int au0828_media_device_init(struct au0828_dev *dev, 190bed69196SRafael Lourenço de Lima Chehab struct usb_device *udev) 191bed69196SRafael Lourenço de Lima Chehab { 192bed69196SRafael Lourenço de Lima Chehab #ifdef CONFIG_MEDIA_CONTROLLER 193bed69196SRafael Lourenço de Lima Chehab struct media_device *mdev; 194bed69196SRafael Lourenço de Lima Chehab 195182dde7cSShuah Khan mdev = media_device_get_devres(&udev->dev); 196bed69196SRafael Lourenço de Lima Chehab if (!mdev) 1979f806795SMauro Carvalho Chehab return -ENOMEM; 198bed69196SRafael Lourenço de Lima Chehab 1997b12adf6SShuah Khan /* check if media device is already initialized */ 2007b12adf6SShuah Khan if (!mdev->dev) 201182dde7cSShuah Khan media_device_usb_init(mdev, udev, udev->product); 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 208f90c5d79SShuah Khan static void au0828_media_graph_notify(struct media_entity *new, 209f90c5d79SShuah Khan void *notify_data) 210f90c5d79SShuah Khan { 211f90c5d79SShuah Khan #ifdef CONFIG_MEDIA_CONTROLLER 212f90c5d79SShuah Khan struct au0828_dev *dev = (struct au0828_dev *) notify_data; 213f90c5d79SShuah Khan int ret; 214f90c5d79SShuah Khan 215f90c5d79SShuah Khan if (!dev->decoder) 216f90c5d79SShuah Khan return; 217f90c5d79SShuah Khan 218f90c5d79SShuah Khan switch (new->function) { 219f90c5d79SShuah Khan case MEDIA_ENT_F_AUDIO_MIXER: 220f90c5d79SShuah Khan ret = media_create_pad_link(dev->decoder, 221f90c5d79SShuah Khan AU8522_PAD_AUDIO_OUT, 222f90c5d79SShuah Khan new, 0, 223f90c5d79SShuah Khan MEDIA_LNK_FL_ENABLED); 224f90c5d79SShuah Khan if (ret) 225f90c5d79SShuah Khan dev_err(&dev->usbdev->dev, 226f90c5d79SShuah Khan "Mixer Pad Link Create Error: %d\n", 227f90c5d79SShuah Khan ret); 228f90c5d79SShuah Khan break; 229f90c5d79SShuah Khan default: 230f90c5d79SShuah Khan break; 231f90c5d79SShuah Khan } 232f90c5d79SShuah Khan #endif 233f90c5d79SShuah Khan } 234f90c5d79SShuah Khan 2357b12adf6SShuah Khan static int au0828_media_device_register(struct au0828_dev *dev, 2367b12adf6SShuah Khan struct usb_device *udev) 2377b12adf6SShuah Khan { 2387b12adf6SShuah Khan #ifdef CONFIG_MEDIA_CONTROLLER 2397b12adf6SShuah Khan int ret; 2407b12adf6SShuah Khan 241f90c5d79SShuah Khan if (!dev->media_dev) 242f90c5d79SShuah Khan return 0; 243f90c5d79SShuah Khan 244f90c5d79SShuah Khan if (!media_devnode_is_registered(&dev->media_dev->devnode)) { 2457b12adf6SShuah Khan 2467b12adf6SShuah Khan /* register media device */ 2477b12adf6SShuah Khan ret = media_device_register(dev->media_dev); 2487b12adf6SShuah Khan if (ret) { 2497b12adf6SShuah Khan dev_err(&udev->dev, 2507b12adf6SShuah Khan "Media Device Register Error: %d\n", ret); 2517b12adf6SShuah Khan return ret; 2527b12adf6SShuah Khan } 2537b12adf6SShuah Khan } 254f90c5d79SShuah Khan /* register entity_notify callback */ 255f90c5d79SShuah Khan dev->entity_notify.notify_data = (void *) dev; 256f90c5d79SShuah Khan dev->entity_notify.notify = (void *) au0828_media_graph_notify; 257f90c5d79SShuah Khan ret = media_device_register_entity_notify(dev->media_dev, 258f90c5d79SShuah Khan &dev->entity_notify); 259f90c5d79SShuah Khan if (ret) { 260f90c5d79SShuah Khan dev_err(&udev->dev, 261f90c5d79SShuah Khan "Media Device register entity_notify Error: %d\n", 262f90c5d79SShuah Khan ret); 263f90c5d79SShuah Khan return ret; 264f90c5d79SShuah Khan } 2657b12adf6SShuah Khan #endif 2667b12adf6SShuah Khan return 0; 2677b12adf6SShuah Khan } 268bed69196SRafael Lourenço de Lima Chehab 2690c0d06caSMauro Carvalho Chehab static int au0828_usb_probe(struct usb_interface *interface, 2700c0d06caSMauro Carvalho Chehab const struct usb_device_id *id) 2710c0d06caSMauro Carvalho Chehab { 2728a4e7866SMichael Krufky int ifnum; 273f251b3e7STim Mester int retval = 0; 274f251b3e7STim Mester 2750c0d06caSMauro Carvalho Chehab struct au0828_dev *dev; 2760c0d06caSMauro Carvalho Chehab struct usb_device *usbdev = interface_to_usbdev(interface); 2770c0d06caSMauro Carvalho Chehab 2780c0d06caSMauro Carvalho Chehab ifnum = interface->altsetting->desc.bInterfaceNumber; 2790c0d06caSMauro Carvalho Chehab 2800c0d06caSMauro Carvalho Chehab if (ifnum != 0) 2810c0d06caSMauro Carvalho Chehab return -ENODEV; 2820c0d06caSMauro Carvalho Chehab 2830c0d06caSMauro Carvalho Chehab dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__, 2840c0d06caSMauro Carvalho Chehab le16_to_cpu(usbdev->descriptor.idVendor), 2850c0d06caSMauro Carvalho Chehab le16_to_cpu(usbdev->descriptor.idProduct), 2860c0d06caSMauro Carvalho Chehab ifnum); 2870c0d06caSMauro Carvalho Chehab 2880c0d06caSMauro Carvalho Chehab /* 2890c0d06caSMauro Carvalho Chehab * Make sure we have 480 Mbps of bandwidth, otherwise things like 2900c0d06caSMauro Carvalho Chehab * video stream wouldn't likely work, since 12 Mbps is generally 2910c0d06caSMauro Carvalho Chehab * not enough even for most Digital TV streams. 2920c0d06caSMauro Carvalho Chehab */ 2930c0d06caSMauro Carvalho Chehab if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { 29483afb32aSMauro Carvalho Chehab pr_err("au0828: Device initialization failed.\n"); 29583afb32aSMauro Carvalho Chehab pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n"); 2960c0d06caSMauro Carvalho Chehab return -ENODEV; 2970c0d06caSMauro Carvalho Chehab } 2980c0d06caSMauro Carvalho Chehab 2990c0d06caSMauro Carvalho Chehab dev = kzalloc(sizeof(*dev), GFP_KERNEL); 3000c0d06caSMauro Carvalho Chehab if (dev == NULL) { 30183afb32aSMauro Carvalho Chehab pr_err("%s() Unable to allocate memory\n", __func__); 3020c0d06caSMauro Carvalho Chehab return -ENOMEM; 3030c0d06caSMauro Carvalho Chehab } 3040c0d06caSMauro Carvalho Chehab 3050c0d06caSMauro Carvalho Chehab mutex_init(&dev->lock); 3060c0d06caSMauro Carvalho Chehab mutex_lock(&dev->lock); 3070c0d06caSMauro Carvalho Chehab mutex_init(&dev->mutex); 3080c0d06caSMauro Carvalho Chehab mutex_init(&dev->dvb.lock); 3090c0d06caSMauro Carvalho Chehab dev->usbdev = usbdev; 3100c0d06caSMauro Carvalho Chehab dev->boardnr = id->driver_info; 311e42c8c6eSRafael Lourenço de Lima Chehab dev->board = au0828_boards[dev->boardnr]; 312e42c8c6eSRafael Lourenço de Lima Chehab 3139832e155SJavier Martinez Canillas /* Initialize the media controller */ 3149f806795SMauro Carvalho Chehab retval = au0828_media_device_init(dev, usbdev); 3159f806795SMauro Carvalho Chehab if (retval) { 3169f806795SMauro Carvalho Chehab pr_err("%s() au0828_media_device_init failed\n", 3179f806795SMauro Carvalho Chehab __func__); 3189f806795SMauro Carvalho Chehab mutex_unlock(&dev->lock); 3199f806795SMauro Carvalho Chehab kfree(dev); 3209f806795SMauro Carvalho Chehab return retval; 3219f806795SMauro Carvalho Chehab } 3220c0d06caSMauro Carvalho Chehab 3237b606ffdSMauro Carvalho Chehab retval = au0828_v4l2_device_register(interface, dev); 3240c0d06caSMauro Carvalho Chehab if (retval) { 3257b606ffdSMauro Carvalho Chehab au0828_usb_v4l2_media_release(dev); 3260c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock); 3270c0d06caSMauro Carvalho Chehab kfree(dev); 328e8c26f45SHans Verkuil return retval; 3290c0d06caSMauro Carvalho Chehab } 3300c0d06caSMauro Carvalho Chehab 3310c0d06caSMauro Carvalho Chehab /* Power Up the bridge */ 3320c0d06caSMauro Carvalho Chehab au0828_write(dev, REG_600, 1 << 4); 3330c0d06caSMauro Carvalho Chehab 3340c0d06caSMauro Carvalho Chehab /* Bring up the GPIO's and supporting devices */ 3350c0d06caSMauro Carvalho Chehab au0828_gpio_setup(dev); 3360c0d06caSMauro Carvalho Chehab 3370c0d06caSMauro Carvalho Chehab /* I2C */ 3380c0d06caSMauro Carvalho Chehab au0828_i2c_register(dev); 3390c0d06caSMauro Carvalho Chehab 3400c0d06caSMauro Carvalho Chehab /* Setup */ 3410c0d06caSMauro Carvalho Chehab au0828_card_setup(dev); 3420c0d06caSMauro Carvalho Chehab 3430c0d06caSMauro Carvalho Chehab /* Analog TV */ 34482e92f4cSMauro Carvalho Chehab retval = au0828_analog_register(dev, interface); 34582e92f4cSMauro Carvalho Chehab if (retval) { 34682e92f4cSMauro Carvalho Chehab pr_err("%s() au0282_dev_register failed to register on V4L2\n", 34782e92f4cSMauro Carvalho Chehab __func__); 34882e92f4cSMauro Carvalho Chehab goto done; 34982e92f4cSMauro Carvalho Chehab } 35082e92f4cSMauro Carvalho Chehab 3510c0d06caSMauro Carvalho Chehab /* Digital TV */ 352f251b3e7STim Mester retval = au0828_dvb_register(dev); 353f251b3e7STim Mester if (retval) 354f251b3e7STim Mester pr_err("%s() au0282_dev_register failed\n", 355f251b3e7STim Mester __func__); 356f251b3e7STim Mester 3572fcfd317SMauro Carvalho Chehab /* Remote controller */ 3582fcfd317SMauro Carvalho Chehab au0828_rc_register(dev); 3590c0d06caSMauro Carvalho Chehab 3602fcfd317SMauro Carvalho Chehab /* 3612fcfd317SMauro Carvalho Chehab * Store the pointer to the au0828_dev so it can be accessed in 3622fcfd317SMauro Carvalho Chehab * au0828_usb_disconnect 3632fcfd317SMauro Carvalho Chehab */ 3640c0d06caSMauro Carvalho Chehab usb_set_intfdata(interface, dev); 3650c0d06caSMauro Carvalho Chehab 36683afb32aSMauro Carvalho Chehab pr_info("Registered device AU0828 [%s]\n", 3670c0d06caSMauro Carvalho Chehab dev->board.name == NULL ? "Unset" : dev->board.name); 3680c0d06caSMauro Carvalho Chehab 3690c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock); 3700c0d06caSMauro Carvalho Chehab 3717b12adf6SShuah Khan retval = au0828_media_device_register(dev, usbdev); 3729832e155SJavier Martinez Canillas 3739832e155SJavier Martinez Canillas done: 3749832e155SJavier Martinez Canillas if (retval < 0) 3759832e155SJavier Martinez Canillas au0828_usb_disconnect(interface); 3769832e155SJavier Martinez Canillas 377f251b3e7STim Mester return retval; 3780c0d06caSMauro Carvalho Chehab } 3790c0d06caSMauro Carvalho Chehab 380aaeac199SMauro Carvalho Chehab static int au0828_suspend(struct usb_interface *interface, 381aaeac199SMauro Carvalho Chehab pm_message_t message) 382aaeac199SMauro Carvalho Chehab { 383aaeac199SMauro Carvalho Chehab struct au0828_dev *dev = usb_get_intfdata(interface); 384aaeac199SMauro Carvalho Chehab 385aaeac199SMauro Carvalho Chehab if (!dev) 386aaeac199SMauro Carvalho Chehab return 0; 387aaeac199SMauro Carvalho Chehab 38881187240SMauro Carvalho Chehab pr_info("Suspend\n"); 38981187240SMauro Carvalho Chehab 390aaeac199SMauro Carvalho Chehab au0828_rc_suspend(dev); 3911a1ba95eSMauro Carvalho Chehab au0828_v4l2_suspend(dev); 392b799de75SMauro Carvalho Chehab au0828_dvb_suspend(dev); 393aaeac199SMauro Carvalho Chehab 394aaeac199SMauro Carvalho Chehab /* FIXME: should suspend also ATV/DTV */ 395aaeac199SMauro Carvalho Chehab 396aaeac199SMauro Carvalho Chehab return 0; 397aaeac199SMauro Carvalho Chehab } 398aaeac199SMauro Carvalho Chehab 399aaeac199SMauro Carvalho Chehab static int au0828_resume(struct usb_interface *interface) 400aaeac199SMauro Carvalho Chehab { 401aaeac199SMauro Carvalho Chehab struct au0828_dev *dev = usb_get_intfdata(interface); 402aaeac199SMauro Carvalho Chehab if (!dev) 403aaeac199SMauro Carvalho Chehab return 0; 404aaeac199SMauro Carvalho Chehab 40581187240SMauro Carvalho Chehab pr_info("Resume\n"); 40681187240SMauro Carvalho Chehab 407fa500461SMauro Carvalho Chehab /* Power Up the bridge */ 408fa500461SMauro Carvalho Chehab au0828_write(dev, REG_600, 1 << 4); 409fa500461SMauro Carvalho Chehab 410fa500461SMauro Carvalho Chehab /* Bring up the GPIO's and supporting devices */ 411fa500461SMauro Carvalho Chehab au0828_gpio_setup(dev); 412fa500461SMauro Carvalho Chehab 413aaeac199SMauro Carvalho Chehab au0828_rc_resume(dev); 4141a1ba95eSMauro Carvalho Chehab au0828_v4l2_resume(dev); 415b799de75SMauro Carvalho Chehab au0828_dvb_resume(dev); 416aaeac199SMauro Carvalho Chehab 417aaeac199SMauro Carvalho Chehab /* FIXME: should resume also ATV/DTV */ 418aaeac199SMauro Carvalho Chehab 419aaeac199SMauro Carvalho Chehab return 0; 420aaeac199SMauro Carvalho Chehab } 421aaeac199SMauro Carvalho Chehab 4220c0d06caSMauro Carvalho Chehab static struct usb_driver au0828_usb_driver = { 42383afb32aSMauro Carvalho Chehab .name = KBUILD_MODNAME, 4240c0d06caSMauro Carvalho Chehab .probe = au0828_usb_probe, 4250c0d06caSMauro Carvalho Chehab .disconnect = au0828_usb_disconnect, 4260c0d06caSMauro Carvalho Chehab .id_table = au0828_usb_id_table, 427aaeac199SMauro Carvalho Chehab .suspend = au0828_suspend, 428aaeac199SMauro Carvalho Chehab .resume = au0828_resume, 429aaeac199SMauro Carvalho Chehab .reset_resume = au0828_resume, 4300c0d06caSMauro Carvalho Chehab }; 4310c0d06caSMauro Carvalho Chehab 4320c0d06caSMauro Carvalho Chehab static int __init au0828_init(void) 4330c0d06caSMauro Carvalho Chehab { 4340c0d06caSMauro Carvalho Chehab int ret; 4350c0d06caSMauro Carvalho Chehab 4360c0d06caSMauro Carvalho Chehab if (au0828_debug & 1) 43783afb32aSMauro Carvalho Chehab pr_info("%s() Debugging is enabled\n", __func__); 4380c0d06caSMauro Carvalho Chehab 4390c0d06caSMauro Carvalho Chehab if (au0828_debug & 2) 44083afb32aSMauro Carvalho Chehab pr_info("%s() USB Debugging is enabled\n", __func__); 4410c0d06caSMauro Carvalho Chehab 4420c0d06caSMauro Carvalho Chehab if (au0828_debug & 4) 44383afb32aSMauro Carvalho Chehab pr_info("%s() I2C Debugging is enabled\n", __func__); 4440c0d06caSMauro Carvalho Chehab 4450c0d06caSMauro Carvalho Chehab if (au0828_debug & 8) 44683afb32aSMauro Carvalho Chehab pr_info("%s() Bridge Debugging is enabled\n", 4470c0d06caSMauro Carvalho Chehab __func__); 4480c0d06caSMauro Carvalho Chehab 4492fcfd317SMauro Carvalho Chehab if (au0828_debug & 16) 45083afb32aSMauro Carvalho Chehab pr_info("%s() IR Debugging is enabled\n", 4512fcfd317SMauro Carvalho Chehab __func__); 4522fcfd317SMauro Carvalho Chehab 45383afb32aSMauro Carvalho Chehab pr_info("au0828 driver loaded\n"); 4540c0d06caSMauro Carvalho Chehab 4550c0d06caSMauro Carvalho Chehab ret = usb_register(&au0828_usb_driver); 4560c0d06caSMauro Carvalho Chehab if (ret) 45783afb32aSMauro Carvalho Chehab pr_err("usb_register failed, error = %d\n", ret); 4580c0d06caSMauro Carvalho Chehab 4590c0d06caSMauro Carvalho Chehab return ret; 4600c0d06caSMauro Carvalho Chehab } 4610c0d06caSMauro Carvalho Chehab 4620c0d06caSMauro Carvalho Chehab static void __exit au0828_exit(void) 4630c0d06caSMauro Carvalho Chehab { 4640c0d06caSMauro Carvalho Chehab usb_deregister(&au0828_usb_driver); 4650c0d06caSMauro Carvalho Chehab } 4660c0d06caSMauro Carvalho Chehab 4670c0d06caSMauro Carvalho Chehab module_init(au0828_init); 4680c0d06caSMauro Carvalho Chehab module_exit(au0828_exit); 4690c0d06caSMauro Carvalho Chehab 4700c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); 4710c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); 4720c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 4732fcfd317SMauro Carvalho Chehab MODULE_VERSION("0.0.3"); 474