// SPDX-License-Identifier: GPL-2.0-only /* * Driver for mt2063 Micronas tuner * * Copyright (c) 2011 Mauro Carvalho Chehab * * This driver came from a driver originally written by: * Henry Wang <[email protected]> * Made publicly available by Terratec, at: * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> #include <linux/videodev2.h> #include <linux/gcd.h> #include "mt2063.h" static unsigned int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(…) …; #define dprintk(level, fmt, arg...) … /* positive error codes used internally */ /* Info: Unavoidable LO-related spur may be present in the output */ #define MT2063_SPUR_PRESENT_ERR … /* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */ #define MT2063_SPUR_CNT_MASK … #define MT2063_SPUR_SHIFT … /* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */ #define MT2063_UPC_RANGE … /* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */ #define MT2063_DNC_RANGE … /* * Constant defining the version of the following structure * and therefore the API for this code. * * When compiling the tuner driver, the preprocessor will * check against this version number to make sure that * it matches the version that the tuner driver knows about. */ /* DECT Frequency Avoidance */ #define MT2063_DECT_AVOID_US_FREQS … #define MT2063_DECT_AVOID_EURO_FREQS … #define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) … #define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) … enum MT2063_DECT_Avoid_Type { … }; #define MT2063_MAX_ZONES … struct MT2063_ExclZone_t { … }; /* * Structure of data needed for Spur Avoidance */ struct MT2063_AvoidSpursData_t { … }; /* * Parameter for function MT2063_SetPowerMask that specifies the power down * of various sections of the MT2063. */ enum MT2063_Mask_Bits { … }; /* * Possible values for MT2063_DNC_OUTPUT */ enum MT2063_DNC_Output_Enable { … }; /* * Two-wire serial bus subaddresses of the tuner registers. * Also known as the tuner's register addresses. */ enum MT2063_Register_Offsets { … }; struct mt2063_state { … }; /* * mt2063_write - Write data into the I2C bus */ static int mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) { … } /* * mt2063_write - Write register data into the I2C bus, caching the value */ static int mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) { … } /* * mt2063_read - Read data from the I2C bus */ static int mt2063_read(struct mt2063_state *state, u8 subAddress, u8 *pData, u32 cnt) { … } /* * FIXME: Is this really needed? */ static int MT2063_Sleep(struct dvb_frontend *fe) { … } /* * Microtune spur avoidance */ /* Implement ceiling, floor functions. */ #define ceil(n, d) … #define floor(n, d) … struct MT2063_FIFZone_t { … }; static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t *pAS_Info, struct MT2063_ExclZone_t *pPrevNode) { … } static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t *pAS_Info, struct MT2063_ExclZone_t *pPrevNode, struct MT2063_ExclZone_t *pNodeToRemove) { … } /* * MT_AddExclZone() * * Add (and merge) an exclusion zone into the list. * If the range (f_min, f_max) is totally outside the * 1st IF BW, ignore the entry. * If the range (f_min, f_max) is negative, ignore the entry. */ static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info, u32 f_min, u32 f_max) { … } /* * Reset all exclusion zones. * Add zones to protect the PLL FracN regions near zero */ static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info) { … } /* * MT_ChooseFirstIF - Choose the best available 1st IF * If f_Desired is not excluded, choose that first. * Otherwise, return the value closest to f_Center that is * not excluded */ static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info) { … } /** * IsSpurInBand() - Checks to see if a spur will be present within the IF's * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) * * ma mb mc md * <--+-+-+-------------------+-------------------+-+-+--> * | ^ 0 ^ | * ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^ * a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2 * * Note that some equations are doubled to prevent round-off * problems when calculating fIFBW/2 * * @pAS_Info: Avoid Spurs information block * @fm: If spur, amount f_IF1 has to move negative * @fp: If spur, amount f_IF1 has to move positive * * Returns 1 if an LO spur would be present, otherwise 0. */ static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, u32 *fm, u32 * fp) { … } /* * MT_AvoidSpurs() - Main entry point to avoid spurs. * Checks for existing spurs in present LO1, LO2 freqs * and if present, chooses spur-free LO1, LO2 combination * that tunes the same input/output frequencies. */ static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) { … } /* * Constants used by the tuning algorithm */ #define MT2063_REF_FREQ … #define MT2063_IF1_BW … #define MT2063_TUNE_STEP_SIZE … #define MT2063_SPUR_STEP_HZ … #define MT2063_ZIF_BW … #define MT2063_MAX_HARMONICS_1 … #define MT2063_MAX_HARMONICS_2 … #define MT2063_MIN_LO_SEP … #define MT2063_LO1_FRACN_AVOID … #define MT2063_LO2_FRACN_AVOID … #define MT2063_MIN_FIN_FREQ … #define MT2063_MAX_FIN_FREQ … #define MT2063_MIN_FOUT_FREQ … #define MT2063_MAX_FOUT_FREQ … #define MT2063_MIN_DNC_FREQ … #define MT2063_MAX_DNC_FREQ … #define MT2063_MIN_UPC_FREQ … #define MT2063_MAX_UPC_FREQ … /* * Define the supported Part/Rev codes for the MT2063 */ #define MT2063_B0 … #define MT2063_B1 … #define MT2063_B2 … #define MT2063_B3 … /** * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked * * @state: struct mt2063_state pointer * * This function returns 0, if no lock, 1 if locked and a value < 1 if error */ static int mt2063_lockStatus(struct mt2063_state *state) { … } /* * Constants for setting receiver modes. * (6 modes defined at this time, enumerated by mt2063_delivery_sys) * (DNC1GC & DNC2GC are the values, which are used, when the specific * DNC Output is selected, the other is always off) * * enum mt2063_delivery_sys * -------------+---------------------------------------------- * Mode 0 : | MT2063_CABLE_QAM * Mode 1 : | MT2063_CABLE_ANALOG * Mode 2 : | MT2063_OFFAIR_COFDM * Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS * Mode 4 : | MT2063_OFFAIR_ANALOG * Mode 5 : | MT2063_OFFAIR_8VSB * --------------+---------------------------------------------- * * |<---------- Mode -------------->| * Reg Field | 0 | 1 | 2 | 3 | 4 | 5 | * ------------+-----+-----+-----+-----+-----+-----+ * RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF * LNARin | 0 | 0 | 3 | 3 | 3 | 3 * FIFFQen | 1 | 1 | 1 | 1 | 1 | 1 * FIFFq | 0 | 0 | 0 | 0 | 0 | 0 * DNC1gc | 0 | 0 | 0 | 0 | 0 | 0 * DNC2gc | 0 | 0 | 0 | 0 | 0 | 0 * GCU Auto | 1 | 1 | 1 | 1 | 1 | 1 * LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31 * LNA Target | 44 | 43 | 43 | 43 | 43 | 43 * ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0 * RF max Atn | 31 | 31 | 31 | 31 | 31 | 31 * PD1 Target | 36 | 36 | 38 | 38 | 36 | 38 * ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0 * FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5 * PD2 Target | 40 | 33 | 42 | 42 | 33 | 42 */ enum mt2063_delivery_sys { … }; static const char *mt2063_mode_name[] = …; static const u8 RFAGCEN[] = …; static const u8 LNARIN[] = …; static const u8 FIFFQEN[] = …; static const u8 FIFFQ[] = …; static const u8 DNC1GC[] = …; static const u8 DNC2GC[] = …; static const u8 ACLNAMAX[] = …; static const u8 LNATGT[] = …; static const u8 RFOVDIS[] = …; static const u8 ACRFMAX[] = …; static const u8 PD1TGT[] = …; static const u8 FIFOVDIS[] = …; static const u8 ACFIFMAX[] = …; static const u8 PD2TGT[] = …; /* * mt2063_set_dnc_output_enable() */ static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, enum MT2063_DNC_Output_Enable *pValue) { … } /* * mt2063_set_dnc_output_enable() */ static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, enum MT2063_DNC_Output_Enable nValue) { … } /* * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with * the selected enum mt2063_delivery_sys type. * * (DNC1GC & DNC2GC are the values, which are used, when the specific * DNC Output is selected, the other is always off) * * @state: ptr to mt2063_state structure * @Mode: desired receiver delivery system * * Note: Register cache must be valid for it to work */ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, enum mt2063_delivery_sys Mode) { … } /* * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various * sections of the MT2063 * * @Bits: Mask bits to be cleared. * * See definition of MT2063_Mask_Bits type for description * of each of the power bits. */ static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, enum MT2063_Mask_Bits Bits) { … } /* * MT2063_SoftwareShutdown() - Enables or disables software shutdown function. * When Shutdown is 1, any section whose power * mask is set will be shutdown. */ static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) { … } static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref) { … } /** * MT2063_fLO_FractionalTerm - Calculates the portion contributed by FracN / denom. * This function preserves maximum precision without * risk of overflow. It accurately calculates * f_ref * num / denom to within 1 HZ with fixed math. * * @f_ref: SRO frequency. * @num: Fractional portion of the multiplier * @denom: denominator portion of the ratio * * This calculation handles f_ref as two separate 14-bit fields. * Therefore, a maximum value of 2^28-1 may safely be used for f_ref. * This is the genesis of the magic number "14" and the magic mask value of * 0x03FFF. * * This routine successfully handles denom values up to and including 2^18. * Returns: f_ref * num / denom */ static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom) { … } /* * MT2063_CalcLO1Mult - Calculates Integer divider value and the numerator * value for a FracN PLL. * * This function assumes that the f_LO and f_Ref are * evenly divisible by f_LO_Step. * * @Div: OUTPUT: Whole number portion of the multiplier * @FracN: OUTPUT: Fractional portion of the multiplier * @f_LO: desired LO frequency. * @f_LO_Step: Minimum step size for the LO (in Hz). * @f_Ref: SRO frequency. * @f_Avoid: Range of PLL frequencies to avoid near integer multiples * of f_Ref (in Hz). * * Returns: Recalculated LO frequency. */ static u32 MT2063_CalcLO1Mult(u32 *Div, u32 *FracN, u32 f_LO, u32 f_LO_Step, u32 f_Ref) { … } /** * MT2063_CalcLO2Mult - Calculates Integer divider value and the numerator * value for a FracN PLL. * * This function assumes that the f_LO and f_Ref are * evenly divisible by f_LO_Step. * * @Div: OUTPUT: Whole number portion of the multiplier * @FracN: OUTPUT: Fractional portion of the multiplier * @f_LO: desired LO frequency. * @f_LO_Step: Minimum step size for the LO (in Hz). * @f_Ref: SRO frequency. * * Returns: Recalculated LO frequency. */ static u32 MT2063_CalcLO2Mult(u32 *Div, u32 *FracN, u32 f_LO, u32 f_LO_Step, u32 f_Ref) { … } /* * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be * used for a given input frequency. * * @state: ptr to tuner data structure * @f_in: RF input center frequency (in Hz). * * Returns: ClearTune filter number (0-31) */ static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) { … } /* * MT2063_Tune() - Change the tuner's tuned frequency to RFin. */ static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) { … } static const u8 MT2063B0_defaults[] = …; /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ static const u8 MT2063B1_defaults[] = …; /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ static const u8 MT2063B3_defaults[] = …; static int mt2063_init(struct dvb_frontend *fe) { … } static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status) { … } static void mt2063_release(struct dvb_frontend *fe) { … } static int mt2063_set_analog_params(struct dvb_frontend *fe, struct analog_parameters *params) { … } /* * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. * So, the amount of the needed bandwidth is given by: * Bw = Symbol_rate * (1 + 0.15) * As such, the maximum symbol rate supported by 6 MHz is given by: * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds */ #define MAX_SYMBOL_RATE_6MHz … static int mt2063_set_params(struct dvb_frontend *fe) { … } static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq) { … } static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw) { … } static const struct dvb_tuner_ops mt2063_ops = …; struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, struct mt2063_config *config, struct i2c_adapter *i2c) { … } EXPORT_SYMBOL_GPL(…); #if 0 /* * Ancillary routines visible outside mt2063 * FIXME: Remove them in favor of using standard tuner callbacks */ static int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) { struct mt2063_state *state = fe->tuner_priv; int err = 0; dprintk(2, "\n"); err = MT2063_SoftwareShutdown(state, 1); if (err < 0) printk(KERN_ERR "%s: Couldn't shutdown\n", __func__); return err; } static int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) { struct mt2063_state *state = fe->tuner_priv; int err = 0; dprintk(2, "\n"); err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); if (err < 0) printk(KERN_ERR "%s: Invalid parameter\n", __func__); return err; } #endif MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;