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@desy.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 fe_sec_voltage_t voltage; 30 fe_sec_tone_mode_t 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 u8 buf[10]; 45 if (time_after(jiffies,st->next_status_check)) { 46 vp702x_usb_in_op(st->d,READ_STATUS,0,0,buf,10); 47 48 st->lock = buf[4]; 49 vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x11,0,&st->snr,1); 50 vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x15,0,&st->sig,1); 51 52 st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; 53 } 54 return 0; 55} 56 57static u8 vp702x_chksum(u8 *buf,int f, int count) 58{ 59 u8 s = 0; 60 int i; 61 for (i = f; i < f+count; i++) 62 s += buf[i]; 63 return ~s+1; 64} 65 66static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) 67{ 68 struct vp702x_fe_state *st = fe->demodulator_priv; 69 vp702x_fe_refresh_state(st); 70 deb_fe("%s\n",__FUNCTION__); 71 72 if (st->lock == 0) 73 *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; 74 else 75 *status = 0; 76 77 if (*status & FE_HAS_LOCK) 78 st->status_check_interval = 1000; 79 else 80 st->status_check_interval = 250; 81 return 0; 82} 83 84/* not supported by this Frontend */ 85static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber) 86{ 87 struct vp702x_fe_state *st = fe->demodulator_priv; 88 vp702x_fe_refresh_state(st); 89 *ber = 0; 90 return 0; 91} 92 93/* not supported by this Frontend */ 94static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) 95{ 96 struct vp702x_fe_state *st = fe->demodulator_priv; 97 vp702x_fe_refresh_state(st); 98 *unc = 0; 99 return 0; 100} 101 102static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) 103{ 104 struct vp702x_fe_state *st = fe->demodulator_priv; 105 vp702x_fe_refresh_state(st); 106 107 *strength = (st->sig << 8) | st->sig; 108 return 0; 109} 110 111static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr) 112{ 113 u8 _snr; 114 struct vp702x_fe_state *st = fe->demodulator_priv; 115 vp702x_fe_refresh_state(st); 116 117 _snr = (st->snr & 0x1f) * 0xff / 0x1f; 118 *snr = (_snr << 8) | _snr; 119 return 0; 120} 121 122static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) 123{ 124 deb_fe("%s\n",__FUNCTION__); 125 tune->min_delay_ms = 2000; 126 return 0; 127} 128 129static int vp702x_fe_set_frontend(struct dvb_frontend* fe, 130 struct dvb_frontend_parameters *fep) 131{ 132 struct vp702x_fe_state *st = fe->demodulator_priv; 133 u32 freq = fep->frequency/1000; 134 /*CalFrequency*/ 135/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */ 136 u64 sr; 137 u8 cmd[8] = { 0 },ibuf[10]; 138 139 cmd[0] = (freq >> 8) & 0x7f; 140 cmd[1] = freq & 0xff; 141 cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */ 142 143 sr = (u64) (fep->u.qpsk.symbol_rate/1000) << 20; 144 do_div(sr,88000); 145 cmd[3] = (sr >> 12) & 0xff; 146 cmd[4] = (sr >> 4) & 0xff; 147 cmd[5] = (sr << 4) & 0xf0; 148 149 deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n", 150 fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, 151 (unsigned long) sr, (unsigned long) sr); 152 153/* if (fep->inversion == INVERSION_ON) 154 cmd[6] |= 0x80; */ 155 156 if (st->voltage == SEC_VOLTAGE_18) 157 cmd[6] |= 0x40; 158 159/* if (fep->u.qpsk.symbol_rate > 8000000) 160 cmd[6] |= 0x20; 161 162 if (fep->frequency < 1531000) 163 cmd[6] |= 0x04; 164 165 if (st->tone_mode == SEC_TONE_ON) 166 cmd[6] |= 0x01;*/ 167 168 cmd[7] = vp702x_chksum(cmd,0,7); 169 170 st->status_check_interval = 250; 171 st->next_status_check = jiffies; 172 173 vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); 174 175 if (ibuf[2] == 0 && ibuf[3] == 0) 176 deb_fe("tuning failed.\n"); 177 else 178 deb_fe("tuning succeeded.\n"); 179 180 return 0; 181} 182 183static int vp702x_fe_init(struct dvb_frontend *fe) 184{ 185 struct vp702x_fe_state *st = fe->demodulator_priv; 186 deb_fe("%s\n",__FUNCTION__); 187 vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0); 188 return 0; 189} 190 191static int vp702x_fe_sleep(struct dvb_frontend *fe) 192{ 193 deb_fe("%s\n",__FUNCTION__); 194 return 0; 195} 196 197static int vp702x_fe_get_frontend(struct dvb_frontend* fe, 198 struct dvb_frontend_parameters *fep) 199{ 200 deb_fe("%s\n",__FUNCTION__); 201 return 0; 202} 203 204static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, 205 struct dvb_diseqc_master_cmd *m) 206{ 207 struct vp702x_fe_state *st = fe->demodulator_priv; 208 u8 cmd[8],ibuf[10]; 209 memset(cmd,0,8); 210 211 deb_fe("%s\n",__FUNCTION__); 212 213 if (m->msg_len > 4) 214 return -EINVAL; 215 216 cmd[1] = SET_DISEQC_CMD; 217 cmd[2] = m->msg_len; 218 memcpy(&cmd[3], m->msg, m->msg_len); 219 cmd[7] = vp702x_chksum(cmd,0,7); 220 221 vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); 222 223 if (ibuf[2] == 0 && ibuf[3] == 0) 224 deb_fe("diseqc cmd failed.\n"); 225 else 226 deb_fe("diseqc cmd succeeded.\n"); 227 228 return 0; 229} 230 231static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) 232{ 233 deb_fe("%s\n",__FUNCTION__); 234 return 0; 235} 236 237static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) 238{ 239 struct vp702x_fe_state *st = fe->demodulator_priv; 240 u8 ibuf[10]; 241 deb_fe("%s\n",__FUNCTION__); 242 243 st->tone_mode = tone; 244 245 if (tone == SEC_TONE_ON) 246 st->lnb_buf[2] = 0x02; 247 else 248 st->lnb_buf[2] = 0x00; 249 250 st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7); 251 252 vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100); 253 if (ibuf[2] == 0 && ibuf[3] == 0) 254 deb_fe("set_tone cmd failed.\n"); 255 else 256 deb_fe("set_tone cmd succeeded.\n"); 257 258 return 0; 259} 260 261static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t 262 voltage) 263{ 264 struct vp702x_fe_state *st = fe->demodulator_priv; 265 u8 ibuf[10]; 266 deb_fe("%s\n",__FUNCTION__); 267 268 st->voltage = voltage; 269 270 if (voltage != SEC_VOLTAGE_OFF) 271 st->lnb_buf[4] = 0x01; 272 else 273 st->lnb_buf[4] = 0x00; 274 275 st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7); 276 277 vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100); 278 if (ibuf[2] == 0 && ibuf[3] == 0) 279 deb_fe("set_voltage cmd failed.\n"); 280 else 281 deb_fe("set_voltage cmd succeeded.\n"); 282 283 return 0; 284} 285 286static void vp702x_fe_release(struct dvb_frontend* fe) 287{ 288 struct vp702x_fe_state *st = fe->demodulator_priv; 289 kfree(st); 290} 291 292static struct dvb_frontend_ops vp702x_fe_ops; 293 294struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d) 295{ 296 struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL); 297 if (s == NULL) 298 goto error; 299 300 s->d = d; 301 302 memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops)); 303 s->fe.demodulator_priv = s; 304 305 s->lnb_buf[1] = SET_LNB_POWER; 306 s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */ 307 308 return &s->fe; 309error: 310 return NULL; 311} 312 313 314static struct dvb_frontend_ops vp702x_fe_ops = { 315 .info = { 316 .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", 317 .type = FE_QPSK, 318 .frequency_min = 950000, 319 .frequency_max = 2150000, 320 .frequency_stepsize = 1000, /* kHz for QPSK frontends */ 321 .frequency_tolerance = 0, 322 .symbol_rate_min = 1000000, 323 .symbol_rate_max = 45000000, 324 .symbol_rate_tolerance = 500, /* ppm */ 325 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 326 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | 327 FE_CAN_QPSK | 328 FE_CAN_FEC_AUTO 329 }, 330 .release = vp702x_fe_release, 331 332 .init = vp702x_fe_init, 333 .sleep = vp702x_fe_sleep, 334 335 .set_frontend = vp702x_fe_set_frontend, 336 .get_frontend = vp702x_fe_get_frontend, 337 .get_tune_settings = vp702x_fe_get_tune_settings, 338 339 .read_status = vp702x_fe_read_status, 340 .read_ber = vp702x_fe_read_ber, 341 .read_signal_strength = vp702x_fe_read_signal_strength, 342 .read_snr = vp702x_fe_read_snr, 343 .read_ucblocks = vp702x_fe_read_unc_blocks, 344 345 .diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg, 346 .diseqc_send_burst = vp702x_fe_send_diseqc_burst, 347 .set_tone = vp702x_fe_set_tone, 348 .set_voltage = vp702x_fe_set_voltage, 349}; 350