1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/bitfield.h> 4 #include <linux/cleanup.h> 5 #include <linux/dev_printk.h> 6 #include <linux/string.h> 7 #include <linux/string_choices.h> 8 #include <linux/types.h> 9 10 #include "core.h" 11 #include "ref.h" 12 13 /** 14 * zl3073x_ref_freq_factorize - factorize given frequency 15 * @freq: input frequency 16 * @base: base frequency 17 * @mult: multiplier 18 * 19 * Checks if the given frequency can be factorized using one of the 20 * supported base frequencies. If so the base frequency and multiplier 21 * are stored into appropriate parameters if they are not NULL. 22 * 23 * Return: 0 on success, -EINVAL if the frequency cannot be factorized 24 */ 25 int 26 zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult) 27 { 28 static const u16 base_freqs[] = { 29 1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125, 30 128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000, 31 1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250, 32 6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250, 33 32000, 40000, 50000, 62500, 34 }; 35 u32 div; 36 int i; 37 38 for (i = 0; i < ARRAY_SIZE(base_freqs); i++) { 39 div = freq / base_freqs[i]; 40 41 if (div <= U16_MAX && (freq % base_freqs[i]) == 0) { 42 if (base) 43 *base = base_freqs[i]; 44 if (mult) 45 *mult = div; 46 47 return 0; 48 } 49 } 50 51 return -EINVAL; 52 } 53 54 /** 55 * zl3073x_ref_state_update - update input reference status from HW 56 * @zldev: pointer to zl3073x_dev structure 57 * @index: input reference index 58 * 59 * Return: 0 on success, <0 on error 60 */ 61 int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index) 62 { 63 struct zl3073x_ref *ref = &zldev->ref[index]; 64 65 return zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(index), 66 &ref->mon_status); 67 } 68 69 /** 70 * zl3073x_ref_state_fetch - fetch input reference state from hardware 71 * @zldev: pointer to zl3073x_dev structure 72 * @index: input reference index to fetch state for 73 * 74 * Function fetches state for the given input reference from hardware and 75 * stores it for later use. 76 * 77 * Return: 0 on success, <0 on error 78 */ 79 int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) 80 { 81 struct zl3073x_ref *ref = &zldev->ref[index]; 82 int rc; 83 84 /* For differential type inputs the N-pin reference shares 85 * part of the configuration with the P-pin counterpart. 86 */ 87 if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(ref - 1)) { 88 struct zl3073x_ref *p_ref = ref - 1; /* P-pin counterpart*/ 89 90 /* Copy the shared items from the P-pin */ 91 ref->cfg = p_ref->cfg; 92 ref->inv = p_ref->inv; 93 94 return 0; /* Finish - no non-shared items for now */ 95 } 96 97 /* Read reference status */ 98 rc = zl3073x_ref_state_update(zldev, index); 99 if (rc) 100 return rc; 101 102 guard(mutex)(&zldev->multiop_lock); 103 104 /* Read reference configuration */ 105 rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 106 ZL_REG_REF_MB_MASK, BIT(index)); 107 if (rc) 108 return rc; 109 110 /* Read ref_config register */ 111 rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config); 112 if (rc) 113 return rc; 114 115 /* Read frequency related registers */ 116 rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_BASE, &ref->freq_base); 117 if (rc) 118 return rc; 119 rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_MULT, &ref->freq_mult); 120 if (rc) 121 return rc; 122 rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_M, &ref->freq_ratio_m); 123 if (rc) 124 return rc; 125 rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_N, &ref->freq_ratio_n); 126 if (rc) 127 return rc; 128 129 /* Read eSync and N-div rated registers */ 130 rc = zl3073x_read_u32(zldev, ZL_REG_REF_ESYNC_DIV, &ref->esync_n_div); 131 if (rc) 132 return rc; 133 rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref->sync_ctrl); 134 if (rc) 135 return rc; 136 137 /* Read phase compensation register */ 138 if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) { 139 u32 val; 140 141 rc = zl3073x_read_u32(zldev, ZL_REG_REF_PHASE_OFFSET_COMP_32, 142 &val); 143 ref->phase_comp = val; 144 } else { 145 rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, 146 &ref->phase_comp); 147 } 148 if (rc) 149 return rc; 150 151 dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index, 152 str_enabled_disabled(zl3073x_ref_is_enabled(ref)), 153 zl3073x_ref_is_diff(ref) ? "differential" : "single-ended"); 154 155 return rc; 156 } 157 158 /** 159 * zl3073x_ref_state_get - get current input reference state 160 * @zldev: pointer to zl3073x_dev structure 161 * @index: input reference index to get state for 162 * 163 * Return: pointer to given input reference state 164 */ 165 const struct zl3073x_ref * 166 zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index) 167 { 168 return &zldev->ref[index]; 169 } 170 171 /** 172 * zl3073x_ref_state_set - commit input reference state changes to hardware 173 * @zldev: pointer to zl3073x_dev structure 174 * @index: input reference index to set state for 175 * @ref: desired reference state 176 * 177 * Validates that invariant fields have not been modified, skips the HW 178 * write if the mutable configuration is unchanged, and otherwise writes 179 * only the changed cfg fields to hardware via the mailbox interface. 180 * 181 * Return: 0 on success, -EINVAL if invariants changed, <0 on HW error 182 */ 183 int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, 184 const struct zl3073x_ref *ref) 185 { 186 struct zl3073x_ref *dref = &zldev->ref[index]; 187 int rc; 188 189 /* Reject attempts to change invariant fields (set at init only) */ 190 if (WARN_ON(memcmp(&dref->inv, &ref->inv, sizeof(ref->inv)))) 191 return -EINVAL; 192 193 /* Skip HW write if configuration hasn't changed */ 194 if (!memcmp(&dref->cfg, &ref->cfg, sizeof(ref->cfg))) 195 return 0; 196 197 guard(mutex)(&zldev->multiop_lock); 198 199 /* Read reference configuration into mailbox */ 200 rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 201 ZL_REG_REF_MB_MASK, BIT(index)); 202 if (rc) 203 return rc; 204 205 /* Update mailbox with changed values */ 206 if (dref->freq_base != ref->freq_base) 207 rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_BASE, 208 ref->freq_base); 209 if (!rc && dref->freq_mult != ref->freq_mult) 210 rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_MULT, 211 ref->freq_mult); 212 if (!rc && dref->freq_ratio_m != ref->freq_ratio_m) 213 rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_M, 214 ref->freq_ratio_m); 215 if (!rc && dref->freq_ratio_n != ref->freq_ratio_n) 216 rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_N, 217 ref->freq_ratio_n); 218 if (!rc && dref->esync_n_div != ref->esync_n_div) 219 rc = zl3073x_write_u32(zldev, ZL_REG_REF_ESYNC_DIV, 220 ref->esync_n_div); 221 if (!rc && dref->sync_ctrl != ref->sync_ctrl) 222 rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL, 223 ref->sync_ctrl); 224 if (!rc && dref->phase_comp != ref->phase_comp) { 225 if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) 226 rc = zl3073x_write_u32(zldev, 227 ZL_REG_REF_PHASE_OFFSET_COMP_32, 228 ref->phase_comp); 229 else 230 rc = zl3073x_write_u48(zldev, 231 ZL_REG_REF_PHASE_OFFSET_COMP, 232 ref->phase_comp); 233 } 234 if (rc) 235 return rc; 236 237 /* Commit reference configuration */ 238 rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR, 239 ZL_REG_REF_MB_MASK, BIT(index)); 240 if (rc) 241 return rc; 242 243 /* After successful commit store new state */ 244 dref->cfg = ref->cfg; 245 246 return 0; 247 } 248