Skip to content

Commit

Permalink
Add manual fan control
Browse files Browse the repository at this point in the history
Allow fan target duties to be set via ACPI or SMFI command. This will
allow system firmware or OS to set fan duty, which can be used for
testing or implementing user-defined fan tables.

Signed-off-by: Tim Crawford <[email protected]>
  • Loading branch information
crawfxrd committed Dec 31, 2024
1 parent 88173de commit 882041b
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 3 deletions.
27 changes: 27 additions & 0 deletions src/board/system76/common/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ uint8_t acpi_read(uint8_t addr) {
ACPI_16(0xD2, fan2_rpm);
#endif // FAN2_PWM

case 0xD4:
data = fan_get_mode();
break;

#if HAVE_LED_AIRPLANE_N
// Airplane mode LED
case 0xD9:
Expand Down Expand Up @@ -224,6 +228,29 @@ void acpi_write(uint8_t addr, uint8_t data) {
(void)battery_save_thresholds();
break;

case 0xCE:
if (fan_get_mode() == FAN_MANUAL) {
fan1_pwm_target = data;
}
break;

#ifdef FAN2_PWM
case 0xCF:
if (fan_get_mode() == FAN_MANUAL) {
fan2_pwm_target = data;
}
break;
#endif

case 0xD4:
switch (data) {
case FAN_AUTO:
case FAN_MANUAL:
fan_set_mode(data);
break;
}
break;

#if HAVE_LED_AIRPLANE_N
// Airplane mode LED
case 0xD9:
Expand Down
9 changes: 9 additions & 0 deletions src/board/system76/common/fan.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#endif

bool fan_max = false;
static enum FanMode fan_mode = FAN_AUTO;

uint8_t fan1_pwm_actual = 0;
uint8_t fan1_pwm_target = 0;
Expand Down Expand Up @@ -261,3 +262,11 @@ void fan_update_duty(void) {
fan2_rpm = fan_get_tach1_rpm();
#endif
}

enum FanMode fan_get_mode(void) {
return fan_mode;
}

void fan_set_mode(enum FanMode mode) {
fan_mode = mode;
}
8 changes: 8 additions & 0 deletions src/board/system76/common/include/board/fan.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ struct Fan {
uint8_t pwm_min;
};

enum FanMode {
FAN_AUTO,
FAN_MANUAL,
};

extern bool fan_max;

extern uint8_t fan1_pwm_actual;
Expand All @@ -34,4 +39,7 @@ void fan_reset(void);
void fan_update_duty(void);
void fan_update_target(void);

enum FanMode fan_get_mode(void);
void fan_set_mode(enum FanMode);

#endif // _BOARD_FAN_H
5 changes: 4 additions & 1 deletion src/board/system76/common/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,10 @@ void main(void) {
last_time_1sec = time;

battery_event();
fan_update_target();

if (fan_get_mode() == FAN_AUTO) {
fan_update_target();
}
}

// Idle until next timer interrupt
Expand Down
25 changes: 25 additions & 0 deletions src/board/system76/common/smfi.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,24 @@ static enum Result cmd_fan_set_pwm(void) {
return RES_ERR;
}

static enum Result cmd_fan_get_mode(void) {
smfi_cmd[SMFI_CMD_DATA] = fan_get_mode();
return RES_OK;
}

static enum Result cmd_fan_set_mode(void) {
enum FanMode mode = smfi_cmd[SMFI_CMD_DATA];

switch (mode) {
case FAN_AUTO:
case FAN_MANUAL:
fan_set_mode(mode);
return RES_OK;
}

return RES_ERR;
}

static enum Result cmd_keymap_get(void) {
int16_t layer = smfi_cmd[SMFI_CMD_DATA];
int16_t output = smfi_cmd[SMFI_CMD_DATA + 1];
Expand Down Expand Up @@ -421,6 +439,13 @@ void smfi_event(void) {
break;
#endif // CONFIG_SECURITY

case CMD_FAN_GET_MODE:
smfi_cmd[SMFI_CMD_RES] = cmd_fan_get_mode();
break;
case CMD_FAN_SET_MODE:
smfi_cmd[SMFI_CMD_RES] = cmd_fan_set_mode();
break;

#endif // !defined(__SCRATCH__)
case CMD_SPI:
smfi_cmd[SMFI_CMD_RES] = cmd_spi();
Expand Down
5 changes: 4 additions & 1 deletion src/common/include/common/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ enum Command {
CMD_SECURITY_GET = 20,
// Set security state
CMD_SECURITY_SET = 21,
//TODO
// Get fan control mode
CMD_FAN_GET_MODE = 22,
// Set fan control mode
CMD_FAN_SET_MODE = 23,
};

enum Result {
Expand Down
34 changes: 34 additions & 0 deletions tool/src/ec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ enum Cmd {
SetNoInput = 19,
SecurityGet = 20,
SecuritySet = 21,
FanGetMode = 22,
FanSetMode = 23,
}

const CMD_SPI_FLAG_READ: u8 = 1 << 0;
Expand Down Expand Up @@ -73,6 +75,25 @@ impl TryFrom<u8> for SecurityState {
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum FanMode {
Auto = 0,
Manual = 1,
}

impl TryFrom<u8> for FanMode {
type Error = Error;

fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Auto),
1 => Ok(Self::Manual),
_ => Err(Error::Verify),
}
}
}

/// Run EC commands using a provided access method
pub struct Ec<A: Access> {
access: A,
Expand Down Expand Up @@ -327,6 +348,19 @@ impl<A: Access> Ec<A> {
self.command(Cmd::SecuritySet, &mut data)
}

/// Get fan control mode.
pub unsafe fn fan_get_mode(&mut self) -> Result<FanMode, Error> {
let mut data = [0];
self.command(Cmd::FanGetMode, &mut data)?;
FanMode::try_from(data[0])
}

/// Set fan control mode.
pub unsafe fn fan_set_mode(&mut self, mode: FanMode) -> Result<(), Error> {
let mut data = [mode as u8];
self.command(Cmd::FanSetMode, &mut data)
}

pub fn into_dyn(self) -> Ec<Box<dyn Access>>
where A: 'static {
Ec {
Expand Down
2 changes: 1 addition & 1 deletion tool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern crate alloc;
pub use self::access::*;
mod access;

pub use self::ec::{Ec, SecurityState};
pub use self::ec::{Ec, FanMode, SecurityState};
mod ec;

pub use self::error::Error;
Expand Down
8 changes: 8 additions & 0 deletions tool/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ unsafe fn fan_set_pwm(ec: &mut Ec<Box<dyn Access>>, index: u8, duty: u8) -> Resu
ec.fan_set_pwm(index, duty)
}

unsafe fn fan_get_mode(ec: &mut Ec<Box<dyn Access>>) -> Result<(), Error> {
todo!()
}

unsafe fn fan_set_mode(ec: &mut Ec<Box<dyn Access>>, mode: ectool::FanMode) -> Result<(), Error> {
todo!()
}

unsafe fn keymap_get(ec: &mut Ec<Box<dyn Access>>, layer: u8, output: u8, input: u8) -> Result<(), Error> {
let value = ec.keymap_get(layer, output, input)?;
println!("{:04X}", value);
Expand Down

0 comments on commit 882041b

Please sign in to comment.