aboutsummaryrefslogtreecommitdiff
path: root/embassy-mspm0/src/i2c_target.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-mspm0/src/i2c_target.rs')
-rw-r--r--embassy-mspm0/src/i2c_target.rs94
1 files changed, 84 insertions, 10 deletions
diff --git a/embassy-mspm0/src/i2c_target.rs b/embassy-mspm0/src/i2c_target.rs
index 7183280bd..86be91415 100644
--- a/embassy-mspm0/src/i2c_target.rs
+++ b/embassy-mspm0/src/i2c_target.rs
@@ -8,16 +8,36 @@ use core::marker::PhantomData;
8use core::sync::atomic::Ordering; 8use core::sync::atomic::Ordering;
9use core::task::Poll; 9use core::task::Poll;
10 10
11use embassy_embedded_hal::SetConfig;
11use mspm0_metapac::i2c::vals::CpuIntIidxStat; 12use mspm0_metapac::i2c::vals::CpuIntIidxStat;
12 13
13use crate::gpio::{AnyPin, SealedPin}; 14use crate::gpio::{AnyPin, SealedPin};
14use crate::interrupt;
15use crate::interrupt::InterruptExt; 15use crate::interrupt::InterruptExt;
16use crate::mode::{Async, Blocking, Mode}; 16use crate::mode::{Async, Blocking, Mode};
17use crate::pac::{self, i2c::vals}; 17use crate::pac::{self, i2c::vals};
18use crate::Peri; 18use crate::{i2c, i2c_target, interrupt, Peri};
19// Re-use I2c controller types 19// Re-use I2c controller types
20use crate::i2c::{ClockSel, Config, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; 20use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State};
21
22#[non_exhaustive]
23#[derive(Clone, Copy, PartialEq, Eq, Debug)]
24/// Config
25pub struct Config {
26 /// 7-bit Target Address
27 pub target_addr: u8,
28
29 /// Control if the target should ack to and report general calls.
30 pub general_call: bool,
31}
32
33impl Default for Config {
34 fn default() -> Self {
35 Self {
36 target_addr: 0x48,
37 general_call: false,
38 }
39 }
40}
21 41
22/// I2C error 42/// I2C error
23#[derive(Debug, PartialEq, Eq, Clone, Copy)] 43#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -75,24 +95,71 @@ pub struct I2cTarget<'d, M: Mode> {
75 state: &'static State, 95 state: &'static State,
76 scl: Option<Peri<'d, AnyPin>>, 96 scl: Option<Peri<'d, AnyPin>>,
77 sda: Option<Peri<'d, AnyPin>>, 97 sda: Option<Peri<'d, AnyPin>>,
78 config: Config, 98 config: i2c::Config,
99 target_config: i2c_target::Config,
79 _phantom: PhantomData<M>, 100 _phantom: PhantomData<M>,
80} 101}
81 102
103impl<'d> SetConfig for I2cTarget<'d, Async> {
104 type Config = (i2c::Config, i2c_target::Config);
105 type ConfigError = ConfigError;
106
107 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
108 self.info.interrupt.disable();
109
110 if let Some(ref sda) = self.sda {
111 sda.update_pf(config.0.sda_pf());
112 }
113
114 if let Some(ref scl) = self.scl {
115 scl.update_pf(config.0.scl_pf());
116 }
117
118 self.config = config.0.clone();
119 self.target_config = config.1.clone();
120
121 self.reset()
122 }
123}
124
125impl<'d> SetConfig for I2cTarget<'d, Blocking> {
126 type Config = (i2c::Config, i2c_target::Config);
127 type ConfigError = ConfigError;
128
129 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
130 if let Some(ref sda) = self.sda {
131 sda.update_pf(config.0.sda_pf());
132 }
133
134 if let Some(ref scl) = self.scl {
135 scl.update_pf(config.0.scl_pf());
136 }
137
138 self.config = config.0.clone();
139 self.target_config = config.1.clone();
140
141 self.reset()
142 }
143}
144
82impl<'d> I2cTarget<'d, Async> { 145impl<'d> I2cTarget<'d, Async> {
83 /// Create a new asynchronous I2C target driver using interrupts 146 /// Create a new asynchronous I2C target driver using interrupts
147 /// The `config` reuses the i2c controller config to setup the clock while `target_config`
148 /// configures i2c target specific parameters.
84 pub fn new<T: Instance>( 149 pub fn new<T: Instance>(
85 peri: Peri<'d, T>, 150 peri: Peri<'d, T>,
86 scl: Peri<'d, impl SclPin<T>>, 151 scl: Peri<'d, impl SclPin<T>>,
87 sda: Peri<'d, impl SdaPin<T>>, 152 sda: Peri<'d, impl SdaPin<T>>,
88 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 153 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
89 config: Config, 154 config: i2c::Config,
155 target_config: i2c_target::Config,
90 ) -> Result<Self, ConfigError> { 156 ) -> Result<Self, ConfigError> {
91 let mut this = Self::new_inner( 157 let mut this = Self::new_inner(
92 peri, 158 peri,
93 new_pin!(scl, config.scl_pf()), 159 new_pin!(scl, config.scl_pf()),
94 new_pin!(sda, config.sda_pf()), 160 new_pin!(sda, config.sda_pf()),
95 config, 161 config,
162 target_config,
96 ); 163 );
97 this.reset()?; 164 this.reset()?;
98 Ok(this) 165 Ok(this)
@@ -110,17 +177,21 @@ impl<'d> I2cTarget<'d, Async> {
110 177
111impl<'d> I2cTarget<'d, Blocking> { 178impl<'d> I2cTarget<'d, Blocking> {
112 /// Create a new blocking I2C target driver. 179 /// Create a new blocking I2C target driver.
180 /// The `config` reuses the i2c controller config to setup the clock while `target_config`
181 /// configures i2c target specific parameters.
113 pub fn new_blocking<T: Instance>( 182 pub fn new_blocking<T: Instance>(
114 peri: Peri<'d, T>, 183 peri: Peri<'d, T>,
115 scl: Peri<'d, impl SclPin<T>>, 184 scl: Peri<'d, impl SclPin<T>>,
116 sda: Peri<'d, impl SdaPin<T>>, 185 sda: Peri<'d, impl SdaPin<T>>,
117 config: Config, 186 config: i2c::Config,
187 target_config: i2c_target::Config,
118 ) -> Result<Self, ConfigError> { 188 ) -> Result<Self, ConfigError> {
119 let mut this = Self::new_inner( 189 let mut this = Self::new_inner(
120 peri, 190 peri,
121 new_pin!(scl, config.scl_pf()), 191 new_pin!(scl, config.scl_pf()),
122 new_pin!(sda, config.sda_pf()), 192 new_pin!(sda, config.sda_pf()),
123 config, 193 config,
194 target_config,
124 ); 195 );
125 this.reset()?; 196 this.reset()?;
126 Ok(this) 197 Ok(this)
@@ -140,7 +211,8 @@ impl<'d, M: Mode> I2cTarget<'d, M> {
140 _peri: Peri<'d, T>, 211 _peri: Peri<'d, T>,
141 scl: Option<Peri<'d, AnyPin>>, 212 scl: Option<Peri<'d, AnyPin>>,
142 sda: Option<Peri<'d, AnyPin>>, 213 sda: Option<Peri<'d, AnyPin>>,
143 config: Config, 214 config: i2c::Config,
215 target_config: i2c_target::Config,
144 ) -> Self { 216 ) -> Self {
145 if let Some(ref scl) = scl { 217 if let Some(ref scl) = scl {
146 let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize); 218 let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize);
@@ -161,17 +233,19 @@ impl<'d, M: Mode> I2cTarget<'d, M> {
161 scl, 233 scl,
162 sda, 234 sda,
163 config, 235 config,
236 target_config,
164 _phantom: PhantomData, 237 _phantom: PhantomData,
165 } 238 }
166 } 239 }
167 240
168 fn init(&mut self) -> Result<(), ConfigError> { 241 fn init(&mut self) -> Result<(), ConfigError> {
169 let mut config = self.config; 242 let mut config = self.config;
243 let target_config = self.target_config;
170 let regs = self.info.regs; 244 let regs = self.info.regs;
171 245
172 config.check_config()?; 246 config.check_config()?;
173 // Target address must be 7-bit 247 // Target address must be 7-bit
174 if !(config.target_addr < 0x80) { 248 if !(target_config.target_addr < 0x80) {
175 return Err(ConfigError::InvalidTargetAddress); 249 return Err(ConfigError::InvalidTargetAddress);
176 } 250 }
177 251
@@ -213,7 +287,7 @@ impl<'d, M: Mode> I2cTarget<'d, M> {
213 // target address can be enabled and configured by using I2Cx.TOAR2 register. 287 // target address can be enabled and configured by using I2Cx.TOAR2 register.
214 regs.target(0).toar().modify(|w| { 288 regs.target(0).toar().modify(|w| {
215 w.set_oaren(true); 289 w.set_oaren(true);
216 w.set_oar(config.target_addr as u16); 290 w.set_oar(target_config.target_addr as u16);
217 }); 291 });
218 292
219 self.state 293 self.state
@@ -221,7 +295,7 @@ impl<'d, M: Mode> I2cTarget<'d, M> {
221 .store(config.calculate_clock_source(), Ordering::Relaxed); 295 .store(config.calculate_clock_source(), Ordering::Relaxed);
222 296
223 regs.target(0).tctr().modify(|w| { 297 regs.target(0).tctr().modify(|w| {
224 w.set_gencall(config.general_call); 298 w.set_gencall(target_config.general_call);
225 w.set_tclkstretch(true); 299 w.set_tclkstretch(true);
226 // Disable target wakeup, follow TI example. (TI note: Workaround for errata I2C_ERR_04.) 300 // Disable target wakeup, follow TI example. (TI note: Workaround for errata I2C_ERR_04.)
227 w.set_twuen(false); 301 w.set_twuen(false);