/** * zl3073x_ref_freq_factorize - factorize given frequency * @freq: input frequency * @base: base frequency * @mult: multiplier * * Checks if the given frequency can be factorized using one of the * supported base frequencies. If so the base frequency and multiplier * are stored into appropriate parameters if they are not NULL. * * Return: 0 on success, -EINVAL if the frequency cannot be factorized
*/ int
zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult)
{ staticconst u16 base_freqs[] = {
1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125,
128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000,
1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250,
6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250,
32000, 40000, 50000, 62500,
};
u32 div; int i;
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;
return 0;
}
}
return -EINVAL;
}
staticbool
zl3073x_check_reg(struct zl3073x_dev *zldev, unsignedint reg, size_t size)
{ /* Check that multiop lock is held when accessing registers * from page 10 and above.
*/ 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;
}
/** * zl3073x_read_u8 - read value from 8bit register * @zldev: zl3073x device pointer * @reg: register to write to * @val: value to write * * Reads value from given 8bit register. * * Returns: 0 on success, <0 on error
*/ int zl3073x_read_u8(struct zl3073x_dev *zldev, unsignedint reg, u8 *val)
{ return zl3073x_read_reg(zldev, reg, val, sizeof(*val));
}
/** * zl3073x_write_u8 - write value to 16bit register * @zldev: zl3073x device pointer * @reg: register to write to * @val: value to write * * Writes value into given 8bit register. * * Returns: 0 on success, <0 on error
*/ int zl3073x_write_u8(struct zl3073x_dev *zldev, unsignedint reg, u8 val)
{ return zl3073x_write_reg(zldev, reg, &val, sizeof(val));
}
/** * zl3073x_read_u16 - read value from 16bit register * @zldev: zl3073x device pointer * @reg: register to write to * @val: value to write * * Reads value from given 16bit register. * * Returns: 0 on success, <0 on error
*/ int zl3073x_read_u16(struct zl3073x_dev *zldev, unsignedint reg, u16 *val)
{ int rc;
rc = zl3073x_read_reg(zldev, reg, val, sizeof(*val)); if (!rc)
be16_to_cpus(val);
return rc;
}
/** * zl3073x_write_u16 - write value to 16bit register * @zldev: zl3073x device pointer * @reg: register to write to * @val: value to write * * Writes value into given 16bit register. * * Returns: 0 on success, <0 on error
*/ int zl3073x_write_u16(struct zl3073x_dev *zldev, unsignedint reg, u16 val)
{
cpu_to_be16s(&val);
/** * zl3073x_read_u32 - read value from 32bit register * @zldev: zl3073x device pointer * @reg: register to write to * @val: value to write * * Reads value from given 32bit register. * * Returns: 0 on success, <0 on error
*/ int zl3073x_read_u32(struct zl3073x_dev *zldev, unsignedint reg, u32 *val)
{ int rc;
rc = zl3073x_read_reg(zldev, reg, val, sizeof(*val)); if (!rc)
be32_to_cpus(val);
return rc;
}
/** * zl3073x_write_u32 - write value to 32bit register * @zldev: zl3073x device pointer * @reg: register to write to * @val: value to write * * Writes value into given 32bit register. * * Returns: 0 on success, <0 on error
*/ int zl3073x_write_u32(struct zl3073x_dev *zldev, unsignedint reg, u32 val)
{
cpu_to_be32s(&val);
/** * zl3073x_read_u48 - read value from 48bit register * @zldev: zl3073x device pointer * @reg: register to write to * @val: value to write * * Reads value from given 48bit register. * * Returns: 0 on success, <0 on error
*/ int zl3073x_read_u48(struct zl3073x_dev *zldev, unsignedint reg, u64 *val)
{
u8 buf[6]; int rc;
/** * zl3073x_write_u48 - write value to 48bit register * @zldev: zl3073x device pointer * @reg: register to write to * @val: value to write * * Writes value into given 48bit register. * The value must be from the interval -S48_MIN to U48_MAX. * * Returns: 0 on success, <0 on error
*/ int zl3073x_write_u48(struct zl3073x_dev *zldev, unsignedint reg, u64 val)
{
u8 buf[6];
/* Check the value belongs to <S48_MIN, U48_MAX> * Any value >= S48_MIN has bits 47..63 set.
*/ 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;
}
/** * zl3073x_poll_zero_u8 - wait for register to be cleared by device * @zldev: zl3073x device pointer * @reg: register to poll (has to be 8bit register) * @mask: bit mask for polling * * Waits for bits specified by @mask in register @reg value to be cleared * by the device. * * Returns: 0 on success, <0 on error
*/ int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsignedint reg, u8 mask)
{ /* Register polling sleep & timeout */ #define ZL_POLL_SLEEP_US 10 #define ZL_POLL_TIMEOUT_US 2000000 unsignedint val;
/* Check the register is 8bit */ if (ZL_REG_SIZE(reg) != 1) {
dev_err(zldev->dev, "Invalid reg 0x%04lx size for polling\n",
ZL_REG_ADDR(reg)); return -EINVAL;
}
/* Map the register address to virtual range */
reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET;
int zl3073x_mb_op(struct zl3073x_dev *zldev, unsignedint op_reg, u8 op_val, unsignedint mask_reg, u16 mask_val)
{ int rc;
/* Set mask for the operation */
rc = zl3073x_write_u16(zldev, mask_reg, mask_val); if (rc) return rc;
/* Trigger the operation */
rc = zl3073x_write_u8(zldev, op_reg, op_val); if (rc) return rc;
/* Wait for the operation to actually finish */ return zl3073x_poll_zero_u8(zldev, op_reg, op_val);
}
/** * zl3073x_ref_state_fetch - get input reference state * @zldev: pointer to zl3073x_dev structure * @index: input reference index to fetch state for * * Function fetches information for the given input reference that are * invariant and stores them for later use. * * Return: 0 on success, <0 on error
*/ staticint
zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
{ struct zl3073x_ref *input = &zldev->ref[index];
u8 ref_config; int rc;
/* If the input is differential then the configuration for N-pin * reference is ignored and P-pin config is used for both.
*/ 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;
dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index,
str_enabled_disabled(input->enabled),
input->diff ? "differential" : "single-ended");
return rc;
}
/** * zl3073x_out_state_fetch - get output state * @zldev: pointer to zl3073x_dev structure * @index: output index to fetch state for * * Function fetches information for the given output (not output pin) * that are invariant and stores them for later use. * * Return: 0 on success, <0 on error
*/ staticint
zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
{ struct zl3073x_out *out = &zldev->out[index];
u8 output_ctrl, output_mode; int rc;
/* Store info about output enablement and synthesizer the output * is connected to.
*/
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);
/* Extract and store output signal format */
out->signal_format = FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT,
output_mode);
dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index,
out->signal_format);
return rc;
}
/** * zl3073x_synth_state_fetch - get synth state * @zldev: pointer to zl3073x_dev structure * @index: synth index to fetch state for * * Function fetches information for the given synthesizer that are * invariant and stores them for later use. * * Return: 0 on success, <0 on error
*/ staticint
zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index)
{ struct zl3073x_synth *synth = &zldev->synth[index];
u16 base, m, n;
u8 synth_ctrl;
u32 mult; int rc;
/* 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 * driven by.
*/
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 * * Read registers with these values
*/
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 - update reference phase offsets * @zldev: pointer to zl3073x_dev structure * @channel: DPLL channel number or -1 * * The function asks device to update phase offsets latch registers with * the latest measured values. There are 2 sets of latch registers: * * 1) Up to 5 DPLL-to-connected-ref registers that contain phase offset * values between particular DPLL channel and its *connected* input * reference. * * 2) 10 selected-DPLL-to-all-ref registers that contain phase offset values * between selected DPLL channel and all input references. * * If the caller is interested in 2) then it has to pass DPLL channel number * in @channel parameter. If it is interested only in 1) then it should pass * @channel parameter with value of -1. * * Return: 0 on success, <0 on error
*/ 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' * to be zero to ensure that the measured data are coherent.
*/
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 - update reference fractional frequency offsets * @zldev: pointer to zl3073x_dev structure * * The function asks device to update fractional frequency offsets latch * registers the latest measured values, reads and stores them into * * Return: 0 on success, <0 on error
*/ 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 * to ensure that the measured data are coherent.
*/
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;
/** * zl3073x_dev_start - Start normal operation * @zldev: zl3073x device pointer * @full: perform full initialization * * The function starts normal operation, which means registering all DPLLs and * their pins, and starting monitoring. If full initialization is requested, * the function additionally initializes the phase offset measurement block and * fetches hardware-invariant parameters. * * Return: 0 on success, <0 on error
*/ int zl3073x_dev_start(struct zl3073x_dev *zldev, bool full)
{ struct zl3073x_dpll *zldpll;
u8 info; int 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 * configured and is ready for normal operation. If it is * cleared then the configuration stored in flash is wrong * or missing. In this situation the driver will expose * only devlink interface to give an opportunity to flash * the correct config.
*/
dev_info(zldev->dev, "FW not fully ready - missing or corrupted config\n");
return 0;
}
if (full) { /* Fetch device state */
rc = zl3073x_dev_state_fetch(zldev); if (rc) return rc;
/** * zl3073x_dev_stop - Stop normal operation * @zldev: zl3073x device pointer * * The function stops the normal operation that mean deregistration of all * DPLLs and their pins and stop monitoring. * * Return: 0 on success, <0 on error
*/ void zl3073x_dev_stop(struct zl3073x_dev *zldev)
{ struct zl3073x_dpll *zldpll;
/* Generate random clock ID as the device has not such property that * could be used for this purpose. A user can later change this value * using devlink.
*/
zldev->clock_id = get_random_u64();
/* Initialize mutex for operations where multiple reads, writes * and/or polls are required to be done atomically.
*/
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.