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 */ 15290cd366bSShuah Khan mutex_lock(&mdev->graph_mutex); 153ffa8576aSShuah Khan dev->media_dev->source_priv = NULL; 154ffa8576aSShuah Khan dev->media_dev->enable_source = NULL; 155ffa8576aSShuah Khan dev->media_dev->disable_source = NULL; 15690cd366bSShuah Khan mutex_unlock(&mdev->graph_mutex); 157ffa8576aSShuah Khan 158bed69196SRafael Lourenço de Lima Chehab media_device_unregister(dev->media_dev); 1599832e155SJavier Martinez Canillas media_device_cleanup(dev->media_dev); 160405ddbfaSMauro Carvalho Chehab kfree(dev->media_dev); 161bed69196SRafael Lourenço de Lima Chehab dev->media_dev = NULL; 162bed69196SRafael Lourenço de Lima Chehab #endif 163bed69196SRafael Lourenço de Lima Chehab } 164bed69196SRafael Lourenço de Lima Chehab 1657b606ffdSMauro Carvalho Chehab void au0828_usb_release(struct au0828_dev *dev) 166823beb7eSHans Verkuil { 167bed69196SRafael Lourenço de Lima Chehab au0828_unregister_media_device(dev); 168bed69196SRafael Lourenço de Lima Chehab 169823beb7eSHans Verkuil /* I2C */ 170823beb7eSHans Verkuil au0828_i2c_unregister(dev); 171823beb7eSHans Verkuil 172823beb7eSHans Verkuil kfree(dev); 173823beb7eSHans Verkuil } 174823beb7eSHans Verkuil 1750c0d06caSMauro Carvalho Chehab static void au0828_usb_disconnect(struct usb_interface *interface) 1760c0d06caSMauro Carvalho Chehab { 1770c0d06caSMauro Carvalho Chehab struct au0828_dev *dev = usb_get_intfdata(interface); 1780c0d06caSMauro Carvalho Chehab 1790c0d06caSMauro Carvalho Chehab dprintk(1, "%s()\n", __func__); 1800c0d06caSMauro Carvalho Chehab 181eb336eabSShuah Khan /* there is a small window after disconnect, before 182eb336eabSShuah Khan dev->usbdev is NULL, for poll (e.g: IR) try to access 183eb336eabSShuah Khan the device and fill the dmesg with error messages. 184eb336eabSShuah Khan Set the status so poll routines can check and avoid 185eb336eabSShuah Khan access after disconnect. 186eb336eabSShuah Khan */ 187e8e3039fSMauro Carvalho Chehab set_bit(DEV_DISCONNECTED, &dev->dev_state); 188eb336eabSShuah Khan 1892fcfd317SMauro Carvalho Chehab au0828_rc_unregister(dev); 1900c0d06caSMauro Carvalho Chehab /* Digital TV */ 1910c0d06caSMauro Carvalho Chehab au0828_dvb_unregister(dev); 1920c0d06caSMauro Carvalho Chehab 1930c0d06caSMauro Carvalho Chehab usb_set_intfdata(interface, NULL); 1940c0d06caSMauro Carvalho Chehab mutex_lock(&dev->mutex); 1950c0d06caSMauro Carvalho Chehab dev->usbdev = NULL; 1960c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->mutex); 1977b606ffdSMauro Carvalho Chehab if (au0828_analog_unregister(dev)) { 1987e9a8ad5SMauro Carvalho Chehab /* 1997e9a8ad5SMauro Carvalho Chehab * No need to call au0828_usb_release() if V4L2 is enabled, 2007e9a8ad5SMauro Carvalho Chehab * as this is already called via au0828_usb_v4l2_release() 2017e9a8ad5SMauro Carvalho Chehab */ 202823beb7eSHans Verkuil return; 203823beb7eSHans Verkuil } 204823beb7eSHans Verkuil au0828_usb_release(dev); 2050c0d06caSMauro Carvalho Chehab } 2060c0d06caSMauro Carvalho Chehab 2079f806795SMauro Carvalho Chehab static int au0828_media_device_init(struct au0828_dev *dev, 208bed69196SRafael Lourenço de Lima Chehab struct usb_device *udev) 209bed69196SRafael Lourenço de Lima Chehab { 210bed69196SRafael Lourenço de Lima Chehab #ifdef CONFIG_MEDIA_CONTROLLER 211bed69196SRafael Lourenço de Lima Chehab struct media_device *mdev; 212bed69196SRafael Lourenço de Lima Chehab 213405ddbfaSMauro Carvalho Chehab mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); 214bed69196SRafael Lourenço de Lima Chehab if (!mdev) 2159f806795SMauro Carvalho Chehab return -ENOMEM; 216bed69196SRafael Lourenço de Lima Chehab 2177b12adf6SShuah Khan /* check if media device is already initialized */ 2187b12adf6SShuah Khan if (!mdev->dev) 219182dde7cSShuah Khan media_device_usb_init(mdev, udev, udev->product); 2206cf5dad1SMauro Carvalho Chehab 221bed69196SRafael Lourenço de Lima Chehab dev->media_dev = mdev; 222bed69196SRafael Lourenço de Lima Chehab #endif 2239f806795SMauro Carvalho Chehab return 0; 224bed69196SRafael Lourenço de Lima Chehab } 225bed69196SRafael Lourenço de Lima Chehab 2260a82edd0SArnd Bergmann #ifdef CONFIG_MEDIA_CONTROLLER 227f90c5d79SShuah Khan static void au0828_media_graph_notify(struct media_entity *new, 228f90c5d79SShuah Khan void *notify_data) 229f90c5d79SShuah Khan { 230f90c5d79SShuah Khan struct au0828_dev *dev = (struct au0828_dev *) notify_data; 231f90c5d79SShuah Khan int ret; 2329096cae1SShuah Khan struct media_entity *entity, *mixer = NULL, *decoder = NULL; 233f90c5d79SShuah Khan 2349096cae1SShuah Khan if (!new) { 2359096cae1SShuah Khan /* 2369096cae1SShuah Khan * Called during au0828 probe time to connect 2379096cae1SShuah Khan * entites that were created prior to registering 2389096cae1SShuah Khan * the notify handler. Find mixer and decoder. 2399096cae1SShuah Khan */ 2409096cae1SShuah Khan media_device_for_each_entity(entity, dev->media_dev) { 2419096cae1SShuah Khan if (entity->function == MEDIA_ENT_F_AUDIO_MIXER) 2429096cae1SShuah Khan mixer = entity; 2439096cae1SShuah Khan else if (entity->function == MEDIA_ENT_F_ATV_DECODER) 2449096cae1SShuah Khan decoder = entity; 2459096cae1SShuah Khan } 2469096cae1SShuah Khan goto create_link; 2479096cae1SShuah Khan } 248f90c5d79SShuah Khan 249f90c5d79SShuah Khan switch (new->function) { 250f90c5d79SShuah Khan case MEDIA_ENT_F_AUDIO_MIXER: 2519096cae1SShuah Khan mixer = new; 2529096cae1SShuah Khan if (dev->decoder) 2539096cae1SShuah Khan decoder = dev->decoder; 2549096cae1SShuah Khan break; 2559096cae1SShuah Khan case MEDIA_ENT_F_ATV_DECODER: 2569096cae1SShuah Khan /* In case, Mixer is added first, find mixer and create link */ 2579096cae1SShuah Khan media_device_for_each_entity(entity, dev->media_dev) { 2589096cae1SShuah Khan if (entity->function == MEDIA_ENT_F_AUDIO_MIXER) 2599096cae1SShuah Khan mixer = entity; 2609096cae1SShuah Khan } 2619096cae1SShuah Khan decoder = new; 262f90c5d79SShuah Khan break; 263f90c5d79SShuah Khan default: 264f90c5d79SShuah Khan break; 265f90c5d79SShuah Khan } 2669096cae1SShuah Khan 2679096cae1SShuah Khan create_link: 2689096cae1SShuah Khan if (decoder && mixer) { 2699096cae1SShuah Khan ret = media_create_pad_link(decoder, 2709096cae1SShuah Khan DEMOD_PAD_AUDIO_OUT, 2719096cae1SShuah Khan mixer, 0, 2729096cae1SShuah Khan MEDIA_LNK_FL_ENABLED); 2739096cae1SShuah Khan if (ret) 2749096cae1SShuah Khan dev_err(&dev->usbdev->dev, 2759096cae1SShuah Khan "Mixer Pad Link Create Error: %d\n", ret); 2769096cae1SShuah Khan } 277f90c5d79SShuah Khan } 278f90c5d79SShuah Khan 27990cd366bSShuah Khan /* Callers should hold graph_mutex */ 280c94903f1SShuah Khan static int au0828_enable_source(struct media_entity *entity, 281c94903f1SShuah Khan struct media_pipeline *pipe) 282c94903f1SShuah Khan { 283c94903f1SShuah Khan struct media_entity *source, *find_source; 284c94903f1SShuah Khan struct media_entity *sink; 285c94903f1SShuah Khan struct media_link *link, *found_link = NULL; 286c94903f1SShuah Khan int ret = 0; 287c94903f1SShuah Khan struct media_device *mdev = entity->graph_obj.mdev; 288c94903f1SShuah Khan struct au0828_dev *dev; 289c94903f1SShuah Khan 290c94903f1SShuah Khan if (!mdev) 291c94903f1SShuah Khan return -ENODEV; 292c94903f1SShuah Khan 293c94903f1SShuah Khan dev = mdev->source_priv; 294c94903f1SShuah Khan 295c94903f1SShuah Khan /* 296c94903f1SShuah Khan * For Audio and V4L2 entity, find the link to which decoder 297c94903f1SShuah Khan * is the sink. Look for an active link between decoder and 298c94903f1SShuah Khan * source (tuner/s-video/Composite), if one exists, nothing 299c94903f1SShuah Khan * to do. If not, look for any active links between source 300c94903f1SShuah Khan * and any other entity. If one exists, source is busy. If 301c94903f1SShuah Khan * source is free, setup link and start pipeline from source. 302c94903f1SShuah Khan * For DVB FE entity, the source for the link is the tuner. 303c94903f1SShuah Khan * Check if tuner is available and setup link and start 304c94903f1SShuah Khan * pipeline. 305c94903f1SShuah Khan */ 306c94903f1SShuah Khan if (entity->function == MEDIA_ENT_F_DTV_DEMOD) { 307c94903f1SShuah Khan sink = entity; 308c94903f1SShuah Khan find_source = dev->tuner; 309c94903f1SShuah Khan } else { 310c94903f1SShuah Khan /* Analog isn't configured or register failed */ 311c94903f1SShuah Khan if (!dev->decoder) { 312c94903f1SShuah Khan ret = -ENODEV; 313c94903f1SShuah Khan goto end; 314c94903f1SShuah Khan } 315c94903f1SShuah Khan 316c94903f1SShuah Khan sink = dev->decoder; 317c94903f1SShuah Khan 318c94903f1SShuah Khan /* 319c94903f1SShuah Khan * Default input is tuner and default input_type 320c94903f1SShuah Khan * is AU0828_VMUX_TELEVISION. 321c94903f1SShuah Khan * FIXME: 322c94903f1SShuah Khan * There is a problem when s_input is called to 323c94903f1SShuah Khan * change the default input. s_input will try to 324c94903f1SShuah Khan * enable_source before attempting to change the 325c94903f1SShuah Khan * input on the device, and will end up enabling 326c94903f1SShuah Khan * default source which is tuner. 327c94903f1SShuah Khan * 328c94903f1SShuah Khan * Additional logic is necessary in au0828 329c94903f1SShuah Khan * to detect that the input has changed and 330c94903f1SShuah Khan * enable the right source. 331c94903f1SShuah Khan */ 332c94903f1SShuah Khan 333c94903f1SShuah Khan if (dev->input_type == AU0828_VMUX_TELEVISION) 334c94903f1SShuah Khan find_source = dev->tuner; 335c94903f1SShuah Khan else if (dev->input_type == AU0828_VMUX_SVIDEO || 336c94903f1SShuah Khan dev->input_type == AU0828_VMUX_COMPOSITE) 337c94903f1SShuah Khan find_source = &dev->input_ent[dev->input_type]; 338c94903f1SShuah Khan else { 339c94903f1SShuah Khan /* unknown input - let user select input */ 340c94903f1SShuah Khan ret = 0; 341c94903f1SShuah Khan goto end; 342c94903f1SShuah Khan } 343c94903f1SShuah Khan } 344c94903f1SShuah Khan 345c94903f1SShuah Khan /* Is an active link between sink and source */ 346c94903f1SShuah Khan if (dev->active_link) { 347c94903f1SShuah Khan /* 348c94903f1SShuah Khan * If DVB is using the tuner and calling entity is 349c94903f1SShuah Khan * audio/video, the following check will be false, 350c94903f1SShuah Khan * since sink is different. Result is Busy. 351c94903f1SShuah Khan */ 352c94903f1SShuah Khan if (dev->active_link->sink->entity == sink && 353c94903f1SShuah Khan dev->active_link->source->entity == find_source) { 354c94903f1SShuah Khan /* 355c94903f1SShuah Khan * Either ALSA or Video own tuner. sink is 356c94903f1SShuah Khan * the same for both. Prevent Video stepping 357c94903f1SShuah Khan * on ALSA when ALSA owns the source. 358c94903f1SShuah Khan */ 359c94903f1SShuah Khan if (dev->active_link_owner != entity && 360c94903f1SShuah Khan dev->active_link_owner->function == 361c94903f1SShuah Khan MEDIA_ENT_F_AUDIO_CAPTURE) { 362c94903f1SShuah Khan pr_debug("ALSA has the tuner\n"); 363c94903f1SShuah Khan ret = -EBUSY; 364c94903f1SShuah Khan goto end; 365c94903f1SShuah Khan } 366c94903f1SShuah Khan ret = 0; 367c94903f1SShuah Khan goto end; 368c94903f1SShuah Khan } else { 369c94903f1SShuah Khan ret = -EBUSY; 370c94903f1SShuah Khan goto end; 371c94903f1SShuah Khan } 372c94903f1SShuah Khan } 373c94903f1SShuah Khan 374c94903f1SShuah Khan list_for_each_entry(link, &sink->links, list) { 375c94903f1SShuah Khan /* Check sink, and source */ 376c94903f1SShuah Khan if (link->sink->entity == sink && 377c94903f1SShuah Khan link->source->entity == find_source) { 378c94903f1SShuah Khan found_link = link; 379c94903f1SShuah Khan break; 380c94903f1SShuah Khan } 381c94903f1SShuah Khan } 382c94903f1SShuah Khan 383c94903f1SShuah Khan if (!found_link) { 384c94903f1SShuah Khan ret = -ENODEV; 385c94903f1SShuah Khan goto end; 386c94903f1SShuah Khan } 387c94903f1SShuah Khan 388c94903f1SShuah Khan /* activate link between source and sink and start pipeline */ 389c94903f1SShuah Khan source = found_link->source->entity; 390c94903f1SShuah Khan ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED); 391c94903f1SShuah Khan if (ret) { 392c94903f1SShuah Khan pr_err("Activate tuner link %s->%s. Error %d\n", 393c94903f1SShuah Khan source->name, sink->name, ret); 394c94903f1SShuah Khan goto end; 395c94903f1SShuah Khan } 396c94903f1SShuah Khan 39720b85227SSakari Ailus ret = __media_pipeline_start(entity, pipe); 398c94903f1SShuah Khan if (ret) { 399c94903f1SShuah Khan pr_err("Start Pipeline: %s->%s Error %d\n", 400c94903f1SShuah Khan source->name, entity->name, ret); 401c94903f1SShuah Khan ret = __media_entity_setup_link(found_link, 0); 402c94903f1SShuah Khan pr_err("Deactivate link Error %d\n", ret); 403c94903f1SShuah Khan goto end; 404c94903f1SShuah Khan } 405c94903f1SShuah Khan /* 406c94903f1SShuah Khan * save active link and active link owner to avoid audio 407c94903f1SShuah Khan * deactivating video owned link from disable_source and 408c94903f1SShuah Khan * vice versa 409c94903f1SShuah Khan */ 410c94903f1SShuah Khan dev->active_link = found_link; 411c94903f1SShuah Khan dev->active_link_owner = entity; 412c94903f1SShuah Khan dev->active_source = source; 413c94903f1SShuah Khan dev->active_sink = sink; 414c94903f1SShuah Khan 415c94903f1SShuah Khan pr_debug("Enabled Source: %s->%s->%s Ret %d\n", 416c94903f1SShuah Khan dev->active_source->name, dev->active_sink->name, 417c94903f1SShuah Khan dev->active_link_owner->name, ret); 418c94903f1SShuah Khan end: 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 42490cd366bSShuah Khan /* Callers should hold graph_mutex */ 425c94903f1SShuah Khan static void au0828_disable_source(struct media_entity *entity) 426c94903f1SShuah Khan { 427c94903f1SShuah Khan int ret = 0; 428c94903f1SShuah Khan struct media_device *mdev = entity->graph_obj.mdev; 429c94903f1SShuah Khan struct au0828_dev *dev; 430c94903f1SShuah Khan 431c94903f1SShuah Khan if (!mdev) 432c94903f1SShuah Khan return; 433c94903f1SShuah Khan 434c94903f1SShuah Khan dev = mdev->source_priv; 435c94903f1SShuah Khan 43690cd366bSShuah Khan if (!dev->active_link) 43790cd366bSShuah Khan return; 438c94903f1SShuah Khan 439c94903f1SShuah Khan /* link is active - stop pipeline from source (tuner) */ 440c94903f1SShuah Khan if (dev->active_link->sink->entity == dev->active_sink && 441c94903f1SShuah Khan dev->active_link->source->entity == dev->active_source) { 442c94903f1SShuah Khan /* 443c94903f1SShuah Khan * prevent video from deactivating link when audio 444c94903f1SShuah Khan * has active pipeline 445c94903f1SShuah Khan */ 446c94903f1SShuah Khan if (dev->active_link_owner != entity) 44790cd366bSShuah Khan return; 44820b85227SSakari Ailus __media_pipeline_stop(entity); 449c94903f1SShuah Khan ret = __media_entity_setup_link(dev->active_link, 0); 450c94903f1SShuah Khan if (ret) 451c94903f1SShuah Khan pr_err("Deactivate link Error %d\n", ret); 452c94903f1SShuah Khan 453c94903f1SShuah Khan pr_debug("Disabled Source: %s->%s->%s Ret %d\n", 454c94903f1SShuah Khan dev->active_source->name, dev->active_sink->name, 455c94903f1SShuah Khan dev->active_link_owner->name, ret); 456c94903f1SShuah Khan 457c94903f1SShuah Khan dev->active_link = NULL; 458c94903f1SShuah Khan dev->active_link_owner = NULL; 459c94903f1SShuah Khan dev->active_source = NULL; 460c94903f1SShuah Khan dev->active_sink = NULL; 461c94903f1SShuah Khan } 462c94903f1SShuah Khan } 4630a82edd0SArnd Bergmann #endif 464c94903f1SShuah Khan 4657b12adf6SShuah Khan static int au0828_media_device_register(struct au0828_dev *dev, 4667b12adf6SShuah Khan struct usb_device *udev) 4677b12adf6SShuah Khan { 4687b12adf6SShuah Khan #ifdef CONFIG_MEDIA_CONTROLLER 4697b12adf6SShuah Khan int ret; 4702e208c64SMauro Carvalho Chehab struct media_entity *entity, *demod = NULL; 4712e208c64SMauro Carvalho Chehab struct media_link *link; 4727b12adf6SShuah Khan 473f90c5d79SShuah Khan if (!dev->media_dev) 474f90c5d79SShuah Khan return 0; 475f90c5d79SShuah Khan 476a087ce70SMauro Carvalho Chehab if (!media_devnode_is_registered(dev->media_dev->devnode)) { 4777b12adf6SShuah Khan 4787b12adf6SShuah Khan /* register media device */ 4797b12adf6SShuah Khan ret = media_device_register(dev->media_dev); 4807b12adf6SShuah Khan if (ret) { 4817b12adf6SShuah Khan dev_err(&udev->dev, 4827b12adf6SShuah Khan "Media Device Register Error: %d\n", ret); 4837b12adf6SShuah Khan return ret; 4847b12adf6SShuah Khan } 4859096cae1SShuah Khan } else { 4869096cae1SShuah Khan /* 4879096cae1SShuah Khan * Call au0828_media_graph_notify() to connect 4889096cae1SShuah Khan * audio graph to our graph. In this case, audio 4899096cae1SShuah Khan * driver registered the device and there is no 4909096cae1SShuah Khan * entity_notify to be called when new entities 4919096cae1SShuah Khan * are added. Invoke it now. 4929096cae1SShuah Khan */ 4939096cae1SShuah Khan au0828_media_graph_notify(NULL, (void *) dev); 4947b12adf6SShuah Khan } 495840f5b05SShuah Khan 496840f5b05SShuah Khan /* 4972e208c64SMauro Carvalho Chehab * Find tuner, decoder and demod. 4982e208c64SMauro Carvalho Chehab * 4992e208c64SMauro Carvalho Chehab * The tuner and decoder should be cached, as they'll be used by 5002e208c64SMauro Carvalho Chehab * au0828_enable_source. 5012e208c64SMauro Carvalho Chehab * 5022e208c64SMauro Carvalho Chehab * It also needs to disable the link between tuner and 5032e208c64SMauro Carvalho Chehab * decoder/demod, to avoid disable step when tuner is requested 5042e208c64SMauro Carvalho Chehab * by video or audio. Note that this step can't be done until dvb 5052e208c64SMauro Carvalho Chehab * graph is created during dvb register. 506840f5b05SShuah Khan */ 507840f5b05SShuah Khan media_device_for_each_entity(entity, dev->media_dev) { 5082e208c64SMauro Carvalho Chehab switch (entity->function) { 5092e208c64SMauro Carvalho Chehab case MEDIA_ENT_F_TUNER: 5102e208c64SMauro Carvalho Chehab dev->tuner = entity; 5112e208c64SMauro Carvalho Chehab break; 5122e208c64SMauro Carvalho Chehab case MEDIA_ENT_F_ATV_DECODER: 5132e208c64SMauro Carvalho Chehab dev->decoder = entity; 5142e208c64SMauro Carvalho Chehab break; 5152e208c64SMauro Carvalho Chehab case MEDIA_ENT_F_DTV_DEMOD: 516840f5b05SShuah Khan demod = entity; 5172e208c64SMauro Carvalho Chehab break; 518840f5b05SShuah Khan } 5192e208c64SMauro Carvalho Chehab } 520840f5b05SShuah Khan 5212e208c64SMauro Carvalho Chehab /* Disable link between tuner->demod and/or tuner->decoder */ 5222e208c64SMauro Carvalho Chehab if (dev->tuner) { 5232e208c64SMauro Carvalho Chehab list_for_each_entry(link, &dev->tuner->links, list) { 5242e208c64SMauro Carvalho Chehab if (demod && link->sink->entity == demod) 525840f5b05SShuah Khan media_entity_setup_link(link, 0); 5262e208c64SMauro Carvalho Chehab if (dev->decoder && link->sink->entity == dev->decoder) 5272e208c64SMauro Carvalho Chehab media_entity_setup_link(link, 0); 528840f5b05SShuah Khan } 529840f5b05SShuah Khan } 530840f5b05SShuah Khan 531f90c5d79SShuah Khan /* register entity_notify callback */ 532f90c5d79SShuah Khan dev->entity_notify.notify_data = (void *) dev; 533f90c5d79SShuah Khan dev->entity_notify.notify = (void *) au0828_media_graph_notify; 534f90c5d79SShuah Khan ret = media_device_register_entity_notify(dev->media_dev, 535f90c5d79SShuah Khan &dev->entity_notify); 536f90c5d79SShuah Khan if (ret) { 537f90c5d79SShuah Khan dev_err(&udev->dev, 538f90c5d79SShuah Khan "Media Device register entity_notify Error: %d\n", 539f90c5d79SShuah Khan ret); 540f90c5d79SShuah Khan return ret; 541f90c5d79SShuah Khan } 542c94903f1SShuah Khan /* set enable_source */ 54390cd366bSShuah Khan mutex_lock(&dev->media_dev->graph_mutex); 544c94903f1SShuah Khan dev->media_dev->source_priv = (void *) dev; 545c94903f1SShuah Khan dev->media_dev->enable_source = au0828_enable_source; 546c94903f1SShuah Khan dev->media_dev->disable_source = au0828_disable_source; 54790cd366bSShuah Khan mutex_unlock(&dev->media_dev->graph_mutex); 5487b12adf6SShuah Khan #endif 5497b12adf6SShuah Khan return 0; 5507b12adf6SShuah Khan } 551bed69196SRafael Lourenço de Lima Chehab 5520c0d06caSMauro Carvalho Chehab static int au0828_usb_probe(struct usb_interface *interface, 5530c0d06caSMauro Carvalho Chehab const struct usb_device_id *id) 5540c0d06caSMauro Carvalho Chehab { 5558a4e7866SMichael Krufky int ifnum; 556f251b3e7STim Mester int retval = 0; 557f251b3e7STim Mester 5580c0d06caSMauro Carvalho Chehab struct au0828_dev *dev; 5590c0d06caSMauro Carvalho Chehab struct usb_device *usbdev = interface_to_usbdev(interface); 5600c0d06caSMauro Carvalho Chehab 5610c0d06caSMauro Carvalho Chehab ifnum = interface->altsetting->desc.bInterfaceNumber; 5620c0d06caSMauro Carvalho Chehab 5630c0d06caSMauro Carvalho Chehab if (ifnum != 0) 5640c0d06caSMauro Carvalho Chehab return -ENODEV; 5650c0d06caSMauro Carvalho Chehab 5660c0d06caSMauro Carvalho Chehab dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__, 5670c0d06caSMauro Carvalho Chehab le16_to_cpu(usbdev->descriptor.idVendor), 5680c0d06caSMauro Carvalho Chehab le16_to_cpu(usbdev->descriptor.idProduct), 5690c0d06caSMauro Carvalho Chehab ifnum); 5700c0d06caSMauro Carvalho Chehab 5710c0d06caSMauro Carvalho Chehab /* 5720c0d06caSMauro Carvalho Chehab * Make sure we have 480 Mbps of bandwidth, otherwise things like 5730c0d06caSMauro Carvalho Chehab * video stream wouldn't likely work, since 12 Mbps is generally 5740c0d06caSMauro Carvalho Chehab * not enough even for most Digital TV streams. 5750c0d06caSMauro Carvalho Chehab */ 5760c0d06caSMauro Carvalho Chehab if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { 57783afb32aSMauro Carvalho Chehab pr_err("au0828: Device initialization failed.\n"); 57883afb32aSMauro Carvalho Chehab pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n"); 5790c0d06caSMauro Carvalho Chehab return -ENODEV; 5800c0d06caSMauro Carvalho Chehab } 5810c0d06caSMauro Carvalho Chehab 5820c0d06caSMauro Carvalho Chehab dev = kzalloc(sizeof(*dev), GFP_KERNEL); 5830c0d06caSMauro Carvalho Chehab if (dev == NULL) { 58483afb32aSMauro Carvalho Chehab pr_err("%s() Unable to allocate memory\n", __func__); 5850c0d06caSMauro Carvalho Chehab return -ENOMEM; 5860c0d06caSMauro Carvalho Chehab } 5870c0d06caSMauro Carvalho Chehab 5880c0d06caSMauro Carvalho Chehab mutex_init(&dev->lock); 5890c0d06caSMauro Carvalho Chehab mutex_lock(&dev->lock); 5900c0d06caSMauro Carvalho Chehab mutex_init(&dev->mutex); 5910c0d06caSMauro Carvalho Chehab mutex_init(&dev->dvb.lock); 5920c0d06caSMauro Carvalho Chehab dev->usbdev = usbdev; 5930c0d06caSMauro Carvalho Chehab dev->boardnr = id->driver_info; 594e42c8c6eSRafael Lourenço de Lima Chehab dev->board = au0828_boards[dev->boardnr]; 595e42c8c6eSRafael Lourenço de Lima Chehab 5969832e155SJavier Martinez Canillas /* Initialize the media controller */ 5979f806795SMauro Carvalho Chehab retval = au0828_media_device_init(dev, usbdev); 5989f806795SMauro Carvalho Chehab if (retval) { 5999f806795SMauro Carvalho Chehab pr_err("%s() au0828_media_device_init failed\n", 6009f806795SMauro Carvalho Chehab __func__); 6019f806795SMauro Carvalho Chehab mutex_unlock(&dev->lock); 6029f806795SMauro Carvalho Chehab kfree(dev); 6039f806795SMauro Carvalho Chehab return retval; 6049f806795SMauro Carvalho Chehab } 6050c0d06caSMauro Carvalho Chehab 6067b606ffdSMauro Carvalho Chehab retval = au0828_v4l2_device_register(interface, dev); 6070c0d06caSMauro Carvalho Chehab if (retval) { 6087b606ffdSMauro Carvalho Chehab au0828_usb_v4l2_media_release(dev); 6090c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock); 6100c0d06caSMauro Carvalho Chehab kfree(dev); 611e8c26f45SHans Verkuil return retval; 6120c0d06caSMauro Carvalho Chehab } 6130c0d06caSMauro Carvalho Chehab 6140c0d06caSMauro Carvalho Chehab /* Power Up the bridge */ 6150c0d06caSMauro Carvalho Chehab au0828_write(dev, REG_600, 1 << 4); 6160c0d06caSMauro Carvalho Chehab 6170c0d06caSMauro Carvalho Chehab /* Bring up the GPIO's and supporting devices */ 6180c0d06caSMauro Carvalho Chehab au0828_gpio_setup(dev); 6190c0d06caSMauro Carvalho Chehab 6200c0d06caSMauro Carvalho Chehab /* I2C */ 6210c0d06caSMauro Carvalho Chehab au0828_i2c_register(dev); 6220c0d06caSMauro Carvalho Chehab 6230c0d06caSMauro Carvalho Chehab /* Setup */ 6240c0d06caSMauro Carvalho Chehab au0828_card_setup(dev); 6250c0d06caSMauro Carvalho Chehab 6260c0d06caSMauro Carvalho Chehab /* Analog TV */ 62782e92f4cSMauro Carvalho Chehab retval = au0828_analog_register(dev, interface); 62882e92f4cSMauro Carvalho Chehab if (retval) { 62982e92f4cSMauro Carvalho Chehab pr_err("%s() au0282_dev_register failed to register on V4L2\n", 63082e92f4cSMauro Carvalho Chehab __func__); 63182e92f4cSMauro Carvalho Chehab goto done; 63282e92f4cSMauro Carvalho Chehab } 63382e92f4cSMauro Carvalho Chehab 6340c0d06caSMauro Carvalho Chehab /* Digital TV */ 635f251b3e7STim Mester retval = au0828_dvb_register(dev); 636f251b3e7STim Mester if (retval) 637f251b3e7STim Mester pr_err("%s() au0282_dev_register failed\n", 638f251b3e7STim Mester __func__); 639f251b3e7STim Mester 6402fcfd317SMauro Carvalho Chehab /* Remote controller */ 6412fcfd317SMauro Carvalho Chehab au0828_rc_register(dev); 6420c0d06caSMauro Carvalho Chehab 6432fcfd317SMauro Carvalho Chehab /* 6442fcfd317SMauro Carvalho Chehab * Store the pointer to the au0828_dev so it can be accessed in 6452fcfd317SMauro Carvalho Chehab * au0828_usb_disconnect 6462fcfd317SMauro Carvalho Chehab */ 6470c0d06caSMauro Carvalho Chehab usb_set_intfdata(interface, dev); 6480c0d06caSMauro Carvalho Chehab 64983afb32aSMauro Carvalho Chehab pr_info("Registered device AU0828 [%s]\n", 6500c0d06caSMauro Carvalho Chehab dev->board.name == NULL ? "Unset" : dev->board.name); 6510c0d06caSMauro Carvalho Chehab 6520c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock); 6530c0d06caSMauro Carvalho Chehab 6547b12adf6SShuah Khan retval = au0828_media_device_register(dev, usbdev); 6559832e155SJavier Martinez Canillas 6569832e155SJavier Martinez Canillas done: 6579832e155SJavier Martinez Canillas if (retval < 0) 6589832e155SJavier Martinez Canillas au0828_usb_disconnect(interface); 6599832e155SJavier Martinez Canillas 660f251b3e7STim Mester return retval; 6610c0d06caSMauro Carvalho Chehab } 6620c0d06caSMauro Carvalho Chehab 663aaeac199SMauro Carvalho Chehab static int au0828_suspend(struct usb_interface *interface, 664aaeac199SMauro Carvalho Chehab pm_message_t message) 665aaeac199SMauro Carvalho Chehab { 666aaeac199SMauro Carvalho Chehab struct au0828_dev *dev = usb_get_intfdata(interface); 667aaeac199SMauro Carvalho Chehab 668aaeac199SMauro Carvalho Chehab if (!dev) 669aaeac199SMauro Carvalho Chehab return 0; 670aaeac199SMauro Carvalho Chehab 67181187240SMauro Carvalho Chehab pr_info("Suspend\n"); 67281187240SMauro Carvalho Chehab 673aaeac199SMauro Carvalho Chehab au0828_rc_suspend(dev); 6741a1ba95eSMauro Carvalho Chehab au0828_v4l2_suspend(dev); 675b799de75SMauro Carvalho Chehab au0828_dvb_suspend(dev); 676aaeac199SMauro Carvalho Chehab 677aaeac199SMauro Carvalho Chehab /* FIXME: should suspend also ATV/DTV */ 678aaeac199SMauro Carvalho Chehab 679aaeac199SMauro Carvalho Chehab return 0; 680aaeac199SMauro Carvalho Chehab } 681aaeac199SMauro Carvalho Chehab 682aaeac199SMauro Carvalho Chehab static int au0828_resume(struct usb_interface *interface) 683aaeac199SMauro Carvalho Chehab { 684aaeac199SMauro Carvalho Chehab struct au0828_dev *dev = usb_get_intfdata(interface); 685aaeac199SMauro Carvalho Chehab if (!dev) 686aaeac199SMauro Carvalho Chehab return 0; 687aaeac199SMauro Carvalho Chehab 68881187240SMauro Carvalho Chehab pr_info("Resume\n"); 68981187240SMauro Carvalho Chehab 690fa500461SMauro Carvalho Chehab /* Power Up the bridge */ 691fa500461SMauro Carvalho Chehab au0828_write(dev, REG_600, 1 << 4); 692fa500461SMauro Carvalho Chehab 693fa500461SMauro Carvalho Chehab /* Bring up the GPIO's and supporting devices */ 694fa500461SMauro Carvalho Chehab au0828_gpio_setup(dev); 695fa500461SMauro Carvalho Chehab 696aaeac199SMauro Carvalho Chehab au0828_rc_resume(dev); 6971a1ba95eSMauro Carvalho Chehab au0828_v4l2_resume(dev); 698b799de75SMauro Carvalho Chehab au0828_dvb_resume(dev); 699aaeac199SMauro Carvalho Chehab 700aaeac199SMauro Carvalho Chehab /* FIXME: should resume also ATV/DTV */ 701aaeac199SMauro Carvalho Chehab 702aaeac199SMauro Carvalho Chehab return 0; 703aaeac199SMauro Carvalho Chehab } 704aaeac199SMauro Carvalho Chehab 7050c0d06caSMauro Carvalho Chehab static struct usb_driver au0828_usb_driver = { 70683afb32aSMauro Carvalho Chehab .name = KBUILD_MODNAME, 7070c0d06caSMauro Carvalho Chehab .probe = au0828_usb_probe, 7080c0d06caSMauro Carvalho Chehab .disconnect = au0828_usb_disconnect, 7090c0d06caSMauro Carvalho Chehab .id_table = au0828_usb_id_table, 710aaeac199SMauro Carvalho Chehab .suspend = au0828_suspend, 711aaeac199SMauro Carvalho Chehab .resume = au0828_resume, 712aaeac199SMauro Carvalho Chehab .reset_resume = au0828_resume, 7130c0d06caSMauro Carvalho Chehab }; 7140c0d06caSMauro Carvalho Chehab 7150c0d06caSMauro Carvalho Chehab static int __init au0828_init(void) 7160c0d06caSMauro Carvalho Chehab { 7170c0d06caSMauro Carvalho Chehab int ret; 7180c0d06caSMauro Carvalho Chehab 7190c0d06caSMauro Carvalho Chehab if (au0828_debug & 1) 72083afb32aSMauro Carvalho Chehab pr_info("%s() Debugging is enabled\n", __func__); 7210c0d06caSMauro Carvalho Chehab 7220c0d06caSMauro Carvalho Chehab if (au0828_debug & 2) 72383afb32aSMauro Carvalho Chehab pr_info("%s() USB Debugging is enabled\n", __func__); 7240c0d06caSMauro Carvalho Chehab 7250c0d06caSMauro Carvalho Chehab if (au0828_debug & 4) 72683afb32aSMauro Carvalho Chehab pr_info("%s() I2C Debugging is enabled\n", __func__); 7270c0d06caSMauro Carvalho Chehab 7280c0d06caSMauro Carvalho Chehab if (au0828_debug & 8) 72983afb32aSMauro Carvalho Chehab pr_info("%s() Bridge Debugging is enabled\n", 7300c0d06caSMauro Carvalho Chehab __func__); 7310c0d06caSMauro Carvalho Chehab 7322fcfd317SMauro Carvalho Chehab if (au0828_debug & 16) 73383afb32aSMauro Carvalho Chehab pr_info("%s() IR Debugging is enabled\n", 7342fcfd317SMauro Carvalho Chehab __func__); 7352fcfd317SMauro Carvalho Chehab 73683afb32aSMauro Carvalho Chehab pr_info("au0828 driver loaded\n"); 7370c0d06caSMauro Carvalho Chehab 7380c0d06caSMauro Carvalho Chehab ret = usb_register(&au0828_usb_driver); 7390c0d06caSMauro Carvalho Chehab if (ret) 74083afb32aSMauro Carvalho Chehab pr_err("usb_register failed, error = %d\n", ret); 7410c0d06caSMauro Carvalho Chehab 7420c0d06caSMauro Carvalho Chehab return ret; 7430c0d06caSMauro Carvalho Chehab } 7440c0d06caSMauro Carvalho Chehab 7450c0d06caSMauro Carvalho Chehab static void __exit au0828_exit(void) 7460c0d06caSMauro Carvalho Chehab { 7470c0d06caSMauro Carvalho Chehab usb_deregister(&au0828_usb_driver); 7480c0d06caSMauro Carvalho Chehab } 7490c0d06caSMauro Carvalho Chehab 7500c0d06caSMauro Carvalho Chehab module_init(au0828_init); 7510c0d06caSMauro Carvalho Chehab module_exit(au0828_exit); 7520c0d06caSMauro Carvalho Chehab 7530c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); 7540c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); 7550c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 7562fcfd317SMauro Carvalho Chehab MODULE_VERSION("0.0.3"); 757