Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0
0003  * DVB-T receiver.
0004  *
0005  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
0006  *
0007  * Thanks to Twinhan who kindly provided hardware and information.
0008  *
0009  * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
0010  */
0011 #include "vp7045.h"
0012 
0013 /* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT
0014  *
0015  * Programming is hidden inside the firmware, so set_frontend is very easy.
0016  * Even though there is a Firmware command that one can use to access the demod
0017  * via its registers. This is used for status information.
0018  */
0019 
0020 struct vp7045_fe_state {
0021     struct dvb_frontend fe;
0022     struct dvb_usb_device *d;
0023 };
0024 
0025 static int vp7045_fe_read_status(struct dvb_frontend *fe,
0026                  enum fe_status *status)
0027 {
0028     struct vp7045_fe_state *state = fe->demodulator_priv;
0029     u8 s0 = vp7045_read_reg(state->d,0x00),
0030        s1 = vp7045_read_reg(state->d,0x01),
0031        s3 = vp7045_read_reg(state->d,0x03);
0032 
0033     *status = 0;
0034     if (s0 & (1 << 4))
0035         *status |= FE_HAS_CARRIER;
0036     if (s0 & (1 << 1))
0037         *status |= FE_HAS_VITERBI;
0038     if (s0 & (1 << 5))
0039         *status |= FE_HAS_LOCK;
0040     if (s1 & (1 << 1))
0041         *status |= FE_HAS_SYNC;
0042     if (s3 & (1 << 6))
0043         *status |= FE_HAS_SIGNAL;
0044 
0045     if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
0046             (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
0047         *status &= ~FE_HAS_LOCK;
0048 
0049     return 0;
0050 }
0051 
0052 static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
0053 {
0054     struct vp7045_fe_state *state = fe->demodulator_priv;
0055     *ber = (vp7045_read_reg(state->d, 0x0D) << 16) |
0056            (vp7045_read_reg(state->d, 0x0E) << 8) |
0057         vp7045_read_reg(state->d, 0x0F);
0058     return 0;
0059 }
0060 
0061 static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
0062 {
0063     struct vp7045_fe_state *state = fe->demodulator_priv;
0064     *unc = (vp7045_read_reg(state->d, 0x10) << 8) |
0065             vp7045_read_reg(state->d, 0x11);
0066     return 0;
0067 }
0068 
0069 static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
0070 {
0071     struct vp7045_fe_state *state = fe->demodulator_priv;
0072     u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) |
0073         vp7045_read_reg(state->d, 0x15);
0074 
0075     *strength = ~signal;
0076     return 0;
0077 }
0078 
0079 static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
0080 {
0081     struct vp7045_fe_state *state = fe->demodulator_priv;
0082     u8 _snr = vp7045_read_reg(state->d, 0x09);
0083     *snr = (_snr << 8) | _snr;
0084     return 0;
0085 }
0086 
0087 static int vp7045_fe_init(struct dvb_frontend* fe)
0088 {
0089     return 0;
0090 }
0091 
0092 static int vp7045_fe_sleep(struct dvb_frontend* fe)
0093 {
0094     return 0;
0095 }
0096 
0097 static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
0098 {
0099     tune->min_delay_ms = 800;
0100     return 0;
0101 }
0102 
0103 static int vp7045_fe_set_frontend(struct dvb_frontend *fe)
0104 {
0105     struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
0106     struct vp7045_fe_state *state = fe->demodulator_priv;
0107     u8 buf[5];
0108     u32 freq = fep->frequency / 1000;
0109 
0110     buf[0] = (freq >> 16) & 0xff;
0111     buf[1] = (freq >>  8) & 0xff;
0112     buf[2] =  freq        & 0xff;
0113     buf[3] = 0;
0114 
0115     switch (fep->bandwidth_hz) {
0116     case 8000000:
0117         buf[4] = 8;
0118         break;
0119     case 7000000:
0120         buf[4] = 7;
0121         break;
0122     case 6000000:
0123         buf[4] = 6;
0124         break;
0125     default:
0126         return -EINVAL;
0127     }
0128 
0129     vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200);
0130     return 0;
0131 }
0132 
0133 static void vp7045_fe_release(struct dvb_frontend* fe)
0134 {
0135     struct vp7045_fe_state *state = fe->demodulator_priv;
0136     kfree(state);
0137 }
0138 
0139 static const struct dvb_frontend_ops vp7045_fe_ops;
0140 
0141 struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
0142 {
0143     struct vp7045_fe_state *s = kzalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL);
0144     if (s == NULL)
0145         goto error;
0146 
0147     s->d = d;
0148     memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
0149     s->fe.demodulator_priv = s;
0150 
0151     return &s->fe;
0152 error:
0153     return NULL;
0154 }
0155 
0156 
0157 static const struct dvb_frontend_ops vp7045_fe_ops = {
0158     .delsys = { SYS_DVBT },
0159     .info = {
0160         .name           = "Twinhan VP7045/46 USB DVB-T",
0161         .frequency_min_hz   =  44250 * kHz,
0162         .frequency_max_hz   = 867250 * kHz,
0163         .frequency_stepsize_hz  =      1 * kHz,
0164         .caps = FE_CAN_INVERSION_AUTO |
0165                 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
0166                 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
0167                 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
0168                 FE_CAN_TRANSMISSION_MODE_AUTO |
0169                 FE_CAN_GUARD_INTERVAL_AUTO |
0170                 FE_CAN_RECOVER |
0171                 FE_CAN_HIERARCHY_AUTO,
0172     },
0173 
0174     .release = vp7045_fe_release,
0175 
0176     .init = vp7045_fe_init,
0177     .sleep = vp7045_fe_sleep,
0178 
0179     .set_frontend = vp7045_fe_set_frontend,
0180     .get_tune_settings = vp7045_fe_get_tune_settings,
0181 
0182     .read_status = vp7045_fe_read_status,
0183     .read_ber = vp7045_fe_read_ber,
0184     .read_signal_strength = vp7045_fe_read_signal_strength,
0185     .read_snr = vp7045_fe_read_snr,
0186     .read_ucblocks = vp7045_fe_read_unc_blocks,
0187 };