#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/platform_profile.h>
+#include <linux/power_supply.h>
#include <linux/rfkill.h>
#include <linux/seq_file.h>
#include <linux/sysfs.h>
#include <linux/wmi.h>
#include "ideapad-laptop.h"
+#include <acpi/battery.h>
#include <acpi/video.h>
#include <dt-bindings/leds/common.h>
struct backlight_device *blightdev;
struct ideapad_dytc_priv *dytc;
struct dentry *debug;
+ struct acpi_battery_hook battery_hook;
unsigned long cfg;
unsigned long r_touchpad_val;
struct {
static DEVICE_ATTR_RW(camera_power);
+static void show_conservation_mode_deprecation_warning(struct device *dev)
+{
+ dev_warn_once(dev, "conservation_mode attribute has been deprecated, see charge_types.\n");
+}
+
static ssize_t conservation_mode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
unsigned long result;
int err;
+ show_conservation_mode_deprecation_warning(dev);
+
err = eval_gbmd(priv->adev->handle, &result);
if (err)
return err;
bool state;
int err;
+ show_conservation_mode_deprecation_warning(dev);
+
err = kstrtobool(buf, &state);
if (err)
return err;
{}
};
-static void ideapad_check_features(struct ideapad_private *priv)
+static int ideapad_psy_ext_set_prop(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct ideapad_private *priv = ext_data;
+
+ switch (val->intval) {
+ case POWER_SUPPLY_CHARGE_TYPE_LONGLIFE:
+ return exec_sbmc(priv->adev->handle, SBMC_CONSERVATION_ON);
+ case POWER_SUPPLY_CHARGE_TYPE_STANDARD:
+ return exec_sbmc(priv->adev->handle, SBMC_CONSERVATION_OFF);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ideapad_psy_ext_get_prop(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct ideapad_private *priv = ext_data;
+ unsigned long result;
+ int err;
+
+ err = eval_gbmd(priv->adev->handle, &result);
+ if (err)
+ return err;
+
+ if (test_bit(GBMD_CONSERVATION_STATE_BIT, &result))
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_LONGLIFE;
+ else
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
+
+ return 0;
+}
+
+static int ideapad_psy_prop_is_writeable(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *data,
+ enum power_supply_property psp)
+{
+ return true;
+}
+
+static const enum power_supply_property ideapad_power_supply_props[] = {
+ POWER_SUPPLY_PROP_CHARGE_TYPES,
+};
+
+static const struct power_supply_ext ideapad_battery_ext = {
+ .name = "ideapad_laptop",
+ .properties = ideapad_power_supply_props,
+ .num_properties = ARRAY_SIZE(ideapad_power_supply_props),
+ .charge_types = (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
+ BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)),
+ .get_property = ideapad_psy_ext_get_prop,
+ .set_property = ideapad_psy_ext_set_prop,
+ .property_is_writeable = ideapad_psy_prop_is_writeable,
+};
+
+static int ideapad_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
+{
+ struct ideapad_private *priv = container_of(hook, struct ideapad_private, battery_hook);
+
+ return power_supply_register_extension(battery, &ideapad_battery_ext,
+ &priv->platform_device->dev, priv);
+}
+
+static int ideapad_battery_remove(struct power_supply *battery,
+ struct acpi_battery_hook *hook)
+{
+ power_supply_unregister_extension(battery, &ideapad_battery_ext);
+
+ return 0;
+}
+
+static int ideapad_check_features(struct ideapad_private *priv)
{
acpi_handle handle = priv->adev->handle;
unsigned long val;
+ int err;
priv->features.set_fn_lock_led =
set_fn_lock_led || dmi_check_system(set_fn_lock_led_list);
if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
priv->features.fan_mode = true;
- if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC"))
+ if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC")) {
priv->features.conservation_mode = true;
+ priv->battery_hook.add_battery = ideapad_battery_add;
+ priv->battery_hook.remove_battery = ideapad_battery_remove;
+ priv->battery_hook.name = "Ideapad Battery Extension";
+
+ err = devm_battery_hook_register(&priv->platform_device->dev, &priv->battery_hook);
+ if (err)
+ return err;
+ }
if (acpi_has_method(handle, "DYTC"))
priv->features.dytc = true;
}
}
}
+
+ return 0;
}
#if IS_ENABLED(CONFIG_ACPI_WMI)
if (err)
return err;
- ideapad_check_features(priv);
+ err = ideapad_check_features(priv);
+ if (err)
+ return err;
ideapad_debugfs_init(priv);