is31fl3743b_driver/
registers.rs

1#![allow(missing_docs)]
2use bilge::prelude::*;
3
4/// Command byte.
5#[bitsize(8)]
6#[derive(DebugBits, FromBits, PartialEq, Clone, Copy)]
7pub(crate) struct Command {
8    /// Page number of the register this command will operate on.
9    pub page: PageNumber,
10
11    /// The chip ID (always 0b101).
12    id: u3,
13
14    /// The type of command this is (read or write).
15    pub rw: CommandType,
16}
17
18impl Default for Command {
19    fn default() -> Self {
20        Self::from(0b0101_0000)
21    }
22}
23
24impl Command {
25    /// Set page number.
26    #[must_use]
27    pub fn with_page(mut self, page: PageNumber) -> Self {
28        self.set_page(page);
29        Self::from(self.value)
30    }
31
32    /// Set R/W command type.
33    #[must_use]
34    pub fn with_rw(mut self, rw: CommandType) -> Self {
35        self.set_rw(rw);
36        Self::from(self.value)
37    }
38}
39
40/// Page number.
41#[bitsize(4)]
42#[derive(Debug, FromBits, PartialEq, PartialOrd)]
43pub(crate) enum PageNumber {
44    /// Page 0.
45    #[fallback]
46    Pg0,
47
48    /// Page 1.
49    Pg1,
50
51    /// Page 2.
52    Pg2,
53}
54
55/// Command type.
56#[bitsize(1)]
57#[derive(Debug, FromBits, PartialEq, PartialOrd)]
58pub(crate) enum CommandType {
59    /// Write command.
60    Write,
61
62    /// Read command.
63    Read,
64}
65
66/// Register addresses
67#[derive(Debug, PartialEq, PartialOrd)]
68pub(crate) enum Register {
69    /// PWM modulation for each LED.
70    Pwm,
71
72    /// Peak current scaling for each LED (as fraction of global current).
73    Scaling,
74
75    /// Operation mode configuration.
76    Configuration,
77
78    /// Global current scaling (as fraction of max current).
79    GlobalCurrentControl,
80
81    /// Set the pull-down resistor for switching columns
82    /// and pull-up resistor for current sink rows.
83    ///
84    /// Also contains setting for phase delay.
85    PullDownUpResistorSelection,
86
87    /// Contains the open information (after performing open test)
88    /// or short information (after performing short test).
89    Open,
90
91    /// Temperature set point and thermal roll-off configuration.
92    TemperatureStatus,
93
94    /// Spread spectrum and sync configuration.
95    SpreadSpectrum,
96
97    /// Performs register reset when written with 0xAE.
98    Reset,
99}
100
101impl Register {
102    /// Returns the page number the register belongs to.
103    pub fn page(&self) -> PageNumber {
104        match *self {
105            Self::Pwm => PageNumber::Pg0,
106            Self::Scaling => PageNumber::Pg1,
107            _ => PageNumber::Pg2,
108        }
109    }
110}
111
112impl From<Register> for u8 {
113    fn from(reg: Register) -> Self {
114        match reg {
115            Register::Configuration => 0x00,
116            Register::Pwm | Register::Scaling | Register::GlobalCurrentControl => 0x01,
117            Register::PullDownUpResistorSelection => 0x02,
118            Register::Open => 0x03,
119            Register::TemperatureStatus => 0x24,
120            Register::SpreadSpectrum => 0x25,
121            Register::Reset => 0x2F,
122        }
123    }
124}
125
126/// Configuration register.
127#[bitsize(8)]
128#[derive(DebugBits, FromBits, PartialEq, Clone, Copy)]
129pub struct Configuration {
130    /// Software shutdown control.
131    pub ssd: bool,
132
133    /// Open/short detection enable.
134    pub osde: Open,
135
136    reserved: u1,
137
138    /// `SWx` setting (controls duty cycle).
139    pub sws: SwxSetting,
140}
141
142impl Default for Configuration {
143    fn default() -> Self {
144        /* Datasheet inconsistently specifies the default as both:
145         *
146         * 0b0000_0000 and 0b0000_1000
147         *
148         * Since 0b0000_1000 is listed twice,
149         * and D3 is explicitly mentioned as must be configured as "1",
150         * go with this default.
151         */
152        Self::from(0b0000_1000)
153    }
154}
155
156impl Configuration {
157    /// Configure software shutdown control.
158    #[must_use]
159    pub fn with_ssd(mut self, ssd: bool) -> Self {
160        self.set_ssd(ssd);
161        Self::from(self.value)
162    }
163
164    /// Configure open/short detection.
165    #[must_use]
166    pub fn with_osde(mut self, osde: Open) -> Self {
167        self.set_osde(osde);
168        Self::from(self.value)
169    }
170
171    /// Configure `SWx` setting.
172    #[must_use]
173    pub fn with_sws(mut self, sws: SwxSetting) -> Self {
174        self.set_sws(sws);
175        Self::from(self.value)
176    }
177}
178
179/// Open/short detection enable.
180#[bitsize(2)]
181#[derive(Debug, FromBits, PartialEq, PartialOrd)]
182pub enum Open {
183    /// Disable Open/short detection.
184    #[fallback]
185    Disabled,
186
187    /// Enable open detection.
188    EnableOpen,
189
190    /// Enable short detection.
191    EnableShort,
192}
193
194/// `SWx` setting.
195#[bitsize(4)]
196#[derive(Debug, FromBits, PartialEq, PartialOrd)]
197pub enum SwxSetting {
198    /// SW1-SW11 active, 1/11.
199    #[fallback]
200    Sw11,
201
202    /// SW1-SW10 active, 1/10.
203    Sw10,
204
205    /// SW1-SW9 active, 1/9.
206    Sw9,
207
208    /// SW1-SW8 active, 1/8.
209    Sw8,
210
211    /// SW1-SW7 active, 1/7.
212    Sw7,
213
214    /// SW1-SW6 active, 1/6.
215    Sw6,
216
217    /// SW1-SW5 active, 1/5.
218    Sw5,
219
220    /// SW1-SW4 active, 1/4.
221    Sw4,
222
223    /// SW1-SW3 active, 1/3.
224    Sw3,
225
226    /// SW1-SW2 active, 1/2.
227    Sw2,
228
229    /// No scan, current sink only.
230    None,
231}
232
233/// Global current control register.
234#[bitsize(8)]
235#[derive(DebugBits, FromBits, PartialEq, Clone, Copy)]
236pub struct GlobalCurrentControl(u8);
237impl Default for GlobalCurrentControl {
238    fn default() -> Self {
239        Self::from(0b0000_0000)
240    }
241}
242
243/// Pull-up/down resistor selection register.
244#[bitsize(8)]
245#[derive(DebugBits, FromBits, PartialEq, Clone, Copy)]
246pub struct PullDownUpResistorSelection {
247    /// `CSy` pull-up resistor selection.
248    pub cspur: Resistor,
249
250    reserved: u1,
251
252    /// `SWx` pull-down resistor selection.
253    pub swpdr: Resistor,
254
255    /// Configure 180 degree phase delay enable.
256    pub phc: bool,
257}
258
259impl Default for PullDownUpResistorSelection {
260    fn default() -> Self {
261        Self::from(0b0011_0011)
262    }
263}
264
265impl PullDownUpResistorSelection {
266    /// Configure `CSy` pull-up resistor.
267    #[must_use]
268    pub fn with_cspur(mut self, cspur: Resistor) -> Self {
269        self.set_cspur(cspur);
270        Self::from(self.value)
271    }
272
273    /// Configure `SWx` pull-down resistor.
274    #[must_use]
275    pub fn with_swpdr(mut self, swpdr: Resistor) -> Self {
276        self.set_swpdr(swpdr);
277        Self::from(self.value)
278    }
279
280    /// Configure 180 degree phase delay.
281    #[must_use]
282    pub fn with_phc(mut self, phc: bool) -> Self {
283        self.set_phc(phc);
284        Self::from(self.value)
285    }
286}
287
288/// Resistor setting (value in Ohms).
289#[bitsize(3)]
290#[derive(Debug, FromBits, PartialEq, PartialOrd)]
291pub enum Resistor {
292    /// No pull-up/down resistor.
293    None,
294
295    /// 0.5k pull-up/down, only in off time.
296    R0_5kOffOnly,
297
298    /// 1.0k pull-up/down, only in off time.
299    R1_0kOffOnly,
300
301    /// 2.0k pull-up/down, only in off time.
302    R2_0kOffOnly,
303
304    /// 1.0k pull-up/down, all the time.
305    R1_0k,
306
307    /// 2.0k pull-up/down, all the time.
308    R2_0k,
309
310    /// 4.0k pull-up/down, all the time.
311    R4_0k,
312
313    /// 8.0k pull-up/down, all the time.
314    R8_0k,
315}
316
317/// Temperature status register.
318#[bitsize(8)]
319#[derive(DebugBits, FromBits, PartialEq, Clone, Copy)]
320pub struct TemperatureStatus {
321    /// Thermal roll-off setting.
322    pub trof: ThermalRollOff,
323
324    /// Temperature point setting.
325    pub ts: TemperaturePoint,
326
327    reserved: u4,
328}
329
330impl Default for TemperatureStatus {
331    fn default() -> Self {
332        Self::from(0b0000_0000)
333    }
334}
335
336impl TemperatureStatus {
337    /// Configure thermal roll-off.
338    #[must_use]
339    pub fn with_trof(mut self, trof: ThermalRollOff) -> Self {
340        self.set_trof(trof);
341        Self::from(self.value)
342    }
343
344    /// Configure temperature point.
345    #[must_use]
346    pub fn with_ts(mut self, ts: TemperaturePoint) -> Self {
347        self.set_ts(ts);
348        Self::from(self.value)
349    }
350}
351
352/// Thermal roll-off setting.
353#[bitsize(2)]
354#[derive(Debug, FromBits, PartialEq, PartialOrd)]
355pub enum ThermalRollOff {
356    /// 100% of output current.
357    P100,
358
359    /// 75% of output current.
360    P75,
361
362    /// 55% of output current.
363    P55,
364
365    /// 30% of output current.
366    P30,
367}
368
369/// Temperature point setting.
370#[bitsize(2)]
371#[derive(Debug, FromBits, PartialEq, PartialOrd)]
372pub enum TemperaturePoint {
373    /// 140 degrees Celsius thermal roll-off start point.
374    D140,
375
376    /// 120 degrees Celsius thermal roll-off start point.
377    D120,
378
379    /// 100 degrees Celsius thermal roll-off start point.
380    D100,
381
382    /// 90 degrees Celsius thermal roll-off start point.
383    D90,
384}
385
386/// Spread spectrum register.
387#[bitsize(8)]
388#[derive(DebugBits, FromBits, PartialEq, Clone, Copy)]
389pub struct SpreadSpectrum {
390    /// Spread spectrum cycle time.
391    pub clt: CycleTime,
392
393    /// Spread spectrum range.
394    pub rng: Range,
395
396    /// Spread spectrum enable.
397    pub ssp: bool,
398
399    reserved: u1,
400
401    /// Sync configure.
402    pub sync: Sync,
403}
404
405impl Default for SpreadSpectrum {
406    fn default() -> Self {
407        Self::from(0b0000_0000)
408    }
409}
410
411impl SpreadSpectrum {
412    /// Configure spread spectrum cycle time.
413    #[must_use]
414    pub fn with_clt(mut self, clt: CycleTime) -> Self {
415        self.set_clt(clt);
416        Self::from(self.value)
417    }
418
419    /// Configure spread spectrum range.
420    #[must_use]
421    pub fn with_rng(mut self, rng: Range) -> Self {
422        self.set_rng(rng);
423        Self::from(self.value)
424    }
425
426    /// Configure spread spectrum enable.
427    #[must_use]
428    pub fn with_ssp(mut self, ssp: bool) -> Self {
429        self.set_ssp(ssp);
430        Self::from(self.value)
431    }
432
433    /// Configure sync enable.
434    #[must_use]
435    pub fn with_sync(mut self, sync: Sync) -> Self {
436        self.set_sync(sync);
437        Self::from(self.value)
438    }
439}
440
441/// Spread spectrum cycle time setting.
442#[bitsize(2)]
443#[derive(Debug, FromBits, PartialEq, PartialOrd)]
444pub enum CycleTime {
445    /// 1980 microseconds.
446    U1980,
447
448    /// 1200 microseconds.
449    U1200,
450
451    /// 820 microseconds.
452    U820,
453
454    /// 660 microseconds.
455    U660,
456}
457
458/// Spread spectrum range setting.
459#[bitsize(2)]
460#[derive(Debug, FromBits, PartialEq, PartialOrd)]
461pub enum Range {
462    /// +/- 5% range.
463    P5,
464
465    /// +/- 15% range.
466    P15,
467
468    /// +/- 24% range.
469    P24,
470
471    /// +/- 34% range.
472    P34,
473}
474
475/// Sync setting.
476#[bitsize(2)]
477#[derive(Debug, FromBits, PartialEq, PartialOrd)]
478pub enum Sync {
479    /// Disabled, 30k pull-down resistor.
480    #[fallback]
481    Disabled,
482
483    /// Slave mode, clock input.
484    Slave = 0b10,
485
486    /// Master mode, clock output.
487    Master,
488}
489
490#[cfg(test)]
491mod tests {
492    use super::*;
493
494    #[test]
495    fn default_command() {
496        let cmd = Command::default();
497        assert_eq!(cmd.value, 0x50);
498    }
499
500    #[test]
501    fn modify_page() {
502        let cmd = Command::default().with_page(PageNumber::Pg1);
503        assert_eq!(cmd.value, 0x51);
504    }
505
506    #[test]
507    fn modify_rw() {
508        let cmd = Command::default().with_rw(CommandType::Write);
509        assert_eq!(cmd.value, 0x50);
510    }
511
512    #[test]
513    fn default_configuration() {
514        let cfg = Configuration::default();
515        assert_eq!(cfg.value, 0x8);
516    }
517
518    #[test]
519    fn modify_ssd() {
520        let cfg = Configuration::default().with_ssd(true);
521        assert_eq!(cfg.value, 0x9);
522    }
523
524    #[test]
525    fn modify_osde() {
526        let cfg = Configuration::default().with_osde(Open::EnableShort);
527        assert_eq!(cfg.value, 0xC);
528    }
529
530    #[test]
531    fn modify_sws() {
532        let cfg = Configuration::default().with_sws(SwxSetting::Sw5);
533        assert_eq!(cfg.value, 0x68);
534    }
535
536    #[test]
537    fn default_pur_pdr() {
538        let pur_pdr = PullDownUpResistorSelection::default();
539        assert_eq!(pur_pdr.value, 0x33);
540    }
541
542    #[test]
543    fn modify_cspur() {
544        let pur_pdr = PullDownUpResistorSelection::default().with_cspur(Resistor::R2_0k);
545        assert_eq!(pur_pdr.value, 0x35);
546    }
547
548    #[test]
549    fn modify_swpdr() {
550        let pur_pdr = PullDownUpResistorSelection::default().with_swpdr(Resistor::R8_0k);
551        assert_eq!(pur_pdr.value, 0x73);
552    }
553
554    #[test]
555    fn default_temperature() {
556        let temperature = TemperatureStatus::default();
557        assert_eq!(temperature.value, 0x0);
558    }
559
560    #[test]
561    fn modify_trof() {
562        let temperature = TemperatureStatus::default().with_trof(ThermalRollOff::P55);
563        assert_eq!(temperature.value, 0x2);
564    }
565
566    #[test]
567    fn modify_ts() {
568        let temperature = TemperatureStatus::default().with_ts(TemperaturePoint::D120);
569        assert_eq!(temperature.value, 0x4);
570    }
571
572    #[test]
573    fn default_spread_spectrum() {
574        let spread_spectrum = SpreadSpectrum::default();
575        assert_eq!(spread_spectrum.value, 0x0);
576    }
577
578    #[test]
579    fn modify_clt() {
580        let spread_spectrum = SpreadSpectrum::default().with_clt(CycleTime::U660);
581        assert_eq!(spread_spectrum.value, 0x3);
582    }
583
584    #[test]
585    fn modify_rng() {
586        let spread_spectrum = SpreadSpectrum::default().with_rng(Range::P15);
587        assert_eq!(spread_spectrum.value, 0x4);
588    }
589
590    #[test]
591    fn modify_ssp() {
592        let spread_spectrum = SpreadSpectrum::default().with_ssp(true);
593        assert_eq!(spread_spectrum.value, 0x10);
594    }
595
596    #[test]
597    fn modify_sync() {
598        let spread_spectrum = SpreadSpectrum::default().with_sync(Sync::Master);
599        assert_eq!(spread_spectrum.value, 0xC0);
600    }
601}