linux/drivers/media/radio/radio-shark2.c
<<
>>
Prefs
   1/*
   2 * Linux V4L2 radio driver for the Griffin radioSHARK2 USB radio receiver
   3 *
   4 * Note the radioSHARK2 offers the audio through a regular USB audio device,
   5 * this driver only handles the tuning.
   6 *
   7 * The info necessary to drive the shark2 was taken from the small userspace
   8 * shark2.c program by Hisaaki Shibata, which he kindly placed in the Public
   9 * Domain.
  10 *
  11 * Copyright (c) 2012 Hans de Goede <hdegoede@redhat.com>
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License as published by
  15 * the Free Software Foundation; either version 2 of the License, or
  16 * (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, write to the Free Software
  25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  26 */
  27
  28#include <linux/init.h>
  29#include <linux/kernel.h>
  30#include <linux/leds.h>
  31#include <linux/module.h>
  32#include <linux/slab.h>
  33#include <linux/usb.h>
  34#include <linux/workqueue.h>
  35#include <media/v4l2-device.h>
  36#include "radio-tea5777.h"
  37
  38#if defined(CONFIG_LEDS_CLASS) || \
  39    (defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK2_MODULE))
  40#define SHARK_USE_LEDS 1
  41#endif
  42
  43MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
  44MODULE_DESCRIPTION("Griffin radioSHARK2, USB radio receiver driver");
  45MODULE_LICENSE("GPL");
  46
  47static int debug;
  48module_param(debug, int, 0);
  49MODULE_PARM_DESC(debug, "Debug level (0-1)");
  50
  51#define SHARK_IN_EP             0x83
  52#define SHARK_OUT_EP            0x05
  53
  54#define TB_LEN 7
  55#define DRV_NAME "radioshark2"
  56
  57#define v4l2_dev_to_shark(d) container_of(d, struct shark_device, v4l2_dev)
  58
  59enum { BLUE_LED, RED_LED, NO_LEDS };
  60
  61struct shark_device {
  62        struct usb_device *usbdev;
  63        struct v4l2_device v4l2_dev;
  64        struct radio_tea5777 tea;
  65
  66#ifdef SHARK_USE_LEDS
  67        struct work_struct led_work;
  68        struct led_classdev leds[NO_LEDS];
  69        char led_names[NO_LEDS][32];
  70        atomic_t brightness[NO_LEDS];
  71        unsigned long brightness_new;
  72#endif
  73
  74        u8 *transfer_buffer;
  75};
  76
  77static atomic_t shark_instance = ATOMIC_INIT(0);
  78
  79static int shark_write_reg(struct radio_tea5777 *tea, u64 reg)
  80{
  81        struct shark_device *shark = tea->private_data;
  82        int i, res, actual_len;
  83
  84        memset(shark->transfer_buffer, 0, TB_LEN);
  85        shark->transfer_buffer[0] = 0x81; /* Write register command */
  86        for (i = 0; i < 6; i++)
  87                shark->transfer_buffer[i + 1] = (reg >> (40 - i * 8)) & 0xff;
  88
  89        v4l2_dbg(1, debug, tea->v4l2_dev, "shark2-write: %*ph\n",
  90                 7, shark->transfer_buffer);
  91
  92        res = usb_interrupt_msg(shark->usbdev,
  93                                usb_sndintpipe(shark->usbdev, SHARK_OUT_EP),
  94                                shark->transfer_buffer, TB_LEN,
  95                                &actual_len, 1000);
  96        if (res < 0) {
  97                v4l2_err(tea->v4l2_dev, "write error: %d\n", res);
  98                return res;
  99        }
 100
 101        return 0;
 102}
 103
 104static int shark_read_reg(struct radio_tea5777 *tea, u32 *reg_ret)
 105{
 106        struct shark_device *shark = tea->private_data;
 107        int i, res, actual_len;
 108        u32 reg = 0;
 109
 110        memset(shark->transfer_buffer, 0, TB_LEN);
 111        shark->transfer_buffer[0] = 0x82;
 112        res = usb_interrupt_msg(shark->usbdev,
 113                                usb_sndintpipe(shark->usbdev, SHARK_OUT_EP),
 114                                shark->transfer_buffer, TB_LEN,
 115                                &actual_len, 1000);
 116        if (res < 0) {
 117                v4l2_err(tea->v4l2_dev, "request-read error: %d\n", res);
 118                return res;
 119        }
 120
 121        res = usb_interrupt_msg(shark->usbdev,
 122                                usb_rcvintpipe(shark->usbdev, SHARK_IN_EP),
 123                                shark->transfer_buffer, TB_LEN,
 124                                &actual_len, 1000);
 125        if (res < 0) {
 126                v4l2_err(tea->v4l2_dev, "read error: %d\n", res);
 127                return res;
 128        }
 129
 130        for (i = 0; i < 3; i++)
 131                reg |= shark->transfer_buffer[i] << (16 - i * 8);
 132
 133        v4l2_dbg(1, debug, tea->v4l2_dev, "shark2-read: %*ph\n",
 134                 3, shark->transfer_buffer);
 135
 136        *reg_ret = reg;
 137        return 0;
 138}
 139
 140static struct radio_tea5777_ops shark_tea_ops = {
 141        .write_reg = shark_write_reg,
 142        .read_reg  = shark_read_reg,
 143};
 144
 145#ifdef SHARK_USE_LEDS
 146static void shark_led_work(struct work_struct *work)
 147{
 148        struct shark_device *shark =
 149                container_of(work, struct shark_device, led_work);
 150        int i, res, brightness, actual_len;
 151
 152        for (i = 0; i < 2; i++) {
 153                if (!test_and_clear_bit(i, &shark->brightness_new))
 154                        continue;
 155
 156                brightness = atomic_read(&shark->brightness[i]);
 157                memset(shark->transfer_buffer, 0, TB_LEN);
 158                shark->transfer_buffer[0] = 0x83 + i;
 159                shark->transfer_buffer[1] = brightness;
 160                res = usb_interrupt_msg(shark->usbdev,
 161                                        usb_sndintpipe(shark->usbdev,
 162                                                       SHARK_OUT_EP),
 163                                        shark->transfer_buffer, TB_LEN,
 164                                        &actual_len, 1000);
 165                if (res < 0)
 166                        v4l2_err(&shark->v4l2_dev, "set LED %s error: %d\n",
 167                                 shark->led_names[i], res);
 168        }
 169}
 170
 171static void shark_led_set_blue(struct led_classdev *led_cdev,
 172                               enum led_brightness value)
 173{
 174        struct shark_device *shark =
 175                container_of(led_cdev, struct shark_device, leds[BLUE_LED]);
 176
 177        atomic_set(&shark->brightness[BLUE_LED], value);
 178        set_bit(BLUE_LED, &shark->brightness_new);
 179        schedule_work(&shark->led_work);
 180}
 181
 182static void shark_led_set_red(struct led_classdev *led_cdev,
 183                              enum led_brightness value)
 184{
 185        struct shark_device *shark =
 186                container_of(led_cdev, struct shark_device, leds[RED_LED]);
 187
 188        atomic_set(&shark->brightness[RED_LED], value);
 189        set_bit(RED_LED, &shark->brightness_new);
 190        schedule_work(&shark->led_work);
 191}
 192
 193static const struct led_classdev shark_led_templates[NO_LEDS] = {
 194        [BLUE_LED] = {
 195                .name           = "%s:blue:",
 196                .brightness     = LED_OFF,
 197                .max_brightness = 127,
 198                .brightness_set = shark_led_set_blue,
 199        },
 200        [RED_LED] = {
 201                .name           = "%s:red:",
 202                .brightness     = LED_OFF,
 203                .max_brightness = 1,
 204                .brightness_set = shark_led_set_red,
 205        },
 206};
 207
 208static int shark_register_leds(struct shark_device *shark, struct device *dev)
 209{
 210        int i, retval;
 211
 212        atomic_set(&shark->brightness[BLUE_LED], 127);
 213        INIT_WORK(&shark->led_work, shark_led_work);
 214        for (i = 0; i < NO_LEDS; i++) {
 215                shark->leds[i] = shark_led_templates[i];
 216                snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
 217                         shark->leds[i].name, shark->v4l2_dev.name);
 218                shark->leds[i].name = shark->led_names[i];
 219                retval = led_classdev_register(dev, &shark->leds[i]);
 220                if (retval) {
 221                        v4l2_err(&shark->v4l2_dev,
 222                                 "couldn't register led: %s\n",
 223                                 shark->led_names[i]);
 224                        return retval;
 225                }
 226        }
 227        return 0;
 228}
 229
 230static void shark_unregister_leds(struct shark_device *shark)
 231{
 232        int i;
 233
 234        for (i = 0; i < NO_LEDS; i++)
 235                led_classdev_unregister(&shark->leds[i]);
 236
 237        cancel_work_sync(&shark->led_work);
 238}
 239
 240static void shark_resume_leds(struct shark_device *shark)
 241{
 242        int i;
 243
 244        for (i = 0; i < NO_LEDS; i++)
 245                set_bit(i, &shark->brightness_new);
 246
 247        schedule_work(&shark->led_work);
 248}
 249#else
 250static int shark_register_leds(struct shark_device *shark, struct device *dev)
 251{
 252        v4l2_warn(&shark->v4l2_dev,
 253                  "CONFIG_LEDS_CLASS not enabled, LED support disabled\n");
 254        return 0;
 255}
 256static inline void shark_unregister_leds(struct shark_device *shark) { }
 257static inline void shark_resume_leds(struct shark_device *shark) { }
 258#endif
 259
 260static void usb_shark_disconnect(struct usb_interface *intf)
 261{
 262        struct v4l2_device *v4l2_dev = usb_get_intfdata(intf);
 263        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
 264
 265        mutex_lock(&shark->tea.mutex);
 266        v4l2_device_disconnect(&shark->v4l2_dev);
 267        radio_tea5777_exit(&shark->tea);
 268        mutex_unlock(&shark->tea.mutex);
 269
 270        shark_unregister_leds(shark);
 271
 272        v4l2_device_put(&shark->v4l2_dev);
 273}
 274
 275static void usb_shark_release(struct v4l2_device *v4l2_dev)
 276{
 277        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
 278
 279        v4l2_device_unregister(&shark->v4l2_dev);
 280        kfree(shark->transfer_buffer);
 281        kfree(shark);
 282}
 283
 284static int usb_shark_probe(struct usb_interface *intf,
 285                           const struct usb_device_id *id)
 286{
 287        struct shark_device *shark;
 288        int retval = -ENOMEM;
 289
 290        shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
 291        if (!shark)
 292                return retval;
 293
 294        shark->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL);
 295        if (!shark->transfer_buffer)
 296                goto err_alloc_buffer;
 297
 298        v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
 299
 300        retval = shark_register_leds(shark, &intf->dev);
 301        if (retval)
 302                goto err_reg_leds;
 303
 304        shark->v4l2_dev.release = usb_shark_release;
 305        retval = v4l2_device_register(&intf->dev, &shark->v4l2_dev);
 306        if (retval) {
 307                v4l2_err(&shark->v4l2_dev, "couldn't register v4l2_device\n");
 308                goto err_reg_dev;
 309        }
 310
 311        shark->usbdev = interface_to_usbdev(intf);
 312        shark->tea.v4l2_dev = &shark->v4l2_dev;
 313        shark->tea.private_data = shark;
 314        shark->tea.ops = &shark_tea_ops;
 315        shark->tea.has_am = true;
 316        shark->tea.write_before_read = true;
 317        strlcpy(shark->tea.card, "Griffin radioSHARK2",
 318                sizeof(shark->tea.card));
 319        usb_make_path(shark->usbdev, shark->tea.bus_info,
 320                sizeof(shark->tea.bus_info));
 321
 322        retval = radio_tea5777_init(&shark->tea, THIS_MODULE);
 323        if (retval) {
 324                v4l2_err(&shark->v4l2_dev, "couldn't init tea5777\n");
 325                goto err_init_tea;
 326        }
 327
 328        return 0;
 329
 330err_init_tea:
 331        v4l2_device_unregister(&shark->v4l2_dev);
 332err_reg_dev:
 333        shark_unregister_leds(shark);
 334err_reg_leds:
 335        kfree(shark->transfer_buffer);
 336err_alloc_buffer:
 337        kfree(shark);
 338
 339        return retval;
 340}
 341
 342#ifdef CONFIG_PM
 343static int usb_shark_suspend(struct usb_interface *intf, pm_message_t message)
 344{
 345        return 0;
 346}
 347
 348static int usb_shark_resume(struct usb_interface *intf)
 349{
 350        struct v4l2_device *v4l2_dev = usb_get_intfdata(intf);
 351        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
 352        int ret;
 353
 354        mutex_lock(&shark->tea.mutex);
 355        ret = radio_tea5777_set_freq(&shark->tea);
 356        mutex_unlock(&shark->tea.mutex);
 357
 358        shark_resume_leds(shark);
 359
 360        return ret;
 361}
 362#endif
 363
 364/* Specify the bcdDevice value, as the radioSHARK and radioSHARK2 share ids */
 365static struct usb_device_id usb_shark_device_table[] = {
 366        { .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
 367                         USB_DEVICE_ID_MATCH_INT_CLASS,
 368          .idVendor     = 0x077d,
 369          .idProduct    = 0x627a,
 370          .bcdDevice_lo = 0x0010,
 371          .bcdDevice_hi = 0x0010,
 372          .bInterfaceClass = 3,
 373        },
 374        { }
 375};
 376MODULE_DEVICE_TABLE(usb, usb_shark_device_table);
 377
 378static struct usb_driver usb_shark_driver = {
 379        .name                   = DRV_NAME,
 380        .probe                  = usb_shark_probe,
 381        .disconnect             = usb_shark_disconnect,
 382        .id_table               = usb_shark_device_table,
 383#ifdef CONFIG_PM
 384        .suspend                = usb_shark_suspend,
 385        .resume                 = usb_shark_resume,
 386        .reset_resume           = usb_shark_resume,
 387#endif
 388};
 389module_usb_driver(usb_shark_driver);
 390