for (i = 0; i < ARRAY_SIZE(base_freqs); i++) {
div = freq / base_freqs[i];
if (div <= U16_MAX && (freq % base_freqs[i]) == 0) { if (base)
*base = base_freqs[i]; if (mult)
*mult = div;
return0;
}
}
return -EINVAL;
}
staticbool
zl3073x_check_reg(struct zl3073x_dev *zldev, unsignedint reg, size_t size)
{ /* Check that multiop lock is held when accessing registers *frompage10andabove.
*/ if (ZL_REG_PAGE(reg) >= 10)
lockdep_assert_held(&zldev->multiop_lock);
/* Check the index is in valid range for indexed register */ if (ZL_REG_OFFSET(reg) > ZL_REG_MAX_OFFSET(reg)) {
dev_err(zldev->dev, "Index out of range for reg 0x%04lx\n",
ZL_REG_ADDR(reg)); returnfalse;
} /* Check the requested size corresponds to register size */ if (ZL_REG_SIZE(reg) != size) {
dev_err(zldev->dev, "Invalid size %zu for reg 0x%04lx\n",
size, ZL_REG_ADDR(reg)); returnfalse;
}
/* Check the value belongs to <S48_MIN, U48_MAX> *Anyvalue>=S48_MINhasbits47..63set.
*/ if (val > GENMASK_ULL(47, 0) && val < GENMASK_ULL(63, 47)) {
dev_err(zldev->dev, "Value 0x%0llx out of range\n", val); return -EINVAL;
}
/* If the input is differential then the configuration for N-pin *referenceisignoredandP-pinconfigisusedforboth.
*/ if (zl3073x_is_n_pin(index) &&
zl3073x_ref_is_diff(zldev, index - 1)) {
input->enabled = zl3073x_ref_is_enabled(zldev, index - 1);
input->diff = true;
/* Store info about output enablement and synthesizer the output *isconnectedto.
*/
out->enabled = FIELD_GET(ZL_OUTPUT_CTRL_EN, output_ctrl);
out->synth = FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, output_ctrl);
dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index,
str_enabled_disabled(out->enabled), out->synth);
/* Read synth control register */
rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth_ctrl); if (rc) return rc;
/* Store info about synth enablement and DPLL channel the synth is *drivenby.
*/
synth->enabled = FIELD_GET(ZL_SYNTH_CTRL_EN, synth_ctrl);
synth->dpll = FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, synth_ctrl);
dev_dbg(zldev->dev, "SYNTH%u is %s and driven by DPLL%u\n", index,
str_enabled_disabled(synth->enabled), synth->dpll);
/* The output frequency is determined by the following formula: *base*multiplier*numerator/denominator * *Readregisterswiththesevalues
*/
rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &base); if (rc) return rc;
rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &mult); if (rc) return rc;
rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &m); if (rc) return rc;
rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &n); if (rc) return rc;
/* Check denominator for zero to avoid div by 0 */ if (!n) {
dev_err(zldev->dev, "Zero divisor for SYNTH%u retrieved from device\n",
index); return -EINVAL;
}
/* Compute and store synth frequency */
zldev->synth[index].freq = div_u64(mul_u32_u32(base * m, mult), n);
staticint
zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
{ int rc;
u8 i;
for (i = 0; i < ZL3073X_NUM_REFS; i++) {
rc = zl3073x_ref_state_fetch(zldev, i); if (rc) {
dev_err(zldev->dev, "Failed to fetch input state: %pe\n",
ERR_PTR(rc)); return rc;
}
}
for (i = 0; i < ZL3073X_NUM_SYNTHS; i++) {
rc = zl3073x_synth_state_fetch(zldev, i); if (rc) {
dev_err(zldev->dev, "Failed to fetch synth state: %pe\n",
ERR_PTR(rc)); return rc;
}
}
for (i = 0; i < ZL3073X_NUM_OUTS; i++) {
rc = zl3073x_out_state_fetch(zldev, i); if (rc) {
dev_err(zldev->dev, "Failed to fetch output state: %pe\n",
ERR_PTR(rc)); return rc;
}
}
return rc;
}
/** *zl3073x_ref_phase_offsets_update-updatereferencephaseoffsets *@zldev:pointertozl3073x_devstructure *@channel:DPLLchannelnumberor-1 * *Thefunctionasksdevicetoupdatephaseoffsetslatchregisterswith *thelatestmeasuredvalues.Thereare2setsoflatchregisters: * *1)Upto5DPLL-to-connected-refregistersthatcontainphaseoffset *valuesbetweenparticularDPLLchannelandits*connected*input *reference. * *2)10selected-DPLL-to-all-refregistersthatcontainphaseoffsetvalues *betweenselectedDPLLchannelandallinputreferences. * *Ifthecallerisinterestedin2)thenithastopassDPLLchannelnumber *in@channelparameter.Ifitisinterestedonlyin1)thenitshouldpass *@channelparameterwithvalueof-1. * *Return:0onsuccess,<0onerror
*/ int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel)
{ int rc;
/* Per datasheet we have to wait for 'dpll_ref_phase_err_rqst_rd' *tobezerotoensurethatthemeasureddataarecoherent.
*/
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
ZL_REF_PHASE_ERR_READ_RQST_RD); if (rc) return rc;
/* Select DPLL channel if it is specified */ if (channel != -1) {
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MEAS_IDX, channel); if (rc) return rc;
}
/* Request to update phase offsets measurement values */
rc = zl3073x_write_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
ZL_REF_PHASE_ERR_READ_RQST_RD); if (rc) return rc;
/* Wait for finish */ return zl3073x_poll_zero_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
ZL_REF_PHASE_ERR_READ_RQST_RD);
}
/** *zl3073x_ref_ffo_update-updatereferencefractionalfrequencyoffsets *@zldev:pointertozl3073x_devstructure * *Thefunctionasksdevicetoupdatefractionalfrequencyoffsetslatch *registersthelatestmeasuredvalues,readsandstorestheminto * *Return:0onsuccess,<0onerror
*/ staticint
zl3073x_ref_ffo_update(struct zl3073x_dev *zldev)
{ int i, rc;
/* Per datasheet we have to wait for 'ref_freq_meas_ctrl' to be zero *toensurethatthemeasureddataarecoherent.
*/
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
ZL_REF_FREQ_MEAS_CTRL); if (rc) return rc;
/* Select all references for measurement */
rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_MASK_3_0,
GENMASK(7, 0)); /* REF0P..REF3N */ if (rc) return rc;
rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_MASK_4,
GENMASK(1, 0)); /* REF4P..REF4N */ if (rc) return rc;
/* Request frequency offset measurement */
rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF); if (rc) return rc;
/* Wait for finish */
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
ZL_REF_FREQ_MEAS_CTRL); if (rc) return rc;
/* Read DPLL-to-REFx frequency offset measurements */ for (i = 0; i < ZL3073X_NUM_REFS; i++) {
s32 value;
/* Read value stored in units of 2^-32 signed */
rc = zl3073x_read_u32(zldev, ZL_REG_REF_FREQ(i), &value); if (rc) return rc;
rc = zl3073x_read_u8(zldev, ZL_REG_INFO, &info); if (rc) {
dev_err(zldev->dev, "Failed to read device status info\n"); return rc;
}
if (!FIELD_GET(ZL_INFO_READY, info)) { /* The ready bit indicates that the firmware was successfully *configuredandisreadyfornormaloperation.Ifitis *clearedthentheconfigurationstoredinflashiswrong *ormissing.Inthissituationthedriverwillexpose *onlydevlinkinterfacetogiveanopportunitytoflash *thecorrectconfig.
*/
dev_info(zldev->dev, "FW not fully ready - missing or corrupted config\n");
return0;
}
if (full) { /* Fetch device state */
rc = zl3073x_dev_state_fetch(zldev); if (rc) return rc;
/* Generate random clock ID as the device has not such property that *couldbeusedforthispurpose.Ausercanlaterchangethisvalue *usingdevlink.
*/
zldev->clock_id = get_random_u64();
/* Initialize mutex for operations where multiple reads, writes *and/orpollsarerequiredtobedoneatomically.
*/
rc = devm_mutex_init(zldev->dev, &zldev->multiop_lock); if (rc) return dev_err_probe(zldev->dev, rc, "Failed to initialize mutex\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.