mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 04:23:35 +02:00
Merge branch 'dpll-zl3073x-add-ref-sync-pair-support'
Ivan Vecera says: ==================== dpll: zl3073x: add ref-sync pair support This series adds Reference-Sync pair support to the ZL3073x DPLL driver. A Ref-Sync pair consists of a clock reference and a low-frequency sync signal (e.g. 1 PPS) where the DPLL locks to the clock reference but phase-aligns to the sync reference. Patches 1-3 are preparatory cleanups and helper additions: - Clean up esync get/set callbacks with early returns and use the zl3073x_out_is_ndiv() helper - Convert open-coded clear-and-set bitfield patterns to FIELD_MODIFY() - Add ref sync control and output clock type accessor helpers Patch 4 adds the 'ref-sync-sources' phandle-array property to the dpll-pin device tree binding schema and updates the ZL3073x binding examples. Patch 5 implements the driver support: - ref_sync_get/set callbacks with frequency validation - Automatic sync source exclusion from reference selection - Device tree based ref-sync pair registration Tested and verified on Microchip EDS2 (pcb8385) development board. ==================== Link: https://patch.msgid.link/20260408102716.443099-1-ivecera@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
d24b443429
|
|
@ -36,6 +36,19 @@ properties:
|
|||
description: String exposed as the pin board label
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
|
||||
ref-sync-sources:
|
||||
description: |
|
||||
List of phandles to input pins that can serve as the sync source
|
||||
in a Reference-Sync pair with this pin acting as the clock source.
|
||||
A Ref-Sync pair consists of a clock reference and a low-frequency
|
||||
sync signal. The DPLL locks to the clock reference but
|
||||
phase-aligns to the sync reference.
|
||||
Only valid for input pins. Each referenced pin must be a
|
||||
different input pin on the same device.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
maxItems: 1
|
||||
|
||||
supported-frequencies-hz:
|
||||
description: List of supported frequencies for this pin, expressed in Hz.
|
||||
|
||||
|
|
|
|||
|
|
@ -52,11 +52,19 @@ examples:
|
|||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pin@0 { /* REF0P */
|
||||
sync0: pin@0 { /* REF0P - 1 PPS sync source */
|
||||
reg = <0>;
|
||||
connection-type = "ext";
|
||||
label = "Input 0";
|
||||
supported-frequencies-hz = /bits/ 64 <1 1000>;
|
||||
label = "SMA1";
|
||||
supported-frequencies-hz = /bits/ 64 <1>;
|
||||
};
|
||||
|
||||
pin@1 { /* REF0N - clock source, can pair with sync0 */
|
||||
reg = <1>;
|
||||
connection-type = "ext";
|
||||
label = "SMA2";
|
||||
supported-frequencies-hz = /bits/ 64 <10000 10000000>;
|
||||
ref-sync-sources = <&sync0>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -90,11 +98,19 @@ examples:
|
|||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pin@0 { /* REF0P */
|
||||
sync1: pin@0 { /* REF0P - 1 PPS sync source */
|
||||
reg = <0>;
|
||||
connection-type = "ext";
|
||||
label = "Input 0";
|
||||
supported-frequencies-hz = /bits/ 64 <1 1000>;
|
||||
connection-type = "gnss";
|
||||
label = "GNSS_1PPS_IN";
|
||||
supported-frequencies-hz = /bits/ 64 <1>;
|
||||
};
|
||||
|
||||
pin@1 { /* REF0N - clock source */
|
||||
reg = <1>;
|
||||
connection-type = "gnss";
|
||||
label = "GNSS_10M_IN";
|
||||
supported-frequencies-hz = /bits/ 64 <10000000>;
|
||||
ref-sync-sources = <&sync1>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -66,8 +66,7 @@ static inline u8 zl3073x_chan_ref_get(const struct zl3073x_chan *chan)
|
|||
*/
|
||||
static inline void zl3073x_chan_mode_set(struct zl3073x_chan *chan, u8 mode)
|
||||
{
|
||||
chan->mode_refsel &= ~ZL_DPLL_MODE_REFSEL_MODE;
|
||||
chan->mode_refsel |= FIELD_PREP(ZL_DPLL_MODE_REFSEL_MODE, mode);
|
||||
FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_MODE, &chan->mode_refsel, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -77,8 +76,7 @@ static inline void zl3073x_chan_mode_set(struct zl3073x_chan *chan, u8 mode)
|
|||
*/
|
||||
static inline void zl3073x_chan_ref_set(struct zl3073x_chan *chan, u8 ref)
|
||||
{
|
||||
chan->mode_refsel &= ~ZL_DPLL_MODE_REFSEL_REF;
|
||||
chan->mode_refsel |= FIELD_PREP(ZL_DPLL_MODE_REFSEL_REF, ref);
|
||||
FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_REF, &chan->mode_refsel, ref);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -110,13 +108,10 @@ zl3073x_chan_ref_prio_set(struct zl3073x_chan *chan, u8 ref, u8 prio)
|
|||
{
|
||||
u8 *val = &chan->ref_prio[ref / 2];
|
||||
|
||||
if (!(ref & 1)) {
|
||||
*val &= ~ZL_DPLL_REF_PRIO_REF_P;
|
||||
*val |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_P, prio);
|
||||
} else {
|
||||
*val &= ~ZL_DPLL_REF_PRIO_REF_N;
|
||||
*val |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_N, prio);
|
||||
}
|
||||
if (!(ref & 1))
|
||||
FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_P, val, prio);
|
||||
else
|
||||
FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_N, val, prio);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -805,8 +805,7 @@ int zl3073x_dev_phase_avg_factor_set(struct zl3073x_dev *zldev, u8 factor)
|
|||
value = (factor + 1) & 0x0f;
|
||||
|
||||
/* Update phase measurement control register */
|
||||
dpll_meas_ctrl &= ~ZL_DPLL_MEAS_CTRL_AVG_FACTOR;
|
||||
dpll_meas_ctrl |= FIELD_PREP(ZL_DPLL_MEAS_CTRL_AVG_FACTOR, value);
|
||||
FIELD_MODIFY(ZL_DPLL_MEAS_CTRL_AVG_FACTOR, &dpll_meas_ctrl, value);
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MEAS_CTRL, dpll_meas_ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sprintf.h>
|
||||
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
* @dpll: DPLL the pin is registered to
|
||||
* @dpll_pin: pointer to registered dpll_pin
|
||||
* @tracker: tracking object for the acquired reference
|
||||
* @fwnode: firmware node handle
|
||||
* @label: package label
|
||||
* @dir: pin direction
|
||||
* @id: pin id
|
||||
|
|
@ -46,6 +48,7 @@ struct zl3073x_dpll_pin {
|
|||
struct zl3073x_dpll *dpll;
|
||||
struct dpll_pin *dpll_pin;
|
||||
dpll_tracker tracker;
|
||||
struct fwnode_handle *fwnode;
|
||||
char label[8];
|
||||
enum dpll_pin_direction dir;
|
||||
u8 id;
|
||||
|
|
@ -133,7 +136,13 @@ zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
|
|||
ref_id = zl3073x_input_pin_ref_get(pin->id);
|
||||
ref = zl3073x_ref_state_get(zldev, ref_id);
|
||||
|
||||
switch (FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref->sync_ctrl)) {
|
||||
if (!pin->esync_control || zl3073x_ref_freq_get(ref) <= 1)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
esync->range = esync_freq_ranges;
|
||||
esync->range_num = ARRAY_SIZE(esync_freq_ranges);
|
||||
|
||||
switch (zl3073x_ref_sync_mode_get(ref)) {
|
||||
case ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75:
|
||||
esync->freq = ref->esync_n_div == ZL_REF_ESYNC_DIV_1HZ ? 1 : 0;
|
||||
esync->pulse = 25;
|
||||
|
|
@ -144,17 +153,6 @@ zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
|
|||
break;
|
||||
}
|
||||
|
||||
/* If the pin supports esync control expose its range but only
|
||||
* if the current reference frequency is > 1 Hz.
|
||||
*/
|
||||
if (pin->esync_control && zl3073x_ref_freq_get(ref) > 1) {
|
||||
esync->range = esync_freq_ranges;
|
||||
esync->range_num = ARRAY_SIZE(esync_freq_ranges);
|
||||
} else {
|
||||
esync->range = NULL;
|
||||
esync->range_num = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -180,8 +178,7 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
|
|||
else
|
||||
sync_mode = ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75;
|
||||
|
||||
ref.sync_ctrl &= ~ZL_REF_SYNC_CTRL_MODE;
|
||||
ref.sync_ctrl |= FIELD_PREP(ZL_REF_SYNC_CTRL_MODE, sync_mode);
|
||||
zl3073x_ref_sync_mode_set(&ref, sync_mode);
|
||||
|
||||
if (freq) {
|
||||
/* 1 Hz is only supported frequency now */
|
||||
|
|
@ -192,6 +189,109 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
|
|||
return zl3073x_ref_state_set(zldev, ref_id, &ref);
|
||||
}
|
||||
|
||||
static int
|
||||
zl3073x_dpll_input_pin_ref_sync_get(const struct dpll_pin *dpll_pin,
|
||||
void *pin_priv,
|
||||
const struct dpll_pin *ref_sync_pin,
|
||||
void *ref_sync_pin_priv,
|
||||
enum dpll_pin_state *state,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv;
|
||||
struct zl3073x_dpll_pin *pin = pin_priv;
|
||||
struct zl3073x_dpll *zldpll = pin->dpll;
|
||||
struct zl3073x_dev *zldev = zldpll->dev;
|
||||
const struct zl3073x_ref *ref;
|
||||
u8 ref_id, mode, pair;
|
||||
|
||||
ref_id = zl3073x_input_pin_ref_get(pin->id);
|
||||
ref = zl3073x_ref_state_get(zldev, ref_id);
|
||||
mode = zl3073x_ref_sync_mode_get(ref);
|
||||
pair = zl3073x_ref_sync_pair_get(ref);
|
||||
|
||||
if (mode == ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR &&
|
||||
pair == zl3073x_input_pin_ref_get(sync_pin->id))
|
||||
*state = DPLL_PIN_STATE_CONNECTED;
|
||||
else
|
||||
*state = DPLL_PIN_STATE_DISCONNECTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
zl3073x_dpll_input_pin_ref_sync_set(const struct dpll_pin *dpll_pin,
|
||||
void *pin_priv,
|
||||
const struct dpll_pin *ref_sync_pin,
|
||||
void *ref_sync_pin_priv,
|
||||
const enum dpll_pin_state state,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv;
|
||||
struct zl3073x_dpll_pin *pin = pin_priv;
|
||||
struct zl3073x_dpll *zldpll = pin->dpll;
|
||||
struct zl3073x_dev *zldev = zldpll->dev;
|
||||
u8 mode, ref_id, sync_ref_id;
|
||||
struct zl3073x_chan chan;
|
||||
struct zl3073x_ref ref;
|
||||
int rc;
|
||||
|
||||
ref_id = zl3073x_input_pin_ref_get(pin->id);
|
||||
sync_ref_id = zl3073x_input_pin_ref_get(sync_pin->id);
|
||||
ref = *zl3073x_ref_state_get(zldev, ref_id);
|
||||
|
||||
if (state == DPLL_PIN_STATE_CONNECTED) {
|
||||
const struct zl3073x_ref *sync_ref;
|
||||
u32 ref_freq, sync_freq;
|
||||
|
||||
sync_ref = zl3073x_ref_state_get(zldev, sync_ref_id);
|
||||
ref_freq = zl3073x_ref_freq_get(&ref);
|
||||
sync_freq = zl3073x_ref_freq_get(sync_ref);
|
||||
|
||||
/* Sync signal must be 8 kHz or less and clock reference
|
||||
* must be 1 kHz or more and higher than the sync signal.
|
||||
*/
|
||||
if (sync_freq > 8000) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"sync frequency must be 8 kHz or less");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ref_freq < 1000) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"clock frequency must be 1 kHz or more");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ref_freq <= sync_freq) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"clock frequency must be higher than sync frequency");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
zl3073x_ref_sync_pair_set(&ref, sync_ref_id);
|
||||
mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR;
|
||||
} else {
|
||||
mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF;
|
||||
}
|
||||
|
||||
zl3073x_ref_sync_mode_set(&ref, mode);
|
||||
|
||||
rc = zl3073x_ref_state_set(zldev, ref_id, &ref);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Exclude sync source from automatic reference selection by setting
|
||||
* its priority to NONE. On disconnect the priority is left as NONE
|
||||
* and the user must explicitly make the pin selectable again.
|
||||
*/
|
||||
if (state == DPLL_PIN_STATE_CONNECTED) {
|
||||
chan = *zl3073x_chan_state_get(zldev, zldpll->id);
|
||||
zl3073x_chan_ref_prio_set(&chan, sync_ref_id,
|
||||
ZL_DPLL_REF_PRIO_NONE);
|
||||
return zl3073x_chan_state_set(zldev, zldpll->id, &chan);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv,
|
||||
const struct dpll_device *dpll, void *dpll_priv,
|
||||
|
|
@ -599,8 +699,8 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
|
|||
struct zl3073x_dpll_pin *pin = pin_priv;
|
||||
const struct zl3073x_synth *synth;
|
||||
const struct zl3073x_out *out;
|
||||
u8 clock_type, out_id;
|
||||
u32 synth_freq;
|
||||
u32 synth_freq, out_freq;
|
||||
u8 out_id;
|
||||
|
||||
out_id = zl3073x_output_pin_out_get(pin->id);
|
||||
out = zl3073x_out_state_get(zldev, out_id);
|
||||
|
|
@ -609,29 +709,30 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
|
|||
* for N-division is also used for the esync divider so both cannot
|
||||
* be used.
|
||||
*/
|
||||
switch (zl3073x_out_signal_format_get(out)) {
|
||||
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
|
||||
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
|
||||
if (zl3073x_out_is_ndiv(out))
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get attached synth frequency */
|
||||
synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out));
|
||||
synth_freq = zl3073x_synth_freq_get(synth);
|
||||
out_freq = synth_freq / out->div;
|
||||
|
||||
clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode);
|
||||
if (clock_type != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) {
|
||||
if (!pin->esync_control || out_freq <= 1)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
esync->range = esync_freq_ranges;
|
||||
esync->range_num = ARRAY_SIZE(esync_freq_ranges);
|
||||
|
||||
if (zl3073x_out_clock_type_get(out) != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) {
|
||||
/* No need to read esync data if it is not enabled */
|
||||
esync->freq = 0;
|
||||
esync->pulse = 0;
|
||||
|
||||
goto finish;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute esync frequency */
|
||||
esync->freq = synth_freq / out->div / out->esync_n_period;
|
||||
esync->freq = out_freq / out->esync_n_period;
|
||||
|
||||
/* By comparing the esync_pulse_width to the half of the pulse width
|
||||
* the esync pulse percentage can be determined.
|
||||
|
|
@ -640,18 +741,6 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
|
|||
*/
|
||||
esync->pulse = (50 * out->esync_n_width) / out->div;
|
||||
|
||||
finish:
|
||||
/* Set supported esync ranges if the pin supports esync control and
|
||||
* if the output frequency is > 1 Hz.
|
||||
*/
|
||||
if (pin->esync_control && (synth_freq / out->div) > 1) {
|
||||
esync->range = esync_freq_ranges;
|
||||
esync->range_num = ARRAY_SIZE(esync_freq_ranges);
|
||||
} else {
|
||||
esync->range = NULL;
|
||||
esync->range_num = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -667,8 +756,8 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
|
|||
struct zl3073x_dpll_pin *pin = pin_priv;
|
||||
const struct zl3073x_synth *synth;
|
||||
struct zl3073x_out out;
|
||||
u8 clock_type, out_id;
|
||||
u32 synth_freq;
|
||||
u8 out_id;
|
||||
|
||||
out_id = zl3073x_output_pin_out_get(pin->id);
|
||||
out = *zl3073x_out_state_get(zldev, out_id);
|
||||
|
|
@ -677,23 +766,16 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
|
|||
* for N-division is also used for the esync divider so both cannot
|
||||
* be used.
|
||||
*/
|
||||
switch (zl3073x_out_signal_format_get(&out)) {
|
||||
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
|
||||
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
|
||||
if (zl3073x_out_is_ndiv(&out))
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Select clock type */
|
||||
if (freq)
|
||||
clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC;
|
||||
else
|
||||
clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL;
|
||||
|
||||
/* Update clock type in output mode */
|
||||
out.mode &= ~ZL_OUTPUT_MODE_CLOCK_TYPE;
|
||||
out.mode |= FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type);
|
||||
if (freq)
|
||||
zl3073x_out_clock_type_set(&out,
|
||||
ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC);
|
||||
else
|
||||
zl3073x_out_clock_type_set(&out,
|
||||
ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL);
|
||||
|
||||
/* If esync is being disabled just write mailbox and finish */
|
||||
if (!freq)
|
||||
|
|
@ -745,9 +827,9 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin,
|
|||
struct zl3073x_dev *zldev = zldpll->dev;
|
||||
struct zl3073x_dpll_pin *pin = pin_priv;
|
||||
const struct zl3073x_synth *synth;
|
||||
u8 out_id, signal_format;
|
||||
u32 new_div, synth_freq;
|
||||
struct zl3073x_out out;
|
||||
u8 out_id;
|
||||
|
||||
out_id = zl3073x_output_pin_out_get(pin->id);
|
||||
out = *zl3073x_out_state_get(zldev, out_id);
|
||||
|
|
@ -757,12 +839,8 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin,
|
|||
synth_freq = zl3073x_synth_freq_get(synth);
|
||||
new_div = synth_freq / (u32)frequency;
|
||||
|
||||
/* Get used signal format for the given output */
|
||||
signal_format = zl3073x_out_signal_format_get(&out);
|
||||
|
||||
/* Check signal format */
|
||||
if (signal_format != ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV &&
|
||||
signal_format != ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV) {
|
||||
if (!zl3073x_out_is_ndiv(&out)) {
|
||||
/* For non N-divided signal formats the frequency is computed
|
||||
* as division of synth frequency and output divisor.
|
||||
*/
|
||||
|
|
@ -1175,6 +1253,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
|
|||
.phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set,
|
||||
.prio_get = zl3073x_dpll_input_pin_prio_get,
|
||||
.prio_set = zl3073x_dpll_input_pin_prio_set,
|
||||
.ref_sync_get = zl3073x_dpll_input_pin_ref_sync_get,
|
||||
.ref_sync_set = zl3073x_dpll_input_pin_ref_sync_set,
|
||||
.state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get,
|
||||
.state_on_dpll_set = zl3073x_dpll_input_pin_state_on_dpll_set,
|
||||
};
|
||||
|
|
@ -1267,8 +1347,11 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
|
|||
if (IS_ERR(props))
|
||||
return PTR_ERR(props);
|
||||
|
||||
/* Save package label, esync capability and phase adjust granularity */
|
||||
/* Save package label, fwnode, esync capability and phase adjust
|
||||
* granularity.
|
||||
*/
|
||||
strscpy(pin->label, props->package_label);
|
||||
pin->fwnode = fwnode_handle_get(props->fwnode);
|
||||
pin->esync_control = props->esync_control;
|
||||
pin->phase_gran = props->dpll_props.phase_gran;
|
||||
|
||||
|
|
@ -1313,6 +1396,8 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
|
|||
dpll_pin_put(pin->dpll_pin, &pin->tracker);
|
||||
pin->dpll_pin = NULL;
|
||||
err_pin_get:
|
||||
fwnode_handle_put(pin->fwnode);
|
||||
pin->fwnode = NULL;
|
||||
zl3073x_pin_props_put(props);
|
||||
|
||||
return rc;
|
||||
|
|
@ -1342,6 +1427,9 @@ zl3073x_dpll_pin_unregister(struct zl3073x_dpll_pin *pin)
|
|||
|
||||
dpll_pin_put(pin->dpll_pin, &pin->tracker);
|
||||
pin->dpll_pin = NULL;
|
||||
|
||||
fwnode_handle_put(pin->fwnode);
|
||||
pin->fwnode = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1855,6 +1943,88 @@ zl3073x_dpll_free(struct zl3073x_dpll *zldpll)
|
|||
kfree(zldpll);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_dpll_ref_sync_pair_register - register ref_sync pairs for a pin
|
||||
* @pin: pointer to zl3073x_dpll_pin structure
|
||||
*
|
||||
* Iterates 'ref-sync-sources' phandles in the pin's firmware node and
|
||||
* registers each declared pairing.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_dpll_ref_sync_pair_register(struct zl3073x_dpll_pin *pin)
|
||||
{
|
||||
struct zl3073x_dev *zldev = pin->dpll->dev;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct dpll_pin *sync_pin;
|
||||
dpll_tracker tracker;
|
||||
int n, rc;
|
||||
|
||||
for (n = 0; ; n++) {
|
||||
/* Get n'th ref-sync source */
|
||||
fwnode = fwnode_find_reference(pin->fwnode, "ref-sync-sources",
|
||||
n);
|
||||
if (IS_ERR(fwnode)) {
|
||||
rc = PTR_ERR(fwnode);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find associated dpll pin */
|
||||
sync_pin = fwnode_dpll_pin_find(fwnode, &tracker);
|
||||
fwnode_handle_put(fwnode);
|
||||
if (!sync_pin) {
|
||||
dev_warn(zldev->dev, "%s: ref-sync source %d not found",
|
||||
pin->label, n);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Register new ref-sync pair */
|
||||
rc = dpll_pin_ref_sync_pair_add(pin->dpll_pin, sync_pin);
|
||||
dpll_pin_put(sync_pin, &tracker);
|
||||
|
||||
/* -EBUSY means pairing already exists from another DPLL's
|
||||
* registration.
|
||||
*/
|
||||
if (rc && rc != -EBUSY) {
|
||||
dev_err(zldev->dev,
|
||||
"%s: failed to add ref-sync source %d: %pe",
|
||||
pin->label, n, ERR_PTR(rc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc != -ENOENT ? rc : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_dpll_ref_sync_pairs_register - register ref_sync pairs for a DPLL
|
||||
* @zldpll: pointer to zl3073x_dpll structure
|
||||
*
|
||||
* Iterates all registered input pins of the given DPLL and establishes
|
||||
* ref_sync pairings declared by 'ref-sync-sources' phandles in the
|
||||
* device tree.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_dpll_ref_sync_pairs_register(struct zl3073x_dpll *zldpll)
|
||||
{
|
||||
struct zl3073x_dpll_pin *pin;
|
||||
int rc;
|
||||
|
||||
list_for_each_entry(pin, &zldpll->pins, list) {
|
||||
if (!zl3073x_dpll_is_input_pin(pin) || !pin->fwnode)
|
||||
continue;
|
||||
|
||||
rc = zl3073x_dpll_ref_sync_pair_register(pin);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_dpll_register - register DPLL device and all its pins
|
||||
* @zldpll: pointer to zl3073x_dpll structure
|
||||
|
|
@ -1878,6 +2048,13 @@ zl3073x_dpll_register(struct zl3073x_dpll *zldpll)
|
|||
return rc;
|
||||
}
|
||||
|
||||
rc = zl3073x_dpll_ref_sync_pairs_register(zldpll);
|
||||
if (rc) {
|
||||
zl3073x_dpll_pins_unregister(zldpll);
|
||||
zl3073x_dpll_device_unregister(zldpll);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,8 +194,7 @@ zl3073x_flash_cmd_wait(struct zl3073x_dev *zldev, u32 operation,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
value &= ~ZL_WRITE_FLASH_OP;
|
||||
value |= FIELD_PREP(ZL_WRITE_FLASH_OP, operation);
|
||||
FIELD_MODIFY(ZL_WRITE_FLASH_OP, &value, operation);
|
||||
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_WRITE_FLASH, value);
|
||||
if (rc)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,28 @@ const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
|
|||
int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index,
|
||||
const struct zl3073x_out *out);
|
||||
|
||||
/**
|
||||
* zl3073x_out_clock_type_get - get output clock type
|
||||
* @out: pointer to out state
|
||||
*
|
||||
* Return: clock type of given output (ZL_OUTPUT_MODE_CLOCK_TYPE_*)
|
||||
*/
|
||||
static inline u8 zl3073x_out_clock_type_get(const struct zl3073x_out *out)
|
||||
{
|
||||
return FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_out_clock_type_set - set output clock type
|
||||
* @out: pointer to out state
|
||||
* @type: clock type (ZL_OUTPUT_MODE_CLOCK_TYPE_*)
|
||||
*/
|
||||
static inline void
|
||||
zl3073x_out_clock_type_set(struct zl3073x_out *out, u8 type)
|
||||
{
|
||||
FIELD_MODIFY(ZL_OUTPUT_MODE_CLOCK_TYPE, &out->mode, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_out_signal_format_get - get output signal format
|
||||
* @out: pointer to out state
|
||||
|
|
|
|||
|
|
@ -120,6 +120,52 @@ zl3073x_ref_freq_set(struct zl3073x_ref *ref, u32 freq)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_ref_sync_mode_get - get sync control mode
|
||||
* @ref: pointer to ref state
|
||||
*
|
||||
* Return: sync control mode (ZL_REF_SYNC_CTRL_MODE_*)
|
||||
*/
|
||||
static inline u8
|
||||
zl3073x_ref_sync_mode_get(const struct zl3073x_ref *ref)
|
||||
{
|
||||
return FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref->sync_ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_ref_sync_mode_set - set sync control mode
|
||||
* @ref: pointer to ref state
|
||||
* @mode: sync control mode (ZL_REF_SYNC_CTRL_MODE_*)
|
||||
*/
|
||||
static inline void
|
||||
zl3073x_ref_sync_mode_set(struct zl3073x_ref *ref, u8 mode)
|
||||
{
|
||||
FIELD_MODIFY(ZL_REF_SYNC_CTRL_MODE, &ref->sync_ctrl, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_ref_sync_pair_get - get sync pair reference index
|
||||
* @ref: pointer to ref state
|
||||
*
|
||||
* Return: paired reference index
|
||||
*/
|
||||
static inline u8
|
||||
zl3073x_ref_sync_pair_get(const struct zl3073x_ref *ref)
|
||||
{
|
||||
return FIELD_GET(ZL_REF_SYNC_CTRL_PAIR, ref->sync_ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_ref_sync_pair_set - set sync pair reference index
|
||||
* @ref: pointer to ref state
|
||||
* @pair: paired reference index
|
||||
*/
|
||||
static inline void
|
||||
zl3073x_ref_sync_pair_set(struct zl3073x_ref *ref, u8 pair)
|
||||
{
|
||||
FIELD_MODIFY(ZL_REF_SYNC_CTRL_PAIR, &ref->sync_ctrl, pair);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_ref_is_diff - check if the given input reference is differential
|
||||
* @ref: pointer to ref state
|
||||
|
|
|
|||
|
|
@ -213,7 +213,9 @@
|
|||
#define ZL_REG_REF_SYNC_CTRL ZL_REG(10, 0x2e, 1)
|
||||
#define ZL_REF_SYNC_CTRL_MODE GENMASK(2, 0)
|
||||
#define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF 0
|
||||
#define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR 1
|
||||
#define ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75 2
|
||||
#define ZL_REF_SYNC_CTRL_PAIR GENMASK(7, 4)
|
||||
|
||||
#define ZL_REG_REF_ESYNC_DIV ZL_REG(10, 0x30, 4)
|
||||
#define ZL_REF_ESYNC_DIV_1HZ 0
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user