linux/drivers/media/usb/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
 145static int friio_ext_ctl(struct dvb_usb_adapter *adap,
 146                         u32 sat_color, int lnb_on)
 147{
 148        int i;
 149        int ret;
 150        struct i2c_msg msg;
 151        u8 *buf;
 152        u32 mask;
 153        u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
 154
 155        buf = kmalloc(2, GFP_KERNEL);
 156        if (!buf)
 157                return -ENOMEM;
 158
 159        msg.addr = 0x00;
 160        msg.flags = 0;
 161        msg.len = 2;
 162        msg.buf = buf;
 163
 164        buf[0] = 0x00;
 165
 166        /* send 2bit header (&B10) */
 167        buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE;
 168        ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 169        buf[1] |= FRIIO_CTL_CLK;
 170        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 171
 172        buf[1] = lnb | FRIIO_CTL_STROBE;
 173        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 174        buf[1] |= FRIIO_CTL_CLK;
 175        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 176
 177        /* send 32bit(satur, R, G, B) data in serial */
 178        mask = 1 << 31;
 179        for (i = 0; i < 32; i++) {
 180                buf[1] = lnb | FRIIO_CTL_STROBE;
 181                if (sat_color & mask)
 182                        buf[1] |= FRIIO_CTL_LED;
 183                ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 184                buf[1] |= FRIIO_CTL_CLK;
 185                ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 186                mask >>= 1;
 187        }
 188
 189        /* set the strobe off */
 190        buf[1] = lnb;
 191        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 192        buf[1] |= FRIIO_CTL_CLK;
 193        ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
 194
 195        kfree(buf);
 196        return (ret == 70);
 197}
 198
 199
 200static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
 201
 202/* TODO: move these init cmds to the FE's init routine? */
 203static u8 streaming_init_cmds[][2] = {
 204        {0x33, 0x08},
 205        {0x37, 0x40},
 206        {0x3A, 0x1F},
 207        {0x3B, 0xFF},
 208        {0x3C, 0x1F},
 209        {0x3D, 0xFF},
 210        {0x38, 0x00},
 211        {0x35, 0x00},
 212        {0x39, 0x00},
 213        {0x36, 0x00},
 214};
 215static int cmdlen = sizeof(streaming_init_cmds) / 2;
 216
 217/*
 218 * Command sequence in this init function is a replay
 219 *  of the captured USB commands from the Windows proprietary driver.
 220 */
 221static int friio_initialize(struct dvb_usb_device *d)
 222{
 223        int ret;
 224        int i;
 225        int retry = 0;
 226        u8 *rbuf, *wbuf;
 227
 228        deb_info("%s called.\n", __func__);
 229
 230        wbuf = kmalloc(3, GFP_KERNEL);
 231        if (!wbuf)
 232                return -ENOMEM;
 233
 234        rbuf = kmalloc(2, GFP_KERNEL);
 235        if (!rbuf) {
 236                kfree(wbuf);
 237                return -ENOMEM;
 238        }
 239
 240        /* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
 241        /* because the i2c device is not set up yet. */
 242        wbuf[0] = 0x11;
 243        wbuf[1] = 0x02;
 244        ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
 245        if (ret < 0)
 246                goto error;
 247        msleep(2);
 248
 249        wbuf[0] = 0x11;
 250        wbuf[1] = 0x00;
 251        ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
 252        if (ret < 0)
 253                goto error;
 254        msleep(1);
 255
 256        /* following msgs should be in the FE's init code? */
 257        /* cmd sequence to identify the device type? (friio black/white) */
 258        wbuf[0] = 0x03;
 259        wbuf[1] = 0x80;
 260        /* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */
 261        ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
 262                              GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
 263                              0x1200, 0x0100, wbuf, 2, 2000);
 264        if (ret < 0)
 265                goto error;
 266
 267        msleep(2);
 268        wbuf[0] = 0x00;
 269        wbuf[2] = 0x01;         /* reg.0x0100 */
 270        wbuf[1] = 0x00;
 271        ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2);
 272        /* my Friio White returns 0xffff. */
 273        if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
 274                goto error;
 275
 276        msleep(2);
 277        wbuf[0] = 0x03;
 278        wbuf[1] = 0x80;
 279        ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
 280                              GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
 281                              0x9000, 0x0100, wbuf, 2, 2000);
 282        if (ret < 0)
 283                goto error;
 284
 285        msleep(2);
 286        wbuf[0] = 0x00;
 287        wbuf[2] = 0x01;         /* reg.0x0100 */
 288        wbuf[1] = 0x00;
 289        ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2);
 290        /* my Friio White returns 0xffff again. */
 291        if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
 292                goto error;
 293
 294        msleep(1);
 295
 296restart:
 297        /* ============ start DEMOD init cmds ================== */
 298        /* read PLL status to clear the POR bit */
 299        wbuf[0] = JDVBT90502_2ND_I2C_REG;
 300        wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1;    /* +1 for reading */
 301        ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0);
 302        if (ret < 0)
 303                goto error;
 304
 305        msleep(5);
 306        /* note: DEMODULATOR has 16bit register-address. */
 307        wbuf[0] = 0x00;
 308        wbuf[2] = 0x01;         /* reg addr: 0x0100 */
 309        wbuf[1] = 0x00;         /* val: not used */
 310        ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1);
 311        if (ret < 0)
 312                goto error;
 313/*
 314        msleep(1);
 315        wbuf[0] = 0x80;
 316        wbuf[1] = 0x00;
 317        ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1);
 318        if (ret < 0)
 319                goto error;
 320 */
 321        if (rbuf[0] & 0x80) {   /* still in PowerOnReset state? */
 322                if (++retry > 3) {
 323                        deb_info("failed to get the correct"
 324                                 " FE demod status:0x%02x\n", rbuf[0]);
 325                        goto error;
 326                }
 327                msleep(100);
 328                goto restart;
 329        }
 330
 331        /* TODO: check return value in rbuf */
 332        /* =========== end DEMOD init cmds ===================== */
 333        msleep(1);
 334
 335        wbuf[0] = 0x30;
 336        wbuf[1] = 0x04;
 337        ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
 338        if (ret < 0)
 339                goto error;
 340
 341        msleep(2);
 342        /* following 2 cmds unnecessary? */
 343        wbuf[0] = 0x00;
 344        wbuf[1] = 0x01;
 345        ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
 346        if (ret < 0)
 347                goto error;
 348
 349        wbuf[0] = 0x06;
 350        wbuf[1] = 0x0F;
 351        ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
 352        if (ret < 0)
 353                goto error;
 354
 355        /* some streaming ctl cmds (maybe) */
 356        msleep(10);
 357        for (i = 0; i < cmdlen; i++) {
 358                ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2,
 359                                    NULL, 0);
 360                if (ret < 0)
 361                        goto error;
 362                msleep(1);
 363        }
 364        msleep(20);
 365
 366        /* change the LED color etc. */
 367        ret = friio_streaming_ctrl(&d->adapter[0], 0);
 368        if (ret < 0)
 369                goto error;
 370
 371        return 0;
 372
 373error:
 374        kfree(wbuf);
 375        kfree(rbuf);
 376        deb_info("%s:ret == %d\n", __func__, ret);
 377        return -EIO;
 378}
 379
 380/* Callbacks for DVB USB */
 381
 382static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 383{
 384        int ret;
 385
 386        deb_info("%s called.(%d)\n", __func__, onoff);
 387
 388        /* set the LED color and saturation (and LNB on) */
 389        if (onoff)
 390                ret = friio_ext_ctl(adap, 0x6400ff64, 1);
 391        else
 392                ret = friio_ext_ctl(adap, 0x96ff00ff, 1);
 393
 394        if (ret != 1) {
 395                deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret);
 396                return -EREMOTEIO;
 397        }
 398        return 0;
 399}
 400
 401static int friio_frontend_attach(struct dvb_usb_adapter *adap)
 402{
 403        if (friio_initialize(adap->dev) < 0)
 404                return -EIO;
 405
 406        adap->fe_adap[0].fe = jdvbt90502_attach(adap->dev);
 407        if (adap->fe_adap[0].fe == NULL)
 408                return -EIO;
 409
 410        return 0;
 411}
 412
 413/* DVB USB Driver stuff */
 414static struct dvb_usb_device_properties friio_properties;
 415
 416static int friio_probe(struct usb_interface *intf,
 417                       const struct usb_device_id *id)
 418{
 419        struct dvb_usb_device *d;
 420        struct usb_host_interface *alt;
 421        int ret;
 422
 423        if (intf->num_altsetting < GL861_ALTSETTING_COUNT)
 424                return -ENODEV;
 425
 426        alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING);
 427        if (alt == NULL) {
 428                deb_rc("not alt found!\n");
 429                return -ENODEV;
 430        }
 431        ret = usb_set_interface(interface_to_usbdev(intf),
 432                                alt->desc.bInterfaceNumber,
 433                                alt->desc.bAlternateSetting);
 434        if (ret != 0) {
 435                deb_rc("failed to set alt-setting!\n");
 436                return ret;
 437        }
 438
 439        ret = dvb_usb_device_init(intf, &friio_properties,
 440                                  THIS_MODULE, &d, adapter_nr);
 441        if (ret == 0)
 442                friio_streaming_ctrl(&d->adapter[0], 1);
 443
 444        return ret;
 445}
 446
 447
 448struct jdvbt90502_config friio_fe_config = {
 449        .demod_address = FRIIO_DEMOD_ADDR,
 450        .pll_address = FRIIO_PLL_ADDR,
 451};
 452
 453static struct i2c_algorithm gl861_i2c_algo = {
 454        .master_xfer   = gl861_i2c_xfer,
 455        .functionality = gl861_i2c_func,
 456};
 457
 458static struct usb_device_id friio_table[] = {
 459        { USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) },
 460        { }             /* Terminating entry */
 461};
 462MODULE_DEVICE_TABLE(usb, friio_table);
 463
 464
 465static struct dvb_usb_device_properties friio_properties = {
 466        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
 467        .usb_ctrl = DEVICE_SPECIFIC,
 468
 469        .size_of_priv = 0,
 470
 471        .num_adapters = 1,
 472        .adapter = {
 473                /* caps:0 =>  no pid filter, 188B TS packet */
 474                /* GL861 has a HW pid filter, but no info available. */
 475                {
 476                .num_frontends = 1,
 477                .fe = {{
 478                        .caps  = 0,
 479
 480                        .frontend_attach  = friio_frontend_attach,
 481                        .streaming_ctrl = friio_streaming_ctrl,
 482
 483                        .stream = {
 484                                .type = USB_BULK,
 485                                /* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */
 486                                .count = 8,
 487                                .endpoint = 0x01,
 488                                .u = {
 489                                        /* GL861 has 6KB buf inside */
 490                                        .bulk = {
 491                                                .buffersize = 16384,
 492                                        }
 493                                }
 494                        },
 495                }},
 496                }
 497        },
 498        .i2c_algo = &gl861_i2c_algo,
 499
 500        .num_device_descs = 1,
 501        .devices = {
 502                {
 503                        .name = "774 Friio ISDB-T USB2.0",
 504                        .cold_ids = { NULL },
 505                        .warm_ids = { &friio_table[0], NULL },
 506                },
 507        }
 508};
 509
 510static struct usb_driver friio_driver = {
 511        .name           = "dvb_usb_friio",
 512        .probe          = friio_probe,
 513        .disconnect     = dvb_usb_device_exit,
 514        .id_table       = friio_table,
 515};
 516
 517module_usb_driver(friio_driver);
 518
 519MODULE_AUTHOR("Akihiro Tsukada <tskd2@yahoo.co.jp>");
 520MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver");
 521MODULE_VERSION("0.2");
 522MODULE_LICENSE("GPL");
 523