Commit 8857df3aceb7a8eb7558059b7da109e41dd1fb95

Authored by Michael Hennerich
Committed by Jonathan Cameron
1 parent dfffd0d65f

iio: frequency: ADF4350: Fix potential reference div factor overflow.

With small channel spacing values and high reference frequencies it is
possible to exceed the range of the 10-bit counter.
Workaround by checking the range and widening some constrains.

We don't use the REG1_PHASE value in this case the datasheet recommends to set
it to 1 if not used.

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>

Showing 2 changed files with 17 additions and 9 deletions Side-by-side Diff

drivers/iio/frequency/adf4350.c
... ... @@ -129,7 +129,7 @@
129 129 {
130 130 struct adf4350_platform_data *pdata = st->pdata;
131 131 u64 tmp;
132   - u32 div_gcd, prescaler;
  132 + u32 div_gcd, prescaler, chspc;
133 133 u16 mdiv, r_cnt = 0;
134 134 u8 band_sel_div;
135 135  
136 136  
137 137  
... ... @@ -158,15 +158,21 @@
158 158 if (pdata->ref_div_factor)
159 159 r_cnt = pdata->ref_div_factor - 1;
160 160  
  161 + chspc = st->chspc;
  162 +
161 163 do {
162   - r_cnt = adf4350_tune_r_cnt(st, r_cnt);
  164 + do {
  165 + do {
  166 + r_cnt = adf4350_tune_r_cnt(st, r_cnt);
  167 + st->r1_mod = st->fpfd / chspc;
  168 + if (r_cnt > ADF4350_MAX_R_CNT) {
  169 + /* try higher spacing values */
  170 + chspc++;
  171 + r_cnt = 0;
  172 + }
  173 + } while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt);
  174 + } while (r_cnt == 0);
163 175  
164   - st->r1_mod = st->fpfd / st->chspc;
165   - while (st->r1_mod > ADF4350_MAX_MODULUS) {
166   - r_cnt = adf4350_tune_r_cnt(st, r_cnt);
167   - st->r1_mod = st->fpfd / st->chspc;
168   - }
169   -
170 176 tmp = freq * (u64)st->r1_mod + (st->fpfd > 1);
171 177 do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */
172 178 st->r0_fract = do_div(tmp, st->r1_mod);
... ... @@ -194,7 +200,7 @@
194 200 st->regs[ADF4350_REG0] = ADF4350_REG0_INT(st->r0_int) |
195 201 ADF4350_REG0_FRACT(st->r0_fract);
196 202  
197   - st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(0) |
  203 + st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(1) |
198 204 ADF4350_REG1_MOD(st->r1_mod) |
199 205 prescaler;
200 206  
include/linux/iio/frequency/adf4350.h
... ... @@ -87,6 +87,8 @@
87 87 #define ADF4350_MAX_BANDSEL_CLK 125000 /* Hz */
88 88 #define ADF4350_MAX_FREQ_REFIN 250000000 /* Hz */
89 89 #define ADF4350_MAX_MODULUS 4095
  90 +#define ADF4350_MAX_R_CNT 1023
  91 +
90 92  
91 93 /**
92 94 * struct adf4350_platform_data - platform specific information