1 // SPDX-License-Identifier: GPL-2.0-only
2 /* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0
5 * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
6 * Metzler Brothers Systementwicklung GbR
8 * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
10 * Thanks to Twinhan who kindly provided hardware and information.
12 * This file can be removed soon, after the DST-driver is rewritten to provice
13 * the frontend-controlling separately.
15 * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
19 struct vp702x_fe_state
{
20 struct dvb_frontend fe
;
21 struct dvb_usb_device
*d
;
23 struct dvb_frontend_ops ops
;
25 enum fe_sec_voltage voltage
;
26 enum fe_sec_tone_mode tone_mode
;
34 unsigned long next_status_check
;
35 unsigned long status_check_interval
;
38 static int vp702x_fe_refresh_state(struct vp702x_fe_state
*st
)
40 struct vp702x_device_state
*dst
= st
->d
->priv
;
43 if (time_after(jiffies
, st
->next_status_check
)) {
44 mutex_lock(&dst
->buf_mutex
);
47 vp702x_usb_in_op(st
->d
, READ_STATUS
, 0, 0, buf
, 10);
50 vp702x_usb_in_op(st
->d
, READ_TUNER_REG_REQ
, 0x11, 0, buf
, 1);
53 vp702x_usb_in_op(st
->d
, READ_TUNER_REG_REQ
, 0x15, 0, buf
, 1);
56 mutex_unlock(&dst
->buf_mutex
);
57 st
->next_status_check
= jiffies
+ (st
->status_check_interval
*HZ
)/1000;
62 static u8
vp702x_chksum(u8
*buf
,int f
, int count
)
66 for (i
= f
; i
< f
+count
; i
++)
71 static int vp702x_fe_read_status(struct dvb_frontend
*fe
,
72 enum fe_status
*status
)
74 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
75 vp702x_fe_refresh_state(st
);
76 deb_fe("%s\n",__func__
);
79 *status
= FE_HAS_LOCK
| FE_HAS_SYNC
| FE_HAS_VITERBI
| FE_HAS_SIGNAL
| FE_HAS_CARRIER
;
83 if (*status
& FE_HAS_LOCK
)
84 st
->status_check_interval
= 1000;
86 st
->status_check_interval
= 250;
90 /* not supported by this Frontend */
91 static int vp702x_fe_read_ber(struct dvb_frontend
* fe
, u32
*ber
)
93 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
94 vp702x_fe_refresh_state(st
);
99 /* not supported by this Frontend */
100 static int vp702x_fe_read_unc_blocks(struct dvb_frontend
* fe
, u32
*unc
)
102 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
103 vp702x_fe_refresh_state(st
);
108 static int vp702x_fe_read_signal_strength(struct dvb_frontend
* fe
, u16
*strength
)
110 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
111 vp702x_fe_refresh_state(st
);
113 *strength
= (st
->sig
<< 8) | st
->sig
;
117 static int vp702x_fe_read_snr(struct dvb_frontend
* fe
, u16
*snr
)
120 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
121 vp702x_fe_refresh_state(st
);
123 _snr
= (st
->snr
& 0x1f) * 0xff / 0x1f;
124 *snr
= (_snr
<< 8) | _snr
;
128 static int vp702x_fe_get_tune_settings(struct dvb_frontend
* fe
, struct dvb_frontend_tune_settings
*tune
)
130 deb_fe("%s\n",__func__
);
131 tune
->min_delay_ms
= 2000;
135 static int vp702x_fe_set_frontend(struct dvb_frontend
*fe
)
137 struct dtv_frontend_properties
*fep
= &fe
->dtv_property_cache
;
138 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
139 struct vp702x_device_state
*dst
= st
->d
->priv
;
140 u32 freq
= fep
->frequency
/1000;
142 /* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
146 mutex_lock(&dst
->buf_mutex
);
151 cmd
[0] = (freq
>> 8) & 0x7f;
152 cmd
[1] = freq
& 0xff;
153 cmd
[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */
155 sr
= (u64
) (fep
->symbol_rate
/1000) << 20;
157 cmd
[3] = (sr
>> 12) & 0xff;
158 cmd
[4] = (sr
>> 4) & 0xff;
159 cmd
[5] = (sr
<< 4) & 0xf0;
161 deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n",
162 fep
->frequency
, freq
, freq
, fep
->symbol_rate
,
163 (unsigned long) sr
, (unsigned long) sr
);
165 /* if (fep->inversion == INVERSION_ON)
168 if (st
->voltage
== SEC_VOLTAGE_18
)
171 /* if (fep->symbol_rate > 8000000)
174 if (fep->frequency < 1531000)
177 if (st->tone_mode == SEC_TONE_ON)
180 cmd
[7] = vp702x_chksum(cmd
,0,7);
182 st
->status_check_interval
= 250;
183 st
->next_status_check
= jiffies
;
185 vp702x_usb_inout_op(st
->d
, cmd
, 8, cmd
, 10, 100);
187 if (cmd
[2] == 0 && cmd
[3] == 0)
188 deb_fe("tuning failed.\n");
190 deb_fe("tuning succeeded.\n");
192 mutex_unlock(&dst
->buf_mutex
);
197 static int vp702x_fe_init(struct dvb_frontend
*fe
)
199 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
200 deb_fe("%s\n",__func__
);
201 vp702x_usb_in_op(st
->d
, RESET_TUNER
, 0, 0, NULL
, 0);
205 static int vp702x_fe_sleep(struct dvb_frontend
*fe
)
207 deb_fe("%s\n",__func__
);
211 static int vp702x_fe_send_diseqc_msg (struct dvb_frontend
* fe
,
212 struct dvb_diseqc_master_cmd
*m
)
215 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
216 struct vp702x_device_state
*dst
= st
->d
->priv
;
218 deb_fe("%s\n",__func__
);
223 mutex_lock(&dst
->buf_mutex
);
226 cmd
[1] = SET_DISEQC_CMD
;
228 memcpy(&cmd
[3], m
->msg
, m
->msg_len
);
229 cmd
[7] = vp702x_chksum(cmd
, 0, 7);
231 vp702x_usb_inout_op(st
->d
, cmd
, 8, cmd
, 10, 100);
233 if (cmd
[2] == 0 && cmd
[3] == 0)
234 deb_fe("diseqc cmd failed.\n");
236 deb_fe("diseqc cmd succeeded.\n");
238 mutex_unlock(&dst
->buf_mutex
);
243 static int vp702x_fe_send_diseqc_burst(struct dvb_frontend
*fe
,
244 enum fe_sec_mini_cmd burst
)
246 deb_fe("%s\n",__func__
);
250 static int vp702x_fe_set_tone(struct dvb_frontend
*fe
,
251 enum fe_sec_tone_mode tone
)
253 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
254 struct vp702x_device_state
*dst
= st
->d
->priv
;
257 deb_fe("%s\n",__func__
);
259 st
->tone_mode
= tone
;
261 if (tone
== SEC_TONE_ON
)
262 st
->lnb_buf
[2] = 0x02;
264 st
->lnb_buf
[2] = 0x00;
266 st
->lnb_buf
[7] = vp702x_chksum(st
->lnb_buf
, 0, 7);
268 mutex_lock(&dst
->buf_mutex
);
271 memcpy(buf
, st
->lnb_buf
, 8);
273 vp702x_usb_inout_op(st
->d
, buf
, 8, buf
, 10, 100);
274 if (buf
[2] == 0 && buf
[3] == 0)
275 deb_fe("set_tone cmd failed.\n");
277 deb_fe("set_tone cmd succeeded.\n");
279 mutex_unlock(&dst
->buf_mutex
);
284 static int vp702x_fe_set_voltage(struct dvb_frontend
*fe
,
285 enum fe_sec_voltage voltage
)
287 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
288 struct vp702x_device_state
*dst
= st
->d
->priv
;
290 deb_fe("%s\n",__func__
);
292 st
->voltage
= voltage
;
294 if (voltage
!= SEC_VOLTAGE_OFF
)
295 st
->lnb_buf
[4] = 0x01;
297 st
->lnb_buf
[4] = 0x00;
299 st
->lnb_buf
[7] = vp702x_chksum(st
->lnb_buf
, 0, 7);
301 mutex_lock(&dst
->buf_mutex
);
304 memcpy(buf
, st
->lnb_buf
, 8);
306 vp702x_usb_inout_op(st
->d
, buf
, 8, buf
, 10, 100);
307 if (buf
[2] == 0 && buf
[3] == 0)
308 deb_fe("set_voltage cmd failed.\n");
310 deb_fe("set_voltage cmd succeeded.\n");
312 mutex_unlock(&dst
->buf_mutex
);
316 static void vp702x_fe_release(struct dvb_frontend
* fe
)
318 struct vp702x_fe_state
*st
= fe
->demodulator_priv
;
322 static const struct dvb_frontend_ops vp702x_fe_ops
;
324 struct dvb_frontend
* vp702x_fe_attach(struct dvb_usb_device
*d
)
326 struct vp702x_fe_state
*s
= kzalloc(sizeof(struct vp702x_fe_state
), GFP_KERNEL
);
332 memcpy(&s
->fe
.ops
,&vp702x_fe_ops
,sizeof(struct dvb_frontend_ops
));
333 s
->fe
.demodulator_priv
= s
;
335 s
->lnb_buf
[1] = SET_LNB_POWER
;
336 s
->lnb_buf
[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
344 static const struct dvb_frontend_ops vp702x_fe_ops
= {
345 .delsys
= { SYS_DVBS
},
347 .name
= "Twinhan DST-like frontend (VP7021/VP7020) DVB-S",
348 .frequency_min_hz
= 950 * MHz
,
349 .frequency_max_hz
= 2150 * MHz
,
350 .frequency_stepsize_hz
= 1 * MHz
,
351 .symbol_rate_min
= 1000000,
352 .symbol_rate_max
= 45000000,
353 .symbol_rate_tolerance
= 500, /* ppm */
354 .caps
= FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
355 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
|
359 .release
= vp702x_fe_release
,
361 .init
= vp702x_fe_init
,
362 .sleep
= vp702x_fe_sleep
,
364 .set_frontend
= vp702x_fe_set_frontend
,
365 .get_tune_settings
= vp702x_fe_get_tune_settings
,
367 .read_status
= vp702x_fe_read_status
,
368 .read_ber
= vp702x_fe_read_ber
,
369 .read_signal_strength
= vp702x_fe_read_signal_strength
,
370 .read_snr
= vp702x_fe_read_snr
,
371 .read_ucblocks
= vp702x_fe_read_unc_blocks
,
373 .diseqc_send_master_cmd
= vp702x_fe_send_diseqc_msg
,
374 .diseqc_send_burst
= vp702x_fe_send_diseqc_burst
,
375 .set_tone
= vp702x_fe_set_tone
,
376 .set_voltage
= vp702x_fe_set_voltage
,