diff options
| author | Sang-Heon Jeon <ekffu200098@gmail.com> | 2026-08-24 01:18:14 +0900 |
|---|---|---|
| committer | Julia Lawall <Julia.Lawall@inria.fr> | 2026-08-23 22:12:11 +0200 |
| commit | 2bd30b8dc75b823dd7bbef9d7bc68e1fd7ecee5c (patch) | |
| tree | dcc4da1d99f17541c5590ac63c77da4bf372a4ab /drivers/dpll/zl3073x/ref.c | |
| download | linux-stable-2bd30b8dc75b823dd7bbef9d7bc68e1fd7ecee5c.tar.gz linux-stable-2bd30b8dc75b823dd7bbef9d7bc68e1fd7ecee5c.zip | |
coccinelle: alloc_cast: drop removed allocatorsgrafted
- pci_alloc_consistent() and pci_zalloc_consistent() were removed by
commit 7968778914e5
("PCI: Remove the deprecated "pci-dma-compat.h" API")
- kmem_alloc() was removed by commit f078d4ea8276
("xfs: convert kmem_alloc() to kmalloc()")
- kmem_zalloc() was removed by commit 10634530f7ba
("xfs: convert kmem_zalloc() to kzalloc()")
- kmem_zone_alloc() and kmem_zone_zalloc() were removed by commit
bae633a4a283 ("xfs: remove xfs_zone_{alloc,zalloc} helpers")
So drop them from the rules.
No functional change.
Signed-off-by: Sang-Heon Jeon <ekffu200098@gmail.com>
Signed-off-by: Julia Lawall <Julia.Lawall@inria.fr>
Diffstat (limited to 'drivers/dpll/zl3073x/ref.c')
| -rw-r--r-- | drivers/dpll/zl3073x/ref.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/drivers/dpll/zl3073x/ref.c b/drivers/dpll/zl3073x/ref.c new file mode 100644 index 000000000..825ac30bc --- /dev/null +++ b/drivers/dpll/zl3073x/ref.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/dev_printk.h> +#include <linux/string.h> +#include <linux/string_choices.h> +#include <linux/types.h> + +#include "core.h" +#include "ref.h" + +/** + * 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) +{ + static const 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; +} + +/** + * zl3073x_ref_state_update - update input reference status from HW + * @zldev: pointer to zl3073x_dev structure + * @index: input reference index + * + * Return: 0 on success, <0 on error + */ +int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index) +{ + struct zl3073x_ref *ref = &zldev->ref[index]; + + return zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(index), + &ref->mon_status); +} + +/** + * zl3073x_ref_state_fetch - fetch input reference state from hardware + * @zldev: pointer to zl3073x_dev structure + * @index: input reference index to fetch state for + * + * Function fetches state for the given input reference from hardware and + * stores it for later use. + * + * Return: 0 on success, <0 on error + */ +int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) +{ + struct zl3073x_ref *ref = &zldev->ref[index]; + int rc; + + /* For differential type inputs the N-pin reference shares + * part of the configuration with the P-pin counterpart. + */ + if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(ref - 1)) { + struct zl3073x_ref *p_ref = ref - 1; /* P-pin counterpart*/ + + /* Copy the shared items from the P-pin */ + ref->cfg = p_ref->cfg; + ref->inv = p_ref->inv; + + return 0; /* Finish - no non-shared items for now */ + } + + /* Read reference status */ + rc = zl3073x_ref_state_update(zldev, index); + if (rc) + return rc; + + guard(mutex)(&zldev->multiop_lock); + + /* Read reference configuration */ + rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, + ZL_REG_REF_MB_MASK, BIT(index)); + if (rc) + return rc; + + /* Read ref_config register */ + rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config); + if (rc) + return rc; + + /* Read frequency related registers */ + rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_BASE, &ref->freq_base); + if (rc) + return rc; + rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_MULT, &ref->freq_mult); + if (rc) + return rc; + rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_M, &ref->freq_ratio_m); + if (rc) + return rc; + rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_N, &ref->freq_ratio_n); + if (rc) + return rc; + + /* Read eSync and N-div rated registers */ + rc = zl3073x_read_u32(zldev, ZL_REG_REF_ESYNC_DIV, &ref->esync_n_div); + if (rc) + return rc; + rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref->sync_ctrl); + if (rc) + return rc; + + /* Read phase compensation register */ + if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) { + u32 val; + + rc = zl3073x_read_u32(zldev, ZL_REG_REF_PHASE_OFFSET_COMP_32, + &val); + ref->phase_comp = val; + } else { + rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, + &ref->phase_comp); + } + if (rc) + return rc; + + dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index, + str_enabled_disabled(zl3073x_ref_is_enabled(ref)), + zl3073x_ref_is_diff(ref) ? "differential" : "single-ended"); + + return rc; +} + +/** + * zl3073x_ref_state_get - get current input reference state + * @zldev: pointer to zl3073x_dev structure + * @index: input reference index to get state for + * + * Return: pointer to given input reference state + */ +const struct zl3073x_ref * +zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index) +{ + return &zldev->ref[index]; +} + +/** + * zl3073x_ref_state_set - commit input reference state changes to hardware + * @zldev: pointer to zl3073x_dev structure + * @index: input reference index to set state for + * @ref: desired reference state + * + * Validates that invariant fields have not been modified, skips the HW + * write if the mutable configuration is unchanged, and otherwise writes + * only the changed cfg fields to hardware via the mailbox interface. + * + * Return: 0 on success, -EINVAL if invariants changed, <0 on HW error + */ +int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, + const struct zl3073x_ref *ref) +{ + struct zl3073x_ref *dref = &zldev->ref[index]; + int rc; + + /* Reject attempts to change invariant fields (set at init only) */ + if (WARN_ON(memcmp(&dref->inv, &ref->inv, sizeof(ref->inv)))) + return -EINVAL; + + /* Skip HW write if configuration hasn't changed */ + if (!memcmp(&dref->cfg, &ref->cfg, sizeof(ref->cfg))) + return 0; + + guard(mutex)(&zldev->multiop_lock); + + /* Read reference configuration into mailbox */ + rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, + ZL_REG_REF_MB_MASK, BIT(index)); + if (rc) + return rc; + + /* Update mailbox with changed values */ + if (dref->freq_base != ref->freq_base) + rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_BASE, + ref->freq_base); + if (!rc && dref->freq_mult != ref->freq_mult) + rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_MULT, + ref->freq_mult); + if (!rc && dref->freq_ratio_m != ref->freq_ratio_m) + rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_M, + ref->freq_ratio_m); + if (!rc && dref->freq_ratio_n != ref->freq_ratio_n) + rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_N, + ref->freq_ratio_n); + if (!rc && dref->esync_n_div != ref->esync_n_div) + rc = zl3073x_write_u32(zldev, ZL_REG_REF_ESYNC_DIV, + ref->esync_n_div); + if (!rc && dref->sync_ctrl != ref->sync_ctrl) + rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL, + ref->sync_ctrl); + if (!rc && dref->phase_comp != ref->phase_comp) { + if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) + rc = zl3073x_write_u32(zldev, + ZL_REG_REF_PHASE_OFFSET_COMP_32, + ref->phase_comp); + else + rc = zl3073x_write_u48(zldev, + ZL_REG_REF_PHASE_OFFSET_COMP, + ref->phase_comp); + } + if (rc) + return rc; + + /* Commit reference configuration */ + rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR, + ZL_REG_REF_MB_MASK, BIT(index)); + if (rc) + return rc; + + /* After successful commit store new state */ + dref->cfg = ref->cfg; + + return 0; +} |
