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.c325
1 files changed, 145 insertions, 180 deletions
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index 7b160ee98115..9d43a12db73c 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung Laptop driver
*
* Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
* Copyright (C) 2009,2011 Novell Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -18,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>
@@ -28,6 +24,7 @@
#include <linux/ctype.h>
#include <linux/efi.h>
#include <linux/suspend.h>
+#include <acpi/battery.h>
#include <acpi/video.h>
/*
@@ -156,7 +153,7 @@ struct sabi_config {
static const struct sabi_config sabi_configs[] = {
{
- /* I don't know if it is really 2, but it it is
+ /* I don't know if it is really 2, but it is
* less than 3 anyway */
.sabi_version = 2,
@@ -353,6 +350,8 @@ struct samsung_laptop {
struct notifier_block pm_nb;
+ struct acpi_battery_hook battery_hook;
+
bool handle_backlight;
bool has_stepping_quirk;
@@ -360,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,
@@ -392,7 +381,7 @@ MODULE_PARM_DESC(force,
"Disable the DMI check and forces the driver to be loaded");
static bool debug;
-module_param(debug, bool, S_IRUGO | S_IWUSR);
+module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug enabled or not");
static int sabi_command(struct samsung_laptop *samsung, u16 command,
@@ -568,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);
@@ -675,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,
@@ -709,9 +698,14 @@ static ssize_t set_performance_level(struct device *dev,
return count;
}
-static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
+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;
@@ -754,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,
@@ -768,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;
@@ -778,9 +776,87 @@ static ssize_t set_battery_life_extender(struct device *dev,
return count;
}
-static DEVICE_ATTR(battery_life_extender, S_IWUSR | S_IRUGO,
+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;
@@ -827,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,
@@ -847,7 +923,7 @@ static ssize_t set_usb_charge(struct device *dev,
return count;
}
-static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(usb_charge, 0644,
get_usb_charge, set_usb_charge);
static int read_lid_handling(struct samsung_laptop *samsung)
@@ -892,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,
@@ -912,7 +988,7 @@ static ssize_t set_lid_handling(struct device *dev,
return count;
}
-static DEVICE_ATTR(lid_handling, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(lid_handling, 0644,
get_lid_handling, set_lid_handling);
static struct attribute *platform_attributes[] = {
@@ -1058,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;
@@ -1125,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);
@@ -1142,8 +1231,7 @@ static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
static void samsung_leds_exit(struct samsung_laptop *samsung)
{
- if (!IS_ERR_OR_NULL(samsung->kbd_led.dev))
- led_classdev_unregister(&samsung->kbd_led);
+ led_classdev_unregister(&samsung->kbd_led);
if (samsung->led_workqueue)
destroy_workqueue(samsung->led_workqueue);
}
@@ -1206,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;
@@ -1215,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;
@@ -1280,15 +1368,12 @@ static void samsung_debugfs_exit(struct samsung_laptop *samsung)
debugfs_remove_recursive(samsung->debug.root);
}
-static int samsung_debugfs_init(struct samsung_laptop *samsung)
+static void samsung_debugfs_init(struct samsung_laptop *samsung)
{
- struct dentry *dent;
+ struct dentry *root;
- samsung->debug.root = debugfs_create_dir("samsung-laptop", NULL);
- if (!samsung->debug.root) {
- pr_err("failed to create debugfs directory");
- goto error_debugfs;
- }
+ root = debugfs_create_dir("samsung-laptop", NULL);
+ samsung->debug.root = root;
samsung->debug.f0000_wrapper.data = samsung->f0000_segment;
samsung->debug.f0000_wrapper.size = 0xffff;
@@ -1299,60 +1384,17 @@ static int samsung_debugfs_init(struct samsung_laptop *samsung)
samsung->debug.sdiag_wrapper.data = samsung->sdiag;
samsung->debug.sdiag_wrapper.size = strlen(samsung->sdiag);
- dent = debugfs_create_u16("command", S_IRUGO | S_IWUSR,
- samsung->debug.root, &samsung->debug.command);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_u32("d0", S_IRUGO | S_IWUSR, samsung->debug.root,
- &samsung->debug.data.d0);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_u32("d1", S_IRUGO | S_IWUSR, samsung->debug.root,
- &samsung->debug.data.d1);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_u16("d2", S_IRUGO | S_IWUSR, samsung->debug.root,
- &samsung->debug.data.d2);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_u8("d3", S_IRUGO | S_IWUSR, samsung->debug.root,
- &samsung->debug.data.d3);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_blob("data", S_IRUGO | S_IWUSR,
- samsung->debug.root,
- &samsung->debug.data_wrapper);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_blob("f0000_segment", S_IRUSR | S_IWUSR,
- samsung->debug.root,
- &samsung->debug.f0000_wrapper);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_file("call", S_IFREG | S_IRUGO,
- samsung->debug.root, samsung,
- &samsung_laptop_call_fops);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_blob("sdiag", S_IRUGO | S_IWUSR,
- samsung->debug.root,
- &samsung->debug.sdiag_wrapper);
- if (!dent)
- goto error_debugfs;
-
- return 0;
-
-error_debugfs:
- samsung_debugfs_exit(samsung);
- return -ENOMEM;
+ debugfs_create_u16("command", 0644, root, &samsung->debug.command);
+ debugfs_create_u32("d0", 0644, root, &samsung->debug.data.d0);
+ debugfs_create_u32("d1", 0644, root, &samsung->debug.data.d1);
+ debugfs_create_u16("d2", 0644, root, &samsung->debug.data.d2);
+ debugfs_create_u8("d3", 0644, root, &samsung->debug.data.d3);
+ debugfs_create_blob("data", 0444, root, &samsung->debug.data_wrapper);
+ debugfs_create_blob("f0000_segment", 0400, root,
+ &samsung->debug.f0000_wrapper);
+ debugfs_create_file("call", 0444, root, samsung,
+ &samsung_laptop_call_fops);
+ debugfs_create_blob("sdiag", 0444, root, &samsung->debug.sdiag_wrapper);
}
static void samsung_sabi_exit(struct samsung_laptop *samsung)
@@ -1437,7 +1479,7 @@ static int __init samsung_sabi_init(struct samsung_laptop *samsung)
int ret = 0;
int i;
- samsung->f0000_segment = ioremap_nocache(0xf0000, 0xffff);
+ samsung->f0000_segment = ioremap(0xf0000, 0xffff);
if (!samsung->f0000_segment) {
if (debug || force)
pr_err("Can't map the segment at 0xf0000\n");
@@ -1477,7 +1519,7 @@ static int __init samsung_sabi_init(struct samsung_laptop *samsung)
if (debug)
samsung_sabi_infos(samsung, loca, ifaceP);
- samsung->sabi_iface = ioremap_nocache(ifaceP, 16);
+ samsung->sabi_iface = ioremap(ifaceP, 16);
if (!samsung->sabi_iface) {
pr_err("Can't remap %x\n", ifaceP);
ret = -EINVAL;
@@ -1537,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);
@@ -1595,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."),
@@ -1707,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)
@@ -1745,9 +1710,11 @@ static int __init samsung_init(void)
if (ret)
goto error_lid_handling;
- ret = samsung_debugfs_init(samsung);
+ ret = samsung_battery_hook_init(samsung);
if (ret)
- goto error_debugfs;
+ goto error_lid_handling;
+
+ samsung_debugfs_init(samsung);
samsung->pm_nb.notifier_call = samsung_pm_notification;
register_pm_notifier(&samsung->pm_nb);
@@ -1755,8 +1722,6 @@ static int __init samsung_init(void)
samsung_platform_device = samsung->platform_device;
return ret;
-error_debugfs:
- samsung_lid_handling_exit(samsung);
error_lid_handling:
samsung_leds_exit(samsung);
error_leds:
@@ -1798,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");