Skip to content

Commit 6d710ec

Browse files
antheasij-intel
authored andcommitted
platform/x86: ayaneo-ec: Add charge control support
Ayaneo devices support charge inhibition via the EC. This inhibition only works while the device is powered on, and resets between restarts. However, it is maintained across suspend/resume cycles. The EC does not support charge threshold control. Instead, userspace software on Windows manually toggles charge inhibition depending on battery level. Reviewed-by: Armin Wolf <W_Armin@gmx.de> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev> Link: https://patch.msgid.link/20251119174505.597218-4-lkml@antheas.dev Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
1 parent 536522f commit 6d710ec

2 files changed

Lines changed: 113 additions & 0 deletions

File tree

drivers/platform/x86/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ config AYANEO_EC
315315
tristate "Ayaneo EC platform control"
316316
depends on DMI
317317
depends on ACPI_EC
318+
depends on ACPI_BATTERY
318319
depends on HWMON
319320
help
320321
Enables support for the platform EC of Ayaneo devices. This

drivers/platform/x86/ayaneo-ec.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <linux/kernel.h>
1616
#include <linux/module.h>
1717
#include <linux/platform_device.h>
18+
#include <linux/power_supply.h>
19+
#include <acpi/battery.h>
1820

1921
#define AYANEO_PWM_ENABLE_REG 0x4A
2022
#define AYANEO_PWM_REG 0x4B
@@ -23,17 +25,27 @@
2325

2426
#define AYANEO_FAN_REG 0x76
2527

28+
#define EC_CHARGE_CONTROL_BEHAVIOURS \
29+
(BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \
30+
BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE))
31+
#define AYANEO_CHARGE_REG 0x1e
32+
#define AYANEO_CHARGE_VAL_AUTO 0xaa
33+
#define AYANEO_CHARGE_VAL_INHIBIT 0x55
34+
2635
struct ayaneo_ec_quirk {
2736
bool has_fan_control;
37+
bool has_charge_control;
2838
};
2939

3040
struct ayaneo_ec_platform_data {
3141
struct platform_device *pdev;
3242
struct ayaneo_ec_quirk *quirks;
43+
struct acpi_battery_hook battery_hook;
3344
};
3445

3546
static const struct ayaneo_ec_quirk quirk_ayaneo3 = {
3647
.has_fan_control = true,
48+
.has_charge_control = true,
3749
};
3850

3951
static const struct dmi_system_id dmi_table[] = {
@@ -164,11 +176,102 @@ static const struct hwmon_chip_info ayaneo_ec_chip_info = {
164176
.info = ayaneo_ec_sensors,
165177
};
166178

179+
static int ayaneo_psy_ext_get_prop(struct power_supply *psy,
180+
const struct power_supply_ext *ext,
181+
void *data,
182+
enum power_supply_property psp,
183+
union power_supply_propval *val)
184+
{
185+
int ret;
186+
u8 tmp;
187+
188+
switch (psp) {
189+
case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
190+
ret = ec_read(AYANEO_CHARGE_REG, &tmp);
191+
if (ret)
192+
return ret;
193+
194+
if (tmp == AYANEO_CHARGE_VAL_INHIBIT)
195+
val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
196+
else
197+
val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
198+
return 0;
199+
default:
200+
return -EINVAL;
201+
}
202+
}
203+
204+
static int ayaneo_psy_ext_set_prop(struct power_supply *psy,
205+
const struct power_supply_ext *ext,
206+
void *data,
207+
enum power_supply_property psp,
208+
const union power_supply_propval *val)
209+
{
210+
u8 raw_val;
211+
212+
switch (psp) {
213+
case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
214+
switch (val->intval) {
215+
case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
216+
raw_val = AYANEO_CHARGE_VAL_AUTO;
217+
break;
218+
case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
219+
raw_val = AYANEO_CHARGE_VAL_INHIBIT;
220+
break;
221+
default:
222+
return -EINVAL;
223+
}
224+
return ec_write(AYANEO_CHARGE_REG, raw_val);
225+
default:
226+
return -EINVAL;
227+
}
228+
}
229+
230+
static int ayaneo_psy_prop_is_writeable(struct power_supply *psy,
231+
const struct power_supply_ext *ext,
232+
void *data,
233+
enum power_supply_property psp)
234+
{
235+
return true;
236+
}
237+
238+
static const enum power_supply_property ayaneo_psy_ext_props[] = {
239+
POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
240+
};
241+
242+
static const struct power_supply_ext ayaneo_psy_ext = {
243+
.name = "ayaneo-charge-control",
244+
.properties = ayaneo_psy_ext_props,
245+
.num_properties = ARRAY_SIZE(ayaneo_psy_ext_props),
246+
.charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS,
247+
.get_property = ayaneo_psy_ext_get_prop,
248+
.set_property = ayaneo_psy_ext_set_prop,
249+
.property_is_writeable = ayaneo_psy_prop_is_writeable,
250+
};
251+
252+
static int ayaneo_add_battery(struct power_supply *battery,
253+
struct acpi_battery_hook *hook)
254+
{
255+
struct ayaneo_ec_platform_data *data =
256+
container_of(hook, struct ayaneo_ec_platform_data, battery_hook);
257+
258+
return power_supply_register_extension(battery, &ayaneo_psy_ext,
259+
&data->pdev->dev, NULL);
260+
}
261+
262+
static int ayaneo_remove_battery(struct power_supply *battery,
263+
struct acpi_battery_hook *hook)
264+
{
265+
power_supply_unregister_extension(battery, &ayaneo_psy_ext);
266+
return 0;
267+
}
268+
167269
static int ayaneo_ec_probe(struct platform_device *pdev)
168270
{
169271
const struct dmi_system_id *dmi_entry;
170272
struct ayaneo_ec_platform_data *data;
171273
struct device *hwdev;
274+
int ret;
172275

173276
dmi_entry = dmi_first_match(dmi_table);
174277
if (!dmi_entry)
@@ -189,6 +292,15 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
189292
return PTR_ERR(hwdev);
190293
}
191294

295+
if (data->quirks->has_charge_control) {
296+
data->battery_hook.add_battery = ayaneo_add_battery;
297+
data->battery_hook.remove_battery = ayaneo_remove_battery;
298+
data->battery_hook.name = "Ayaneo Battery";
299+
ret = devm_battery_hook_register(&pdev->dev, &data->battery_hook);
300+
if (ret)
301+
return ret;
302+
}
303+
192304
return 0;
193305
}
194306

0 commit comments

Comments
 (0)