linux/drivers/media/usb/dvb-usb/vp702x-fe.c
<<
>>
Prefs
   1/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0
   2 * DVB-S receiver.
   3 *
   4 * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
   5 *                    Metzler Brothers Systementwicklung GbR
   6 *
   7 * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
   8 *
   9 * Thanks to Twinhan who kindly provided hardware and information.
  10 *
  11 * This file can be removed soon, after the DST-driver is rewritten to provice
  12 * the frontend-controlling separately.
  13 *
  14 *      This program is free software; you can redistribute it and/or modify it
  15 *      under the terms of the GNU General Public License as published by the Free
  16 *      Software Foundation, version 2.
  17 *
  18 * see Documentation/dvb/README.dvb-usb for more information
  19 *
  20 */
  21#include "vp702x.h"
  22
  23struct vp702x_fe_state {
  24        struct dvb_frontend fe;
  25        struct dvb_usb_device *d;
  26
  27        struct dvb_frontend_ops ops;
  28
  29        enum fe_sec_voltage voltage;
  30        enum fe_sec_tone_mode tone_mode;
  31
  32        u8 lnb_buf[8];
  33
  34        u8 lock;
  35        u8 sig;
  36        u8 snr;
  37
  38        unsigned long next_status_check;
  39        unsigned long status_check_interval;
  40};
  41
  42static int vp702x_fe_refresh_state(struct vp702x_fe_state *st)
  43{
  44        struct vp702x_device_state *dst = st->d->priv;
  45        u8 *buf;
  46
  47        if (time_after(jiffies, st->next_status_check)) {
  48                mutex_lock(&dst->buf_mutex);
  49                buf = dst->buf;
  50
  51                vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10);
  52                st->lock = buf[4];
  53
  54                vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1);
  55                st->snr = buf[0];
  56
  57                vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1);
  58                st->sig = buf[0];
  59
  60                mutex_unlock(&dst->buf_mutex);
  61                st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
  62        }
  63        return 0;
  64}
  65
  66static u8 vp702x_chksum(u8 *buf,int f, int count)
  67{
  68        u8 s = 0;
  69        int i;
  70        for (i = f; i < f+count; i++)
  71                s += buf[i];
  72        return ~s+1;
  73}
  74
  75static int vp702x_fe_read_status(struct dvb_frontend *fe,
  76                                 enum fe_status *status)
  77{
  78        struct vp702x_fe_state *st = fe->demodulator_priv;
  79        vp702x_fe_refresh_state(st);
  80        deb_fe("%s\n",__func__);
  81
  82        if (st->lock == 0)
  83                *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
  84        else
  85                *status = 0;
  86
  87        if (*status & FE_HAS_LOCK)
  88                st->status_check_interval = 1000;
  89        else
  90                st->status_check_interval = 250;
  91        return 0;
  92}
  93
  94/* not supported by this Frontend */
  95static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
  96{
  97        struct vp702x_fe_state *st = fe->demodulator_priv;
  98        vp702x_fe_refresh_state(st);
  99        *ber = 0;
 100        return 0;
 101}
 102
 103/* not supported by this Frontend */
 104static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
 105{
 106        struct vp702x_fe_state *st = fe->demodulator_priv;
 107        vp702x_fe_refresh_state(st);
 108        *unc = 0;
 109        return 0;
 110}
 111
 112static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
 113{
 114        struct vp702x_fe_state *st = fe->demodulator_priv;
 115        vp702x_fe_refresh_state(st);
 116
 117        *strength = (st->sig << 8) | st->sig;
 118        return 0;
 119}
 120
 121static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
 122{
 123        u8 _snr;
 124        struct vp702x_fe_state *st = fe->demodulator_priv;
 125        vp702x_fe_refresh_state(st);
 126
 127        _snr = (st->snr & 0x1f) * 0xff / 0x1f;
 128        *snr = (_snr << 8) | _snr;
 129        return 0;
 130}
 131
 132static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
 133{
 134        deb_fe("%s\n",__func__);
 135        tune->min_delay_ms = 2000;
 136        return 0;
 137}
 138
 139static int vp702x_fe_set_frontend(struct dvb_frontend *fe)
 140{
 141        struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
 142        struct vp702x_fe_state *st = fe->demodulator_priv;
 143        struct vp702x_device_state *dst = st->d->priv;
 144        u32 freq = fep->frequency/1000;
 145        /*CalFrequency*/
 146/*      u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
 147        u64 sr;
 148        u8 *cmd;
 149
 150        mutex_lock(&dst->buf_mutex);
 151
 152        cmd = dst->buf;
 153        memset(cmd, 0, 10);
 154
 155        cmd[0] = (freq >> 8) & 0x7f;
 156        cmd[1] =  freq       & 0xff;
 157        cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */
 158
 159        sr = (u64) (fep->symbol_rate/1000) << 20;
 160        do_div(sr,88000);
 161        cmd[3] = (sr >> 12) & 0xff;
 162        cmd[4] = (sr >> 4)  & 0xff;
 163        cmd[5] = (sr << 4)  & 0xf0;
 164
 165        deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n",
 166                        fep->frequency, freq, freq, fep->symbol_rate,
 167                        (unsigned long) sr, (unsigned long) sr);
 168
 169/*      if (fep->inversion == INVERSION_ON)
 170                cmd[6] |= 0x80; */
 171
 172        if (st->voltage == SEC_VOLTAGE_18)
 173                cmd[6] |= 0x40;
 174
 175/*      if (fep->symbol_rate > 8000000)
 176                cmd[6] |= 0x20;
 177
 178        if (fep->frequency < 1531000)
 179                cmd[6] |= 0x04;
 180
 181        if (st->tone_mode == SEC_TONE_ON)
 182                cmd[6] |= 0x01;*/
 183
 184        cmd[7] = vp702x_chksum(cmd,0,7);
 185
 186        st->status_check_interval = 250;
 187        st->next_status_check = jiffies;
 188
 189        vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
 190
 191        if (cmd[2] == 0 && cmd[3] == 0)
 192                deb_fe("tuning failed.\n");
 193        else
 194                deb_fe("tuning succeeded.\n");
 195
 196        mutex_unlock(&dst->buf_mutex);
 197
 198        return 0;
 199}
 200
 201static int vp702x_fe_init(struct dvb_frontend *fe)
 202{
 203        struct vp702x_fe_state *st = fe->demodulator_priv;
 204        deb_fe("%s\n",__func__);
 205        vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
 206        return 0;
 207}
 208
 209static int vp702x_fe_sleep(struct dvb_frontend *fe)
 210{
 211        deb_fe("%s\n",__func__);
 212        return 0;
 213}
 214
 215static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
 216                                    struct dvb_diseqc_master_cmd *m)
 217{
 218        u8 *cmd;
 219        struct vp702x_fe_state *st = fe->demodulator_priv;
 220        struct vp702x_device_state *dst = st->d->priv;
 221
 222        deb_fe("%s\n",__func__);
 223
 224        if (m->msg_len > 4)
 225                return -EINVAL;
 226
 227        mutex_lock(&dst->buf_mutex);
 228
 229        cmd = dst->buf;
 230        cmd[1] = SET_DISEQC_CMD;
 231        cmd[2] = m->msg_len;
 232        memcpy(&cmd[3], m->msg, m->msg_len);
 233        cmd[7] = vp702x_chksum(cmd, 0, 7);
 234
 235        vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
 236
 237        if (cmd[2] == 0 && cmd[3] == 0)
 238                deb_fe("diseqc cmd failed.\n");
 239        else
 240                deb_fe("diseqc cmd succeeded.\n");
 241
 242        mutex_unlock(&dst->buf_mutex);
 243
 244        return 0;
 245}
 246
 247static int vp702x_fe_send_diseqc_burst(struct dvb_frontend *fe,
 248                                       enum fe_sec_mini_cmd burst)
 249{
 250        deb_fe("%s\n",__func__);
 251        return 0;
 252}
 253
 254static int vp702x_fe_set_tone(struct dvb_frontend *fe,
 255                              enum fe_sec_tone_mode tone)
 256{
 257        struct vp702x_fe_state *st = fe->demodulator_priv;
 258        struct vp702x_device_state *dst = st->d->priv;
 259        u8 *buf;
 260
 261        deb_fe("%s\n",__func__);
 262
 263        st->tone_mode = tone;
 264
 265        if (tone == SEC_TONE_ON)
 266                st->lnb_buf[2] = 0x02;
 267        else
 268                st->lnb_buf[2] = 0x00;
 269
 270        st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
 271
 272        mutex_lock(&dst->buf_mutex);
 273
 274        buf = dst->buf;
 275        memcpy(buf, st->lnb_buf, 8);
 276
 277        vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
 278        if (buf[2] == 0 && buf[3] == 0)
 279                deb_fe("set_tone cmd failed.\n");
 280        else
 281                deb_fe("set_tone cmd succeeded.\n");
 282
 283        mutex_unlock(&dst->buf_mutex);
 284
 285        return 0;
 286}
 287
 288static int vp702x_fe_set_voltage(struct dvb_frontend *fe,
 289                                 enum fe_sec_voltage voltage)
 290{
 291        struct vp702x_fe_state *st = fe->demodulator_priv;
 292        struct vp702x_device_state *dst = st->d->priv;
 293        u8 *buf;
 294        deb_fe("%s\n",__func__);
 295
 296        st->voltage = voltage;
 297
 298        if (voltage != SEC_VOLTAGE_OFF)
 299                st->lnb_buf[4] = 0x01;
 300        else
 301                st->lnb_buf[4] = 0x00;
 302
 303        st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
 304
 305        mutex_lock(&dst->buf_mutex);
 306
 307        buf = dst->buf;
 308        memcpy(buf, st->lnb_buf, 8);
 309
 310        vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
 311        if (buf[2] == 0 && buf[3] == 0)
 312                deb_fe("set_voltage cmd failed.\n");
 313        else
 314                deb_fe("set_voltage cmd succeeded.\n");
 315
 316        mutex_unlock(&dst->buf_mutex);
 317        return 0;
 318}
 319
 320static void vp702x_fe_release(struct dvb_frontend* fe)
 321{
 322        struct vp702x_fe_state *st = fe->demodulator_priv;
 323        kfree(st);
 324}
 325
 326static const struct dvb_frontend_ops vp702x_fe_ops;
 327
 328struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d)
 329{
 330        struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL);
 331        if (s == NULL)
 332                goto error;
 333
 334        s->d = d;
 335
 336        memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
 337        s->fe.demodulator_priv = s;
 338
 339        s->lnb_buf[1] = SET_LNB_POWER;
 340        s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
 341
 342        return &s->fe;
 343error:
 344        return NULL;
 345}
 346
 347
 348static const struct dvb_frontend_ops vp702x_fe_ops = {
 349        .delsys = { SYS_DVBS },
 350        .info = {
 351                .name           = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S",
 352                .frequency_min       = 950000,
 353                .frequency_max       = 2150000,
 354                .frequency_stepsize  = 1000,   /* kHz for QPSK frontends */
 355                .frequency_tolerance = 0,
 356                .symbol_rate_min     = 1000000,
 357                .symbol_rate_max     = 45000000,
 358                .symbol_rate_tolerance = 500,  /* ppm */
 359                .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 360                FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
 361                FE_CAN_QPSK |
 362                FE_CAN_FEC_AUTO
 363        },
 364        .release = vp702x_fe_release,
 365
 366        .init  = vp702x_fe_init,
 367        .sleep = vp702x_fe_sleep,
 368
 369        .set_frontend = vp702x_fe_set_frontend,
 370        .get_tune_settings = vp702x_fe_get_tune_settings,
 371
 372        .read_status = vp702x_fe_read_status,
 373        .read_ber = vp702x_fe_read_ber,
 374        .read_signal_strength = vp702x_fe_read_signal_strength,
 375        .read_snr = vp702x_fe_read_snr,
 376        .read_ucblocks = vp702x_fe_read_unc_blocks,
 377
 378        .diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg,
 379        .diseqc_send_burst = vp702x_fe_send_diseqc_burst,
 380        .set_tone = vp702x_fe_set_tone,
 381        .set_voltage = vp702x_fe_set_voltage,
 382};
 383