Skip to content

Commit da757b6

Browse files
committed
feat(hal): Add preliminary support for LEDC
Signed-off-by: Hanrui Li <[email protected]>
1 parent 8c39a2f commit da757b6

File tree

3 files changed

+229
-0
lines changed

3 files changed

+229
-0
lines changed

allwinner-hal/src/ledc/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//! LED control (LEDC) peripheral.
2+
3+
pub mod register;

allwinner-hal/src/ledc/register.rs

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
use volatile_register::RW;
2+
3+
/// LEDC Controller registers.
4+
#[repr(C)]
5+
pub struct RegisterBlock {
6+
/// LEDC Control Register.
7+
pub ledc_control: RW<LedcControl>,
8+
}
9+
10+
/// LEDC RGB mode.
11+
///
12+
/// By default, the software configures data to LEDC according to
13+
/// GRB (MSB) mode, the LEDC internal combines data to output to
14+
/// the external LED.
15+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16+
#[repr(u32)]
17+
pub enum RgbMode {
18+
GRB = 0b000,
19+
GBR = 0b001,
20+
RGB = 0b010,
21+
RBG = 0b011,
22+
BGR = 0b100,
23+
BRG = 0b101,
24+
}
25+
26+
/// LEDC Control Register.
27+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
28+
#[repr(transparent)]
29+
pub struct LedcControl(u32);
30+
31+
impl LedcControl {
32+
/// That the bit is enabled indicates LEDC can be started when LEDC
33+
/// data finished transmission or LEDC_EN is cleared to 0 by
34+
/// hardware in LEDC_SOFT_RESET situation.
35+
const LED_EN: u32 = 1 << 0;
36+
/// Write 1 to clear it automatically.
37+
/// The ranges of LEDC soft reset include the following points: all
38+
/// internal status registers, the control state machine returns to in
39+
/// idle status, the LEDC FIFO read & write point is cleared to 0, the
40+
/// LEDC interrupt is cleared; and the affected registers are
41+
/// followed.
42+
const LED_SOFT_RST: u32 = 1 << 1;
43+
/// MSB control for Blue data.
44+
const LED_MSB_B: u32 = 1 << 2;
45+
/// MSB control for Red data.
46+
const LED_MSB_R: u32 = 1 << 3;
47+
/// MSB control for Green data.
48+
const LED_MSB_G: u32 = 1 << 4;
49+
/// Adjust sequence of the combined GRB data.
50+
const LED_MSB_TOP: u32 = 1 << 5;
51+
/// The software writes 1 to the bit, the CPU triggers LEDC to
52+
/// transfer a reset to LED.
53+
/// Only when LEDC is in IDLE status, the reset can be performed.
54+
/// After the reset finished, the control state machine returns to
55+
/// the IDLE status. To return LEDC to the IDLE status, it also needs
56+
/// to be used with SOFT_RESET.
57+
/// When the software sets the bit, the software can read the bit
58+
/// to check if the reset is complete.
59+
const RESET_LED_EN: u32 = 1 << 10;
60+
61+
/// LEDC is enabled.
62+
#[inline]
63+
pub const fn is_enabled(self) -> bool {
64+
(self.0 & Self::LED_EN) != 0
65+
}
66+
67+
/// Set or clear LEDC enable bit.
68+
#[inline]
69+
pub const fn set_enable(self, enable: bool) -> Self {
70+
if enable {
71+
Self(self.0 | Self::LED_EN)
72+
} else {
73+
Self(self.0 & !Self::LED_EN)
74+
}
75+
}
76+
77+
/// Get the red LEDC MSB control bit.
78+
#[inline]
79+
pub const fn is_red_msb(self) -> bool {
80+
(self.0 & Self::LED_MSB_R) != 0
81+
}
82+
/// Get the blue LEDC MSB control bit.
83+
#[inline]
84+
pub const fn is_blue_msb(self) -> bool {
85+
(self.0 & Self::LED_MSB_B) != 0
86+
}
87+
/// Get the green LEDC MSB control bit.
88+
#[inline]
89+
pub const fn is_green_msb(self) -> bool {
90+
(self.0 & Self::LED_MSB_G) != 0
91+
}
92+
93+
/// Set or clear the red LEDC MSB control bit.
94+
#[inline]
95+
pub const fn set_red_msb(self, msb: bool) -> Self {
96+
let mut value = self.0;
97+
if msb {
98+
value |= Self::LED_MSB_R;
99+
} else {
100+
value &= !Self::LED_MSB_R;
101+
}
102+
Self(value)
103+
}
104+
/// Set or clear the blue LEDC MSB control bit.
105+
#[inline]
106+
pub const fn set_blue_msb(self, msb: bool) -> Self {
107+
let mut value = self.0;
108+
if msb {
109+
value |= Self::LED_MSB_B;
110+
} else {
111+
value &= !Self::LED_MSB_B;
112+
}
113+
Self(value)
114+
}
115+
/// Set or clear the green LEDC MSB control bit.
116+
#[inline]
117+
pub const fn set_green_msb(self, msb: bool) -> Self {
118+
let mut value = self.0;
119+
if msb {
120+
value |= Self::LED_MSB_G;
121+
} else {
122+
value &= !Self::LED_MSB_G;
123+
}
124+
Self(value)
125+
}
126+
127+
/// LEDC MSB_TOP control bit.
128+
#[inline]
129+
pub const fn is_msb_top(self) -> bool {
130+
(self.0 & Self::LED_MSB_TOP) != 0
131+
}
132+
/// Set or clear LEDC MSB_TOP control bit.
133+
#[inline]
134+
pub const fn set_msb_top(self, msb_top: bool) -> Self {
135+
let mut value = self.0;
136+
if msb_top {
137+
value |= Self::LED_MSB_TOP;
138+
} else {
139+
value &= !Self::LED_MSB_TOP;
140+
}
141+
Self(value)
142+
}
143+
144+
/// Reset LED Enable bit status.
145+
#[inline]
146+
pub const fn set_reset_led_enable(self) -> Self {
147+
Self(self.0 | Self::RESET_LED_EN)
148+
}
149+
/// Check whether reset is done.
150+
#[inline]
151+
pub const fn is_reset_done(self) -> bool {
152+
(self.0 & Self::RESET_LED_EN) == 0
153+
}
154+
155+
/// RGB mode selection.
156+
#[inline]
157+
pub const fn rgb_mode(self) -> RgbMode {
158+
let raw_mode = self.0 >> 6 & 0b111;
159+
match raw_mode {
160+
0b000 => RgbMode::GRB,
161+
0b001 => RgbMode::GBR,
162+
0b010 => RgbMode::RGB,
163+
0b011 => RgbMode::RBG,
164+
0b100 => RgbMode::BGR,
165+
0b101 => RgbMode::BRG,
166+
_ => unreachable!(),
167+
}
168+
}
169+
170+
/// Set RGB mode.
171+
#[inline]
172+
pub const fn set_rgb_mode(self, mode: RgbMode) -> Self {
173+
// RGB mode is in bits [8:6].
174+
let mut value = self.0;
175+
value &= !(0b111 << 6);
176+
value |= (mode as u32) << 6;
177+
Self(value)
178+
}
179+
180+
/// LEDC soft reset status.
181+
#[inline]
182+
pub const fn soft_reset(self) -> bool {
183+
(self.0 & Self::LED_SOFT_RST) != 0
184+
}
185+
186+
/// Clear LEDC soft reset.
187+
#[inline]
188+
pub const fn clear_soft_reset(self) -> Self {
189+
// Write 1 to clear it.
190+
Self(self.0 | Self::LED_SOFT_RST)
191+
}
192+
193+
/// Total length of transfer data.
194+
#[inline]
195+
pub const fn total_data_length(self) -> u32 {
196+
(self.0 >> 16) & 0xFFF
197+
}
198+
199+
/// Set total length of transfer data.
200+
#[inline]
201+
pub const fn set_total_data_length(self, length: u32) -> Self {
202+
let mut value = self.0;
203+
value &= !(0xFFF << 16);
204+
value |= (length & 0xFFF) << 16;
205+
Self(value)
206+
}
207+
}
208+
209+
#[cfg(test)]
210+
mod tests {
211+
#[test]
212+
fn test_ledc_control_default_value() {
213+
use super::{LedcControl, RgbMode};
214+
215+
let reg = LedcControl(0x0000_003C);
216+
assert!(!reg.is_enabled());
217+
assert!(!reg.soft_reset());
218+
assert!(reg.is_blue_msb());
219+
assert!(reg.is_red_msb());
220+
assert!(reg.is_green_msb());
221+
assert!(reg.is_msb_top());
222+
assert_eq!(reg.rgb_mode(), RgbMode::GRB);
223+
assert_eq!(reg.total_data_length(), 0);
224+
}
225+
}

allwinner-hal/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod com;
1313
#[macro_use]
1414
pub mod gpio;
1515
pub mod dma;
16+
pub mod ledc;
1617
pub mod phy;
1718
pub mod smhc;
1819
pub mod spi;

0 commit comments

Comments
 (0)