linux/drivers/media/dvb/dvb-usb/friio.c
<<
>>
Prefs
   1/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
   2 *
   3 * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
   4 *
   5 * This module is based off the the gl861 and vp702x modules.
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License as published by the Free
   9 * Software Foundation, version 2.
  10 *
  11 * see Documentation/dvb/README.dvb-usb for more information
  12 */
  13#include "friio.h"
  14
  15/* debug */
  16int dvb_usb_friio_debug;
  17module_param_named(debug, dvb_usb_friio_debug, int, 0644);
  18MODULE_PARM_DESC(debug,
  19                 "set debugging level (1=info,2=xfer,4=rc,8=fe (or-able))."
  20                 DVB_USB_DEBUG_STATUS);
  21
  22DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  23
  24/**
  25 * Indirect I2C access to the PLL via FE.
  26 * whole I2C protocol data to the PLL is sent via the FE's I2C register.
  27 * This is done by a control msg to the FE with the I2C data accompanied, and
  28 * a specific USB request number is assigned for that purpose.
  29 *
  30 * this func sends wbuf[1..] to the I2C register wbuf[0] at addr (= at FE).
  31 * TODO: refoctored, smarter i2c functions.
  32 */
  33static int gl861_i2c_ctrlmsg_data(struct dvb_usb_device *d, u8 addr,
  34                                  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
  35{
  36        u16 index = wbuf[0];    /* must be JDVBT90502_2ND_I2C_REG(=0xFE) */
  37        u16 value = addr << (8 + 1);
  38        int wo = (rbuf == NULL || rlen == 0);   /* write only */
  39        u8 req, type;
  40
  41        deb_xfer("write to PLL:0x%02x via FE reg:0x%02x, len:%d\n",
  42                 wbuf[1], wbuf[0], wlen - 1);
  43
  44        if (wo && wlen >= 2) {
  45                req = GL861_REQ_I2C_DATA_CTRL_WRITE;
  46                type = GL861_WRITE;
  47                udelay(20);
  48                return usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
  49                                       req, type, value, index,
  50                                       &wbuf[1], wlen - 1, 2000);
  51        }
  52
  53        deb_xfer("not supported ctrl-msg, aborting.");
  54        return -EINVAL;
  55}
  56
  57/* normal I2C access (without extra data arguments).
  58 * write to the register wbuf[0] at I2C address addr with the value wbuf[1],
  59 *  or read from the register wbuf[0].
  60 * register address can be 16bit (wbuf[2]<<8 | wbuf[0]) if wlen==3
  61 */
  62static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
  63                         u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
  64{
  65        u16 index;
  66        u16 value = addr << (8 + 1);
  67        int wo = (rbuf == NULL || rlen == 0);   /* write-only */
  68        u8 req, type;
  69        unsigned int pipe;
  70
  71        /* special case for the indirect I2C access to the PLL via FE, */
  72        if (addr == friio_fe_config.demod_address &&
  73            wbuf[0] == JDVBT90502_2ND_I2C_REG)
  74                return gl861_i2c_ctrlmsg_data(d, addr, wbuf, wlen, rbuf, rlen);
  75
  76        if (wo) {
  77                req = GL861_REQ_I2C_WRITE;
  78                type = GL861_WRITE;
  79                pipe = usb_sndctrlpipe(d->udev, 0);
  80        } else {                /* rw */
  81                req = GL861_REQ_I2C_READ;
  82                type = GL861_READ;
  83                pipe = usb_rcvctrlpipe(d->udev, 0);
  84        }
  85
  86        switch (wlen) {
  87        case 1:
  88                index = wbuf[0];
  89                break;
  90        case 2:
  91                index = wbuf[0];
  92                value = value + wbuf[1];
  93                break;
  94        case 3:
  95                /* special case for 16bit register-address */
  96                index = (wbuf[2] << 8) | wbuf[0];
  97                value = value + wbuf[1];
  98                break;
  99        default:
 100                deb_xfer("wlen = %x, aborting.", wlen);
 101                return -EINVAL;
 102        }
 103        msleep(1);
 104        return usb_control_msg(d->udev, pipe, req, type,
 105                               value, index, rbuf, rlen, 2000);
 106}
 107
 108/* I2C */
 109static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 110                          int num)
 111{
 112        struct dvb_usb_device *d = i2c_get_adapdata(adap);
 113        int i;
 114
 115
 116        if (num > 2)
 117                return -EINVAL;
 118
 119        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 120                return -EAGAIN;
 121
 122        for (i = 0; i < num; i++) {
 123                /* write/read request */
 124                if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
 125                        if (gl861_i2c_msg(d, msg[i].addr,
 126                                          msg[i].buf, msg[i].len,
 127                                          msg[i + 1].buf, msg[i + 1].len) < 0)
 128                                break;
 129                        i++;
 130                } else
 131                        if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
 132                                          msg[i].len, NULL, 0) < 0)
 133                                break;
 134        }
 135
 136        mutex_unlock(&d->i2c_mutex);
 137        return i;
 138}
 139
 140static u32 gl861_i2c_func(struct i2c_adapter *adapter)
 141{
 142        return I2C_FUNC_I2C;
 143}
 144
 145
 146static int friio_ext_ctl(struct dvb_usb_adapter *adap,
 147                         u32 sat_color, int lnb_on)
 148{
 149        int i;
 150        int ret;
 151        struct i2c_msg msg;
 152        u8 buf[2];
 153        u32 mask;
 154        u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
 155
 156        msg.addr = 0x00;
 157        msg.flags = 0;
 158        msg.len = 2;
 159        msg.buf = buf;
 160
 161        buf[0] = 0x00;
 162
 163        /* send 2bit header (&B10) */
 164        buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE;
 165        ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 166        buf[1] |= FRIIO_CTL_CLK;
 167        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 168
 169        buf[1] = lnb | FRIIO_CTL_STROBE;
 170        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 171        buf[1] |= FRIIO_CTL_CLK;
 172        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 173
 174        /* send 32bit(satur, R, G, B) data in serial */
 175        mask = 1 << 31;
 176        for (i = 0; i < 32; i++) {
 177                buf[1] = lnb | FRIIO_CTL_STROBE;
 178                if (sat_color & mask)
 179                        buf[1] |= FRIIO_CTL_LED;
 180                ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 181                buf[1] |= FRIIO_CTL_CLK;
 182                ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 183                mask >>= 1;
 184        }
 185
 186        /* set the strobe off */
 187        buf[1] = lnb;
 188        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 189        buf[1] |= FRIIO_CTL_CLK;
 190        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 191
 192        return (ret == 70);
 193}
 194
 195
 196static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
 197
 198/* TODO: move these init cmds to the FE's init routine? */
 199static u8 streaming_init_cmds[][2] = {
 200        {0x33, 0x08},
 201        {0x37, 0x40},
 202        {0x3A, 0x1F},
 203        {0x3B, 0xFF},
 204        {0x3C, 0x1F},
 205        {0x3D, 0xFF},
 206        {0x38, 0x00},
 207        {0x35, 0x00},
 208        {0x39, 0x00},
 209        {0x36, 0x00},
 210};
 211static int cmdlen = sizeof(streaming_init_cmds) / 2;
 212
 213/*
 214 * Command sequence in this init function is a replay
 215 *  of the captured USB commands from the Windows proprietary driver.
 216 */
 217static int friio_initialize(struct dvb_usb_device *d)
 218{
 219        int ret;
 220        int i;
 221        int retry = 0;
 222        u8 rbuf[2];
 223        u8 wbuf[3];
 224
 225        deb_info("%s called.\n", __func__);
 226
 227        /* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
 228        /* because the i2c device is not set up yet. */
 229        wbuf[0] = 0x11;
 230        wbuf[1] = 0x02;
 231        ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
 232        if (ret < 0)
 233                goto error;
 234        msleep(2);
 235
 236        wbuf[0] = 0x11;
 237        wbuf[1] = 0x00;
 238        ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
 239        if (ret < 0)
 240                goto error;
 241        msleep(1);
 242
 243        /* following msgs should be in the FE's init code? */
 244        /* cmd sequence to identify the device type? (friio black/white) */
 245        wbuf[0] = 0x03;
 246        wbuf[1] = 0x80;
 247        /* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */
 248        ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
 249                              GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
 250                              0x1200, 0x0100, wbuf, 2, 2000);
 251        if (ret < 0)
 252                goto error;
 253
 254        msleep(2);
 255        wbuf[0] = 0x00;
 256        wbuf[2] = 0x01;         /* reg.0x0100 */
 257        wbuf[1] = 0x00;
 258        ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2);
 259        /* my Friio White returns 0xffff. */
 260        if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
 261                goto error;
 262
 263        msleep(2);
 264        wbuf[0] = 0x03;
 265        wbuf[1] = 0x80;
 266        ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
 267                              GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
 268                              0x9000, 0x0100, wbuf, 2, 2000);
 269        if (ret < 0)
 270                goto error;
 271
 272        msleep(2);
 273        wbuf[0] = 0x00;
 274        wbuf[2] = 0x01;         /* reg.0x0100 */
 275        wbuf[1] = 0x00;
 276        ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2);
 277        /* my Friio White returns 0xffff again. */
 278        if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
 279                goto error;
 280
 281        msleep(1);
 282
 283restart:
 284        /* ============ start DEMOD init cmds ================== */
 285        /* read PLL status to clear the POR bit */
 286        wbuf[0] = JDVBT90502_2ND_I2C_REG;
 287        wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1;    /* +1 for reading */
 288        ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0);
 289        if (ret < 0)
 290                goto error;
 291
 292        msleep(5);
 293        /* note: DEMODULATOR has 16bit register-address. */
 294        wbuf[0] = 0x00;
 295        wbuf[2] = 0x01;         /* reg addr: 0x0100 */
 296        wbuf[1] = 0x00;         /* val: not used */
 297        ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1);
 298        if (ret < 0)
 299                goto error;
 300/*
 301        msleep(1);
 302        wbuf[0] = 0x80;
 303        wbuf[1] = 0x00;
 304        ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1);
 305        if (ret < 0)
 306                goto error;
 307 */
 308        if (rbuf[0] & 0x80) {   /* still in PowerOnReset state? */
 309                if (++retry > 3) {
 310                        deb_info("failed to get the correct"
 311                                 " FE demod status:0x%02x\n", rbuf[0]);
 312                        goto error;
 313                }
 314                msleep(100);
 315                goto restart;
 316        }
 317
 318        /* TODO: check return value in rbuf */
 319        /* =========== end DEMOD init cmds ===================== */
 320        msleep(1);
 321
 322        wbuf[0] = 0x30;
 323        wbuf[1] = 0x04;
 324        ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
 325        if (ret < 0)
 326                goto error;
 327
 328        msleep(2);
 329        /* following 2 cmds unnecessary? */
 330        wbuf[0] = 0x00;
 331        wbuf[1] = 0x01;
 332        ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
 333        if (ret < 0)
 334                goto error;
 335
 336        wbuf[0] = 0x06;
 337        wbuf[1] = 0x0F;
 338        ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
 339        if (ret < 0)
 340                goto error;
 341
 342        /* some streaming ctl cmds (maybe) */
 343        msleep(10);
 344        for (i = 0; i < cmdlen; i++) {
 345                ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2,
 346                                    NULL, 0);
 347                if (ret < 0)
 348                        goto error;
 349                msleep(1);
 350        }
 351        msleep(20);
 352
 353        /* change the LED color etc. */
 354        ret = friio_streaming_ctrl(&d->adapter[0], 0);
 355        if (ret < 0)
 356                goto error;
 357
 358        return 0;
 359
 360error:
 361        deb_info("%s:ret == %d\n", __func__, ret);
 362        return -EIO;
 363}
 364
 365/* Callbacks for DVB USB */
 366
 367static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 368{
 369        int ret;
 370
 371        deb_info("%s called.(%d)\n", __func__, onoff);
 372
 373        /* set the LED color and saturation (and LNB on) */
 374        if (onoff)
 375                ret = friio_ext_ctl(adap, 0x6400ff64, 1);
 376        else
 377                ret = friio_ext_ctl(adap, 0x96ff00ff, 1);
 378
 379        if (ret != 1) {
 380                deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret);
 381                return -EREMOTEIO;
 382        }
 383        return 0;
 384}
 385
 386static int friio_frontend_attach(struct dvb_usb_adapter *adap)
 387{
 388        if (friio_initialize(adap->dev) < 0)
 389                return -EIO;
 390
 391        adap->fe = jdvbt90502_attach(adap->dev);
 392        if (adap->fe == NULL)
 393                return -EIO;
 394
 395        return 0;
 396}
 397
 398/* DVB USB Driver stuff */
 399static struct dvb_usb_device_properties friio_properties;
 400
 401static int friio_probe(struct usb_interface *intf,
 402                       const struct usb_device_id *id)
 403{
 404        struct dvb_usb_device *d;
 405        struct usb_host_interface *alt;
 406        int ret;
 407
 408        if (intf->num_altsetting < GL861_ALTSETTING_COUNT)
 409                return -ENODEV;
 410
 411        alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING);
 412        if (alt == NULL) {
 413                deb_rc("not alt found!\n");
 414                return -ENODEV;
 415        }
 416        ret = usb_set_interface(interface_to_usbdev(intf),
 417                                alt->desc.bInterfaceNumber,
 418                                alt->desc.bAlternateSetting);
 419        if (ret != 0) {
 420                deb_rc("failed to set alt-setting!\n");
 421                return ret;
 422        }
 423
 424        ret = dvb_usb_device_init(intf, &friio_properties,
 425                                  THIS_MODULE, &d, adapter_nr);
 426        if (ret == 0)
 427                friio_streaming_ctrl(&d->adapter[0], 1);
 428
 429        return ret;
 430}
 431
 432
 433struct jdvbt90502_config friio_fe_config = {
 434        .demod_address = FRIIO_DEMOD_ADDR,
 435        .pll_address = FRIIO_PLL_ADDR,
 436};
 437
 438static struct i2c_algorithm gl861_i2c_algo = {
 439        .master_xfer   = gl861_i2c_xfer,
 440        .functionality = gl861_i2c_func,
 441};
 442
 443static struct usb_device_id friio_table[] = {
 444        { USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) },
 445        { }             /* Terminating entry */
 446};
 447MODULE_DEVICE_TABLE(usb, friio_table);
 448
 449
 450static struct dvb_usb_device_properties friio_properties = {
 451        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
 452        .usb_ctrl = DEVICE_SPECIFIC,
 453
 454        .size_of_priv = 0,
 455
 456        .num_adapters = 1,
 457        .adapter = {
 458                /* caps:0 =>  no pid filter, 188B TS packet */
 459                /* GL861 has a HW pid filter, but no info available. */
 460                {
 461                        .caps  = 0,
 462
 463                        .frontend_attach  = friio_frontend_attach,
 464                        .streaming_ctrl = friio_streaming_ctrl,
 465
 466                        .stream = {
 467                                .type = USB_BULK,
 468                                /* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */
 469                                .count = 8,
 470                                .endpoint = 0x01,
 471                                .u = {
 472                                        /* GL861 has 6KB buf inside */
 473                                        .bulk = {
 474                                                .buffersize = 16384,
 475                                        }
 476                                }
 477                        },
 478                }
 479        },
 480        .i2c_algo = &gl861_i2c_algo,
 481
 482        .num_device_descs = 1,
 483        .devices = {
 484                {
 485                        .name = "774 Friio ISDB-T USB2.0",
 486                        .cold_ids = { NULL },
 487                        .warm_ids = { &friio_table[0], NULL },
 488                },
 489        }
 490};
 491
 492static struct usb_driver friio_driver = {
 493        .name           = "dvb_usb_friio",
 494        .probe          = friio_probe,
 495        .disconnect     = dvb_usb_device_exit,
 496        .id_table       = friio_table,
 497};
 498
 499
 500/* module stuff */
 501static int __init friio_module_init(void)
 502{
 503        int ret;
 504
 505        ret = usb_register(&friio_driver);
 506        if (ret)
 507                err("usb_register failed. Error number %d", ret);
 508
 509        return ret;
 510}
 511
 512
 513static void __exit friio_module_exit(void)
 514{
 515        /* deregister this driver from the USB subsystem */
 516        usb_deregister(&friio_driver);
 517}
 518
 519module_init(friio_module_init);
 520module_exit(friio_module_exit);
 521
 522MODULE_AUTHOR("Akihiro Tsukada <tskd2@yahoo.co.jp>");
 523MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver");
 524MODULE_VERSION("0.2");
 525MODULE_LICENSE("GPL");
 526