Skip to content

Commit 4118804

Browse files
committed
supply: allow USB data disconnection
Allow USB data disconnection via sysfs openemc_supply_connect_data file.
1 parent 256309a commit 4118804

File tree

5 files changed

+161
-71
lines changed

5 files changed

+161
-71
lines changed

openemc-driver/openemc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
#define OPENEMC_SUPPLY_USB_COMMUNICATION 0x93
115115
#define OPENEMC_SUPPLY_VOLTAGE 0x94
116116
#define OPENEMC_SUPPLY_CURRENT 0x95
117+
#define OPENEMC_SUPPLY_CONNECT_DATA 0x96
117118

118119
/* Board IO register definitions */
119120
#define OPENEMC_BOARD_IO 0xe0

openemc-driver/openemc_supply.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,54 @@ static const struct power_supply_desc openemc_supply_desc = {
178178
.get_property = openemc_supply_get_property,
179179
};
180180

181+
static ssize_t openemc_supply_connect_data_show(struct device *dev,
182+
struct device_attribute *attr,
183+
char *buf)
184+
{
185+
struct openemc_supply *sup = dev_get_drvdata(dev);
186+
int ret;
187+
u8 connect;
188+
189+
ret = openemc_read_u8(sup->emc, OPENEMC_SUPPLY_CONNECT_DATA, &connect);
190+
if (ret < 0)
191+
return ret;
192+
193+
if (connect == 0)
194+
return sprintf(buf, "disconnect");
195+
else
196+
return sprintf(buf, "connect");
197+
}
198+
static ssize_t openemc_supply_connect_data_store(struct device *dev,
199+
struct device_attribute *attr,
200+
const char *buf, size_t count)
201+
{
202+
struct openemc_supply *sup = dev_get_drvdata(dev);
203+
u8 connect;
204+
int ret;
205+
206+
if (sysfs_streq(buf, "disconnect"))
207+
connect = 0;
208+
else if (sysfs_streq(buf, "connect"))
209+
connect = 1;
210+
else
211+
return -EINVAL;
212+
213+
ret = openemc_write_u8(sup->emc, OPENEMC_SUPPLY_CONNECT_DATA, connect);
214+
if (ret != 0)
215+
return ret;
216+
217+
return count;
218+
}
219+
static DEVICE_ATTR_RW(openemc_supply_connect_data);
220+
221+
static struct attribute *openemc_supply_attrs[] = {
222+
&dev_attr_openemc_supply_connect_data.attr, NULL
223+
};
224+
225+
static const struct attribute_group openemc_supply_group = {
226+
.attrs = openemc_supply_attrs,
227+
};
228+
181229
static int openemc_supply_probe(struct platform_device *pdev)
182230
{
183231
const struct of_device_id *match;
@@ -248,6 +296,10 @@ static int openemc_supply_probe(struct platform_device *pdev)
248296
}
249297
}
250298

299+
ret = devm_device_add_group(&pdev->dev, &openemc_supply_group);
300+
if (ret < 0)
301+
return ret;
302+
251303
dev_info(sup->dev, "OpenEMC power supply %s registered\n",
252304
psy_desc->name);
253305

openemc-firmware/src/main.rs

Lines changed: 86 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ mod app {
313313
bq25713: Option<Bq25713<I2c2Master>>,
314314
/// Latest power supply report.
315315
power_supply: Option<PowerSupply>,
316+
/// Connect USB data lines of supply?
317+
power_supply_connect_data: bool,
316318
/// Latest battery report.
317319
battery: Option<Battery>,
318320
/// Undervoltage power off in progress?
@@ -748,6 +750,7 @@ mod app {
748750
max14636,
749751
bq25713,
750752
power_supply: None,
753+
power_supply_connect_data: false,
751754
battery: None,
752755
undervoltage_power_off: false,
753756
bootloader_crc32,
@@ -955,7 +958,7 @@ mod app {
955958

956959
/// Updates the power supply status.
957960
#[task(
958-
shared = [i2c2, stusb4500, max14636, bq25713, power_supply, irq, board, &power_mode],
961+
shared = [i2c2, stusb4500, max14636, bq25713, power_supply, power_supply_connect_data, irq, board, &power_mode],
959962
local = [
960963
first: Option<Instant> = None,
961964
last_change: Option<Instant> = None,
@@ -974,84 +977,94 @@ mod app {
974977
cx.shared.max14636,
975978
cx.shared.bq25713,
976979
cx.shared.power_supply,
980+
cx.shared.power_supply_connect_data,
977981
cx.shared.irq,
978982
cx.shared.board,
979983
)
980-
.lock(|i2c2, stusb4500, max14636, bq25713, power_supply, irq, board| {
981-
// Merge power supply reports.
982-
let mut report = PowerSupply::default();
983-
if let Some(stusb4500) = stusb4500 {
984-
let stusb4500_report = stusb4500.report();
985-
defmt::trace!("STUSB4500 power supply report: {:?}", &stusb4500_report);
986-
report = report.merge(stusb4500.report());
987-
}
988-
if let Some(max14636) = max14636 {
989-
let max14636_report = max14636.report();
990-
defmt::trace!("MAX14636 power supply report: {:?}", &max14636_report);
991-
report = report.merge(&max14636_report);
992-
}
984+
.lock(
985+
|i2c2, stusb4500, max14636, bq25713, power_supply, power_supply_connect_data, irq, board| {
986+
// Set USB data connection.
987+
if let Some(max14636) = max14636 {
988+
if max14636.good_battery() != *power_supply_connect_data {
989+
max14636.set_good_battery(*power_supply_connect_data);
990+
}
991+
}
993992

994-
// Update power supply status.
995-
if Some(&report) != power_supply.as_ref() {
996-
defmt::info!("Power supply: {:?}", report);
993+
// Merge power supply reports.
994+
let mut report = PowerSupply::default();
995+
if let Some(stusb4500) = stusb4500 {
996+
let stusb4500_report = stusb4500.report();
997+
defmt::trace!("STUSB4500 power supply report: {:?}", &stusb4500_report);
998+
report = report.merge(stusb4500.report());
999+
}
1000+
if let Some(max14636) = max14636 {
1001+
let max14636_report = max14636.report();
1002+
defmt::trace!("MAX14636 power supply report: {:?}", &max14636_report);
1003+
report = report.merge(&max14636_report);
1004+
}
9971005

998-
// Store report and notify host.
999-
irq.pend_soft(IrqState::SUPPLY | IrqState::BATTERY);
1000-
*power_supply = Some(report.clone());
1001-
*last_change = monotonics::now();
1002-
}
1006+
// Update power supply status.
1007+
if Some(&report) != power_supply.as_ref() {
1008+
defmt::info!("Power supply: {:?}", report);
10031009

1004-
// Check for power on and shutdown in charging mode.
1005-
if *cx.shared.power_mode == PowerMode::Charging {
1006-
if board.check_power_on_requested() {
1007-
defmt::info!("Power on requested");
1008-
let _ = power_restart::spawn(BootReason::Restart);
1010+
// Store report and notify host.
1011+
irq.pend_soft(IrqState::SUPPLY | IrqState::BATTERY);
1012+
*power_supply = Some(report.clone());
1013+
*last_change = monotonics::now();
10091014
}
10101015

1011-
if !report.is_connected() && monotonics::now() - *first > grace_period {
1012-
defmt::info!("Shutdown because power supply disconnected");
1013-
let _ = power_off::spawn();
1016+
// Check for power on and shutdown in charging mode.
1017+
if *cx.shared.power_mode == PowerMode::Charging {
1018+
if board.check_power_on_requested() {
1019+
defmt::info!("Power on requested");
1020+
let _ = power_restart::spawn(BootReason::Restart);
1021+
}
1022+
1023+
if !report.is_connected() && monotonics::now() - *first > grace_period {
1024+
defmt::info!("Shutdown because power supply disconnected");
1025+
let _ = power_off::spawn();
1026+
}
10141027
}
1015-
}
10161028

1017-
// Calculate input current limit.
1018-
let limit_opt = if report.is_unknown() {
1019-
None
1020-
} else {
1021-
Some(board.input_current_limit(&report, monotonics::now() - *last_change))
1022-
};
1029+
// Calculate input current limit.
1030+
let limit_opt = if report.is_unknown() {
1031+
None
1032+
} else {
1033+
Some(board.input_current_limit(&report, monotonics::now() - *last_change))
1034+
};
1035+
1036+
// Configure battery charger.
1037+
match &limit_opt {
1038+
_ if limit_opt == *cx.local.limit_opt => (),
1039+
Some(limit) => match (i2c2, bq25713) {
1040+
(Some(i2c2), Some(bq25713)) => {
1041+
defmt::info!(
1042+
"Setting BQ25713 maximum input current to {} mA and ICO to {}",
1043+
limit.max_input_current_ma,
1044+
limit.ico
1045+
);
10231046

1024-
// Configure battery charger.
1025-
match &limit_opt {
1026-
_ if limit_opt == *cx.local.limit_opt => (),
1027-
Some(limit) => match (i2c2, bq25713) {
1028-
(Some(i2c2), Some(bq25713)) => {
1029-
defmt::info!(
1030-
"Setting BQ25713 maximum input current to {} mA and ICO to {}",
1031-
limit.max_input_current_ma,
1032-
limit.ico
1033-
);
1034-
1035-
let res = bq25713.set_input_current_limit(i2c2, limit).and_then(|_| {
1036-
if limit.max_input_current_ma > 0 && !bq25713.is_charge_enabled() {
1037-
bq25713.set_charge_enable(i2c2, true)?;
1038-
} else if limit.max_input_current_ma == 0 && bq25713.is_charge_enabled() {
1039-
bq25713.set_charge_enable(i2c2, false)?;
1047+
let res = bq25713.set_input_current_limit(i2c2, limit).and_then(|_| {
1048+
if limit.max_input_current_ma > 0 && !bq25713.is_charge_enabled() {
1049+
bq25713.set_charge_enable(i2c2, true)?;
1050+
} else if limit.max_input_current_ma == 0 && bq25713.is_charge_enabled() {
1051+
bq25713.set_charge_enable(i2c2, false)?;
1052+
}
1053+
Ok(())
1054+
});
1055+
match res {
1056+
Ok(()) => *cx.local.limit_opt = limit_opt,
1057+
Err(err) => defmt::error!("Cannot configure BQ25713 charging: {}", err),
10401058
}
1041-
Ok(())
1042-
});
1043-
match res {
1044-
Ok(()) => *cx.local.limit_opt = limit_opt,
1045-
Err(err) => defmt::error!("Cannot configure BQ25713 charging: {}", err),
10461059
}
1047-
}
1048-
_ => {
1049-
*cx.local.limit_opt = limit_opt;
1050-
}
1051-
},
1052-
None => *cx.local.limit_opt = limit_opt,
1053-
}
1054-
});
1060+
_ => {
1061+
*cx.local.limit_opt = limit_opt;
1062+
}
1063+
},
1064+
None => *cx.local.limit_opt = limit_opt,
1065+
}
1066+
},
1067+
);
10551068

10561069
defmt::unwrap!(power_supply_update::spawn_after(500u64.millis()));
10571070
}
@@ -1475,6 +1488,7 @@ mod app {
14751488
adc_buf,
14761489
board,
14771490
power_supply,
1491+
power_supply_connect_data,
14781492
battery,
14791493
flash,
14801494
crc,
@@ -1886,6 +1900,12 @@ mod app {
18861900
}
18871901
});
18881902
}
1903+
Event::Read { reg: reg::SUPPLY_CONNECT_DATA } => {
1904+
cx.shared.power_supply_connect_data.lock(|&mut connect| respond_u8(connect.into()));
1905+
}
1906+
Event::Write { reg: reg::SUPPLY_CONNECT_DATA, value } => {
1907+
cx.shared.power_supply_connect_data.lock(|connect| *connect = value.as_u8() != 0);
1908+
}
18891909
Event::Read { reg: reg::BOARD_IO } => {
18901910
cx.shared.board.lock(|board| {
18911911
let data = board.io_read();

openemc-firmware/src/reg.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,10 @@ pub const SUPPLY_VOLTAGE: u8 = 0x94;
278278
/// External power supply current in mA. (read-only, u32)
279279
pub const SUPPLY_CURRENT: u8 = 0x95;
280280

281+
/// External power supply USB communication connection. (read/write, u8)
282+
/// 0=disconnected, 1=connected.
283+
pub const SUPPLY_CONNECT_DATA: u8 = 0x96;
284+
281285
/// Read or write to board handler. (read/write)
282286
/// First byte of read response is length.
283287
pub const BOARD_IO: u8 = 0xe0;

openemc-firmware/src/supply/max14636.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@
1818

1919
//! MAX14636 USB charger detector driver.
2020
21-
use stm32f1xx_hal::gpio::{ErasedPin, Floating, Input, Output, PullUp};
21+
use stm32f1xx_hal::gpio::{ErasedPin, Floating, Input, Output, PinState, PullUp};
2222

2323
use super::PowerSupply;
2424

2525
/// MAX14636 USB charger detector driver.
2626
pub struct Max14636 {
27-
_good_bat: ErasedPin<Output>,
27+
good_bat: ErasedPin<Output>,
2828
sw_open: ErasedPin<Input<PullUp>>,
2929
chg_al_n: ErasedPin<Input<PullUp>>,
3030
chg_det: ErasedPin<Input<Floating>>,
@@ -33,11 +33,24 @@ pub struct Max14636 {
3333
impl Max14636 {
3434
/// Creates a new driver instance.
3535
pub fn new(
36-
mut good_bat: ErasedPin<Output>, sw_open: ErasedPin<Input<PullUp>>, chg_al_n: ErasedPin<Input<PullUp>>,
36+
good_bat: ErasedPin<Output>, sw_open: ErasedPin<Input<PullUp>>, chg_al_n: ErasedPin<Input<PullUp>>,
3737
chg_det: ErasedPin<Input<Floating>>,
3838
) -> Self {
39-
good_bat.set_high();
40-
Self { _good_bat: good_bat, sw_open, chg_al_n, chg_det }
39+
Self { good_bat, sw_open, chg_al_n, chg_det }
40+
}
41+
42+
/// Sets the good battery state.
43+
///
44+
/// The USB data connection is established when `good_battery` is true.
45+
/// Otherwise the USB data lines are disconnected.
46+
pub fn set_good_battery(&mut self, good_battery: bool) {
47+
defmt::info!("Setting good battery to {:?}", good_battery);
48+
self.good_bat.set_state(if good_battery { PinState::High } else { PinState::Low });
49+
}
50+
51+
/// Whether the good battery state is set.
52+
pub fn good_battery(&self) -> bool {
53+
self.good_bat.is_set_high()
4154
}
4255

4356
/// Power supply report.

0 commit comments

Comments
 (0)