components/
cyw4343.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright OxidOS Automotive 2025.
4
5//! CYW4343x components.
6//!
7//! This provides two components:
8//!
9//! 1. `CYW4343xSpiBusComponent` provides the SPI implementation for the `CYW4343xBus` interface
10//! 2. `CYW4343xComponent` provides the CYW4343 driver
11//!
12//! Usage
13//! -----
14//!
15//! ```rust
16//! // Bus component
17//! let cyw4343_spi_bus = components::cyw4343::CYW4343xSpiBusComponent::new(
18//!     mux_alarm, // Mux alarm
19//!     pio_gspi,  // Should implement the `SpiMasterDevice` interface
20//!     fw, nvram, // Firmware buffers
21//! )
22//! .finalize(!components::cyw4343x_spi_bus_component_static!(
23//!     PioGSpi<'static>, // Type of the Spi peripheral
24//!     RPTimer           // Underlying alarm peripheral
25//! ));
26//! // ...
27//!
28//! // Driver component
29//! let cyw4343_device = components::cyw4343::CYW4343xComponent::new(
30//!     pwr,             // Power pin
31//!     mux_alarm,       // Mux alarm
32//!     cyw4343_spi_bus, // Bus
33//!     clm,             // CLM (Country-Locale Matrix) buffer
34//! )
35//! .finalize(components::cyw4343_component_static!(
36//!     RPGpioPin,
37//!     RPTimer,
38//!     CYW4343xSpiBus
39//! ));
40//! ```
41
42use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
43use capsules_extra::cyw4343::spi_bus;
44use capsules_extra::cyw4343::CYW4343x;
45use capsules_extra::cyw4343::CYW4343xBus;
46use core::mem::MaybeUninit;
47use kernel::component::Component;
48use kernel::hil::{gpio, spi, time};
49use time::Alarm;
50
51// Setup static space for the objects.
52#[macro_export]
53macro_rules! cyw4343_component_static {
54    ($P:ty, $A:ty, $B:ty $(,)?) => {{
55        let alarm = kernel::static_buf!(
56            capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>
57        );
58        let driver = kernel::static_buf!(
59            capsules_extra::cyw4343::CYW4343x<
60                'static,
61                $P,
62                capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>,
63                $B,
64            >
65        );
66        let buffer = kernel::static_buf!([u8; 1600]);
67
68        (alarm, driver, buffer)
69    }};
70}
71
72pub struct CYW4343xComponent<
73    P: 'static + gpio::Pin,
74    A: 'static + time::Alarm<'static>,
75    B: 'static + CYW4343xBus<'static>,
76> {
77    pwr: &'static P,
78    alarm: &'static MuxAlarm<'static, A>,
79    bus: &'static B,
80    clm: &'static [u8],
81}
82
83impl<
84        P: 'static + gpio::Pin,
85        A: 'static + time::Alarm<'static>,
86        B: 'static + CYW4343xBus<'static>,
87    > CYW4343xComponent<P, A, B>
88{
89    pub fn new(
90        pwr: &'static P,
91        alarm: &'static MuxAlarm<'static, A>,
92        bus: &'static B,
93        clm: &'static [u8],
94    ) -> Self {
95        Self {
96            pwr,
97            alarm,
98            bus,
99            clm,
100        }
101    }
102}
103
104impl<
105        P: 'static + gpio::Pin,
106        A: 'static + time::Alarm<'static>,
107        B: 'static + CYW4343xBus<'static>,
108    > Component for CYW4343xComponent<P, A, B>
109{
110    type StaticInput = (
111        &'static mut MaybeUninit<VirtualMuxAlarm<'static, A>>,
112        &'static mut MaybeUninit<CYW4343x<'static, P, VirtualMuxAlarm<'static, A>, B>>,
113        &'static mut MaybeUninit<[u8; 1600]>,
114    );
115    type Output = &'static CYW4343x<'static, P, VirtualMuxAlarm<'static, A>, B>;
116
117    fn finalize(self, static_memory: Self::StaticInput) -> Self::Output {
118        let alarm = static_memory.0.write(VirtualMuxAlarm::new(self.alarm));
119        let buffer = static_memory.2.write([0; 1600]);
120        alarm.setup();
121        let driver = static_memory
122            .1
123            .write(CYW4343x::new(alarm, self.bus, self.pwr, self.clm, buffer));
124        alarm.set_alarm_client(driver);
125        self.bus.set_client(driver);
126        driver
127    }
128}
129
130#[macro_export]
131macro_rules! cyw4343x_spi_bus_component_static {
132    ($S:ty, $A:ty) => {{
133        let extra = kernel::static_buf!([u8; capsules_extra::cyw4343::spi_bus::WORD_SIZE]);
134        let buffer = kernel::static_buf!([u8; capsules_extra::cyw4343::spi_bus::MAX_PACKET_SIZE]);
135        let alarm = kernel::static_buf!(
136            capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>
137        );
138        let bus = kernel::static_buf!(
139            capsules_extra::cyw4343::spi_bus::CYW4343xSpiBus<
140                'static,
141                $S,
142                capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>,
143            >
144        );
145
146        (extra, buffer, alarm, bus)
147    }};
148}
149
150pub struct CYW4343xSpiBusComponent<
151    A: 'static + time::Alarm<'static>,
152    S: 'static + spi::SpiMasterDevice<'static>,
153> {
154    alarm: &'static MuxAlarm<'static, A>,
155    spi: &'static S,
156    fw: &'static [u8],
157    nv: &'static [u8],
158}
159
160impl<A: 'static + time::Alarm<'static>, S: 'static + spi::SpiMasterDevice<'static>>
161    CYW4343xSpiBusComponent<A, S>
162{
163    pub fn new(
164        alarm: &'static MuxAlarm<'static, A>,
165        spi: &'static S,
166        fw: &'static [u8],
167        nv: &'static [u8],
168    ) -> Self {
169        Self { alarm, spi, fw, nv }
170    }
171}
172
173impl<A: 'static + time::Alarm<'static>, S: 'static + spi::SpiMasterDevice<'static>> Component
174    for CYW4343xSpiBusComponent<A, S>
175{
176    type StaticInput = (
177        &'static mut MaybeUninit<[u8; spi_bus::WORD_SIZE]>,
178        &'static mut MaybeUninit<[u8; spi_bus::MAX_PACKET_SIZE]>,
179        &'static mut MaybeUninit<VirtualMuxAlarm<'static, A>>,
180        &'static mut MaybeUninit<spi_bus::CYW4343xSpiBus<'static, S, VirtualMuxAlarm<'static, A>>>,
181    );
182    type Output = &'static spi_bus::CYW4343xSpiBus<'static, S, VirtualMuxAlarm<'static, A>>;
183
184    fn finalize(self, static_memory: Self::StaticInput) -> Self::Output {
185        let extra = static_memory.0.write([0; spi_bus::WORD_SIZE]);
186        let buf = static_memory.1.write([0; spi_bus::MAX_PACKET_SIZE]);
187
188        let alarm = static_memory.2.write(VirtualMuxAlarm::new(self.alarm));
189        alarm.setup();
190
191        let bus = static_memory.3.write(spi_bus::CYW4343xSpiBus::new(
192            self.spi, alarm, extra, buf, self.fw, self.nv,
193        ));
194
195        alarm.set_alarm_client(bus);
196        self.spi.set_client(bus);
197
198        bus
199    }
200}