Commit 8857df3aceb7a8eb7558059b7da109e41dd1fb95
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