diff options
-rw-r--r-- | drivers/dpll/zl3073x/dpll.c | 88 | ||||
-rw-r--r-- | drivers/dpll/zl3073x/prop.c | 1 |
2 files changed, 89 insertions, 0 deletions
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c index 70c452a877ef..406b3e48f251 100644 --- a/drivers/dpll/zl3073x/dpll.c +++ b/drivers/dpll/zl3073x/dpll.c @@ -288,6 +288,56 @@ zl3073x_dpll_ref_prio_get(struct zl3073x_dpll_pin *pin, u8 *prio) } /** + * zl3073x_dpll_ref_prio_set - set priority for given input pin + * @pin: pointer to pin + * @prio: place to store priority + * + * Sets priority for the given input pin. + * + * Return: 0 on success, <0 on error + */ +static int +zl3073x_dpll_ref_prio_set(struct zl3073x_dpll_pin *pin, u8 prio) +{ + struct zl3073x_dpll *zldpll = pin->dpll; + struct zl3073x_dev *zldev = zldpll->dev; + u8 ref, ref_prio; + int rc; + + guard(mutex)(&zldev->multiop_lock); + + /* Read DPLL configuration into mailbox */ + rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, + ZL_REG_DPLL_MB_MASK, BIT(zldpll->id)); + if (rc) + return rc; + + /* Read reference priority - one value shared between P&N pins */ + ref = zl3073x_input_pin_ref_get(pin->id); + rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REF_PRIO(ref / 2), &ref_prio); + if (rc) + return rc; + + /* Update nibble according pin type */ + if (zl3073x_dpll_is_p_pin(pin)) { + ref_prio &= ~ZL_DPLL_REF_PRIO_REF_P; + ref_prio |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_P, prio); + } else { + ref_prio &= ~ZL_DPLL_REF_PRIO_REF_N; + ref_prio |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_N, prio); + } + + /* Update reference priority */ + rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_REF_PRIO(ref / 2), ref_prio); + if (rc) + return rc; + + /* Commit configuration */ + return zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_WR, + ZL_REG_DPLL_MB_MASK, BIT(zldpll->id)); +} + +/** * zl3073x_dpll_ref_state_get - get status for given input pin * @pin: pointer to pin * @state: place to store status @@ -401,6 +451,42 @@ zl3073x_dpll_input_pin_state_on_dpll_set(const struct dpll_pin *dpll_pin, } static int +zl3073x_dpll_input_pin_prio_get(const struct dpll_pin *dpll_pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u32 *prio, struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll_pin *pin = pin_priv; + + *prio = pin->prio; + + return 0; +} + +static int +zl3073x_dpll_input_pin_prio_set(const struct dpll_pin *dpll_pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u32 prio, struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll_pin *pin = pin_priv; + int rc; + + if (prio > ZL_DPLL_REF_PRIO_MAX) + return -EINVAL; + + /* If the pin is selectable then update HW registers */ + if (pin->selectable) { + rc = zl3073x_dpll_ref_prio_set(pin, prio); + if (rc) + return rc; + } + + /* Save priority */ + pin->prio = prio; + + return 0; +} + +static int zl3073x_dpll_output_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, void *pin_priv, const struct dpll_device *dpll, @@ -493,6 +579,8 @@ zl3073x_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv, static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { .direction_get = zl3073x_dpll_pin_direction_get, + .prio_get = zl3073x_dpll_input_pin_prio_get, + .prio_set = zl3073x_dpll_input_pin_prio_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, }; diff --git a/drivers/dpll/zl3073x/prop.c b/drivers/dpll/zl3073x/prop.c index c3224e78cbf0..4cf7e8aefcb3 100644 --- a/drivers/dpll/zl3073x/prop.c +++ b/drivers/dpll/zl3073x/prop.c @@ -205,6 +205,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, if (dir == DPLL_PIN_DIRECTION_INPUT) { props->dpll_props.type = DPLL_PIN_TYPE_EXT; props->dpll_props.capabilities = + DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE | DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; } else { props->dpll_props.type = DPLL_PIN_TYPE_GNSS; |