1607f2c00SIvan Vecera // SPDX-License-Identifier: GPL-2.0-only 2607f2c00SIvan Vecera 3607f2c00SIvan Vecera #include <linux/bitfield.h> 4607f2c00SIvan Vecera #include <linux/cleanup.h> 5607f2c00SIvan Vecera #include <linux/dev_printk.h> 6607f2c00SIvan Vecera #include <linux/string.h> 7607f2c00SIvan Vecera #include <linux/string_choices.h> 8607f2c00SIvan Vecera #include <linux/types.h> 9607f2c00SIvan Vecera 10607f2c00SIvan Vecera #include "core.h" 11607f2c00SIvan Vecera #include "ref.h" 12607f2c00SIvan Vecera 13607f2c00SIvan Vecera /** 14607f2c00SIvan Vecera * zl3073x_ref_freq_factorize - factorize given frequency 15607f2c00SIvan Vecera * @freq: input frequency 16607f2c00SIvan Vecera * @base: base frequency 17607f2c00SIvan Vecera * @mult: multiplier 18607f2c00SIvan Vecera * 19607f2c00SIvan Vecera * Checks if the given frequency can be factorized using one of the 20607f2c00SIvan Vecera * supported base frequencies. If so the base frequency and multiplier 21607f2c00SIvan Vecera * are stored into appropriate parameters if they are not NULL. 22607f2c00SIvan Vecera * 23607f2c00SIvan Vecera * Return: 0 on success, -EINVAL if the frequency cannot be factorized 24607f2c00SIvan Vecera */ 25607f2c00SIvan Vecera int 26607f2c00SIvan Vecera zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult) 27607f2c00SIvan Vecera { 28607f2c00SIvan Vecera static const u16 base_freqs[] = { 29607f2c00SIvan Vecera 1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125, 30607f2c00SIvan Vecera 128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000, 31607f2c00SIvan Vecera 1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250, 32607f2c00SIvan Vecera 6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250, 33607f2c00SIvan Vecera 32000, 40000, 50000, 62500, 34607f2c00SIvan Vecera }; 35607f2c00SIvan Vecera u32 div; 36607f2c00SIvan Vecera int i; 37607f2c00SIvan Vecera 38607f2c00SIvan Vecera for (i = 0; i < ARRAY_SIZE(base_freqs); i++) { 39607f2c00SIvan Vecera div = freq / base_freqs[i]; 40607f2c00SIvan Vecera 41607f2c00SIvan Vecera if (div <= U16_MAX && (freq % base_freqs[i]) == 0) { 42607f2c00SIvan Vecera if (base) 43607f2c00SIvan Vecera *base = base_freqs[i]; 44607f2c00SIvan Vecera if (mult) 45607f2c00SIvan Vecera *mult = div; 46607f2c00SIvan Vecera 47607f2c00SIvan Vecera return 0; 48607f2c00SIvan Vecera } 49607f2c00SIvan Vecera } 50607f2c00SIvan Vecera 51607f2c00SIvan Vecera return -EINVAL; 52607f2c00SIvan Vecera } 53607f2c00SIvan Vecera 54607f2c00SIvan Vecera /** 55607f2c00SIvan Vecera * zl3073x_ref_state_fetch - fetch input reference state from hardware 56607f2c00SIvan Vecera * @zldev: pointer to zl3073x_dev structure 57607f2c00SIvan Vecera * @index: input reference index to fetch state for 58607f2c00SIvan Vecera * 59607f2c00SIvan Vecera * Function fetches state for the given input reference from hardware and 60607f2c00SIvan Vecera * stores it for later use. 61607f2c00SIvan Vecera * 62607f2c00SIvan Vecera * Return: 0 on success, <0 on error 63607f2c00SIvan Vecera */ 64607f2c00SIvan Vecera int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) 65607f2c00SIvan Vecera { 66607f2c00SIvan Vecera struct zl3073x_ref *ref = &zldev->ref[index]; 67607f2c00SIvan Vecera int rc; 68607f2c00SIvan Vecera 69607f2c00SIvan Vecera /* For differential type inputs the N-pin reference shares 70607f2c00SIvan Vecera * part of the configuration with the P-pin counterpart. 71607f2c00SIvan Vecera */ 72607f2c00SIvan Vecera if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(ref - 1)) { 73*5bc02b19SIvan Vecera struct zl3073x_ref *p_ref = ref - 1; /* P-pin counterpart*/ 74607f2c00SIvan Vecera 75607f2c00SIvan Vecera /* Copy the shared items from the P-pin */ 76607f2c00SIvan Vecera ref->config = p_ref->config; 77*5bc02b19SIvan Vecera ref->esync_n_div = p_ref->esync_n_div; 78*5bc02b19SIvan Vecera ref->freq_base = p_ref->freq_base; 79*5bc02b19SIvan Vecera ref->freq_mult = p_ref->freq_mult; 80*5bc02b19SIvan Vecera ref->freq_ratio_m = p_ref->freq_ratio_m; 81*5bc02b19SIvan Vecera ref->freq_ratio_n = p_ref->freq_ratio_n; 82*5bc02b19SIvan Vecera ref->phase_comp = p_ref->phase_comp; 83*5bc02b19SIvan Vecera ref->sync_ctrl = p_ref->sync_ctrl; 84607f2c00SIvan Vecera 85607f2c00SIvan Vecera return 0; /* Finish - no non-shared items for now */ 86607f2c00SIvan Vecera } 87607f2c00SIvan Vecera 88607f2c00SIvan Vecera guard(mutex)(&zldev->multiop_lock); 89607f2c00SIvan Vecera 90607f2c00SIvan Vecera /* Read reference configuration */ 91607f2c00SIvan Vecera rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 92607f2c00SIvan Vecera ZL_REG_REF_MB_MASK, BIT(index)); 93607f2c00SIvan Vecera if (rc) 94607f2c00SIvan Vecera return rc; 95607f2c00SIvan Vecera 96607f2c00SIvan Vecera /* Read ref_config register */ 97607f2c00SIvan Vecera rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config); 98607f2c00SIvan Vecera if (rc) 99607f2c00SIvan Vecera return rc; 100607f2c00SIvan Vecera 101*5bc02b19SIvan Vecera /* Read frequency related registers */ 102*5bc02b19SIvan Vecera rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_BASE, &ref->freq_base); 103*5bc02b19SIvan Vecera if (rc) 104*5bc02b19SIvan Vecera return rc; 105*5bc02b19SIvan Vecera rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_MULT, &ref->freq_mult); 106*5bc02b19SIvan Vecera if (rc) 107*5bc02b19SIvan Vecera return rc; 108*5bc02b19SIvan Vecera rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_M, &ref->freq_ratio_m); 109*5bc02b19SIvan Vecera if (rc) 110*5bc02b19SIvan Vecera return rc; 111*5bc02b19SIvan Vecera rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_N, &ref->freq_ratio_n); 112*5bc02b19SIvan Vecera if (rc) 113*5bc02b19SIvan Vecera return rc; 114*5bc02b19SIvan Vecera 115*5bc02b19SIvan Vecera /* Read eSync and N-div rated registers */ 116*5bc02b19SIvan Vecera rc = zl3073x_read_u32(zldev, ZL_REG_REF_ESYNC_DIV, &ref->esync_n_div); 117*5bc02b19SIvan Vecera if (rc) 118*5bc02b19SIvan Vecera return rc; 119*5bc02b19SIvan Vecera rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref->sync_ctrl); 120*5bc02b19SIvan Vecera if (rc) 121*5bc02b19SIvan Vecera return rc; 122*5bc02b19SIvan Vecera 123*5bc02b19SIvan Vecera /* Read phase compensation register */ 124*5bc02b19SIvan Vecera rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, 125*5bc02b19SIvan Vecera &ref->phase_comp); 126*5bc02b19SIvan Vecera if (rc) 127*5bc02b19SIvan Vecera return rc; 128*5bc02b19SIvan Vecera 129607f2c00SIvan Vecera dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index, 130607f2c00SIvan Vecera str_enabled_disabled(zl3073x_ref_is_enabled(ref)), 131607f2c00SIvan Vecera zl3073x_ref_is_diff(ref) ? "differential" : "single-ended"); 132607f2c00SIvan Vecera 133607f2c00SIvan Vecera return rc; 134607f2c00SIvan Vecera } 135607f2c00SIvan Vecera 136607f2c00SIvan Vecera /** 137607f2c00SIvan Vecera * zl3073x_ref_state_get - get current input reference state 138607f2c00SIvan Vecera * @zldev: pointer to zl3073x_dev structure 139607f2c00SIvan Vecera * @index: input reference index to get state for 140607f2c00SIvan Vecera * 141607f2c00SIvan Vecera * Return: pointer to given input reference state 142607f2c00SIvan Vecera */ 143607f2c00SIvan Vecera const struct zl3073x_ref * 144607f2c00SIvan Vecera zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index) 145607f2c00SIvan Vecera { 146607f2c00SIvan Vecera return &zldev->ref[index]; 147607f2c00SIvan Vecera } 148*5bc02b19SIvan Vecera 149*5bc02b19SIvan Vecera int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, 150*5bc02b19SIvan Vecera const struct zl3073x_ref *ref) 151*5bc02b19SIvan Vecera { 152*5bc02b19SIvan Vecera struct zl3073x_ref *dref = &zldev->ref[index]; 153*5bc02b19SIvan Vecera int rc; 154*5bc02b19SIvan Vecera 155*5bc02b19SIvan Vecera guard(mutex)(&zldev->multiop_lock); 156*5bc02b19SIvan Vecera 157*5bc02b19SIvan Vecera /* Read reference configuration into mailbox */ 158*5bc02b19SIvan Vecera rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 159*5bc02b19SIvan Vecera ZL_REG_REF_MB_MASK, BIT(index)); 160*5bc02b19SIvan Vecera if (rc) 161*5bc02b19SIvan Vecera return rc; 162*5bc02b19SIvan Vecera 163*5bc02b19SIvan Vecera /* Update mailbox with changed values */ 164*5bc02b19SIvan Vecera if (dref->freq_base != ref->freq_base) 165*5bc02b19SIvan Vecera rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_BASE, 166*5bc02b19SIvan Vecera ref->freq_base); 167*5bc02b19SIvan Vecera if (!rc && dref->freq_mult != ref->freq_mult) 168*5bc02b19SIvan Vecera rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_MULT, 169*5bc02b19SIvan Vecera ref->freq_mult); 170*5bc02b19SIvan Vecera if (!rc && dref->freq_ratio_m != ref->freq_ratio_m) 171*5bc02b19SIvan Vecera rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_M, 172*5bc02b19SIvan Vecera ref->freq_ratio_m); 173*5bc02b19SIvan Vecera if (!rc && dref->freq_ratio_n != ref->freq_ratio_n) 174*5bc02b19SIvan Vecera rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_N, 175*5bc02b19SIvan Vecera ref->freq_ratio_n); 176*5bc02b19SIvan Vecera if (!rc && dref->esync_n_div != ref->esync_n_div) 177*5bc02b19SIvan Vecera rc = zl3073x_write_u32(zldev, ZL_REG_REF_ESYNC_DIV, 178*5bc02b19SIvan Vecera ref->esync_n_div); 179*5bc02b19SIvan Vecera if (!rc && dref->sync_ctrl != ref->sync_ctrl) 180*5bc02b19SIvan Vecera rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL, 181*5bc02b19SIvan Vecera ref->sync_ctrl); 182*5bc02b19SIvan Vecera if (!rc && dref->phase_comp != ref->phase_comp) 183*5bc02b19SIvan Vecera rc = zl3073x_write_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, 184*5bc02b19SIvan Vecera ref->phase_comp); 185*5bc02b19SIvan Vecera if (rc) 186*5bc02b19SIvan Vecera return rc; 187*5bc02b19SIvan Vecera 188*5bc02b19SIvan Vecera /* Commit reference configuration */ 189*5bc02b19SIvan Vecera rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR, 190*5bc02b19SIvan Vecera ZL_REG_REF_MB_MASK, BIT(index)); 191*5bc02b19SIvan Vecera if (rc) 192*5bc02b19SIvan Vecera return rc; 193*5bc02b19SIvan Vecera 194*5bc02b19SIvan Vecera /* After successful commit store new state */ 195*5bc02b19SIvan Vecera dref->freq_base = ref->freq_base; 196*5bc02b19SIvan Vecera dref->freq_mult = ref->freq_mult; 197*5bc02b19SIvan Vecera dref->freq_ratio_m = ref->freq_ratio_m; 198*5bc02b19SIvan Vecera dref->freq_ratio_n = ref->freq_ratio_n; 199*5bc02b19SIvan Vecera dref->esync_n_div = ref->esync_n_div; 200*5bc02b19SIvan Vecera dref->sync_ctrl = ref->sync_ctrl; 201*5bc02b19SIvan Vecera dref->phase_comp = ref->phase_comp; 202*5bc02b19SIvan Vecera 203*5bc02b19SIvan Vecera return 0; 204*5bc02b19SIvan Vecera } 205