1use crate::dma::{self, DmaChannel, DmaChannelClient};
8use crate::gpio::RPGpioPin;
9use crate::pio::{Pio, PioSmClient, SMNumber, StateMachineConfiguration};
10use kernel::hil::gpio::{self, Output as _};
11use kernel::hil::spi::{self, SpiMasterDevice};
12use kernel::utilities::cells::OptionalCell;
13use kernel::utilities::leasable_buffer::SubSliceMut;
14use kernel::ErrorCode;
15
16const PROG: [u16; 11] = [
18 0x6020, 0x6040, 0xe081, 0x6001, 0x1043, 0xe080, 0xa042, 0x5001, 0x0087, 0x20a0, 0xc000, ];
32
33pub struct PioGSpi<'a> {
35 pio: &'a Pio,
36 dma: DmaChannel<'a>,
37 clock_pin: u32,
38 dio_pin: u32,
39 cs_pin: &'a RPGpioPin<'a>,
40 sm_number: SMNumber,
41 write_buffer: OptionalCell<SubSliceMut<'static, u8>>,
42 read_buffer: OptionalCell<SubSliceMut<'static, u8>>,
43 client: OptionalCell<&'a dyn spi::SpiMasterClient>,
44 irq_client: OptionalCell<&'a dyn gpio::Client>,
45 pending: OptionalCell<Pending>,
46}
47
48#[derive(Debug)]
49enum Pending {
50 Write,
51 Read,
52}
53
54impl<'a> PioGSpi<'a> {
55 pub fn new(
57 pio: &'a Pio,
58 dma: DmaChannel<'a>,
59 clock_pin: u32,
60 dio_pin: u32,
61 cs_pin: &'a RPGpioPin<'a>,
62 sm_number: SMNumber,
63 ) -> Self {
64 Self {
65 pio,
66 dma,
67 clock_pin,
68 dio_pin,
69 cs_pin,
70 sm_number,
71 pending: OptionalCell::empty(),
72 client: OptionalCell::empty(),
73 irq_client: OptionalCell::empty(),
74 write_buffer: OptionalCell::empty(),
75 read_buffer: OptionalCell::empty(),
76 }
77 }
78
79 pub fn sm_number(&self) -> SMNumber {
81 self.sm_number
82 }
83
84 pub fn set_irq_client(&self, client: &'a dyn gpio::Client) {
85 self.irq_client.set(client);
86 }
87
88 pub fn init(&self) {
90 self.pio.init();
91 self.cs_pin.set();
92
93 self.pio.add_program16(None::<usize>, &PROG).unwrap();
95
96 let config = StateMachineConfiguration {
97 out_pins_count: 1,
98 out_pins_base: self.dio_pin,
99 set_pins_count: 1,
100 set_pins_base: self.dio_pin,
101 in_pins_base: self.dio_pin,
102 side_set_base: self.clock_pin,
103 side_set_bit_count: 1,
104 in_push_threshold: 0,
105 out_pull_threshold: 0,
106 div_int: 2u32,
107 div_frac: 0u32,
108 wrap: 10,
109 wrap_to: 3,
110 in_autopush: true,
111 out_autopull: true,
112 in_shift_direction_right: false,
113 out_shift_direction_right: false,
114 ..Default::default()
115 };
116
117 self.pio
118 .cyw43_spi_program_init(self.sm_number, self.clock_pin, self.dio_pin, &config);
119
120 self.pio
121 .set_irq_source(0, crate::pio::InterruptSources::Interrupt0, true);
122 }
123}
124
125impl DmaChannelClient for PioGSpi<'_> {
126 fn transfer_done(&self) {
127 let Some(pending) = self.pending.take() else {
128 return;
129 };
130
131 if let Pending::Write = pending {
132 let read_buffer = self.read_buffer.take();
133 if let Some(read_buffer) = read_buffer {
134 self.dma_pull(read_buffer.as_ptr() as u32, read_buffer.len() as u32 / 4);
135 self.pending.set(Pending::Read);
136 self.read_buffer.set(read_buffer);
137 return;
138 }
139 }
140
141 let write_buffer = self.write_buffer.take().unwrap();
142 let len = write_buffer.len();
143
144 self.cs_pin.set();
145 self.client
146 .map(|client| client.read_write_done(write_buffer, self.read_buffer.take(), Ok(len)));
147 }
148}
149
150impl PioGSpi<'_> {
151 fn dma_pull(&self, addr: u32, len: u32) {
152 assert!(addr.is_multiple_of(4));
153 let current_sm = self.pio.sm(self.sm_number);
154 self.dma
155 .set_read_addr(current_sm.rx_fifo_addr(self.pio.number()));
156 self.dma.set_write_addr(addr);
157
158 self.dma.set_len(len);
159 self.dma.enable(
160 dma::DmaPeripheral::PioRxFifo(self.pio.number(), self.sm_number),
161 dma::DataSize::Word,
162 dma::Transfer::PeripheralToMemory,
163 false,
164 );
165 }
166
167 fn dma_push(&self, addr: u32, len: u32) {
168 assert!(addr.is_multiple_of(4));
169 let current_sm = self.pio.sm(self.sm_number);
170 self.dma.set_read_addr(addr);
171 self.dma
172 .set_write_addr(current_sm.tx_fifo_addr(self.pio.number()));
173
174 self.dma.set_len(len);
175
176 self.dma.enable(
177 dma::DmaPeripheral::PioTxFifo(self.pio.number(), self.sm_number),
178 dma::DataSize::Word,
179 dma::Transfer::MemoryToPeripheral,
180 false,
181 );
182 }
183}
184
185impl<'a> SpiMasterDevice<'a> for PioGSpi<'a> {
186 fn set_client(&self, client: &'a dyn spi::SpiMasterClient) {
187 self.client.set(client);
188 }
189
190 fn read_write_bytes(
191 &self,
192 write_buffer: SubSliceMut<'static, u8>,
193 read_buffer: Option<SubSliceMut<'static, u8>>,
194 ) -> Result<
195 (),
196 (
197 ErrorCode,
198 SubSliceMut<'static, u8>,
199 Option<SubSliceMut<'static, u8>>,
200 ),
201 > {
202 assert!(write_buffer.len().is_multiple_of(4));
203
204 let current_sm = self.pio.sm(self.sm_number);
205 self.cs_pin.clear();
206 current_sm.set_enabled(false);
207
208 let write_bits = (write_buffer.len() as u32) * 8 - 1;
210 let read_bits = read_buffer
211 .as_ref()
212 .map(|rx| rx.len() * 8 - 1)
213 .unwrap_or_default();
214
215 current_sm.push_blocking(write_bits).unwrap();
216 current_sm.push_blocking(read_bits as _).unwrap();
217
218 current_sm.exec(0);
219 current_sm.set_enabled(true);
220
221 self.dma_push(write_buffer.as_ptr() as u32, write_buffer.len() as u32 / 4);
222
223 self.write_buffer.set(write_buffer);
224 self.read_buffer.insert(read_buffer);
225 self.pending.set(Pending::Write);
226
227 Ok(())
228 }
229
230 fn set_rate(&self, _: u32) -> Result<(), ErrorCode> {
231 Err(ErrorCode::NOSUPPORT)
232 }
233
234 fn set_polarity(&self, _: kernel::hil::spi::ClockPolarity) -> Result<(), ErrorCode> {
235 Err(ErrorCode::NOSUPPORT)
236 }
237
238 fn set_phase(&self, _: kernel::hil::spi::ClockPhase) -> Result<(), ErrorCode> {
239 Err(ErrorCode::NOSUPPORT)
240 }
241
242 fn configure(
243 &self,
244 _: kernel::hil::spi::ClockPolarity,
245 _: kernel::hil::spi::ClockPhase,
246 _: u32,
247 ) -> Result<(), ErrorCode> {
248 Err(ErrorCode::NOSUPPORT)
249 }
250
251 fn get_polarity(&self) -> kernel::hil::spi::ClockPolarity {
252 kernel::hil::spi::ClockPolarity::IdleLow
253 }
254
255 fn get_phase(&self) -> kernel::hil::spi::ClockPhase {
256 kernel::hil::spi::ClockPhase::SampleLeading
257 }
258
259 fn get_rate(&self) -> u32 {
260 0
261 }
262}
263
264impl PioSmClient for PioGSpi<'_> {
265 fn on_irq(&self) {
266 self.pio.interrupt_clear(0);
268 self.irq_client.map(|client| client.fired());
269 }
270}