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 235c94903f1SShuah Khan static int au0828_enable_source(struct media_entity *entity, 236c94903f1SShuah Khan struct media_pipeline *pipe) 237c94903f1SShuah Khan { 238c94903f1SShuah Khan #ifdef CONFIG_MEDIA_CONTROLLER 239c94903f1SShuah Khan struct media_entity *source, *find_source; 240c94903f1SShuah Khan struct media_entity *sink; 241c94903f1SShuah Khan struct media_link *link, *found_link = NULL; 242c94903f1SShuah Khan int ret = 0; 243c94903f1SShuah Khan struct media_device *mdev = entity->graph_obj.mdev; 244c94903f1SShuah Khan struct au0828_dev *dev; 245c94903f1SShuah Khan 246c94903f1SShuah Khan if (!mdev) 247c94903f1SShuah Khan return -ENODEV; 248c94903f1SShuah Khan 249c94903f1SShuah Khan mutex_lock(&mdev->graph_mutex); 250c94903f1SShuah Khan 251c94903f1SShuah Khan dev = mdev->source_priv; 252c94903f1SShuah Khan 253c94903f1SShuah Khan /* 254c94903f1SShuah Khan * For Audio and V4L2 entity, find the link to which decoder 255c94903f1SShuah Khan * is the sink. Look for an active link between decoder and 256c94903f1SShuah Khan * source (tuner/s-video/Composite), if one exists, nothing 257c94903f1SShuah Khan * to do. If not, look for any active links between source 258c94903f1SShuah Khan * and any other entity. If one exists, source is busy. If 259c94903f1SShuah Khan * source is free, setup link and start pipeline from source. 260c94903f1SShuah Khan * For DVB FE entity, the source for the link is the tuner. 261c94903f1SShuah Khan * Check if tuner is available and setup link and start 262c94903f1SShuah Khan * pipeline. 263c94903f1SShuah Khan */ 264c94903f1SShuah Khan if (entity->function == MEDIA_ENT_F_DTV_DEMOD) { 265c94903f1SShuah Khan sink = entity; 266c94903f1SShuah Khan find_source = dev->tuner; 267c94903f1SShuah Khan } else { 268c94903f1SShuah Khan /* Analog isn't configured or register failed */ 269c94903f1SShuah Khan if (!dev->decoder) { 270c94903f1SShuah Khan ret = -ENODEV; 271c94903f1SShuah Khan goto end; 272c94903f1SShuah Khan } 273c94903f1SShuah Khan 274c94903f1SShuah Khan sink = dev->decoder; 275c94903f1SShuah Khan 276c94903f1SShuah Khan /* 277c94903f1SShuah Khan * Default input is tuner and default input_type 278c94903f1SShuah Khan * is AU0828_VMUX_TELEVISION. 279c94903f1SShuah Khan * FIXME: 280c94903f1SShuah Khan * There is a problem when s_input is called to 281c94903f1SShuah Khan * change the default input. s_input will try to 282c94903f1SShuah Khan * enable_source before attempting to change the 283c94903f1SShuah Khan * input on the device, and will end up enabling 284c94903f1SShuah Khan * default source which is tuner. 285c94903f1SShuah Khan * 286c94903f1SShuah Khan * Additional logic is necessary in au0828 287c94903f1SShuah Khan * to detect that the input has changed and 288c94903f1SShuah Khan * enable the right source. 289c94903f1SShuah Khan */ 290c94903f1SShuah Khan 291c94903f1SShuah Khan if (dev->input_type == AU0828_VMUX_TELEVISION) 292c94903f1SShuah Khan find_source = dev->tuner; 293c94903f1SShuah Khan else if (dev->input_type == AU0828_VMUX_SVIDEO || 294c94903f1SShuah Khan dev->input_type == AU0828_VMUX_COMPOSITE) 295c94903f1SShuah Khan find_source = &dev->input_ent[dev->input_type]; 296c94903f1SShuah Khan else { 297c94903f1SShuah Khan /* unknown input - let user select input */ 298c94903f1SShuah Khan ret = 0; 299c94903f1SShuah Khan goto end; 300c94903f1SShuah Khan } 301c94903f1SShuah Khan } 302c94903f1SShuah Khan 303c94903f1SShuah Khan /* Is an active link between sink and source */ 304c94903f1SShuah Khan if (dev->active_link) { 305c94903f1SShuah Khan /* 306c94903f1SShuah Khan * If DVB is using the tuner and calling entity is 307c94903f1SShuah Khan * audio/video, the following check will be false, 308c94903f1SShuah Khan * since sink is different. Result is Busy. 309c94903f1SShuah Khan */ 310c94903f1SShuah Khan if (dev->active_link->sink->entity == sink && 311c94903f1SShuah Khan dev->active_link->source->entity == find_source) { 312c94903f1SShuah Khan /* 313c94903f1SShuah Khan * Either ALSA or Video own tuner. sink is 314c94903f1SShuah Khan * the same for both. Prevent Video stepping 315c94903f1SShuah Khan * on ALSA when ALSA owns the source. 316c94903f1SShuah Khan */ 317c94903f1SShuah Khan if (dev->active_link_owner != entity && 318c94903f1SShuah Khan dev->active_link_owner->function == 319c94903f1SShuah Khan MEDIA_ENT_F_AUDIO_CAPTURE) { 320c94903f1SShuah Khan pr_debug("ALSA has the tuner\n"); 321c94903f1SShuah Khan ret = -EBUSY; 322c94903f1SShuah Khan goto end; 323c94903f1SShuah Khan } 324c94903f1SShuah Khan ret = 0; 325c94903f1SShuah Khan goto end; 326c94903f1SShuah Khan } else { 327c94903f1SShuah Khan ret = -EBUSY; 328c94903f1SShuah Khan goto end; 329c94903f1SShuah Khan } 330c94903f1SShuah Khan } 331c94903f1SShuah Khan 332c94903f1SShuah Khan list_for_each_entry(link, &sink->links, list) { 333c94903f1SShuah Khan /* Check sink, and source */ 334c94903f1SShuah Khan if (link->sink->entity == sink && 335c94903f1SShuah Khan link->source->entity == find_source) { 336c94903f1SShuah Khan found_link = link; 337c94903f1SShuah Khan break; 338c94903f1SShuah Khan } 339c94903f1SShuah Khan } 340c94903f1SShuah Khan 341c94903f1SShuah Khan if (!found_link) { 342c94903f1SShuah Khan ret = -ENODEV; 343c94903f1SShuah Khan goto end; 344c94903f1SShuah Khan } 345c94903f1SShuah Khan 346c94903f1SShuah Khan /* activate link between source and sink and start pipeline */ 347c94903f1SShuah Khan source = found_link->source->entity; 348c94903f1SShuah Khan ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED); 349c94903f1SShuah Khan if (ret) { 350c94903f1SShuah Khan pr_err("Activate tuner link %s->%s. Error %d\n", 351c94903f1SShuah Khan source->name, sink->name, ret); 352c94903f1SShuah Khan goto end; 353c94903f1SShuah Khan } 354c94903f1SShuah Khan 355c94903f1SShuah Khan ret = __media_entity_pipeline_start(entity, pipe); 356c94903f1SShuah Khan if (ret) { 357c94903f1SShuah Khan pr_err("Start Pipeline: %s->%s Error %d\n", 358c94903f1SShuah Khan source->name, entity->name, ret); 359c94903f1SShuah Khan ret = __media_entity_setup_link(found_link, 0); 360c94903f1SShuah Khan pr_err("Deactivate link Error %d\n", ret); 361c94903f1SShuah Khan goto end; 362c94903f1SShuah Khan } 363c94903f1SShuah Khan /* 364c94903f1SShuah Khan * save active link and active link owner to avoid audio 365c94903f1SShuah Khan * deactivating video owned link from disable_source and 366c94903f1SShuah Khan * vice versa 367c94903f1SShuah Khan */ 368c94903f1SShuah Khan dev->active_link = found_link; 369c94903f1SShuah Khan dev->active_link_owner = entity; 370c94903f1SShuah Khan dev->active_source = source; 371c94903f1SShuah Khan dev->active_sink = sink; 372c94903f1SShuah Khan 373c94903f1SShuah Khan pr_debug("Enabled Source: %s->%s->%s Ret %d\n", 374c94903f1SShuah Khan dev->active_source->name, dev->active_sink->name, 375c94903f1SShuah Khan dev->active_link_owner->name, ret); 376c94903f1SShuah Khan end: 377c94903f1SShuah Khan mutex_unlock(&mdev->graph_mutex); 378c94903f1SShuah Khan pr_debug("au0828_enable_source() end %s %d %d\n", 379c94903f1SShuah Khan entity->name, entity->function, ret); 380c94903f1SShuah Khan return ret; 381c94903f1SShuah Khan #endif 382c94903f1SShuah Khan return 0; 383c94903f1SShuah Khan } 384c94903f1SShuah Khan 385c94903f1SShuah Khan static void au0828_disable_source(struct media_entity *entity) 386c94903f1SShuah Khan { 387c94903f1SShuah Khan #ifdef CONFIG_MEDIA_CONTROLLER 388c94903f1SShuah Khan int ret = 0; 389c94903f1SShuah Khan struct media_device *mdev = entity->graph_obj.mdev; 390c94903f1SShuah Khan struct au0828_dev *dev; 391c94903f1SShuah Khan 392c94903f1SShuah Khan if (!mdev) 393c94903f1SShuah Khan return; 394c94903f1SShuah Khan 395c94903f1SShuah Khan mutex_lock(&mdev->graph_mutex); 396c94903f1SShuah Khan dev = mdev->source_priv; 397c94903f1SShuah Khan 398c94903f1SShuah Khan if (!dev->active_link) { 399c94903f1SShuah Khan ret = -ENODEV; 400c94903f1SShuah Khan goto end; 401c94903f1SShuah Khan } 402c94903f1SShuah Khan 403c94903f1SShuah Khan /* link is active - stop pipeline from source (tuner) */ 404c94903f1SShuah Khan if (dev->active_link->sink->entity == dev->active_sink && 405c94903f1SShuah Khan dev->active_link->source->entity == dev->active_source) { 406c94903f1SShuah Khan /* 407c94903f1SShuah Khan * prevent video from deactivating link when audio 408c94903f1SShuah Khan * has active pipeline 409c94903f1SShuah Khan */ 410c94903f1SShuah Khan if (dev->active_link_owner != entity) 411c94903f1SShuah Khan goto end; 412c94903f1SShuah Khan __media_entity_pipeline_stop(entity); 413c94903f1SShuah Khan ret = __media_entity_setup_link(dev->active_link, 0); 414c94903f1SShuah Khan if (ret) 415c94903f1SShuah Khan pr_err("Deactivate link Error %d\n", ret); 416c94903f1SShuah Khan 417c94903f1SShuah Khan pr_debug("Disabled Source: %s->%s->%s Ret %d\n", 418c94903f1SShuah Khan dev->active_source->name, dev->active_sink->name, 419c94903f1SShuah Khan dev->active_link_owner->name, ret); 420c94903f1SShuah Khan 421c94903f1SShuah Khan dev->active_link = NULL; 422c94903f1SShuah Khan dev->active_link_owner = NULL; 423c94903f1SShuah Khan dev->active_source = NULL; 424c94903f1SShuah Khan dev->active_sink = NULL; 425c94903f1SShuah Khan } 426c94903f1SShuah Khan 427c94903f1SShuah Khan end: 428c94903f1SShuah Khan mutex_unlock(&mdev->graph_mutex); 429c94903f1SShuah Khan #endif 430c94903f1SShuah Khan } 431c94903f1SShuah Khan 4327b12adf6SShuah Khan static int au0828_media_device_register(struct au0828_dev *dev, 4337b12adf6SShuah Khan struct usb_device *udev) 4347b12adf6SShuah Khan { 4357b12adf6SShuah Khan #ifdef CONFIG_MEDIA_CONTROLLER 4367b12adf6SShuah Khan int ret; 4377b12adf6SShuah Khan 438f90c5d79SShuah Khan if (!dev->media_dev) 439f90c5d79SShuah Khan return 0; 440f90c5d79SShuah Khan 441f90c5d79SShuah Khan if (!media_devnode_is_registered(&dev->media_dev->devnode)) { 4427b12adf6SShuah Khan 4437b12adf6SShuah Khan /* register media device */ 4447b12adf6SShuah Khan ret = media_device_register(dev->media_dev); 4457b12adf6SShuah Khan if (ret) { 4467b12adf6SShuah Khan dev_err(&udev->dev, 4477b12adf6SShuah Khan "Media Device Register Error: %d\n", ret); 4487b12adf6SShuah Khan return ret; 4497b12adf6SShuah Khan } 4507b12adf6SShuah Khan } 451f90c5d79SShuah Khan /* register entity_notify callback */ 452f90c5d79SShuah Khan dev->entity_notify.notify_data = (void *) dev; 453f90c5d79SShuah Khan dev->entity_notify.notify = (void *) au0828_media_graph_notify; 454f90c5d79SShuah Khan ret = media_device_register_entity_notify(dev->media_dev, 455f90c5d79SShuah Khan &dev->entity_notify); 456f90c5d79SShuah Khan if (ret) { 457f90c5d79SShuah Khan dev_err(&udev->dev, 458f90c5d79SShuah Khan "Media Device register entity_notify Error: %d\n", 459f90c5d79SShuah Khan ret); 460f90c5d79SShuah Khan return ret; 461f90c5d79SShuah Khan } 462c94903f1SShuah Khan /* set enable_source */ 463c94903f1SShuah Khan dev->media_dev->source_priv = (void *) dev; 464c94903f1SShuah Khan dev->media_dev->enable_source = au0828_enable_source; 465c94903f1SShuah Khan dev->media_dev->disable_source = au0828_disable_source; 4667b12adf6SShuah Khan #endif 4677b12adf6SShuah Khan return 0; 4687b12adf6SShuah Khan } 469bed69196SRafael Lourenço de Lima Chehab 4700c0d06caSMauro Carvalho Chehab static int au0828_usb_probe(struct usb_interface *interface, 4710c0d06caSMauro Carvalho Chehab const struct usb_device_id *id) 4720c0d06caSMauro Carvalho Chehab { 4738a4e7866SMichael Krufky int ifnum; 474f251b3e7STim Mester int retval = 0; 475f251b3e7STim Mester 4760c0d06caSMauro Carvalho Chehab struct au0828_dev *dev; 4770c0d06caSMauro Carvalho Chehab struct usb_device *usbdev = interface_to_usbdev(interface); 4780c0d06caSMauro Carvalho Chehab 4790c0d06caSMauro Carvalho Chehab ifnum = interface->altsetting->desc.bInterfaceNumber; 4800c0d06caSMauro Carvalho Chehab 4810c0d06caSMauro Carvalho Chehab if (ifnum != 0) 4820c0d06caSMauro Carvalho Chehab return -ENODEV; 4830c0d06caSMauro Carvalho Chehab 4840c0d06caSMauro Carvalho Chehab dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__, 4850c0d06caSMauro Carvalho Chehab le16_to_cpu(usbdev->descriptor.idVendor), 4860c0d06caSMauro Carvalho Chehab le16_to_cpu(usbdev->descriptor.idProduct), 4870c0d06caSMauro Carvalho Chehab ifnum); 4880c0d06caSMauro Carvalho Chehab 4890c0d06caSMauro Carvalho Chehab /* 4900c0d06caSMauro Carvalho Chehab * Make sure we have 480 Mbps of bandwidth, otherwise things like 4910c0d06caSMauro Carvalho Chehab * video stream wouldn't likely work, since 12 Mbps is generally 4920c0d06caSMauro Carvalho Chehab * not enough even for most Digital TV streams. 4930c0d06caSMauro Carvalho Chehab */ 4940c0d06caSMauro Carvalho Chehab if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { 49583afb32aSMauro Carvalho Chehab pr_err("au0828: Device initialization failed.\n"); 49683afb32aSMauro Carvalho Chehab pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n"); 4970c0d06caSMauro Carvalho Chehab return -ENODEV; 4980c0d06caSMauro Carvalho Chehab } 4990c0d06caSMauro Carvalho Chehab 5000c0d06caSMauro Carvalho Chehab dev = kzalloc(sizeof(*dev), GFP_KERNEL); 5010c0d06caSMauro Carvalho Chehab if (dev == NULL) { 50283afb32aSMauro Carvalho Chehab pr_err("%s() Unable to allocate memory\n", __func__); 5030c0d06caSMauro Carvalho Chehab return -ENOMEM; 5040c0d06caSMauro Carvalho Chehab } 5050c0d06caSMauro Carvalho Chehab 5060c0d06caSMauro Carvalho Chehab mutex_init(&dev->lock); 5070c0d06caSMauro Carvalho Chehab mutex_lock(&dev->lock); 5080c0d06caSMauro Carvalho Chehab mutex_init(&dev->mutex); 5090c0d06caSMauro Carvalho Chehab mutex_init(&dev->dvb.lock); 5100c0d06caSMauro Carvalho Chehab dev->usbdev = usbdev; 5110c0d06caSMauro Carvalho Chehab dev->boardnr = id->driver_info; 512e42c8c6eSRafael Lourenço de Lima Chehab dev->board = au0828_boards[dev->boardnr]; 513e42c8c6eSRafael Lourenço de Lima Chehab 5149832e155SJavier Martinez Canillas /* Initialize the media controller */ 5159f806795SMauro Carvalho Chehab retval = au0828_media_device_init(dev, usbdev); 5169f806795SMauro Carvalho Chehab if (retval) { 5179f806795SMauro Carvalho Chehab pr_err("%s() au0828_media_device_init failed\n", 5189f806795SMauro Carvalho Chehab __func__); 5199f806795SMauro Carvalho Chehab mutex_unlock(&dev->lock); 5209f806795SMauro Carvalho Chehab kfree(dev); 5219f806795SMauro Carvalho Chehab return retval; 5229f806795SMauro Carvalho Chehab } 5230c0d06caSMauro Carvalho Chehab 5247b606ffdSMauro Carvalho Chehab retval = au0828_v4l2_device_register(interface, dev); 5250c0d06caSMauro Carvalho Chehab if (retval) { 5267b606ffdSMauro Carvalho Chehab au0828_usb_v4l2_media_release(dev); 5270c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock); 5280c0d06caSMauro Carvalho Chehab kfree(dev); 529e8c26f45SHans Verkuil return retval; 5300c0d06caSMauro Carvalho Chehab } 5310c0d06caSMauro Carvalho Chehab 5320c0d06caSMauro Carvalho Chehab /* Power Up the bridge */ 5330c0d06caSMauro Carvalho Chehab au0828_write(dev, REG_600, 1 << 4); 5340c0d06caSMauro Carvalho Chehab 5350c0d06caSMauro Carvalho Chehab /* Bring up the GPIO's and supporting devices */ 5360c0d06caSMauro Carvalho Chehab au0828_gpio_setup(dev); 5370c0d06caSMauro Carvalho Chehab 5380c0d06caSMauro Carvalho Chehab /* I2C */ 5390c0d06caSMauro Carvalho Chehab au0828_i2c_register(dev); 5400c0d06caSMauro Carvalho Chehab 5410c0d06caSMauro Carvalho Chehab /* Setup */ 5420c0d06caSMauro Carvalho Chehab au0828_card_setup(dev); 5430c0d06caSMauro Carvalho Chehab 5440c0d06caSMauro Carvalho Chehab /* Analog TV */ 54582e92f4cSMauro Carvalho Chehab retval = au0828_analog_register(dev, interface); 54682e92f4cSMauro Carvalho Chehab if (retval) { 54782e92f4cSMauro Carvalho Chehab pr_err("%s() au0282_dev_register failed to register on V4L2\n", 54882e92f4cSMauro Carvalho Chehab __func__); 54982e92f4cSMauro Carvalho Chehab goto done; 55082e92f4cSMauro Carvalho Chehab } 55182e92f4cSMauro Carvalho Chehab 5520c0d06caSMauro Carvalho Chehab /* Digital TV */ 553f251b3e7STim Mester retval = au0828_dvb_register(dev); 554f251b3e7STim Mester if (retval) 555f251b3e7STim Mester pr_err("%s() au0282_dev_register failed\n", 556f251b3e7STim Mester __func__); 557f251b3e7STim Mester 5582fcfd317SMauro Carvalho Chehab /* Remote controller */ 5592fcfd317SMauro Carvalho Chehab au0828_rc_register(dev); 5600c0d06caSMauro Carvalho Chehab 5612fcfd317SMauro Carvalho Chehab /* 5622fcfd317SMauro Carvalho Chehab * Store the pointer to the au0828_dev so it can be accessed in 5632fcfd317SMauro Carvalho Chehab * au0828_usb_disconnect 5642fcfd317SMauro Carvalho Chehab */ 5650c0d06caSMauro Carvalho Chehab usb_set_intfdata(interface, dev); 5660c0d06caSMauro Carvalho Chehab 56783afb32aSMauro Carvalho Chehab pr_info("Registered device AU0828 [%s]\n", 5680c0d06caSMauro Carvalho Chehab dev->board.name == NULL ? "Unset" : dev->board.name); 5690c0d06caSMauro Carvalho Chehab 5700c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock); 5710c0d06caSMauro Carvalho Chehab 5727b12adf6SShuah Khan retval = au0828_media_device_register(dev, usbdev); 5739832e155SJavier Martinez Canillas 5749832e155SJavier Martinez Canillas done: 5759832e155SJavier Martinez Canillas if (retval < 0) 5769832e155SJavier Martinez Canillas au0828_usb_disconnect(interface); 5779832e155SJavier Martinez Canillas 578f251b3e7STim Mester return retval; 5790c0d06caSMauro Carvalho Chehab } 5800c0d06caSMauro Carvalho Chehab 581aaeac199SMauro Carvalho Chehab static int au0828_suspend(struct usb_interface *interface, 582aaeac199SMauro Carvalho Chehab pm_message_t message) 583aaeac199SMauro Carvalho Chehab { 584aaeac199SMauro Carvalho Chehab struct au0828_dev *dev = usb_get_intfdata(interface); 585aaeac199SMauro Carvalho Chehab 586aaeac199SMauro Carvalho Chehab if (!dev) 587aaeac199SMauro Carvalho Chehab return 0; 588aaeac199SMauro Carvalho Chehab 58981187240SMauro Carvalho Chehab pr_info("Suspend\n"); 59081187240SMauro Carvalho Chehab 591aaeac199SMauro Carvalho Chehab au0828_rc_suspend(dev); 5921a1ba95eSMauro Carvalho Chehab au0828_v4l2_suspend(dev); 593b799de75SMauro Carvalho Chehab au0828_dvb_suspend(dev); 594aaeac199SMauro Carvalho Chehab 595aaeac199SMauro Carvalho Chehab /* FIXME: should suspend also ATV/DTV */ 596aaeac199SMauro Carvalho Chehab 597aaeac199SMauro Carvalho Chehab return 0; 598aaeac199SMauro Carvalho Chehab } 599aaeac199SMauro Carvalho Chehab 600aaeac199SMauro Carvalho Chehab static int au0828_resume(struct usb_interface *interface) 601aaeac199SMauro Carvalho Chehab { 602aaeac199SMauro Carvalho Chehab struct au0828_dev *dev = usb_get_intfdata(interface); 603aaeac199SMauro Carvalho Chehab if (!dev) 604aaeac199SMauro Carvalho Chehab return 0; 605aaeac199SMauro Carvalho Chehab 60681187240SMauro Carvalho Chehab pr_info("Resume\n"); 60781187240SMauro Carvalho Chehab 608fa500461SMauro Carvalho Chehab /* Power Up the bridge */ 609fa500461SMauro Carvalho Chehab au0828_write(dev, REG_600, 1 << 4); 610fa500461SMauro Carvalho Chehab 611fa500461SMauro Carvalho Chehab /* Bring up the GPIO's and supporting devices */ 612fa500461SMauro Carvalho Chehab au0828_gpio_setup(dev); 613fa500461SMauro Carvalho Chehab 614aaeac199SMauro Carvalho Chehab au0828_rc_resume(dev); 6151a1ba95eSMauro Carvalho Chehab au0828_v4l2_resume(dev); 616b799de75SMauro Carvalho Chehab au0828_dvb_resume(dev); 617aaeac199SMauro Carvalho Chehab 618aaeac199SMauro Carvalho Chehab /* FIXME: should resume also ATV/DTV */ 619aaeac199SMauro Carvalho Chehab 620aaeac199SMauro Carvalho Chehab return 0; 621aaeac199SMauro Carvalho Chehab } 622aaeac199SMauro Carvalho Chehab 6230c0d06caSMauro Carvalho Chehab static struct usb_driver au0828_usb_driver = { 62483afb32aSMauro Carvalho Chehab .name = KBUILD_MODNAME, 6250c0d06caSMauro Carvalho Chehab .probe = au0828_usb_probe, 6260c0d06caSMauro Carvalho Chehab .disconnect = au0828_usb_disconnect, 6270c0d06caSMauro Carvalho Chehab .id_table = au0828_usb_id_table, 628aaeac199SMauro Carvalho Chehab .suspend = au0828_suspend, 629aaeac199SMauro Carvalho Chehab .resume = au0828_resume, 630aaeac199SMauro Carvalho Chehab .reset_resume = au0828_resume, 6310c0d06caSMauro Carvalho Chehab }; 6320c0d06caSMauro Carvalho Chehab 6330c0d06caSMauro Carvalho Chehab static int __init au0828_init(void) 6340c0d06caSMauro Carvalho Chehab { 6350c0d06caSMauro Carvalho Chehab int ret; 6360c0d06caSMauro Carvalho Chehab 6370c0d06caSMauro Carvalho Chehab if (au0828_debug & 1) 63883afb32aSMauro Carvalho Chehab pr_info("%s() Debugging is enabled\n", __func__); 6390c0d06caSMauro Carvalho Chehab 6400c0d06caSMauro Carvalho Chehab if (au0828_debug & 2) 64183afb32aSMauro Carvalho Chehab pr_info("%s() USB Debugging is enabled\n", __func__); 6420c0d06caSMauro Carvalho Chehab 6430c0d06caSMauro Carvalho Chehab if (au0828_debug & 4) 64483afb32aSMauro Carvalho Chehab pr_info("%s() I2C Debugging is enabled\n", __func__); 6450c0d06caSMauro Carvalho Chehab 6460c0d06caSMauro Carvalho Chehab if (au0828_debug & 8) 64783afb32aSMauro Carvalho Chehab pr_info("%s() Bridge Debugging is enabled\n", 6480c0d06caSMauro Carvalho Chehab __func__); 6490c0d06caSMauro Carvalho Chehab 6502fcfd317SMauro Carvalho Chehab if (au0828_debug & 16) 65183afb32aSMauro Carvalho Chehab pr_info("%s() IR Debugging is enabled\n", 6522fcfd317SMauro Carvalho Chehab __func__); 6532fcfd317SMauro Carvalho Chehab 65483afb32aSMauro Carvalho Chehab pr_info("au0828 driver loaded\n"); 6550c0d06caSMauro Carvalho Chehab 6560c0d06caSMauro Carvalho Chehab ret = usb_register(&au0828_usb_driver); 6570c0d06caSMauro Carvalho Chehab if (ret) 65883afb32aSMauro Carvalho Chehab pr_err("usb_register failed, error = %d\n", ret); 6590c0d06caSMauro Carvalho Chehab 6600c0d06caSMauro Carvalho Chehab return ret; 6610c0d06caSMauro Carvalho Chehab } 6620c0d06caSMauro Carvalho Chehab 6630c0d06caSMauro Carvalho Chehab static void __exit au0828_exit(void) 6640c0d06caSMauro Carvalho Chehab { 6650c0d06caSMauro Carvalho Chehab usb_deregister(&au0828_usb_driver); 6660c0d06caSMauro Carvalho Chehab } 6670c0d06caSMauro Carvalho Chehab 6680c0d06caSMauro Carvalho Chehab module_init(au0828_init); 6690c0d06caSMauro Carvalho Chehab module_exit(au0828_exit); 6700c0d06caSMauro Carvalho Chehab 6710c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); 6720c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); 6730c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 6742fcfd317SMauro Carvalho Chehab MODULE_VERSION("0.0.3"); 675