summaryrefslogtreecommitdiff
path: root/drivers/platform/x86/samsung-laptop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/samsung-laptop.c')
-rw-r--r--drivers/platform/x86/samsung-laptop.c220
1 files changed, 120 insertions, 100 deletions
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index c1d9ed9b7b67..9d43a12db73c 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -14,9 +14,9 @@
#include <linux/pci.h>
#include <linux/backlight.h>
#include <linux/leds.h>
-#include <linux/fb.h>
#include <linux/dmi.h>
#include <linux/platform_device.h>
+#include <linux/power_supply.h>
#include <linux/rfkill.h>
#include <linux/acpi.h>
#include <linux/seq_file.h>
@@ -24,6 +24,7 @@
#include <linux/ctype.h>
#include <linux/efi.h>
#include <linux/suspend.h>
+#include <acpi/battery.h>
#include <acpi/video.h>
/*
@@ -349,6 +350,8 @@ struct samsung_laptop {
struct notifier_block pm_nb;
+ struct acpi_battery_hook battery_hook;
+
bool handle_backlight;
bool has_stepping_quirk;
@@ -356,23 +359,13 @@ struct samsung_laptop {
};
struct samsung_quirks {
- bool broken_acpi_video;
bool four_kbd_backlight_levels;
bool enable_kbd_backlight;
- bool use_native_backlight;
bool lid_handling;
};
static struct samsung_quirks samsung_unknown = {};
-static struct samsung_quirks samsung_broken_acpi_video = {
- .broken_acpi_video = true,
-};
-
-static struct samsung_quirks samsung_use_native_backlight = {
- .use_native_backlight = true,
-};
-
static struct samsung_quirks samsung_np740u3e = {
.four_kbd_backlight_levels = true,
.enable_kbd_backlight = true,
@@ -564,7 +557,7 @@ static int update_status(struct backlight_device *bd)
set_brightness(samsung, bd->props.brightness);
- if (bd->props.power == FB_BLANK_UNBLANK)
+ if (bd->props.power == BACKLIGHT_POWER_ON)
sabi_set_commandb(samsung, commands->set_backlight, 1);
else
sabi_set_commandb(samsung, commands->set_backlight, 0);
@@ -671,9 +664,9 @@ static ssize_t get_performance_level(struct device *dev,
/* The logic is backwards, yeah, lots of fun... */
for (i = 0; config->performance_levels[i].name; ++i) {
if (sretval.data[0] == config->performance_levels[i].value)
- return sprintf(buf, "%s\n", config->performance_levels[i].name);
+ return sysfs_emit(buf, "%s\n", config->performance_levels[i].name);
}
- return sprintf(buf, "%s\n", "unknown");
+ return sysfs_emit(buf, "%s\n", "unknown");
}
static ssize_t set_performance_level(struct device *dev,
@@ -708,6 +701,11 @@ static ssize_t set_performance_level(struct device *dev,
static DEVICE_ATTR(performance_level, 0644,
get_performance_level, set_performance_level);
+static void show_battery_life_extender_deprecation_warning(struct device *dev)
+{
+ dev_warn_once(dev, "battery_life_extender attribute has been deprecated, see charge_types.\n");
+}
+
static int read_battery_life_extender(struct samsung_laptop *samsung)
{
const struct sabi_commands *commands = &samsung->config->commands;
@@ -750,11 +748,13 @@ static ssize_t get_battery_life_extender(struct device *dev,
struct samsung_laptop *samsung = dev_get_drvdata(dev);
int ret;
+ show_battery_life_extender_deprecation_warning(dev);
+
ret = read_battery_life_extender(samsung);
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", ret);
+ return sysfs_emit(buf, "%d\n", ret);
}
static ssize_t set_battery_life_extender(struct device *dev,
@@ -764,6 +764,8 @@ static ssize_t set_battery_life_extender(struct device *dev,
struct samsung_laptop *samsung = dev_get_drvdata(dev);
int ret, value;
+ show_battery_life_extender_deprecation_warning(dev);
+
if (!count || kstrtoint(buf, 0, &value) != 0)
return -EINVAL;
@@ -777,6 +779,84 @@ static ssize_t set_battery_life_extender(struct device *dev,
static DEVICE_ATTR(battery_life_extender, 0644,
get_battery_life_extender, set_battery_life_extender);
+static int samsung_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 samsung_laptop *samsung = ext_data;
+
+ switch (val->intval) {
+ case POWER_SUPPLY_CHARGE_TYPE_LONGLIFE:
+ return write_battery_life_extender(samsung, 1);
+ case POWER_SUPPLY_CHARGE_TYPE_STANDARD:
+ return write_battery_life_extender(samsung, 0);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int samsung_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 samsung_laptop *samsung = ext_data;
+ int ret;
+
+ ret = read_battery_life_extender(samsung);
+ if (ret < 0)
+ return ret;
+
+ if (ret == 1)
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_LONGLIFE;
+ else
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
+
+ return 0;
+}
+
+static int samsung_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 samsung_power_supply_props[] = {
+ POWER_SUPPLY_PROP_CHARGE_TYPES,
+};
+
+static const struct power_supply_ext samsung_battery_ext = {
+ .name = "samsung_laptop",
+ .properties = samsung_power_supply_props,
+ .num_properties = ARRAY_SIZE(samsung_power_supply_props),
+ .charge_types = (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
+ BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)),
+ .get_property = samsung_psy_ext_get_prop,
+ .set_property = samsung_psy_ext_set_prop,
+ .property_is_writeable = samsung_psy_prop_is_writeable,
+};
+
+static int samsung_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
+{
+ struct samsung_laptop *samsung = container_of(hook, struct samsung_laptop, battery_hook);
+
+ return power_supply_register_extension(battery, &samsung_battery_ext,
+ &samsung->platform_device->dev, samsung);
+}
+
+static int samsung_battery_remove(struct power_supply *battery,
+ struct acpi_battery_hook *hook)
+{
+ power_supply_unregister_extension(battery, &samsung_battery_ext);
+
+ return 0;
+}
+
static int read_usb_charge(struct samsung_laptop *samsung)
{
const struct sabi_commands *commands = &samsung->config->commands;
@@ -823,7 +903,7 @@ static ssize_t get_usb_charge(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", ret);
+ return sysfs_emit(buf, "%d\n", ret);
}
static ssize_t set_usb_charge(struct device *dev,
@@ -888,7 +968,7 @@ static ssize_t get_lid_handling(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", ret);
+ return sysfs_emit(buf, "%d\n", ret);
}
static ssize_t set_lid_handling(struct device *dev,
@@ -1054,6 +1134,21 @@ static int __init samsung_lid_handling_init(struct samsung_laptop *samsung)
return retval;
}
+static int __init samsung_battery_hook_init(struct samsung_laptop *samsung)
+{
+ int retval = 0;
+
+ if (samsung->config->commands.get_battery_life_extender != 0xFFFF) {
+ samsung->battery_hook.add_battery = samsung_battery_add;
+ samsung->battery_hook.remove_battery = samsung_battery_remove;
+ samsung->battery_hook.name = "Samsung Battery Extension";
+ retval = devm_battery_hook_register(&samsung->platform_device->dev,
+ &samsung->battery_hook);
+ }
+
+ return retval;
+}
+
static int kbd_backlight_enable(struct samsung_laptop *samsung)
{
const struct sabi_commands *commands = &samsung->config->commands;
@@ -1121,8 +1216,6 @@ static void kbd_led_set(struct led_classdev *led_cdev,
if (value > samsung->kbd_led.max_brightness)
value = samsung->kbd_led.max_brightness;
- else if (value < 0)
- value = 0;
samsung->kbd_led_wk = value;
queue_work(samsung->led_workqueue, &samsung->kbd_led_work);
@@ -1201,7 +1294,7 @@ static int __init samsung_backlight_init(struct samsung_laptop *samsung)
samsung->backlight_device = bd;
samsung->backlight_device->props.brightness = read_brightness(samsung);
- samsung->backlight_device->props.power = FB_BLANK_UNBLANK;
+ samsung->backlight_device->props.power = BACKLIGHT_POWER_ON;
backlight_update_status(samsung->backlight_device);
return 0;
@@ -1210,7 +1303,7 @@ static int __init samsung_backlight_init(struct samsung_laptop *samsung)
static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct samsung_laptop *samsung = dev_get_drvdata(dev);
bool ok = true;
@@ -1486,7 +1579,7 @@ static int __init samsung_platform_init(struct samsung_laptop *samsung)
{
struct platform_device *pdev;
- pdev = platform_device_register_simple("samsung", -1, NULL, 0);
+ pdev = platform_device_register_simple("samsung", PLATFORM_DEVID_NONE, NULL, 0);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
@@ -1544,76 +1637,6 @@ static const struct dmi_system_id samsung_dmi_table[] __initconst = {
/* Specific DMI ids for laptop with quirks */
{
.callback = samsung_dmi_matched,
- .ident = "N150P",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
- DMI_MATCH(DMI_BOARD_NAME, "N150P"),
- },
- .driver_data = &samsung_use_native_backlight,
- },
- {
- .callback = samsung_dmi_matched,
- .ident = "N145P/N250P/N260P",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
- DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
- },
- .driver_data = &samsung_use_native_backlight,
- },
- {
- .callback = samsung_dmi_matched,
- .ident = "N150/N210/N220",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
- DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
- },
- .driver_data = &samsung_broken_acpi_video,
- },
- {
- .callback = samsung_dmi_matched,
- .ident = "NF110/NF210/NF310",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
- DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
- },
- .driver_data = &samsung_broken_acpi_video,
- },
- {
- .callback = samsung_dmi_matched,
- .ident = "X360",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
- DMI_MATCH(DMI_BOARD_NAME, "X360"),
- },
- .driver_data = &samsung_broken_acpi_video,
- },
- {
- .callback = samsung_dmi_matched,
- .ident = "N250P",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
- DMI_MATCH(DMI_BOARD_NAME, "N250P"),
- },
- .driver_data = &samsung_use_native_backlight,
- },
- {
- .callback = samsung_dmi_matched,
- .ident = "NC210",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
- DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
- },
- .driver_data = &samsung_broken_acpi_video,
- },
- {
- .callback = samsung_dmi_matched,
.ident = "730U3E/740U3E",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
@@ -1656,15 +1679,8 @@ static int __init samsung_init(void)
samsung->handle_backlight = true;
samsung->quirks = quirks;
-#ifdef CONFIG_ACPI
- if (samsung->quirks->broken_acpi_video)
- acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
- if (samsung->quirks->use_native_backlight)
- acpi_video_set_dmi_backlight_type(acpi_backlight_native);
-
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
samsung->handle_backlight = false;
-#endif
ret = samsung_platform_init(samsung);
if (ret)
@@ -1694,6 +1710,10 @@ static int __init samsung_init(void)
if (ret)
goto error_lid_handling;
+ ret = samsung_battery_hook_init(samsung);
+ if (ret)
+ goto error_lid_handling;
+
samsung_debugfs_init(samsung);
samsung->pm_nb.notifier_call = samsung_pm_notification;
@@ -1743,5 +1763,5 @@ module_init(samsung_init);
module_exit(samsung_exit);
MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
-MODULE_DESCRIPTION("Samsung Backlight driver");
+MODULE_DESCRIPTION("Samsung Laptop driver");
MODULE_LICENSE("GPL");