1
//! Helpers for calculating fractional clock divider values.
2
//!
3
//! Several peripherals (LCD_CAM, I2S, ...) divide their source clock by `N + B/A`, where `B/A`
4
//! is a proper fraction whose numerator and denominator are limited to a few bits.
5

            
6
// Which parts of this module are used depends on the set of drivers supported by the target chip.
7
#![allow(dead_code)]
8

            
9
/// The largest denominator [`FractionalDivider::new`] can be asked for, so that comparing the
10
/// error of two candidates stays within a `u64`. Hardware fields are far narrower than this.
11
const MAX_DENOMINATOR: u32 = 1 << 16;
12

            
13
#[derive(Clone, Copy)]
14
pub(crate) struct Fraction {
15
    pub numerator: u32,
16
    pub denominator: u32,
17
}
18

            
19
/// A candidate fraction, paired with how far it sits from the target.
20
///
21
/// The distance is `|target - fraction|` scaled by `target.denominator * fraction.denominator`,
22
/// which is why comparing two candidates has to undo the differing denominators.
23
#[derive(Clone, Copy)]
24
struct Candidate {
25
    fraction: Fraction,
26
    error: u32,
27
}
28

            
29
impl Candidate {
30
    /// Returns whichever of `self` and `other` is closer to the target, preferring `self` on a
31
    /// tie.
32
    fn closer_of(self, other: Candidate) -> Candidate {
33
        // This is cheaper than it looks, both architectures implement
34
        // widening multiplication cheaply.
35
896
        if self.error as u64 * other.fraction.denominator as u64
36
896
            <= other.error as u64 * self.fraction.denominator as u64
37
        {
38
            self
39
        } else {
40
            other
41
        }
42
    }
43
}
44

            
45
/// Returns the fraction closest to `target` for each denominator from 1 to `max_denominator`,
46
/// stopping early if one of them represents `target` exactly.
47
///
48
/// A denominator only admits one closest numerator, so the closest fraction overall is whichever
49
/// of these is closest.
50
///
51
/// `target` must be between 0 and 1.
52
fn candidates(target: Fraction, max_denominator: u32) -> impl Iterator<Item = Candidate> {
53
    let Fraction {
54
        numerator: n,
55
        denominator: d,
56
    } = target;
57

            
58
    // `acc` tracks `denominator * n % d` and `whole` tracks `denominator * n / d`, so that no
59
    // division is needed per candidate. Stepping `acc` by `n` without overflowing means
60
    // subtracting the complement whenever it would wrap past `d` instead of adding to it.
61
50
    let complement = d - n;
62
    let mut acc = 0_u32;
63
    let mut whole = 0_u32;
64

            
65
    let mut denominator = 0;
66
    let mut exact = false;
67

            
68
    core::iter::from_fn(move || {
69
896
        if exact || denominator == max_denominator {
70
            return None;
71
        }
72
        denominator += 1;
73

            
74
896
        if acc >= complement {
75
146
            acc -= complement;
76
146
            whole += 1;
77
        } else {
78
750
            acc += n;
79
        }
80

            
81
        // A zero remainder means this denominator represents the target exactly, so no larger
82
        // one can do better.
83
        exact = acc == 0;
84

            
85
        // Round to nearest: `acc` is how far the target is above `whole`, `d - acc` how far it
86
        // is below the next integer. Either way that distance is the candidate's error.
87
896
        let below = d - acc;
88
896
        let (numerator, error) = if acc <= below {
89
            (whole, acc)
90
        } else {
91
398
            (whole + 1, below)
92
        };
93

            
94
        Some(Candidate {
95
            fraction: Fraction {
96
                numerator,
97
                denominator,
98
            },
99
            error,
100
        })
101
    })
102
}
103

            
104
/// A clock divider of the form `N + B/A`.
105
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
106
pub(crate) struct FractionalDivider {
107
    /// The integral part of the divider, `N`.
108
    pub integer: u32,
109

            
110
    /// The numerator of the fractional part, `B`. Zero if the divider is integral.
111
    pub numerator: u32,
112

            
113
    /// The denominator of the fractional part, `A`. Zero if the divider is integral.
114
    pub denominator: u32,
115
}
116

            
117
impl FractionalDivider {
118
    /// Calculates the divider that takes `source` closest to `target`.
119
    ///
120
    /// `max_denominator` is the largest value the hardware's `A` field can hold. Callers are
121
    /// responsible for checking [`Self::integer`] against the range of the hardware's `N`
122
    /// field: the divider is rounded up to the next integer when the fractional part cannot
123
    /// be represented, so the result may be one larger than `source / target`.
124
    ///
125
    /// `target` must not be 0, and `max_denominator` must be between 1 and
126
    /// [`MAX_DENOMINATOR`].
127
    pub(crate) fn new(source: u32, target: u32, max_denominator: u32) -> Self {
128
50
        debug_assert!(target != 0);
129
        debug_assert!((1..=MAX_DENOMINATOR).contains(&max_denominator));
130

            
131
50
        let integer = source / target;
132

            
133
        let remainder = Fraction {
134
50
            numerator: source % target,
135
            denominator: target,
136
        };
137
50
        if remainder.numerator == 0 {
138
            return Self::integral(integer);
139
        }
140

            
141
        // Dropping the remainder entirely is always an option, and is the yardstick the
142
        // candidates are measured against.
143
        let dropped = Candidate {
144
            fraction: Fraction {
145
                numerator: 0,
146
                denominator: 1,
147
            },
148
            error: remainder.numerator,
149
        };
150
        let closest = candidates(remainder, max_denominator)
151
            .fold(dropped, Candidate::closer_of)
152
            .fraction;
153

            
154
50
        if closest.numerator == closest.denominator {
155
            // The remainder rounds up to a whole step.
156
            Self::integral(integer + 1)
157
50
        } else if closest.numerator == 0 {
158
            // The remainder is too small to represent, so it rounds away.
159
            Self::integral(integer)
160
        } else {
161
            Self {
162
                integer,
163
                numerator: closest.numerator,
164
                denominator: closest.denominator,
165
            }
166
        }
167
    }
168

            
169
    const fn integral(integer: u32) -> Self {
170
        Self {
171
            integer,
172
            numerator: 0,
173
            denominator: 0,
174
        }
175
    }
176

            
177
    /// Returns the frequency this divider produces from `source`.
178
    pub(crate) fn output_frequency(&self, source: u32) -> u32 {
179
        if self.numerator == 0 || self.denominator == 0 {
180
            return source / self.integer;
181
        }
182

            
183
        // OUTPUT = SOURCE / (N + B/A) = (SOURCE * A) / (N * A + B)
184
        //
185
        // u64 is required to fit the numbers from this arithmetic.
186
        let source = source as u64;
187
        let n = self.integer as u64;
188
        let b = self.numerator as u64;
189
        let a = self.denominator as u64;
190

            
191
        ((source * a) / (n * a + b)) as u32
192
    }
193
}