aboutsummaryrefslogtreecommitdiffstats
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.c146
1 files changed, 139 insertions, 7 deletions
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index ff765d8e1a09..9e701b2256f9 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -124,6 +124,10 @@ struct sabi_commands {
124 u16 get_wireless_status; 124 u16 get_wireless_status;
125 u16 set_wireless_status; 125 u16 set_wireless_status;
126 126
127 /* 0x80 is off, 0x81 is on */
128 u16 get_lid_handling;
129 u16 set_lid_handling;
130
127 /* 0x81 to read, (0x82 | level << 8) to set, 0xaabb to enable */ 131 /* 0x81 to read, (0x82 | level << 8) to set, 0xaabb to enable */
128 u16 kbd_backlight; 132 u16 kbd_backlight;
129 133
@@ -194,6 +198,9 @@ static const struct sabi_config sabi_configs[] = {
194 .get_wireless_status = 0xFFFF, 198 .get_wireless_status = 0xFFFF,
195 .set_wireless_status = 0xFFFF, 199 .set_wireless_status = 0xFFFF,
196 200
201 .get_lid_handling = 0xFFFF,
202 .set_lid_handling = 0xFFFF,
203
197 .kbd_backlight = 0xFFFF, 204 .kbd_backlight = 0xFFFF,
198 205
199 .set_linux = 0x0a, 206 .set_linux = 0x0a,
@@ -254,6 +261,9 @@ static const struct sabi_config sabi_configs[] = {
254 .get_wireless_status = 0x69, 261 .get_wireless_status = 0x69,
255 .set_wireless_status = 0x6a, 262 .set_wireless_status = 0x6a,
256 263
264 .get_lid_handling = 0x6d,
265 .set_lid_handling = 0x6e,
266
257 .kbd_backlight = 0x78, 267 .kbd_backlight = 0x78,
258 268
259 .set_linux = 0xff, 269 .set_linux = 0xff,
@@ -353,6 +363,8 @@ struct samsung_quirks {
353 bool broken_acpi_video; 363 bool broken_acpi_video;
354 bool four_kbd_backlight_levels; 364 bool four_kbd_backlight_levels;
355 bool enable_kbd_backlight; 365 bool enable_kbd_backlight;
366 bool use_native_backlight;
367 bool lid_handling;
356}; 368};
357 369
358static struct samsung_quirks samsung_unknown = {}; 370static struct samsung_quirks samsung_unknown = {};
@@ -361,11 +373,19 @@ static struct samsung_quirks samsung_broken_acpi_video = {
361 .broken_acpi_video = true, 373 .broken_acpi_video = true,
362}; 374};
363 375
376static struct samsung_quirks samsung_use_native_backlight = {
377 .use_native_backlight = true,
378};
379
364static struct samsung_quirks samsung_np740u3e = { 380static struct samsung_quirks samsung_np740u3e = {
365 .four_kbd_backlight_levels = true, 381 .four_kbd_backlight_levels = true,
366 .enable_kbd_backlight = true, 382 .enable_kbd_backlight = true,
367}; 383};
368 384
385static struct samsung_quirks samsung_lid_handling = {
386 .lid_handling = true,
387};
388
369static bool force; 389static bool force;
370module_param(force, bool, 0); 390module_param(force, bool, 0);
371MODULE_PARM_DESC(force, 391MODULE_PARM_DESC(force,
@@ -748,7 +768,7 @@ static ssize_t set_battery_life_extender(struct device *dev,
748 struct samsung_laptop *samsung = dev_get_drvdata(dev); 768 struct samsung_laptop *samsung = dev_get_drvdata(dev);
749 int ret, value; 769 int ret, value;
750 770
751 if (!count || sscanf(buf, "%i", &value) != 1) 771 if (!count || kstrtoint(buf, 0, &value) != 0)
752 return -EINVAL; 772 return -EINVAL;
753 773
754 ret = write_battery_life_extender(samsung, !!value); 774 ret = write_battery_life_extender(samsung, !!value);
@@ -817,7 +837,7 @@ static ssize_t set_usb_charge(struct device *dev,
817 struct samsung_laptop *samsung = dev_get_drvdata(dev); 837 struct samsung_laptop *samsung = dev_get_drvdata(dev);
818 int ret, value; 838 int ret, value;
819 839
820 if (!count || sscanf(buf, "%i", &value) != 1) 840 if (!count || kstrtoint(buf, 0, &value) != 0)
821 return -EINVAL; 841 return -EINVAL;
822 842
823 ret = write_usb_charge(samsung, !!value); 843 ret = write_usb_charge(samsung, !!value);
@@ -830,10 +850,76 @@ static ssize_t set_usb_charge(struct device *dev,
830static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO, 850static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO,
831 get_usb_charge, set_usb_charge); 851 get_usb_charge, set_usb_charge);
832 852
853static int read_lid_handling(struct samsung_laptop *samsung)
854{
855 const struct sabi_commands *commands = &samsung->config->commands;
856 struct sabi_data data;
857 int retval;
858
859 if (commands->get_lid_handling == 0xFFFF)
860 return -ENODEV;
861
862 memset(&data, 0, sizeof(data));
863 retval = sabi_command(samsung, commands->get_lid_handling,
864 &data, &data);
865
866 if (retval)
867 return retval;
868
869 return data.data[0] & 0x1;
870}
871
872static int write_lid_handling(struct samsung_laptop *samsung,
873 int enabled)
874{
875 const struct sabi_commands *commands = &samsung->config->commands;
876 struct sabi_data data;
877
878 memset(&data, 0, sizeof(data));
879 data.data[0] = 0x80 | enabled;
880 return sabi_command(samsung, commands->set_lid_handling,
881 &data, NULL);
882}
883
884static ssize_t get_lid_handling(struct device *dev,
885 struct device_attribute *attr,
886 char *buf)
887{
888 struct samsung_laptop *samsung = dev_get_drvdata(dev);
889 int ret;
890
891 ret = read_lid_handling(samsung);
892 if (ret < 0)
893 return ret;
894
895 return sprintf(buf, "%d\n", ret);
896}
897
898static ssize_t set_lid_handling(struct device *dev,
899 struct device_attribute *attr,
900 const char *buf, size_t count)
901{
902 struct samsung_laptop *samsung = dev_get_drvdata(dev);
903 int ret, value;
904
905 if (!count || kstrtoint(buf, 0, &value) != 0)
906 return -EINVAL;
907
908 ret = write_lid_handling(samsung, !!value);
909 if (ret < 0)
910 return ret;
911
912 return count;
913}
914
915static DEVICE_ATTR(lid_handling, S_IWUSR | S_IRUGO,
916 get_lid_handling, set_lid_handling);
917
833static struct attribute *platform_attributes[] = { 918static struct attribute *platform_attributes[] = {
834 &dev_attr_performance_level.attr, 919 &dev_attr_performance_level.attr,
835 &dev_attr_battery_life_extender.attr, 920 &dev_attr_battery_life_extender.attr,
836 &dev_attr_usb_charge.attr, 921 &dev_attr_usb_charge.attr,
922 &dev_attr_lid_handling.attr,
837 NULL 923 NULL
838}; 924};
839 925
@@ -956,6 +1042,22 @@ static int __init samsung_rfkill_init(struct samsung_laptop *samsung)
956 return 0; 1042 return 0;
957} 1043}
958 1044
1045static void samsung_lid_handling_exit(struct samsung_laptop *samsung)
1046{
1047 if (samsung->quirks->lid_handling)
1048 write_lid_handling(samsung, 0);
1049}
1050
1051static int __init samsung_lid_handling_init(struct samsung_laptop *samsung)
1052{
1053 int retval = 0;
1054
1055 if (samsung->quirks->lid_handling)
1056 retval = write_lid_handling(samsung, 1);
1057
1058 return retval;
1059}
1060
959static int kbd_backlight_enable(struct samsung_laptop *samsung) 1061static int kbd_backlight_enable(struct samsung_laptop *samsung)
960{ 1062{
961 const struct sabi_commands *commands = &samsung->config->commands; 1063 const struct sabi_commands *commands = &samsung->config->commands;
@@ -1111,7 +1213,7 @@ static int __init samsung_backlight_init(struct samsung_laptop *samsung)
1111} 1213}
1112 1214
1113static umode_t samsung_sysfs_is_visible(struct kobject *kobj, 1215static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
1114 struct attribute *attr, int idx) 1216 struct attribute *attr, int idx)
1115{ 1217{
1116 struct device *dev = container_of(kobj, struct device, kobj); 1218 struct device *dev = container_of(kobj, struct device, kobj);
1117 struct platform_device *pdev = to_platform_device(dev); 1219 struct platform_device *pdev = to_platform_device(dev);
@@ -1124,6 +1226,8 @@ static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
1124 ok = !!(read_battery_life_extender(samsung) >= 0); 1226 ok = !!(read_battery_life_extender(samsung) >= 0);
1125 if (attr == &dev_attr_usb_charge.attr) 1227 if (attr == &dev_attr_usb_charge.attr)
1126 ok = !!(read_usb_charge(samsung) >= 0); 1228 ok = !!(read_usb_charge(samsung) >= 0);
1229 if (attr == &dev_attr_lid_handling.attr)
1230 ok = !!(read_lid_handling(samsung) >= 0);
1127 1231
1128 return ok ? attr->mode : 0; 1232 return ok ? attr->mode : 0;
1129} 1233}
@@ -1357,7 +1461,7 @@ static int __init samsung_sabi_init(struct samsung_laptop *samsung)
1357 samsung_sabi_diag(samsung); 1461 samsung_sabi_diag(samsung);
1358 1462
1359 /* Try to find one of the signatures in memory to find the header */ 1463 /* Try to find one of the signatures in memory to find the header */
1360 for (i = 0; sabi_configs[i].test_string != 0; ++i) { 1464 for (i = 0; sabi_configs[i].test_string != NULL; ++i) {
1361 samsung->config = &sabi_configs[i]; 1465 samsung->config = &sabi_configs[i];
1362 loca = find_signature(samsung->f0000_segment, 1466 loca = find_signature(samsung->f0000_segment,
1363 samsung->config->test_string); 1467 samsung->config->test_string);
@@ -1436,6 +1540,9 @@ static int samsung_pm_notification(struct notifier_block *nb,
1436 samsung->quirks->enable_kbd_backlight) 1540 samsung->quirks->enable_kbd_backlight)
1437 kbd_backlight_enable(samsung); 1541 kbd_backlight_enable(samsung);
1438 1542
1543 if (val == PM_POST_HIBERNATION && samsung->quirks->lid_handling)
1544 write_lid_handling(samsung, 1);
1545
1439 return 0; 1546 return 0;
1440} 1547}
1441 1548
@@ -1507,7 +1614,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
1507 DMI_MATCH(DMI_PRODUCT_NAME, "N150P"), 1614 DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
1508 DMI_MATCH(DMI_BOARD_NAME, "N150P"), 1615 DMI_MATCH(DMI_BOARD_NAME, "N150P"),
1509 }, 1616 },
1510 .driver_data = &samsung_broken_acpi_video, 1617 .driver_data = &samsung_use_native_backlight,
1511 }, 1618 },
1512 { 1619 {
1513 .callback = samsung_dmi_matched, 1620 .callback = samsung_dmi_matched,
@@ -1517,7 +1624,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
1517 DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), 1624 DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
1518 DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), 1625 DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
1519 }, 1626 },
1520 .driver_data = &samsung_broken_acpi_video, 1627 .driver_data = &samsung_use_native_backlight,
1521 }, 1628 },
1522 { 1629 {
1523 .callback = samsung_dmi_matched, 1630 .callback = samsung_dmi_matched,
@@ -1557,7 +1664,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
1557 DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), 1664 DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
1558 DMI_MATCH(DMI_BOARD_NAME, "N250P"), 1665 DMI_MATCH(DMI_BOARD_NAME, "N250P"),
1559 }, 1666 },
1560 .driver_data = &samsung_broken_acpi_video, 1667 .driver_data = &samsung_use_native_backlight,
1561 }, 1668 },
1562 { 1669 {
1563 .callback = samsung_dmi_matched, 1670 .callback = samsung_dmi_matched,
@@ -1578,6 +1685,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
1578 }, 1685 },
1579 .driver_data = &samsung_np740u3e, 1686 .driver_data = &samsung_np740u3e,
1580 }, 1687 },
1688 {
1689 .callback = samsung_dmi_matched,
1690 .ident = "300V3Z/300V4Z/300V5Z",
1691 .matches = {
1692 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1693 DMI_MATCH(DMI_PRODUCT_NAME, "300V3Z/300V4Z/300V5Z"),
1694 },
1695 .driver_data = &samsung_lid_handling,
1696 },
1581 { }, 1697 { },
1582}; 1698};
1583MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); 1699MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
@@ -1616,6 +1732,15 @@ static int __init samsung_init(void)
1616 pr_info("Disabling ACPI video driver\n"); 1732 pr_info("Disabling ACPI video driver\n");
1617 acpi_video_unregister(); 1733 acpi_video_unregister();
1618 } 1734 }
1735
1736 if (samsung->quirks->use_native_backlight) {
1737 pr_info("Using native backlight driver\n");
1738 /* Tell acpi-video to not handle the backlight */
1739 acpi_video_dmi_promote_vendor();
1740 acpi_video_unregister();
1741 /* And also do not handle it ourselves */
1742 samsung->handle_backlight = false;
1743 }
1619#endif 1744#endif
1620 1745
1621 ret = samsung_platform_init(samsung); 1746 ret = samsung_platform_init(samsung);
@@ -1648,6 +1773,10 @@ static int __init samsung_init(void)
1648 if (ret) 1773 if (ret)
1649 goto error_leds; 1774 goto error_leds;
1650 1775
1776 ret = samsung_lid_handling_init(samsung);
1777 if (ret)
1778 goto error_lid_handling;
1779
1651 ret = samsung_debugfs_init(samsung); 1780 ret = samsung_debugfs_init(samsung);
1652 if (ret) 1781 if (ret)
1653 goto error_debugfs; 1782 goto error_debugfs;
@@ -1659,6 +1788,8 @@ static int __init samsung_init(void)
1659 return ret; 1788 return ret;
1660 1789
1661error_debugfs: 1790error_debugfs:
1791 samsung_lid_handling_exit(samsung);
1792error_lid_handling:
1662 samsung_leds_exit(samsung); 1793 samsung_leds_exit(samsung);
1663error_leds: 1794error_leds:
1664 samsung_rfkill_exit(samsung); 1795 samsung_rfkill_exit(samsung);
@@ -1683,6 +1814,7 @@ static void __exit samsung_exit(void)
1683 unregister_pm_notifier(&samsung->pm_nb); 1814 unregister_pm_notifier(&samsung->pm_nb);
1684 1815
1685 samsung_debugfs_exit(samsung); 1816 samsung_debugfs_exit(samsung);
1817 samsung_lid_handling_exit(samsung);
1686 samsung_leds_exit(samsung); 1818 samsung_leds_exit(samsung);
1687 samsung_rfkill_exit(samsung); 1819 samsung_rfkill_exit(samsung);
1688 samsung_backlight_exit(samsung); 1820 samsung_backlight_exit(samsung);