156f529ceSJoshua Grisham // SPDX-License-Identifier: GPL-2.0-or-later
256f529ceSJoshua Grisham /*
356f529ceSJoshua Grisham * Samsung Galaxy Book driver
456f529ceSJoshua Grisham *
556f529ceSJoshua Grisham * Copyright (c) 2025 Joshua Grisham <josh@joshuagrisham.com>
656f529ceSJoshua Grisham *
756f529ceSJoshua Grisham * With contributions to the SCAI ACPI device interface:
856f529ceSJoshua Grisham * Copyright (c) 2024 Giulio Girardi <giulio.girardi@protechgroup.it>
956f529ceSJoshua Grisham *
1056f529ceSJoshua Grisham * Implementation inspired by existing x86 platform drivers.
1156f529ceSJoshua Grisham * Thank you to the authors!
1256f529ceSJoshua Grisham */
1356f529ceSJoshua Grisham
1456f529ceSJoshua Grisham #include <linux/acpi.h>
1556f529ceSJoshua Grisham #include <linux/bits.h>
1656f529ceSJoshua Grisham #include <linux/err.h>
1756f529ceSJoshua Grisham #include <linux/i8042.h>
1856f529ceSJoshua Grisham #include <linux/init.h>
1956f529ceSJoshua Grisham #include <linux/input.h>
2056f529ceSJoshua Grisham #include <linux/kernel.h>
2156f529ceSJoshua Grisham #include <linux/leds.h>
2256f529ceSJoshua Grisham #include <linux/module.h>
2356f529ceSJoshua Grisham #include <linux/mutex.h>
2456f529ceSJoshua Grisham #include <linux/platform_device.h>
2556f529ceSJoshua Grisham #include <linux/platform_profile.h>
2656f529ceSJoshua Grisham #include <linux/serio.h>
2756f529ceSJoshua Grisham #include <linux/sysfs.h>
2856f529ceSJoshua Grisham #include <linux/uuid.h>
2956f529ceSJoshua Grisham #include <linux/workqueue.h>
3056f529ceSJoshua Grisham #include <acpi/battery.h>
3156f529ceSJoshua Grisham #include "firmware_attributes_class.h"
3256f529ceSJoshua Grisham
3356f529ceSJoshua Grisham #define DRIVER_NAME "samsung-galaxybook"
3456f529ceSJoshua Grisham
3556f529ceSJoshua Grisham struct samsung_galaxybook {
3656f529ceSJoshua Grisham struct platform_device *platform;
3756f529ceSJoshua Grisham struct acpi_device *acpi;
3856f529ceSJoshua Grisham
3956f529ceSJoshua Grisham struct device *fw_attrs_dev;
4056f529ceSJoshua Grisham struct kset *fw_attrs_kset;
4156f529ceSJoshua Grisham /* block in case firmware attributes are updated in multiple threads */
4256f529ceSJoshua Grisham struct mutex fw_attr_lock;
4356f529ceSJoshua Grisham
4456f529ceSJoshua Grisham bool has_kbd_backlight;
4556f529ceSJoshua Grisham bool has_block_recording;
4656f529ceSJoshua Grisham bool has_performance_mode;
4756f529ceSJoshua Grisham
4856f529ceSJoshua Grisham struct led_classdev kbd_backlight;
4956f529ceSJoshua Grisham struct work_struct kbd_backlight_hotkey_work;
5056f529ceSJoshua Grisham /* block in case brightness updated using hotkey and another thread */
5156f529ceSJoshua Grisham struct mutex kbd_backlight_lock;
5256f529ceSJoshua Grisham
5356f529ceSJoshua Grisham void *i8042_filter_ptr;
5456f529ceSJoshua Grisham
5556f529ceSJoshua Grisham struct work_struct block_recording_hotkey_work;
5656f529ceSJoshua Grisham struct input_dev *camera_lens_cover_switch;
5756f529ceSJoshua Grisham
5856f529ceSJoshua Grisham struct acpi_battery_hook battery_hook;
5956f529ceSJoshua Grisham
6056f529ceSJoshua Grisham u8 profile_performance_modes[PLATFORM_PROFILE_LAST];
6156f529ceSJoshua Grisham };
6256f529ceSJoshua Grisham
6356f529ceSJoshua Grisham enum galaxybook_fw_attr_id {
6456f529ceSJoshua Grisham GB_ATTR_POWER_ON_LID_OPEN,
6556f529ceSJoshua Grisham GB_ATTR_USB_CHARGING,
6656f529ceSJoshua Grisham GB_ATTR_BLOCK_RECORDING,
6756f529ceSJoshua Grisham };
6856f529ceSJoshua Grisham
6956f529ceSJoshua Grisham static const char * const galaxybook_fw_attr_name[] = {
7056f529ceSJoshua Grisham [GB_ATTR_POWER_ON_LID_OPEN] = "power_on_lid_open",
7156f529ceSJoshua Grisham [GB_ATTR_USB_CHARGING] = "usb_charging",
7256f529ceSJoshua Grisham [GB_ATTR_BLOCK_RECORDING] = "block_recording",
7356f529ceSJoshua Grisham };
7456f529ceSJoshua Grisham
7556f529ceSJoshua Grisham static const char * const galaxybook_fw_attr_desc[] = {
7656f529ceSJoshua Grisham [GB_ATTR_POWER_ON_LID_OPEN] = "Power On Lid Open",
7756f529ceSJoshua Grisham [GB_ATTR_USB_CHARGING] = "USB Charging",
7856f529ceSJoshua Grisham [GB_ATTR_BLOCK_RECORDING] = "Block Recording",
7956f529ceSJoshua Grisham };
8056f529ceSJoshua Grisham
8156f529ceSJoshua Grisham #define GB_ATTR_LANGUAGE_CODE "en_US.UTF-8"
8256f529ceSJoshua Grisham
8356f529ceSJoshua Grisham struct galaxybook_fw_attr {
8456f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook;
8556f529ceSJoshua Grisham enum galaxybook_fw_attr_id fw_attr_id;
8656f529ceSJoshua Grisham struct attribute_group attr_group;
8756f529ceSJoshua Grisham struct kobj_attribute display_name;
8856f529ceSJoshua Grisham struct kobj_attribute current_value;
8956f529ceSJoshua Grisham int (*get_value)(struct samsung_galaxybook *galaxybook, bool *value);
9056f529ceSJoshua Grisham int (*set_value)(struct samsung_galaxybook *galaxybook, const bool value);
9156f529ceSJoshua Grisham };
9256f529ceSJoshua Grisham
9356f529ceSJoshua Grisham struct sawb {
9456f529ceSJoshua Grisham u16 safn;
9556f529ceSJoshua Grisham u16 sasb;
9656f529ceSJoshua Grisham u8 rflg;
9756f529ceSJoshua Grisham union {
9856f529ceSJoshua Grisham struct {
9956f529ceSJoshua Grisham u8 gunm;
10056f529ceSJoshua Grisham u8 guds[250];
10156f529ceSJoshua Grisham } __packed;
10256f529ceSJoshua Grisham struct {
10356f529ceSJoshua Grisham u8 caid[16];
10456f529ceSJoshua Grisham u8 fncn;
10556f529ceSJoshua Grisham u8 subn;
10656f529ceSJoshua Grisham u8 iob0;
10756f529ceSJoshua Grisham u8 iob1;
10856f529ceSJoshua Grisham u8 iob2;
10956f529ceSJoshua Grisham u8 iob3;
11056f529ceSJoshua Grisham u8 iob4;
11156f529ceSJoshua Grisham u8 iob5;
11256f529ceSJoshua Grisham u8 iob6;
11356f529ceSJoshua Grisham u8 iob7;
11456f529ceSJoshua Grisham u8 iob8;
11556f529ceSJoshua Grisham u8 iob9;
11656f529ceSJoshua Grisham } __packed;
11756f529ceSJoshua Grisham struct {
11856f529ceSJoshua Grisham u8 iob_prefix[18];
11956f529ceSJoshua Grisham u8 iobs[10];
12056f529ceSJoshua Grisham } __packed;
12156f529ceSJoshua Grisham } __packed;
12256f529ceSJoshua Grisham } __packed;
12356f529ceSJoshua Grisham
12456f529ceSJoshua Grisham #define GB_SAWB_LEN_SETTINGS 0x15
12556f529ceSJoshua Grisham #define GB_SAWB_LEN_PERFORMANCE_MODE 0x100
12656f529ceSJoshua Grisham
12756f529ceSJoshua Grisham #define GB_SAFN 0x5843
12856f529ceSJoshua Grisham
12956f529ceSJoshua Grisham #define GB_SASB_KBD_BACKLIGHT 0x78
13056f529ceSJoshua Grisham #define GB_SASB_POWER_MANAGEMENT 0x7a
13156f529ceSJoshua Grisham #define GB_SASB_USB_CHARGING_GET 0x67
13256f529ceSJoshua Grisham #define GB_SASB_USB_CHARGING_SET 0x68
13356f529ceSJoshua Grisham #define GB_SASB_NOTIFICATIONS 0x86
13456f529ceSJoshua Grisham #define GB_SASB_BLOCK_RECORDING 0x8a
13556f529ceSJoshua Grisham #define GB_SASB_PERFORMANCE_MODE 0x91
13656f529ceSJoshua Grisham
13756f529ceSJoshua Grisham #define GB_SAWB_RFLG_POS 4
13856f529ceSJoshua Grisham #define GB_SAWB_GB_GUNM_POS 5
13956f529ceSJoshua Grisham
14056f529ceSJoshua Grisham #define GB_RFLG_SUCCESS 0xaa
14156f529ceSJoshua Grisham #define GB_GUNM_FAIL 0xff
14256f529ceSJoshua Grisham
14356f529ceSJoshua Grisham #define GB_GUNM_FEATURE_ENABLE 0xbb
14456f529ceSJoshua Grisham #define GB_GUNM_FEATURE_ENABLE_SUCCESS 0xdd
14556f529ceSJoshua Grisham #define GB_GUDS_FEATURE_ENABLE 0xaa
14656f529ceSJoshua Grisham #define GB_GUDS_FEATURE_ENABLE_SUCCESS 0xcc
14756f529ceSJoshua Grisham
14856f529ceSJoshua Grisham #define GB_GUNM_GET 0x81
14956f529ceSJoshua Grisham #define GB_GUNM_SET 0x82
15056f529ceSJoshua Grisham
15156f529ceSJoshua Grisham #define GB_GUNM_POWER_MANAGEMENT 0x82
15256f529ceSJoshua Grisham
15356f529ceSJoshua Grisham #define GB_GUNM_USB_CHARGING_GET 0x80
15456f529ceSJoshua Grisham #define GB_GUNM_USB_CHARGING_ON 0x81
15556f529ceSJoshua Grisham #define GB_GUNM_USB_CHARGING_OFF 0x80
15656f529ceSJoshua Grisham #define GB_GUDS_POWER_ON_LID_OPEN 0xa3
15756f529ceSJoshua Grisham #define GB_GUDS_POWER_ON_LID_OPEN_GET 0x81
15856f529ceSJoshua Grisham #define GB_GUDS_POWER_ON_LID_OPEN_SET 0x80
15956f529ceSJoshua Grisham #define GB_GUDS_BATTERY_CHARGE_CONTROL 0xe9
16056f529ceSJoshua Grisham #define GB_GUDS_BATTERY_CHARGE_CONTROL_GET 0x91
16156f529ceSJoshua Grisham #define GB_GUDS_BATTERY_CHARGE_CONTROL_SET 0x90
16256f529ceSJoshua Grisham #define GB_GUNM_ACPI_NOTIFY_ENABLE 0x80
16356f529ceSJoshua Grisham #define GB_GUDS_ACPI_NOTIFY_ENABLE 0x02
16456f529ceSJoshua Grisham
16556f529ceSJoshua Grisham #define GB_BLOCK_RECORDING_ON 0x0
16656f529ceSJoshua Grisham #define GB_BLOCK_RECORDING_OFF 0x1
16756f529ceSJoshua Grisham
16856f529ceSJoshua Grisham #define GB_FNCN_PERFORMANCE_MODE 0x51
16956f529ceSJoshua Grisham #define GB_SUBN_PERFORMANCE_MODE_LIST 0x01
17056f529ceSJoshua Grisham #define GB_SUBN_PERFORMANCE_MODE_GET 0x02
17156f529ceSJoshua Grisham #define GB_SUBN_PERFORMANCE_MODE_SET 0x03
17256f529ceSJoshua Grisham
17356f529ceSJoshua Grisham /* guid 8246028d-8bca-4a55-ba0f-6f1e6b921b8f */
17456f529ceSJoshua Grisham static const guid_t performance_mode_guid =
17556f529ceSJoshua Grisham GUID_INIT(0x8246028d, 0x8bca, 0x4a55, 0xba, 0x0f, 0x6f, 0x1e, 0x6b, 0x92, 0x1b, 0x8f);
17656f529ceSJoshua Grisham #define GB_PERFORMANCE_MODE_GUID performance_mode_guid
17756f529ceSJoshua Grisham
17856f529ceSJoshua Grisham #define GB_PERFORMANCE_MODE_FANOFF 0xb
17956f529ceSJoshua Grisham #define GB_PERFORMANCE_MODE_LOWNOISE 0xa
18056f529ceSJoshua Grisham #define GB_PERFORMANCE_MODE_OPTIMIZED 0x0
18156f529ceSJoshua Grisham #define GB_PERFORMANCE_MODE_OPTIMIZED_V2 0x2
18256f529ceSJoshua Grisham #define GB_PERFORMANCE_MODE_PERFORMANCE 0x1
18356f529ceSJoshua Grisham #define GB_PERFORMANCE_MODE_PERFORMANCE_V2 0x15
18456f529ceSJoshua Grisham #define GB_PERFORMANCE_MODE_ULTRA 0x16
18556f529ceSJoshua Grisham #define GB_PERFORMANCE_MODE_IGNORE1 0x14
18656f529ceSJoshua Grisham #define GB_PERFORMANCE_MODE_IGNORE2 0xc
18756f529ceSJoshua Grisham
18856f529ceSJoshua Grisham #define GB_ACPI_METHOD_ENABLE "SDLS"
18956f529ceSJoshua Grisham #define GB_ACPI_METHOD_ENABLE_ON 1
19056f529ceSJoshua Grisham #define GB_ACPI_METHOD_ENABLE_OFF 0
19156f529ceSJoshua Grisham #define GB_ACPI_METHOD_SETTINGS "CSFI"
19256f529ceSJoshua Grisham #define GB_ACPI_METHOD_PERFORMANCE_MODE "CSXI"
19356f529ceSJoshua Grisham
19456f529ceSJoshua Grisham #define GB_KBD_BACKLIGHT_MAX_BRIGHTNESS 3
19556f529ceSJoshua Grisham
19656f529ceSJoshua Grisham #define GB_ACPI_NOTIFY_BATTERY_STATE_CHANGED 0x61
19756f529ceSJoshua Grisham #define GB_ACPI_NOTIFY_DEVICE_ON_TABLE 0x6c
19856f529ceSJoshua Grisham #define GB_ACPI_NOTIFY_DEVICE_OFF_TABLE 0x6d
19956f529ceSJoshua Grisham #define GB_ACPI_NOTIFY_HOTKEY_PERFORMANCE_MODE 0x70
20056f529ceSJoshua Grisham
20156f529ceSJoshua Grisham #define GB_KEY_KBD_BACKLIGHT_KEYDOWN 0x2c
20256f529ceSJoshua Grisham #define GB_KEY_KBD_BACKLIGHT_KEYUP 0xac
20356f529ceSJoshua Grisham #define GB_KEY_BLOCK_RECORDING_KEYDOWN 0x1f
20456f529ceSJoshua Grisham #define GB_KEY_BLOCK_RECORDING_KEYUP 0x9f
20556f529ceSJoshua Grisham #define GB_KEY_BATTERY_NOTIFY_KEYUP 0xf
20656f529ceSJoshua Grisham #define GB_KEY_BATTERY_NOTIFY_KEYDOWN 0x8f
20756f529ceSJoshua Grisham
20856f529ceSJoshua Grisham /*
20956f529ceSJoshua Grisham * Optional features which have been determined as not supported on a particular
21056f529ceSJoshua Grisham * device will return GB_NOT_SUPPORTED from their init function. Positive
21156f529ceSJoshua Grisham * EOPNOTSUPP is used as the underlying value instead of negative to
21256f529ceSJoshua Grisham * differentiate this return code from valid upstream failures.
21356f529ceSJoshua Grisham */
21456f529ceSJoshua Grisham #define GB_NOT_SUPPORTED EOPNOTSUPP /* Galaxy Book feature not supported */
21556f529ceSJoshua Grisham
21656f529ceSJoshua Grisham /*
21756f529ceSJoshua Grisham * ACPI method handling
21856f529ceSJoshua Grisham */
21956f529ceSJoshua Grisham
galaxybook_acpi_method(struct samsung_galaxybook * galaxybook,acpi_string method,struct sawb * buf,size_t len)22056f529ceSJoshua Grisham static int galaxybook_acpi_method(struct samsung_galaxybook *galaxybook, acpi_string method,
22156f529ceSJoshua Grisham struct sawb *buf, size_t len)
22256f529ceSJoshua Grisham {
22356f529ceSJoshua Grisham struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
22456f529ceSJoshua Grisham union acpi_object in_obj, *out_obj;
22556f529ceSJoshua Grisham struct acpi_object_list input;
22656f529ceSJoshua Grisham acpi_status status;
22756f529ceSJoshua Grisham int err;
22856f529ceSJoshua Grisham
22956f529ceSJoshua Grisham in_obj.type = ACPI_TYPE_BUFFER;
23056f529ceSJoshua Grisham in_obj.buffer.length = len;
23156f529ceSJoshua Grisham in_obj.buffer.pointer = (u8 *)buf;
23256f529ceSJoshua Grisham
23356f529ceSJoshua Grisham input.count = 1;
23456f529ceSJoshua Grisham input.pointer = &in_obj;
23556f529ceSJoshua Grisham
23656f529ceSJoshua Grisham status = acpi_evaluate_object_typed(galaxybook->acpi->handle, method, &input, &output,
23756f529ceSJoshua Grisham ACPI_TYPE_BUFFER);
23856f529ceSJoshua Grisham
23956f529ceSJoshua Grisham if (ACPI_FAILURE(status)) {
24056f529ceSJoshua Grisham dev_err(&galaxybook->acpi->dev, "failed to execute method %s; got %s\n",
24156f529ceSJoshua Grisham method, acpi_format_exception(status));
24256f529ceSJoshua Grisham return -EIO;
24356f529ceSJoshua Grisham }
24456f529ceSJoshua Grisham
24556f529ceSJoshua Grisham out_obj = output.pointer;
24656f529ceSJoshua Grisham
24756f529ceSJoshua Grisham if (out_obj->buffer.length != len || out_obj->buffer.length < GB_SAWB_GB_GUNM_POS + 1) {
24856f529ceSJoshua Grisham dev_err(&galaxybook->acpi->dev,
24956f529ceSJoshua Grisham "failed to execute %s; response length mismatch\n",
25056f529ceSJoshua Grisham method);
25156f529ceSJoshua Grisham err = -EPROTO;
25256f529ceSJoshua Grisham goto out_free;
25356f529ceSJoshua Grisham }
25456f529ceSJoshua Grisham if (out_obj->buffer.pointer[GB_SAWB_RFLG_POS] != GB_RFLG_SUCCESS) {
25556f529ceSJoshua Grisham dev_err(&galaxybook->acpi->dev,
25656f529ceSJoshua Grisham "failed to execute %s; device did not respond with success code 0x%x\n",
25756f529ceSJoshua Grisham method, GB_RFLG_SUCCESS);
25856f529ceSJoshua Grisham err = -ENXIO;
25956f529ceSJoshua Grisham goto out_free;
26056f529ceSJoshua Grisham }
26156f529ceSJoshua Grisham if (out_obj->buffer.pointer[GB_SAWB_GB_GUNM_POS] == GB_GUNM_FAIL) {
26256f529ceSJoshua Grisham dev_err(&galaxybook->acpi->dev,
26356f529ceSJoshua Grisham "failed to execute %s; device responded with failure code 0x%x\n",
26456f529ceSJoshua Grisham method, GB_GUNM_FAIL);
26556f529ceSJoshua Grisham err = -ENXIO;
26656f529ceSJoshua Grisham goto out_free;
26756f529ceSJoshua Grisham }
26856f529ceSJoshua Grisham
26956f529ceSJoshua Grisham memcpy(buf, out_obj->buffer.pointer, len);
27056f529ceSJoshua Grisham err = 0;
27156f529ceSJoshua Grisham
27256f529ceSJoshua Grisham out_free:
27356f529ceSJoshua Grisham kfree(out_obj);
27456f529ceSJoshua Grisham return err;
27556f529ceSJoshua Grisham }
27656f529ceSJoshua Grisham
galaxybook_enable_acpi_feature(struct samsung_galaxybook * galaxybook,const u16 sasb)27756f529ceSJoshua Grisham static int galaxybook_enable_acpi_feature(struct samsung_galaxybook *galaxybook, const u16 sasb)
27856f529ceSJoshua Grisham {
27956f529ceSJoshua Grisham struct sawb buf = {};
28056f529ceSJoshua Grisham int err;
28156f529ceSJoshua Grisham
28256f529ceSJoshua Grisham buf.safn = GB_SAFN;
28356f529ceSJoshua Grisham buf.sasb = sasb;
28456f529ceSJoshua Grisham buf.gunm = GB_GUNM_FEATURE_ENABLE;
28556f529ceSJoshua Grisham buf.guds[0] = GB_GUDS_FEATURE_ENABLE;
28656f529ceSJoshua Grisham
28756f529ceSJoshua Grisham err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
28856f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
28956f529ceSJoshua Grisham if (err)
29056f529ceSJoshua Grisham return err;
29156f529ceSJoshua Grisham
29256f529ceSJoshua Grisham if (buf.gunm != GB_GUNM_FEATURE_ENABLE_SUCCESS &&
29356f529ceSJoshua Grisham buf.guds[0] != GB_GUDS_FEATURE_ENABLE_SUCCESS)
29456f529ceSJoshua Grisham return -ENODEV;
29556f529ceSJoshua Grisham
29656f529ceSJoshua Grisham return 0;
29756f529ceSJoshua Grisham }
29856f529ceSJoshua Grisham
29956f529ceSJoshua Grisham /*
30056f529ceSJoshua Grisham * Keyboard Backlight
30156f529ceSJoshua Grisham */
30256f529ceSJoshua Grisham
kbd_backlight_acpi_get(struct samsung_galaxybook * galaxybook,enum led_brightness * brightness)30356f529ceSJoshua Grisham static int kbd_backlight_acpi_get(struct samsung_galaxybook *galaxybook,
30456f529ceSJoshua Grisham enum led_brightness *brightness)
30556f529ceSJoshua Grisham {
30656f529ceSJoshua Grisham struct sawb buf = {};
30756f529ceSJoshua Grisham int err;
30856f529ceSJoshua Grisham
30956f529ceSJoshua Grisham buf.safn = GB_SAFN;
31056f529ceSJoshua Grisham buf.sasb = GB_SASB_KBD_BACKLIGHT;
31156f529ceSJoshua Grisham buf.gunm = GB_GUNM_GET;
31256f529ceSJoshua Grisham
31356f529ceSJoshua Grisham err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
31456f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
31556f529ceSJoshua Grisham if (err)
31656f529ceSJoshua Grisham return err;
31756f529ceSJoshua Grisham
31856f529ceSJoshua Grisham *brightness = buf.gunm;
31956f529ceSJoshua Grisham
32056f529ceSJoshua Grisham return 0;
32156f529ceSJoshua Grisham }
32256f529ceSJoshua Grisham
kbd_backlight_acpi_set(struct samsung_galaxybook * galaxybook,const enum led_brightness brightness)32356f529ceSJoshua Grisham static int kbd_backlight_acpi_set(struct samsung_galaxybook *galaxybook,
32456f529ceSJoshua Grisham const enum led_brightness brightness)
32556f529ceSJoshua Grisham {
32656f529ceSJoshua Grisham struct sawb buf = {};
32756f529ceSJoshua Grisham
32856f529ceSJoshua Grisham buf.safn = GB_SAFN;
32956f529ceSJoshua Grisham buf.sasb = GB_SASB_KBD_BACKLIGHT;
33056f529ceSJoshua Grisham buf.gunm = GB_GUNM_SET;
33156f529ceSJoshua Grisham
33256f529ceSJoshua Grisham buf.guds[0] = brightness;
33356f529ceSJoshua Grisham
33456f529ceSJoshua Grisham return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
33556f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
33656f529ceSJoshua Grisham }
33756f529ceSJoshua Grisham
kbd_backlight_show(struct led_classdev * led)33856f529ceSJoshua Grisham static enum led_brightness kbd_backlight_show(struct led_classdev *led)
33956f529ceSJoshua Grisham {
34056f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook =
34156f529ceSJoshua Grisham container_of(led, struct samsung_galaxybook, kbd_backlight);
34256f529ceSJoshua Grisham enum led_brightness brightness;
34356f529ceSJoshua Grisham int err;
34456f529ceSJoshua Grisham
34556f529ceSJoshua Grisham err = kbd_backlight_acpi_get(galaxybook, &brightness);
34656f529ceSJoshua Grisham if (err)
34756f529ceSJoshua Grisham return err;
34856f529ceSJoshua Grisham
34956f529ceSJoshua Grisham return brightness;
35056f529ceSJoshua Grisham }
35156f529ceSJoshua Grisham
kbd_backlight_store(struct led_classdev * led,const enum led_brightness brightness)35256f529ceSJoshua Grisham static int kbd_backlight_store(struct led_classdev *led,
35356f529ceSJoshua Grisham const enum led_brightness brightness)
35456f529ceSJoshua Grisham {
35556f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook =
35656f529ceSJoshua Grisham container_of_const(led, struct samsung_galaxybook, kbd_backlight);
35756f529ceSJoshua Grisham
35856f529ceSJoshua Grisham return kbd_backlight_acpi_set(galaxybook, brightness);
35956f529ceSJoshua Grisham }
36056f529ceSJoshua Grisham
galaxybook_kbd_backlight_init(struct samsung_galaxybook * galaxybook)36156f529ceSJoshua Grisham static int galaxybook_kbd_backlight_init(struct samsung_galaxybook *galaxybook)
36256f529ceSJoshua Grisham {
36356f529ceSJoshua Grisham struct led_init_data init_data = {};
36456f529ceSJoshua Grisham enum led_brightness brightness;
36556f529ceSJoshua Grisham int err;
36656f529ceSJoshua Grisham
36756f529ceSJoshua Grisham err = devm_mutex_init(&galaxybook->platform->dev, &galaxybook->kbd_backlight_lock);
36856f529ceSJoshua Grisham if (err)
36956f529ceSJoshua Grisham return err;
37056f529ceSJoshua Grisham
37156f529ceSJoshua Grisham err = galaxybook_enable_acpi_feature(galaxybook, GB_SASB_KBD_BACKLIGHT);
37256f529ceSJoshua Grisham if (err) {
37356f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev,
37456f529ceSJoshua Grisham "failed to enable kbd_backlight feature, error %d\n", err);
37556f529ceSJoshua Grisham return GB_NOT_SUPPORTED;
37656f529ceSJoshua Grisham }
37756f529ceSJoshua Grisham
37856f529ceSJoshua Grisham err = kbd_backlight_acpi_get(galaxybook, &brightness);
37956f529ceSJoshua Grisham if (err) {
38056f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev,
38156f529ceSJoshua Grisham "failed to get initial kbd_backlight brightness, error %d\n", err);
38256f529ceSJoshua Grisham return GB_NOT_SUPPORTED;
38356f529ceSJoshua Grisham }
38456f529ceSJoshua Grisham
38556f529ceSJoshua Grisham init_data.devicename = DRIVER_NAME;
38656f529ceSJoshua Grisham init_data.default_label = ":" LED_FUNCTION_KBD_BACKLIGHT;
38756f529ceSJoshua Grisham init_data.devname_mandatory = true;
38856f529ceSJoshua Grisham
38956f529ceSJoshua Grisham galaxybook->kbd_backlight.brightness_get = kbd_backlight_show;
39056f529ceSJoshua Grisham galaxybook->kbd_backlight.brightness_set_blocking = kbd_backlight_store;
39156f529ceSJoshua Grisham galaxybook->kbd_backlight.flags = LED_BRIGHT_HW_CHANGED;
39256f529ceSJoshua Grisham galaxybook->kbd_backlight.max_brightness = GB_KBD_BACKLIGHT_MAX_BRIGHTNESS;
39356f529ceSJoshua Grisham
39456f529ceSJoshua Grisham return devm_led_classdev_register_ext(&galaxybook->platform->dev,
39556f529ceSJoshua Grisham &galaxybook->kbd_backlight, &init_data);
39656f529ceSJoshua Grisham }
39756f529ceSJoshua Grisham
39856f529ceSJoshua Grisham /*
39956f529ceSJoshua Grisham * Battery Extension (adds charge_control_end_threshold to the battery device)
40056f529ceSJoshua Grisham */
40156f529ceSJoshua Grisham
charge_control_end_threshold_acpi_get(struct samsung_galaxybook * galaxybook,u8 * value)40256f529ceSJoshua Grisham static int charge_control_end_threshold_acpi_get(struct samsung_galaxybook *galaxybook, u8 *value)
40356f529ceSJoshua Grisham {
40456f529ceSJoshua Grisham struct sawb buf = {};
40556f529ceSJoshua Grisham int err;
40656f529ceSJoshua Grisham
40756f529ceSJoshua Grisham buf.safn = GB_SAFN;
40856f529ceSJoshua Grisham buf.sasb = GB_SASB_POWER_MANAGEMENT;
40956f529ceSJoshua Grisham buf.gunm = GB_GUNM_POWER_MANAGEMENT;
41056f529ceSJoshua Grisham buf.guds[0] = GB_GUDS_BATTERY_CHARGE_CONTROL;
41156f529ceSJoshua Grisham buf.guds[1] = GB_GUDS_BATTERY_CHARGE_CONTROL_GET;
41256f529ceSJoshua Grisham
41356f529ceSJoshua Grisham err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
41456f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
41556f529ceSJoshua Grisham if (err)
41656f529ceSJoshua Grisham return err;
41756f529ceSJoshua Grisham
41856f529ceSJoshua Grisham *value = buf.guds[1];
41956f529ceSJoshua Grisham
42056f529ceSJoshua Grisham return 0;
42156f529ceSJoshua Grisham }
42256f529ceSJoshua Grisham
charge_control_end_threshold_acpi_set(struct samsung_galaxybook * galaxybook,u8 value)42356f529ceSJoshua Grisham static int charge_control_end_threshold_acpi_set(struct samsung_galaxybook *galaxybook, u8 value)
42456f529ceSJoshua Grisham {
42556f529ceSJoshua Grisham struct sawb buf = {};
42656f529ceSJoshua Grisham
42756f529ceSJoshua Grisham buf.safn = GB_SAFN;
42856f529ceSJoshua Grisham buf.sasb = GB_SASB_POWER_MANAGEMENT;
42956f529ceSJoshua Grisham buf.gunm = GB_GUNM_POWER_MANAGEMENT;
43056f529ceSJoshua Grisham buf.guds[0] = GB_GUDS_BATTERY_CHARGE_CONTROL;
43156f529ceSJoshua Grisham buf.guds[1] = GB_GUDS_BATTERY_CHARGE_CONTROL_SET;
43256f529ceSJoshua Grisham buf.guds[2] = value;
43356f529ceSJoshua Grisham
43456f529ceSJoshua Grisham return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
43556f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
43656f529ceSJoshua Grisham }
43756f529ceSJoshua Grisham
galaxybook_battery_ext_property_get(struct power_supply * psy,const struct power_supply_ext * ext,void * ext_data,enum power_supply_property psp,union power_supply_propval * val)43856f529ceSJoshua Grisham static int galaxybook_battery_ext_property_get(struct power_supply *psy,
43956f529ceSJoshua Grisham const struct power_supply_ext *ext,
44056f529ceSJoshua Grisham void *ext_data,
44156f529ceSJoshua Grisham enum power_supply_property psp,
44256f529ceSJoshua Grisham union power_supply_propval *val)
44356f529ceSJoshua Grisham {
44456f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = ext_data;
44556f529ceSJoshua Grisham int err;
44656f529ceSJoshua Grisham
44756f529ceSJoshua Grisham if (psp != POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD)
44856f529ceSJoshua Grisham return -EINVAL;
44956f529ceSJoshua Grisham
45056f529ceSJoshua Grisham err = charge_control_end_threshold_acpi_get(galaxybook, (u8 *)&val->intval);
45156f529ceSJoshua Grisham if (err)
45256f529ceSJoshua Grisham return err;
45356f529ceSJoshua Grisham
45456f529ceSJoshua Grisham /*
45556f529ceSJoshua Grisham * device stores "no end threshold" as 0 instead of 100;
45656f529ceSJoshua Grisham * if device has 0, report 100
45756f529ceSJoshua Grisham */
45856f529ceSJoshua Grisham if (val->intval == 0)
45956f529ceSJoshua Grisham val->intval = 100;
46056f529ceSJoshua Grisham
46156f529ceSJoshua Grisham return 0;
46256f529ceSJoshua Grisham }
46356f529ceSJoshua Grisham
galaxybook_battery_ext_property_set(struct power_supply * psy,const struct power_supply_ext * ext,void * ext_data,enum power_supply_property psp,const union power_supply_propval * val)46456f529ceSJoshua Grisham static int galaxybook_battery_ext_property_set(struct power_supply *psy,
46556f529ceSJoshua Grisham const struct power_supply_ext *ext,
46656f529ceSJoshua Grisham void *ext_data,
46756f529ceSJoshua Grisham enum power_supply_property psp,
46856f529ceSJoshua Grisham const union power_supply_propval *val)
46956f529ceSJoshua Grisham {
47056f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = ext_data;
47156f529ceSJoshua Grisham u8 value;
47256f529ceSJoshua Grisham
47356f529ceSJoshua Grisham if (psp != POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD)
47456f529ceSJoshua Grisham return -EINVAL;
47556f529ceSJoshua Grisham
47656f529ceSJoshua Grisham value = val->intval;
47756f529ceSJoshua Grisham
47856f529ceSJoshua Grisham if (value < 1 || value > 100)
47956f529ceSJoshua Grisham return -EINVAL;
48056f529ceSJoshua Grisham
48156f529ceSJoshua Grisham /*
48256f529ceSJoshua Grisham * device stores "no end threshold" as 0 instead of 100;
48356f529ceSJoshua Grisham * if setting to 100, send 0
48456f529ceSJoshua Grisham */
48556f529ceSJoshua Grisham if (value == 100)
48656f529ceSJoshua Grisham value = 0;
48756f529ceSJoshua Grisham
48856f529ceSJoshua Grisham return charge_control_end_threshold_acpi_set(galaxybook, value);
48956f529ceSJoshua Grisham }
49056f529ceSJoshua Grisham
galaxybook_battery_ext_property_is_writeable(struct power_supply * psy,const struct power_supply_ext * ext,void * ext_data,enum power_supply_property psp)49156f529ceSJoshua Grisham static int galaxybook_battery_ext_property_is_writeable(struct power_supply *psy,
49256f529ceSJoshua Grisham const struct power_supply_ext *ext,
49356f529ceSJoshua Grisham void *ext_data,
49456f529ceSJoshua Grisham enum power_supply_property psp)
49556f529ceSJoshua Grisham {
49656f529ceSJoshua Grisham if (psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD)
49756f529ceSJoshua Grisham return true;
49856f529ceSJoshua Grisham
49956f529ceSJoshua Grisham return false;
50056f529ceSJoshua Grisham }
50156f529ceSJoshua Grisham
50256f529ceSJoshua Grisham static const enum power_supply_property galaxybook_battery_properties[] = {
50356f529ceSJoshua Grisham POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
50456f529ceSJoshua Grisham };
50556f529ceSJoshua Grisham
50656f529ceSJoshua Grisham static const struct power_supply_ext galaxybook_battery_ext = {
50756f529ceSJoshua Grisham .name = DRIVER_NAME,
50856f529ceSJoshua Grisham .properties = galaxybook_battery_properties,
50956f529ceSJoshua Grisham .num_properties = ARRAY_SIZE(galaxybook_battery_properties),
51056f529ceSJoshua Grisham .get_property = galaxybook_battery_ext_property_get,
51156f529ceSJoshua Grisham .set_property = galaxybook_battery_ext_property_set,
51256f529ceSJoshua Grisham .property_is_writeable = galaxybook_battery_ext_property_is_writeable,
51356f529ceSJoshua Grisham };
51456f529ceSJoshua Grisham
galaxybook_battery_add(struct power_supply * battery,struct acpi_battery_hook * hook)51556f529ceSJoshua Grisham static int galaxybook_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
51656f529ceSJoshua Grisham {
51756f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook =
51856f529ceSJoshua Grisham container_of(hook, struct samsung_galaxybook, battery_hook);
51956f529ceSJoshua Grisham
52056f529ceSJoshua Grisham return power_supply_register_extension(battery, &galaxybook_battery_ext,
52156f529ceSJoshua Grisham &battery->dev, galaxybook);
52256f529ceSJoshua Grisham }
52356f529ceSJoshua Grisham
galaxybook_battery_remove(struct power_supply * battery,struct acpi_battery_hook * hook)52456f529ceSJoshua Grisham static int galaxybook_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
52556f529ceSJoshua Grisham {
52656f529ceSJoshua Grisham power_supply_unregister_extension(battery, &galaxybook_battery_ext);
52756f529ceSJoshua Grisham return 0;
52856f529ceSJoshua Grisham }
52956f529ceSJoshua Grisham
galaxybook_battery_threshold_init(struct samsung_galaxybook * galaxybook)53056f529ceSJoshua Grisham static int galaxybook_battery_threshold_init(struct samsung_galaxybook *galaxybook)
53156f529ceSJoshua Grisham {
53256f529ceSJoshua Grisham u8 value;
53356f529ceSJoshua Grisham int err;
53456f529ceSJoshua Grisham
53556f529ceSJoshua Grisham err = charge_control_end_threshold_acpi_get(galaxybook, &value);
53656f529ceSJoshua Grisham if (err) {
53756f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev,
53856f529ceSJoshua Grisham "failed to get initial battery charge end threshold, error %d\n", err);
53956f529ceSJoshua Grisham return 0;
54056f529ceSJoshua Grisham }
54156f529ceSJoshua Grisham
54256f529ceSJoshua Grisham galaxybook->battery_hook.add_battery = galaxybook_battery_add;
54356f529ceSJoshua Grisham galaxybook->battery_hook.remove_battery = galaxybook_battery_remove;
54456f529ceSJoshua Grisham galaxybook->battery_hook.name = "Samsung Galaxy Book Battery Extension";
54556f529ceSJoshua Grisham
54656f529ceSJoshua Grisham return devm_battery_hook_register(&galaxybook->platform->dev, &galaxybook->battery_hook);
54756f529ceSJoshua Grisham }
54856f529ceSJoshua Grisham
54956f529ceSJoshua Grisham /*
55056f529ceSJoshua Grisham * Platform Profile / Performance mode
55156f529ceSJoshua Grisham */
55256f529ceSJoshua Grisham
performance_mode_acpi_get(struct samsung_galaxybook * galaxybook,u8 * performance_mode)55356f529ceSJoshua Grisham static int performance_mode_acpi_get(struct samsung_galaxybook *galaxybook, u8 *performance_mode)
55456f529ceSJoshua Grisham {
55556f529ceSJoshua Grisham struct sawb buf = {};
55656f529ceSJoshua Grisham int err;
55756f529ceSJoshua Grisham
55856f529ceSJoshua Grisham buf.safn = GB_SAFN;
55956f529ceSJoshua Grisham buf.sasb = GB_SASB_PERFORMANCE_MODE;
56056f529ceSJoshua Grisham export_guid(buf.caid, &GB_PERFORMANCE_MODE_GUID);
56156f529ceSJoshua Grisham buf.fncn = GB_FNCN_PERFORMANCE_MODE;
56256f529ceSJoshua Grisham buf.subn = GB_SUBN_PERFORMANCE_MODE_GET;
56356f529ceSJoshua Grisham
56456f529ceSJoshua Grisham err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_PERFORMANCE_MODE,
56556f529ceSJoshua Grisham &buf, GB_SAWB_LEN_PERFORMANCE_MODE);
56656f529ceSJoshua Grisham if (err)
56756f529ceSJoshua Grisham return err;
56856f529ceSJoshua Grisham
56956f529ceSJoshua Grisham *performance_mode = buf.iob0;
57056f529ceSJoshua Grisham
57156f529ceSJoshua Grisham return 0;
57256f529ceSJoshua Grisham }
57356f529ceSJoshua Grisham
performance_mode_acpi_set(struct samsung_galaxybook * galaxybook,const u8 performance_mode)57456f529ceSJoshua Grisham static int performance_mode_acpi_set(struct samsung_galaxybook *galaxybook,
57556f529ceSJoshua Grisham const u8 performance_mode)
57656f529ceSJoshua Grisham {
57756f529ceSJoshua Grisham struct sawb buf = {};
57856f529ceSJoshua Grisham
57956f529ceSJoshua Grisham buf.safn = GB_SAFN;
58056f529ceSJoshua Grisham buf.sasb = GB_SASB_PERFORMANCE_MODE;
58156f529ceSJoshua Grisham export_guid(buf.caid, &GB_PERFORMANCE_MODE_GUID);
58256f529ceSJoshua Grisham buf.fncn = GB_FNCN_PERFORMANCE_MODE;
58356f529ceSJoshua Grisham buf.subn = GB_SUBN_PERFORMANCE_MODE_SET;
58456f529ceSJoshua Grisham buf.iob0 = performance_mode;
58556f529ceSJoshua Grisham
58656f529ceSJoshua Grisham return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_PERFORMANCE_MODE,
58756f529ceSJoshua Grisham &buf, GB_SAWB_LEN_PERFORMANCE_MODE);
58856f529ceSJoshua Grisham }
58956f529ceSJoshua Grisham
get_performance_mode_profile(struct samsung_galaxybook * galaxybook,const u8 performance_mode,enum platform_profile_option * profile)59056f529ceSJoshua Grisham static int get_performance_mode_profile(struct samsung_galaxybook *galaxybook,
59156f529ceSJoshua Grisham const u8 performance_mode,
59256f529ceSJoshua Grisham enum platform_profile_option *profile)
59356f529ceSJoshua Grisham {
59456f529ceSJoshua Grisham switch (performance_mode) {
59556f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_FANOFF:
59656f529ceSJoshua Grisham *profile = PLATFORM_PROFILE_LOW_POWER;
59756f529ceSJoshua Grisham break;
59856f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_LOWNOISE:
59956f529ceSJoshua Grisham *profile = PLATFORM_PROFILE_QUIET;
60056f529ceSJoshua Grisham break;
60156f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_OPTIMIZED:
60256f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_OPTIMIZED_V2:
60356f529ceSJoshua Grisham *profile = PLATFORM_PROFILE_BALANCED;
60456f529ceSJoshua Grisham break;
60556f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_PERFORMANCE:
60656f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_PERFORMANCE_V2:
60756f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_ULTRA:
60856f529ceSJoshua Grisham *profile = PLATFORM_PROFILE_PERFORMANCE;
60956f529ceSJoshua Grisham break;
61056f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_IGNORE1:
61156f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_IGNORE2:
61256f529ceSJoshua Grisham return -EOPNOTSUPP;
61356f529ceSJoshua Grisham default:
61456f529ceSJoshua Grisham dev_warn(&galaxybook->platform->dev,
61556f529ceSJoshua Grisham "unrecognized performance mode 0x%x\n", performance_mode);
61656f529ceSJoshua Grisham return -EOPNOTSUPP;
61756f529ceSJoshua Grisham }
61856f529ceSJoshua Grisham
61956f529ceSJoshua Grisham return 0;
62056f529ceSJoshua Grisham }
62156f529ceSJoshua Grisham
galaxybook_platform_profile_get(struct device * dev,enum platform_profile_option * profile)62256f529ceSJoshua Grisham static int galaxybook_platform_profile_get(struct device *dev,
62356f529ceSJoshua Grisham enum platform_profile_option *profile)
62456f529ceSJoshua Grisham {
62556f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = dev_get_drvdata(dev);
62656f529ceSJoshua Grisham u8 performance_mode;
62756f529ceSJoshua Grisham int err;
62856f529ceSJoshua Grisham
62956f529ceSJoshua Grisham err = performance_mode_acpi_get(galaxybook, &performance_mode);
63056f529ceSJoshua Grisham if (err)
63156f529ceSJoshua Grisham return err;
63256f529ceSJoshua Grisham
63356f529ceSJoshua Grisham return get_performance_mode_profile(galaxybook, performance_mode, profile);
63456f529ceSJoshua Grisham }
63556f529ceSJoshua Grisham
galaxybook_platform_profile_set(struct device * dev,enum platform_profile_option profile)63656f529ceSJoshua Grisham static int galaxybook_platform_profile_set(struct device *dev,
63756f529ceSJoshua Grisham enum platform_profile_option profile)
63856f529ceSJoshua Grisham {
63956f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = dev_get_drvdata(dev);
64056f529ceSJoshua Grisham
64156f529ceSJoshua Grisham return performance_mode_acpi_set(galaxybook,
64256f529ceSJoshua Grisham galaxybook->profile_performance_modes[profile]);
64356f529ceSJoshua Grisham }
64456f529ceSJoshua Grisham
galaxybook_platform_profile_probe(void * drvdata,unsigned long * choices)64556f529ceSJoshua Grisham static int galaxybook_platform_profile_probe(void *drvdata, unsigned long *choices)
64656f529ceSJoshua Grisham {
64756f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = drvdata;
64856f529ceSJoshua Grisham u8 *perfmodes = galaxybook->profile_performance_modes;
64956f529ceSJoshua Grisham enum platform_profile_option profile;
65056f529ceSJoshua Grisham struct sawb buf = {};
65156f529ceSJoshua Grisham unsigned int i;
65256f529ceSJoshua Grisham int err;
65356f529ceSJoshua Grisham
65456f529ceSJoshua Grisham buf.safn = GB_SAFN;
65556f529ceSJoshua Grisham buf.sasb = GB_SASB_PERFORMANCE_MODE;
65656f529ceSJoshua Grisham export_guid(buf.caid, &GB_PERFORMANCE_MODE_GUID);
65756f529ceSJoshua Grisham buf.fncn = GB_FNCN_PERFORMANCE_MODE;
65856f529ceSJoshua Grisham buf.subn = GB_SUBN_PERFORMANCE_MODE_LIST;
65956f529ceSJoshua Grisham
66056f529ceSJoshua Grisham err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_PERFORMANCE_MODE,
66156f529ceSJoshua Grisham &buf, GB_SAWB_LEN_PERFORMANCE_MODE);
66256f529ceSJoshua Grisham if (err) {
66356f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev,
66456f529ceSJoshua Grisham "failed to get supported performance modes, error %d\n", err);
66556f529ceSJoshua Grisham return err;
66656f529ceSJoshua Grisham }
66756f529ceSJoshua Grisham
66856f529ceSJoshua Grisham /* set initial default profile performance mode values */
66956f529ceSJoshua Grisham perfmodes[PLATFORM_PROFILE_LOW_POWER] = GB_PERFORMANCE_MODE_FANOFF;
67056f529ceSJoshua Grisham perfmodes[PLATFORM_PROFILE_QUIET] = GB_PERFORMANCE_MODE_LOWNOISE;
67156f529ceSJoshua Grisham perfmodes[PLATFORM_PROFILE_BALANCED] = GB_PERFORMANCE_MODE_OPTIMIZED;
67256f529ceSJoshua Grisham perfmodes[PLATFORM_PROFILE_PERFORMANCE] = GB_PERFORMANCE_MODE_PERFORMANCE;
67356f529ceSJoshua Grisham
67456f529ceSJoshua Grisham /*
67556f529ceSJoshua Grisham * Value returned in iob0 will have the number of supported performance
67656f529ceSJoshua Grisham * modes per device. The performance mode values will then be given as a
67756f529ceSJoshua Grisham * list after this (iob1-iobX). Loop through the supported values and
67856f529ceSJoshua Grisham * enable their mapped platform_profile choice, overriding "legacy"
67956f529ceSJoshua Grisham * values along the way if a non-legacy value exists.
68056f529ceSJoshua Grisham */
68156f529ceSJoshua Grisham for (i = 1; i <= buf.iob0; i++) {
68256f529ceSJoshua Grisham err = get_performance_mode_profile(galaxybook, buf.iobs[i], &profile);
68356f529ceSJoshua Grisham if (err) {
68456f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev,
68556f529ceSJoshua Grisham "ignoring unmapped performance mode 0x%x\n", buf.iobs[i]);
68656f529ceSJoshua Grisham continue;
68756f529ceSJoshua Grisham }
68856f529ceSJoshua Grisham switch (buf.iobs[i]) {
68956f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_OPTIMIZED_V2:
69056f529ceSJoshua Grisham perfmodes[profile] = GB_PERFORMANCE_MODE_OPTIMIZED_V2;
69156f529ceSJoshua Grisham break;
69256f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_PERFORMANCE_V2:
69356f529ceSJoshua Grisham /* only update if not already overwritten by Ultra */
69456f529ceSJoshua Grisham if (perfmodes[profile] != GB_PERFORMANCE_MODE_ULTRA)
69556f529ceSJoshua Grisham perfmodes[profile] = GB_PERFORMANCE_MODE_PERFORMANCE_V2;
69656f529ceSJoshua Grisham break;
69756f529ceSJoshua Grisham case GB_PERFORMANCE_MODE_ULTRA:
69856f529ceSJoshua Grisham perfmodes[profile] = GB_PERFORMANCE_MODE_ULTRA;
69956f529ceSJoshua Grisham break;
70056f529ceSJoshua Grisham default:
70156f529ceSJoshua Grisham break;
70256f529ceSJoshua Grisham }
70356f529ceSJoshua Grisham set_bit(profile, choices);
70456f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev,
70556f529ceSJoshua Grisham "setting platform profile %d to use performance mode 0x%x\n",
70656f529ceSJoshua Grisham profile, perfmodes[profile]);
70756f529ceSJoshua Grisham }
70856f529ceSJoshua Grisham
70956f529ceSJoshua Grisham /* initialize performance_mode using balanced's mapped value */
71056f529ceSJoshua Grisham if (test_bit(PLATFORM_PROFILE_BALANCED, choices))
71156f529ceSJoshua Grisham return performance_mode_acpi_set(galaxybook, perfmodes[PLATFORM_PROFILE_BALANCED]);
71256f529ceSJoshua Grisham
71356f529ceSJoshua Grisham return 0;
71456f529ceSJoshua Grisham }
71556f529ceSJoshua Grisham
71656f529ceSJoshua Grisham static const struct platform_profile_ops galaxybook_platform_profile_ops = {
71756f529ceSJoshua Grisham .probe = galaxybook_platform_profile_probe,
71856f529ceSJoshua Grisham .profile_get = galaxybook_platform_profile_get,
71956f529ceSJoshua Grisham .profile_set = galaxybook_platform_profile_set,
72056f529ceSJoshua Grisham };
72156f529ceSJoshua Grisham
galaxybook_platform_profile_init(struct samsung_galaxybook * galaxybook)72256f529ceSJoshua Grisham static int galaxybook_platform_profile_init(struct samsung_galaxybook *galaxybook)
72356f529ceSJoshua Grisham {
72456f529ceSJoshua Grisham struct device *platform_profile_dev;
72556f529ceSJoshua Grisham u8 performance_mode;
72656f529ceSJoshua Grisham int err;
72756f529ceSJoshua Grisham
72856f529ceSJoshua Grisham err = performance_mode_acpi_get(galaxybook, &performance_mode);
72956f529ceSJoshua Grisham if (err) {
73056f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev,
73156f529ceSJoshua Grisham "failed to get initial performance mode, error %d\n", err);
73256f529ceSJoshua Grisham return GB_NOT_SUPPORTED;
73356f529ceSJoshua Grisham }
73456f529ceSJoshua Grisham
73556f529ceSJoshua Grisham platform_profile_dev = devm_platform_profile_register(&galaxybook->platform->dev,
73656f529ceSJoshua Grisham DRIVER_NAME, galaxybook,
73756f529ceSJoshua Grisham &galaxybook_platform_profile_ops);
73856f529ceSJoshua Grisham
73956f529ceSJoshua Grisham return PTR_ERR_OR_ZERO(platform_profile_dev);
74056f529ceSJoshua Grisham }
74156f529ceSJoshua Grisham
74256f529ceSJoshua Grisham /*
74356f529ceSJoshua Grisham * Firmware Attributes
74456f529ceSJoshua Grisham */
74556f529ceSJoshua Grisham
74656f529ceSJoshua Grisham /* Power on lid open (device should power on when lid is opened) */
74756f529ceSJoshua Grisham
power_on_lid_open_acpi_get(struct samsung_galaxybook * galaxybook,bool * value)74856f529ceSJoshua Grisham static int power_on_lid_open_acpi_get(struct samsung_galaxybook *galaxybook, bool *value)
74956f529ceSJoshua Grisham {
75056f529ceSJoshua Grisham struct sawb buf = {};
75156f529ceSJoshua Grisham int err;
75256f529ceSJoshua Grisham
75356f529ceSJoshua Grisham buf.safn = GB_SAFN;
75456f529ceSJoshua Grisham buf.sasb = GB_SASB_POWER_MANAGEMENT;
75556f529ceSJoshua Grisham buf.gunm = GB_GUNM_POWER_MANAGEMENT;
75656f529ceSJoshua Grisham buf.guds[0] = GB_GUDS_POWER_ON_LID_OPEN;
75756f529ceSJoshua Grisham buf.guds[1] = GB_GUDS_POWER_ON_LID_OPEN_GET;
75856f529ceSJoshua Grisham
75956f529ceSJoshua Grisham err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
76056f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
76156f529ceSJoshua Grisham if (err)
76256f529ceSJoshua Grisham return err;
76356f529ceSJoshua Grisham
76456f529ceSJoshua Grisham *value = buf.guds[1];
76556f529ceSJoshua Grisham
76656f529ceSJoshua Grisham return 0;
76756f529ceSJoshua Grisham }
76856f529ceSJoshua Grisham
power_on_lid_open_acpi_set(struct samsung_galaxybook * galaxybook,const bool value)76956f529ceSJoshua Grisham static int power_on_lid_open_acpi_set(struct samsung_galaxybook *galaxybook, const bool value)
77056f529ceSJoshua Grisham {
77156f529ceSJoshua Grisham struct sawb buf = {};
77256f529ceSJoshua Grisham
77356f529ceSJoshua Grisham lockdep_assert_held(&galaxybook->fw_attr_lock);
77456f529ceSJoshua Grisham
77556f529ceSJoshua Grisham buf.safn = GB_SAFN;
77656f529ceSJoshua Grisham buf.sasb = GB_SASB_POWER_MANAGEMENT;
77756f529ceSJoshua Grisham buf.gunm = GB_GUNM_POWER_MANAGEMENT;
77856f529ceSJoshua Grisham buf.guds[0] = GB_GUDS_POWER_ON_LID_OPEN;
77956f529ceSJoshua Grisham buf.guds[1] = GB_GUDS_POWER_ON_LID_OPEN_SET;
78056f529ceSJoshua Grisham buf.guds[2] = value ? 1 : 0;
78156f529ceSJoshua Grisham
78256f529ceSJoshua Grisham return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
78356f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
78456f529ceSJoshua Grisham }
78556f529ceSJoshua Grisham
78656f529ceSJoshua Grisham /* USB Charging (USB ports can provide power when device is powered off) */
78756f529ceSJoshua Grisham
usb_charging_acpi_get(struct samsung_galaxybook * galaxybook,bool * value)78856f529ceSJoshua Grisham static int usb_charging_acpi_get(struct samsung_galaxybook *galaxybook, bool *value)
78956f529ceSJoshua Grisham {
79056f529ceSJoshua Grisham struct sawb buf = {};
79156f529ceSJoshua Grisham int err;
79256f529ceSJoshua Grisham
79356f529ceSJoshua Grisham buf.safn = GB_SAFN;
79456f529ceSJoshua Grisham buf.sasb = GB_SASB_USB_CHARGING_GET;
79556f529ceSJoshua Grisham buf.gunm = GB_GUNM_USB_CHARGING_GET;
79656f529ceSJoshua Grisham
79756f529ceSJoshua Grisham err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
79856f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
79956f529ceSJoshua Grisham if (err)
80056f529ceSJoshua Grisham return err;
80156f529ceSJoshua Grisham
80256f529ceSJoshua Grisham *value = buf.gunm == 1;
80356f529ceSJoshua Grisham
80456f529ceSJoshua Grisham return 0;
80556f529ceSJoshua Grisham }
80656f529ceSJoshua Grisham
usb_charging_acpi_set(struct samsung_galaxybook * galaxybook,const bool value)80756f529ceSJoshua Grisham static int usb_charging_acpi_set(struct samsung_galaxybook *galaxybook, const bool value)
80856f529ceSJoshua Grisham {
80956f529ceSJoshua Grisham struct sawb buf = {};
81056f529ceSJoshua Grisham
81156f529ceSJoshua Grisham lockdep_assert_held(&galaxybook->fw_attr_lock);
81256f529ceSJoshua Grisham
81356f529ceSJoshua Grisham buf.safn = GB_SAFN;
81456f529ceSJoshua Grisham buf.sasb = GB_SASB_USB_CHARGING_SET;
81556f529ceSJoshua Grisham buf.gunm = value ? GB_GUNM_USB_CHARGING_ON : GB_GUNM_USB_CHARGING_OFF;
81656f529ceSJoshua Grisham
81756f529ceSJoshua Grisham return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
81856f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
81956f529ceSJoshua Grisham }
82056f529ceSJoshua Grisham
82156f529ceSJoshua Grisham /* Block recording (blocks access to camera and microphone) */
82256f529ceSJoshua Grisham
block_recording_acpi_get(struct samsung_galaxybook * galaxybook,bool * value)82356f529ceSJoshua Grisham static int block_recording_acpi_get(struct samsung_galaxybook *galaxybook, bool *value)
82456f529ceSJoshua Grisham {
82556f529ceSJoshua Grisham struct sawb buf = {};
82656f529ceSJoshua Grisham int err;
82756f529ceSJoshua Grisham
82856f529ceSJoshua Grisham buf.safn = GB_SAFN;
82956f529ceSJoshua Grisham buf.sasb = GB_SASB_BLOCK_RECORDING;
83056f529ceSJoshua Grisham buf.gunm = GB_GUNM_GET;
83156f529ceSJoshua Grisham
83256f529ceSJoshua Grisham err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
83356f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
83456f529ceSJoshua Grisham if (err)
83556f529ceSJoshua Grisham return err;
83656f529ceSJoshua Grisham
83756f529ceSJoshua Grisham *value = buf.gunm == GB_BLOCK_RECORDING_ON;
83856f529ceSJoshua Grisham
83956f529ceSJoshua Grisham return 0;
84056f529ceSJoshua Grisham }
84156f529ceSJoshua Grisham
block_recording_acpi_set(struct samsung_galaxybook * galaxybook,const bool value)84256f529ceSJoshua Grisham static int block_recording_acpi_set(struct samsung_galaxybook *galaxybook, const bool value)
84356f529ceSJoshua Grisham {
84456f529ceSJoshua Grisham struct sawb buf = {};
84556f529ceSJoshua Grisham int err;
84656f529ceSJoshua Grisham
84756f529ceSJoshua Grisham lockdep_assert_held(&galaxybook->fw_attr_lock);
84856f529ceSJoshua Grisham
84956f529ceSJoshua Grisham buf.safn = GB_SAFN;
85056f529ceSJoshua Grisham buf.sasb = GB_SASB_BLOCK_RECORDING;
85156f529ceSJoshua Grisham buf.gunm = GB_GUNM_SET;
85256f529ceSJoshua Grisham buf.guds[0] = value ? GB_BLOCK_RECORDING_ON : GB_BLOCK_RECORDING_OFF;
85356f529ceSJoshua Grisham
85456f529ceSJoshua Grisham err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
85556f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
85656f529ceSJoshua Grisham if (err)
85756f529ceSJoshua Grisham return err;
85856f529ceSJoshua Grisham
85956f529ceSJoshua Grisham input_report_switch(galaxybook->camera_lens_cover_switch,
86056f529ceSJoshua Grisham SW_CAMERA_LENS_COVER, value ? 1 : 0);
86156f529ceSJoshua Grisham input_sync(galaxybook->camera_lens_cover_switch);
86256f529ceSJoshua Grisham
86356f529ceSJoshua Grisham return 0;
86456f529ceSJoshua Grisham }
86556f529ceSJoshua Grisham
galaxybook_block_recording_init(struct samsung_galaxybook * galaxybook)86656f529ceSJoshua Grisham static int galaxybook_block_recording_init(struct samsung_galaxybook *galaxybook)
86756f529ceSJoshua Grisham {
86856f529ceSJoshua Grisham bool value;
86956f529ceSJoshua Grisham int err;
87056f529ceSJoshua Grisham
87156f529ceSJoshua Grisham err = galaxybook_enable_acpi_feature(galaxybook, GB_SASB_BLOCK_RECORDING);
87256f529ceSJoshua Grisham if (err) {
87356f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev,
87456f529ceSJoshua Grisham "failed to initialize block_recording, error %d\n", err);
87556f529ceSJoshua Grisham return GB_NOT_SUPPORTED;
87656f529ceSJoshua Grisham }
87756f529ceSJoshua Grisham
87856f529ceSJoshua Grisham guard(mutex)(&galaxybook->fw_attr_lock);
87956f529ceSJoshua Grisham
88056f529ceSJoshua Grisham err = block_recording_acpi_get(galaxybook, &value);
88156f529ceSJoshua Grisham if (err) {
88256f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev,
88356f529ceSJoshua Grisham "failed to get initial block_recording state, error %d\n", err);
88456f529ceSJoshua Grisham return GB_NOT_SUPPORTED;
88556f529ceSJoshua Grisham }
88656f529ceSJoshua Grisham
88756f529ceSJoshua Grisham galaxybook->camera_lens_cover_switch =
88856f529ceSJoshua Grisham devm_input_allocate_device(&galaxybook->platform->dev);
88956f529ceSJoshua Grisham if (!galaxybook->camera_lens_cover_switch)
89056f529ceSJoshua Grisham return -ENOMEM;
89156f529ceSJoshua Grisham
89256f529ceSJoshua Grisham galaxybook->camera_lens_cover_switch->name = "Samsung Galaxy Book Camera Lens Cover";
89356f529ceSJoshua Grisham galaxybook->camera_lens_cover_switch->phys = DRIVER_NAME "/input0";
89456f529ceSJoshua Grisham galaxybook->camera_lens_cover_switch->id.bustype = BUS_HOST;
89556f529ceSJoshua Grisham
89656f529ceSJoshua Grisham input_set_capability(galaxybook->camera_lens_cover_switch, EV_SW, SW_CAMERA_LENS_COVER);
89756f529ceSJoshua Grisham
89856f529ceSJoshua Grisham err = input_register_device(galaxybook->camera_lens_cover_switch);
89956f529ceSJoshua Grisham if (err)
90056f529ceSJoshua Grisham return err;
90156f529ceSJoshua Grisham
90256f529ceSJoshua Grisham input_report_switch(galaxybook->camera_lens_cover_switch,
90356f529ceSJoshua Grisham SW_CAMERA_LENS_COVER, value ? 1 : 0);
90456f529ceSJoshua Grisham input_sync(galaxybook->camera_lens_cover_switch);
90556f529ceSJoshua Grisham
90656f529ceSJoshua Grisham return 0;
90756f529ceSJoshua Grisham }
90856f529ceSJoshua Grisham
90956f529ceSJoshua Grisham /* Firmware Attributes setup */
91056f529ceSJoshua Grisham
type_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)91156f529ceSJoshua Grisham static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
91256f529ceSJoshua Grisham {
91356f529ceSJoshua Grisham return sysfs_emit(buf, "enumeration\n");
91456f529ceSJoshua Grisham }
91556f529ceSJoshua Grisham
91656f529ceSJoshua Grisham static struct kobj_attribute fw_attr_type = __ATTR_RO(type);
91756f529ceSJoshua Grisham
default_value_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)91856f529ceSJoshua Grisham static ssize_t default_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
91956f529ceSJoshua Grisham {
92056f529ceSJoshua Grisham return sysfs_emit(buf, "0\n");
92156f529ceSJoshua Grisham }
92256f529ceSJoshua Grisham
92356f529ceSJoshua Grisham static struct kobj_attribute fw_attr_default_value = __ATTR_RO(default_value);
92456f529ceSJoshua Grisham
possible_values_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)92556f529ceSJoshua Grisham static ssize_t possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
92656f529ceSJoshua Grisham {
92756f529ceSJoshua Grisham return sysfs_emit(buf, "0;1\n");
92856f529ceSJoshua Grisham }
92956f529ceSJoshua Grisham
93056f529ceSJoshua Grisham static struct kobj_attribute fw_attr_possible_values = __ATTR_RO(possible_values);
93156f529ceSJoshua Grisham
display_name_language_code_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)93256f529ceSJoshua Grisham static ssize_t display_name_language_code_show(struct kobject *kobj, struct kobj_attribute *attr,
93356f529ceSJoshua Grisham char *buf)
93456f529ceSJoshua Grisham {
93556f529ceSJoshua Grisham return sysfs_emit(buf, "%s\n", GB_ATTR_LANGUAGE_CODE);
93656f529ceSJoshua Grisham }
93756f529ceSJoshua Grisham
93856f529ceSJoshua Grisham static struct kobj_attribute fw_attr_display_name_language_code =
93956f529ceSJoshua Grisham __ATTR_RO(display_name_language_code);
94056f529ceSJoshua Grisham
display_name_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)94156f529ceSJoshua Grisham static ssize_t display_name_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
94256f529ceSJoshua Grisham {
94356f529ceSJoshua Grisham struct galaxybook_fw_attr *fw_attr =
94456f529ceSJoshua Grisham container_of(attr, struct galaxybook_fw_attr, display_name);
94556f529ceSJoshua Grisham
94656f529ceSJoshua Grisham return sysfs_emit(buf, "%s\n", galaxybook_fw_attr_desc[fw_attr->fw_attr_id]);
94756f529ceSJoshua Grisham }
94856f529ceSJoshua Grisham
current_value_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)94956f529ceSJoshua Grisham static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
95056f529ceSJoshua Grisham {
95156f529ceSJoshua Grisham struct galaxybook_fw_attr *fw_attr =
95256f529ceSJoshua Grisham container_of(attr, struct galaxybook_fw_attr, current_value);
95356f529ceSJoshua Grisham bool value;
95456f529ceSJoshua Grisham int err;
95556f529ceSJoshua Grisham
95656f529ceSJoshua Grisham err = fw_attr->get_value(fw_attr->galaxybook, &value);
95756f529ceSJoshua Grisham if (err)
95856f529ceSJoshua Grisham return err;
95956f529ceSJoshua Grisham
96056f529ceSJoshua Grisham return sysfs_emit(buf, "%u\n", value);
96156f529ceSJoshua Grisham }
96256f529ceSJoshua Grisham
current_value_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)96356f529ceSJoshua Grisham static ssize_t current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
96456f529ceSJoshua Grisham const char *buf, size_t count)
96556f529ceSJoshua Grisham {
96656f529ceSJoshua Grisham struct galaxybook_fw_attr *fw_attr =
96756f529ceSJoshua Grisham container_of(attr, struct galaxybook_fw_attr, current_value);
96856f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = fw_attr->galaxybook;
96956f529ceSJoshua Grisham bool value;
97056f529ceSJoshua Grisham int err;
97156f529ceSJoshua Grisham
97256f529ceSJoshua Grisham if (!count)
97356f529ceSJoshua Grisham return -EINVAL;
97456f529ceSJoshua Grisham
97556f529ceSJoshua Grisham err = kstrtobool(buf, &value);
97656f529ceSJoshua Grisham if (err)
97756f529ceSJoshua Grisham return err;
97856f529ceSJoshua Grisham
97956f529ceSJoshua Grisham guard(mutex)(&galaxybook->fw_attr_lock);
98056f529ceSJoshua Grisham
98156f529ceSJoshua Grisham err = fw_attr->set_value(galaxybook, value);
98256f529ceSJoshua Grisham if (err)
98356f529ceSJoshua Grisham return err;
98456f529ceSJoshua Grisham
98556f529ceSJoshua Grisham return count;
98656f529ceSJoshua Grisham }
98756f529ceSJoshua Grisham
98856f529ceSJoshua Grisham #define NUM_FW_ATTR_ENUM_ATTRS 6
98956f529ceSJoshua Grisham
galaxybook_fw_attr_init(struct samsung_galaxybook * galaxybook,const enum galaxybook_fw_attr_id fw_attr_id,int (* get_value)(struct samsung_galaxybook * galaxybook,bool * value),int (* set_value)(struct samsung_galaxybook * galaxybook,const bool value))99056f529ceSJoshua Grisham static int galaxybook_fw_attr_init(struct samsung_galaxybook *galaxybook,
99156f529ceSJoshua Grisham const enum galaxybook_fw_attr_id fw_attr_id,
99256f529ceSJoshua Grisham int (*get_value)(struct samsung_galaxybook *galaxybook,
99356f529ceSJoshua Grisham bool *value),
99456f529ceSJoshua Grisham int (*set_value)(struct samsung_galaxybook *galaxybook,
99556f529ceSJoshua Grisham const bool value))
99656f529ceSJoshua Grisham {
99756f529ceSJoshua Grisham struct galaxybook_fw_attr *fw_attr;
99856f529ceSJoshua Grisham struct attribute **attrs;
99956f529ceSJoshua Grisham
100056f529ceSJoshua Grisham fw_attr = devm_kzalloc(&galaxybook->platform->dev, sizeof(*fw_attr), GFP_KERNEL);
100156f529ceSJoshua Grisham if (!fw_attr)
100256f529ceSJoshua Grisham return -ENOMEM;
100356f529ceSJoshua Grisham
100456f529ceSJoshua Grisham attrs = devm_kcalloc(&galaxybook->platform->dev, NUM_FW_ATTR_ENUM_ATTRS + 1,
100556f529ceSJoshua Grisham sizeof(*attrs), GFP_KERNEL);
100656f529ceSJoshua Grisham if (!attrs)
100756f529ceSJoshua Grisham return -ENOMEM;
100856f529ceSJoshua Grisham
100956f529ceSJoshua Grisham attrs[0] = &fw_attr_type.attr;
101056f529ceSJoshua Grisham attrs[1] = &fw_attr_default_value.attr;
101156f529ceSJoshua Grisham attrs[2] = &fw_attr_possible_values.attr;
101256f529ceSJoshua Grisham attrs[3] = &fw_attr_display_name_language_code.attr;
101356f529ceSJoshua Grisham
101456f529ceSJoshua Grisham sysfs_attr_init(&fw_attr->display_name.attr);
101556f529ceSJoshua Grisham fw_attr->display_name.attr.name = "display_name";
101656f529ceSJoshua Grisham fw_attr->display_name.attr.mode = 0444;
101756f529ceSJoshua Grisham fw_attr->display_name.show = display_name_show;
101856f529ceSJoshua Grisham attrs[4] = &fw_attr->display_name.attr;
101956f529ceSJoshua Grisham
102056f529ceSJoshua Grisham sysfs_attr_init(&fw_attr->current_value.attr);
102156f529ceSJoshua Grisham fw_attr->current_value.attr.name = "current_value";
102256f529ceSJoshua Grisham fw_attr->current_value.attr.mode = 0644;
102356f529ceSJoshua Grisham fw_attr->current_value.show = current_value_show;
102456f529ceSJoshua Grisham fw_attr->current_value.store = current_value_store;
102556f529ceSJoshua Grisham attrs[5] = &fw_attr->current_value.attr;
102656f529ceSJoshua Grisham
102756f529ceSJoshua Grisham attrs[6] = NULL;
102856f529ceSJoshua Grisham
102956f529ceSJoshua Grisham fw_attr->galaxybook = galaxybook;
103056f529ceSJoshua Grisham fw_attr->fw_attr_id = fw_attr_id;
103156f529ceSJoshua Grisham fw_attr->attr_group.name = galaxybook_fw_attr_name[fw_attr_id];
103256f529ceSJoshua Grisham fw_attr->attr_group.attrs = attrs;
103356f529ceSJoshua Grisham fw_attr->get_value = get_value;
103456f529ceSJoshua Grisham fw_attr->set_value = set_value;
103556f529ceSJoshua Grisham
103656f529ceSJoshua Grisham return sysfs_create_group(&galaxybook->fw_attrs_kset->kobj, &fw_attr->attr_group);
103756f529ceSJoshua Grisham }
103856f529ceSJoshua Grisham
galaxybook_kset_unregister(void * data)103956f529ceSJoshua Grisham static void galaxybook_kset_unregister(void *data)
104056f529ceSJoshua Grisham {
104156f529ceSJoshua Grisham struct kset *kset = data;
104256f529ceSJoshua Grisham
104356f529ceSJoshua Grisham kset_unregister(kset);
104456f529ceSJoshua Grisham }
104556f529ceSJoshua Grisham
galaxybook_fw_attrs_dev_unregister(void * data)104656f529ceSJoshua Grisham static void galaxybook_fw_attrs_dev_unregister(void *data)
104756f529ceSJoshua Grisham {
104856f529ceSJoshua Grisham struct device *fw_attrs_dev = data;
104956f529ceSJoshua Grisham
105056f529ceSJoshua Grisham device_unregister(fw_attrs_dev);
105156f529ceSJoshua Grisham }
105256f529ceSJoshua Grisham
galaxybook_fw_attrs_init(struct samsung_galaxybook * galaxybook)105356f529ceSJoshua Grisham static int galaxybook_fw_attrs_init(struct samsung_galaxybook *galaxybook)
105456f529ceSJoshua Grisham {
105556f529ceSJoshua Grisham bool value;
105656f529ceSJoshua Grisham int err;
105756f529ceSJoshua Grisham
105856f529ceSJoshua Grisham err = devm_mutex_init(&galaxybook->platform->dev, &galaxybook->fw_attr_lock);
105956f529ceSJoshua Grisham if (err)
106056f529ceSJoshua Grisham return err;
106156f529ceSJoshua Grisham
106256f529ceSJoshua Grisham galaxybook->fw_attrs_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0),
106356f529ceSJoshua Grisham NULL, "%s", DRIVER_NAME);
106456f529ceSJoshua Grisham if (IS_ERR(galaxybook->fw_attrs_dev))
106556f529ceSJoshua Grisham return PTR_ERR(galaxybook->fw_attrs_dev);
106656f529ceSJoshua Grisham
106756f529ceSJoshua Grisham err = devm_add_action_or_reset(&galaxybook->platform->dev,
106856f529ceSJoshua Grisham galaxybook_fw_attrs_dev_unregister,
106956f529ceSJoshua Grisham galaxybook->fw_attrs_dev);
107056f529ceSJoshua Grisham if (err)
107156f529ceSJoshua Grisham return err;
107256f529ceSJoshua Grisham
107356f529ceSJoshua Grisham galaxybook->fw_attrs_kset = kset_create_and_add("attributes", NULL,
107456f529ceSJoshua Grisham &galaxybook->fw_attrs_dev->kobj);
107556f529ceSJoshua Grisham if (!galaxybook->fw_attrs_kset)
107656f529ceSJoshua Grisham return -ENOMEM;
107756f529ceSJoshua Grisham err = devm_add_action_or_reset(&galaxybook->platform->dev,
107856f529ceSJoshua Grisham galaxybook_kset_unregister, galaxybook->fw_attrs_kset);
107956f529ceSJoshua Grisham if (err)
108056f529ceSJoshua Grisham return err;
108156f529ceSJoshua Grisham
108256f529ceSJoshua Grisham err = power_on_lid_open_acpi_get(galaxybook, &value);
108356f529ceSJoshua Grisham if (!err) {
108456f529ceSJoshua Grisham err = galaxybook_fw_attr_init(galaxybook,
108556f529ceSJoshua Grisham GB_ATTR_POWER_ON_LID_OPEN,
108656f529ceSJoshua Grisham &power_on_lid_open_acpi_get,
108756f529ceSJoshua Grisham &power_on_lid_open_acpi_set);
108856f529ceSJoshua Grisham if (err)
108956f529ceSJoshua Grisham return err;
109056f529ceSJoshua Grisham }
109156f529ceSJoshua Grisham
109256f529ceSJoshua Grisham err = usb_charging_acpi_get(galaxybook, &value);
109356f529ceSJoshua Grisham if (!err) {
109456f529ceSJoshua Grisham err = galaxybook_fw_attr_init(galaxybook,
109556f529ceSJoshua Grisham GB_ATTR_USB_CHARGING,
109656f529ceSJoshua Grisham &usb_charging_acpi_get,
109756f529ceSJoshua Grisham &usb_charging_acpi_set);
109856f529ceSJoshua Grisham if (err)
109956f529ceSJoshua Grisham return err;
110056f529ceSJoshua Grisham }
110156f529ceSJoshua Grisham
110256f529ceSJoshua Grisham err = galaxybook_block_recording_init(galaxybook);
11037bb84ca9SJoshua Grisham if (err == GB_NOT_SUPPORTED)
11047bb84ca9SJoshua Grisham return 0;
11057bb84ca9SJoshua Grisham else if (err)
110656f529ceSJoshua Grisham return err;
110756f529ceSJoshua Grisham
11087bb84ca9SJoshua Grisham galaxybook->has_block_recording = true;
11097bb84ca9SJoshua Grisham
111056f529ceSJoshua Grisham return galaxybook_fw_attr_init(galaxybook,
111156f529ceSJoshua Grisham GB_ATTR_BLOCK_RECORDING,
111256f529ceSJoshua Grisham &block_recording_acpi_get,
111356f529ceSJoshua Grisham &block_recording_acpi_set);
111456f529ceSJoshua Grisham }
111556f529ceSJoshua Grisham
111656f529ceSJoshua Grisham /*
111756f529ceSJoshua Grisham * Hotkeys and notifications
111856f529ceSJoshua Grisham */
111956f529ceSJoshua Grisham
galaxybook_kbd_backlight_hotkey_work(struct work_struct * work)112056f529ceSJoshua Grisham static void galaxybook_kbd_backlight_hotkey_work(struct work_struct *work)
112156f529ceSJoshua Grisham {
112256f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook =
112356f529ceSJoshua Grisham from_work(galaxybook, work, kbd_backlight_hotkey_work);
112456f529ceSJoshua Grisham int brightness;
112556f529ceSJoshua Grisham int err;
112656f529ceSJoshua Grisham
112756f529ceSJoshua Grisham guard(mutex)(&galaxybook->kbd_backlight_lock);
112856f529ceSJoshua Grisham
112956f529ceSJoshua Grisham brightness = galaxybook->kbd_backlight.brightness;
113056f529ceSJoshua Grisham if (brightness < galaxybook->kbd_backlight.max_brightness)
113156f529ceSJoshua Grisham brightness++;
113256f529ceSJoshua Grisham else
113356f529ceSJoshua Grisham brightness = 0;
113456f529ceSJoshua Grisham
113556f529ceSJoshua Grisham err = led_set_brightness_sync(&galaxybook->kbd_backlight, brightness);
113656f529ceSJoshua Grisham if (err) {
113756f529ceSJoshua Grisham dev_err(&galaxybook->platform->dev,
113856f529ceSJoshua Grisham "failed to set kbd_backlight brightness, error %d\n", err);
113956f529ceSJoshua Grisham return;
114056f529ceSJoshua Grisham }
114156f529ceSJoshua Grisham
114256f529ceSJoshua Grisham led_classdev_notify_brightness_hw_changed(&galaxybook->kbd_backlight, brightness);
114356f529ceSJoshua Grisham }
114456f529ceSJoshua Grisham
galaxybook_block_recording_hotkey_work(struct work_struct * work)114556f529ceSJoshua Grisham static void galaxybook_block_recording_hotkey_work(struct work_struct *work)
114656f529ceSJoshua Grisham {
114756f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook =
114856f529ceSJoshua Grisham from_work(galaxybook, work, block_recording_hotkey_work);
114956f529ceSJoshua Grisham bool value;
115056f529ceSJoshua Grisham int err;
115156f529ceSJoshua Grisham
115256f529ceSJoshua Grisham guard(mutex)(&galaxybook->fw_attr_lock);
115356f529ceSJoshua Grisham
115456f529ceSJoshua Grisham err = block_recording_acpi_get(galaxybook, &value);
115556f529ceSJoshua Grisham if (err) {
115656f529ceSJoshua Grisham dev_err(&galaxybook->platform->dev,
115756f529ceSJoshua Grisham "failed to get block_recording, error %d\n", err);
115856f529ceSJoshua Grisham return;
115956f529ceSJoshua Grisham }
116056f529ceSJoshua Grisham
116156f529ceSJoshua Grisham err = block_recording_acpi_set(galaxybook, !value);
116256f529ceSJoshua Grisham if (err)
116356f529ceSJoshua Grisham dev_err(&galaxybook->platform->dev,
116456f529ceSJoshua Grisham "failed to set block_recording, error %d\n", err);
116556f529ceSJoshua Grisham }
116656f529ceSJoshua Grisham
galaxybook_i8042_filter(unsigned char data,unsigned char str,struct serio * port,void * context)116756f529ceSJoshua Grisham static bool galaxybook_i8042_filter(unsigned char data, unsigned char str, struct serio *port,
116856f529ceSJoshua Grisham void *context)
116956f529ceSJoshua Grisham {
117056f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = context;
117156f529ceSJoshua Grisham static bool extended;
117256f529ceSJoshua Grisham
117356f529ceSJoshua Grisham if (str & I8042_STR_AUXDATA)
117456f529ceSJoshua Grisham return false;
117556f529ceSJoshua Grisham
117656f529ceSJoshua Grisham if (data == 0xe0) {
117756f529ceSJoshua Grisham extended = true;
117856f529ceSJoshua Grisham return true;
117956f529ceSJoshua Grisham } else if (extended) {
118056f529ceSJoshua Grisham extended = false;
118156f529ceSJoshua Grisham switch (data) {
118256f529ceSJoshua Grisham case GB_KEY_KBD_BACKLIGHT_KEYDOWN:
118356f529ceSJoshua Grisham return true;
118456f529ceSJoshua Grisham case GB_KEY_KBD_BACKLIGHT_KEYUP:
118556f529ceSJoshua Grisham if (galaxybook->has_kbd_backlight)
118656f529ceSJoshua Grisham schedule_work(&galaxybook->kbd_backlight_hotkey_work);
118756f529ceSJoshua Grisham return true;
118856f529ceSJoshua Grisham
118956f529ceSJoshua Grisham case GB_KEY_BLOCK_RECORDING_KEYDOWN:
119056f529ceSJoshua Grisham return true;
119156f529ceSJoshua Grisham case GB_KEY_BLOCK_RECORDING_KEYUP:
119256f529ceSJoshua Grisham if (galaxybook->has_block_recording)
119356f529ceSJoshua Grisham schedule_work(&galaxybook->block_recording_hotkey_work);
119456f529ceSJoshua Grisham return true;
119556f529ceSJoshua Grisham
119656f529ceSJoshua Grisham /* battery notification already sent to battery + SCAI device */
119756f529ceSJoshua Grisham case GB_KEY_BATTERY_NOTIFY_KEYUP:
119856f529ceSJoshua Grisham case GB_KEY_BATTERY_NOTIFY_KEYDOWN:
119956f529ceSJoshua Grisham return true;
120056f529ceSJoshua Grisham
120156f529ceSJoshua Grisham default:
120256f529ceSJoshua Grisham /*
120356f529ceSJoshua Grisham * Report the previously filtered e0 before continuing
120456f529ceSJoshua Grisham * with the next non-filtered byte.
120556f529ceSJoshua Grisham */
120656f529ceSJoshua Grisham serio_interrupt(port, 0xe0, 0);
120756f529ceSJoshua Grisham return false;
120856f529ceSJoshua Grisham }
120956f529ceSJoshua Grisham }
121056f529ceSJoshua Grisham
121156f529ceSJoshua Grisham return false;
121256f529ceSJoshua Grisham }
121356f529ceSJoshua Grisham
galaxybook_i8042_filter_remove(void * data)121456f529ceSJoshua Grisham static void galaxybook_i8042_filter_remove(void *data)
121556f529ceSJoshua Grisham {
121656f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = data;
121756f529ceSJoshua Grisham
121856f529ceSJoshua Grisham i8042_remove_filter(galaxybook_i8042_filter);
121956f529ceSJoshua Grisham cancel_work_sync(&galaxybook->kbd_backlight_hotkey_work);
122056f529ceSJoshua Grisham cancel_work_sync(&galaxybook->block_recording_hotkey_work);
122156f529ceSJoshua Grisham }
122256f529ceSJoshua Grisham
galaxybook_i8042_filter_install(struct samsung_galaxybook * galaxybook)122356f529ceSJoshua Grisham static int galaxybook_i8042_filter_install(struct samsung_galaxybook *galaxybook)
122456f529ceSJoshua Grisham {
122556f529ceSJoshua Grisham int err;
122656f529ceSJoshua Grisham
122756f529ceSJoshua Grisham if (!galaxybook->has_kbd_backlight && !galaxybook->has_block_recording)
122856f529ceSJoshua Grisham return 0;
122956f529ceSJoshua Grisham
123056f529ceSJoshua Grisham INIT_WORK(&galaxybook->kbd_backlight_hotkey_work,
123156f529ceSJoshua Grisham galaxybook_kbd_backlight_hotkey_work);
123256f529ceSJoshua Grisham INIT_WORK(&galaxybook->block_recording_hotkey_work,
123356f529ceSJoshua Grisham galaxybook_block_recording_hotkey_work);
123456f529ceSJoshua Grisham
123556f529ceSJoshua Grisham err = i8042_install_filter(galaxybook_i8042_filter, galaxybook);
123656f529ceSJoshua Grisham if (err)
123756f529ceSJoshua Grisham return err;
123856f529ceSJoshua Grisham
123956f529ceSJoshua Grisham return devm_add_action_or_reset(&galaxybook->platform->dev,
124056f529ceSJoshua Grisham galaxybook_i8042_filter_remove, galaxybook);
124156f529ceSJoshua Grisham }
124256f529ceSJoshua Grisham
124356f529ceSJoshua Grisham /*
124456f529ceSJoshua Grisham * ACPI device setup
124556f529ceSJoshua Grisham */
124656f529ceSJoshua Grisham
galaxybook_acpi_notify(acpi_handle handle,u32 event,void * data)124756f529ceSJoshua Grisham static void galaxybook_acpi_notify(acpi_handle handle, u32 event, void *data)
124856f529ceSJoshua Grisham {
124956f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = data;
125056f529ceSJoshua Grisham
125156f529ceSJoshua Grisham switch (event) {
125256f529ceSJoshua Grisham case GB_ACPI_NOTIFY_BATTERY_STATE_CHANGED:
125356f529ceSJoshua Grisham case GB_ACPI_NOTIFY_DEVICE_ON_TABLE:
125456f529ceSJoshua Grisham case GB_ACPI_NOTIFY_DEVICE_OFF_TABLE:
125556f529ceSJoshua Grisham break;
125656f529ceSJoshua Grisham case GB_ACPI_NOTIFY_HOTKEY_PERFORMANCE_MODE:
125756f529ceSJoshua Grisham if (galaxybook->has_performance_mode)
125856f529ceSJoshua Grisham platform_profile_cycle();
125956f529ceSJoshua Grisham break;
126056f529ceSJoshua Grisham default:
126156f529ceSJoshua Grisham dev_warn(&galaxybook->platform->dev,
126256f529ceSJoshua Grisham "unknown ACPI notification event: 0x%x\n", event);
126356f529ceSJoshua Grisham }
126456f529ceSJoshua Grisham
126556f529ceSJoshua Grisham acpi_bus_generate_netlink_event(DRIVER_NAME, dev_name(&galaxybook->platform->dev),
126656f529ceSJoshua Grisham event, 1);
126756f529ceSJoshua Grisham }
126856f529ceSJoshua Grisham
galaxybook_enable_acpi_notify(struct samsung_galaxybook * galaxybook)126956f529ceSJoshua Grisham static int galaxybook_enable_acpi_notify(struct samsung_galaxybook *galaxybook)
127056f529ceSJoshua Grisham {
127156f529ceSJoshua Grisham struct sawb buf = {};
127256f529ceSJoshua Grisham int err;
127356f529ceSJoshua Grisham
127456f529ceSJoshua Grisham err = galaxybook_enable_acpi_feature(galaxybook, GB_SASB_NOTIFICATIONS);
127556f529ceSJoshua Grisham if (err)
127656f529ceSJoshua Grisham return err;
127756f529ceSJoshua Grisham
127856f529ceSJoshua Grisham buf.safn = GB_SAFN;
127956f529ceSJoshua Grisham buf.sasb = GB_SASB_NOTIFICATIONS;
128056f529ceSJoshua Grisham buf.gunm = GB_GUNM_ACPI_NOTIFY_ENABLE;
128156f529ceSJoshua Grisham buf.guds[0] = GB_GUDS_ACPI_NOTIFY_ENABLE;
128256f529ceSJoshua Grisham
128356f529ceSJoshua Grisham return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS,
128456f529ceSJoshua Grisham &buf, GB_SAWB_LEN_SETTINGS);
128556f529ceSJoshua Grisham }
128656f529ceSJoshua Grisham
galaxybook_acpi_remove_notify_handler(void * data)128756f529ceSJoshua Grisham static void galaxybook_acpi_remove_notify_handler(void *data)
128856f529ceSJoshua Grisham {
128956f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = data;
129056f529ceSJoshua Grisham
129156f529ceSJoshua Grisham acpi_remove_notify_handler(galaxybook->acpi->handle, ACPI_ALL_NOTIFY,
129256f529ceSJoshua Grisham galaxybook_acpi_notify);
129356f529ceSJoshua Grisham }
129456f529ceSJoshua Grisham
galaxybook_acpi_disable(void * data)129556f529ceSJoshua Grisham static void galaxybook_acpi_disable(void *data)
129656f529ceSJoshua Grisham {
129756f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook = data;
129856f529ceSJoshua Grisham
129956f529ceSJoshua Grisham acpi_execute_simple_method(galaxybook->acpi->handle,
130056f529ceSJoshua Grisham GB_ACPI_METHOD_ENABLE, GB_ACPI_METHOD_ENABLE_OFF);
130156f529ceSJoshua Grisham }
130256f529ceSJoshua Grisham
galaxybook_acpi_init(struct samsung_galaxybook * galaxybook)130356f529ceSJoshua Grisham static int galaxybook_acpi_init(struct samsung_galaxybook *galaxybook)
130456f529ceSJoshua Grisham {
130556f529ceSJoshua Grisham acpi_status status;
130656f529ceSJoshua Grisham int err;
130756f529ceSJoshua Grisham
130856f529ceSJoshua Grisham status = acpi_execute_simple_method(galaxybook->acpi->handle, GB_ACPI_METHOD_ENABLE,
130956f529ceSJoshua Grisham GB_ACPI_METHOD_ENABLE_ON);
131056f529ceSJoshua Grisham if (ACPI_FAILURE(status))
131156f529ceSJoshua Grisham return -EIO;
131256f529ceSJoshua Grisham err = devm_add_action_or_reset(&galaxybook->platform->dev,
131356f529ceSJoshua Grisham galaxybook_acpi_disable, galaxybook);
131456f529ceSJoshua Grisham if (err)
131556f529ceSJoshua Grisham return err;
131656f529ceSJoshua Grisham
131756f529ceSJoshua Grisham status = acpi_install_notify_handler(galaxybook->acpi->handle, ACPI_ALL_NOTIFY,
131856f529ceSJoshua Grisham galaxybook_acpi_notify, galaxybook);
131956f529ceSJoshua Grisham if (ACPI_FAILURE(status))
132056f529ceSJoshua Grisham return -EIO;
132156f529ceSJoshua Grisham err = devm_add_action_or_reset(&galaxybook->platform->dev,
132256f529ceSJoshua Grisham galaxybook_acpi_remove_notify_handler, galaxybook);
132356f529ceSJoshua Grisham if (err)
132456f529ceSJoshua Grisham return err;
132556f529ceSJoshua Grisham
132656f529ceSJoshua Grisham err = galaxybook_enable_acpi_notify(galaxybook);
132756f529ceSJoshua Grisham if (err)
132856f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev, "failed to enable ACPI notifications; "
132956f529ceSJoshua Grisham "some hotkeys will not be supported\n");
133056f529ceSJoshua Grisham
133156f529ceSJoshua Grisham err = galaxybook_enable_acpi_feature(galaxybook, GB_SASB_POWER_MANAGEMENT);
133256f529ceSJoshua Grisham if (err)
133356f529ceSJoshua Grisham dev_dbg(&galaxybook->platform->dev,
133456f529ceSJoshua Grisham "failed to initialize ACPI power management features; "
133556f529ceSJoshua Grisham "many features of this driver will not be available\n");
133656f529ceSJoshua Grisham
133756f529ceSJoshua Grisham return 0;
133856f529ceSJoshua Grisham }
133956f529ceSJoshua Grisham
134056f529ceSJoshua Grisham /*
134156f529ceSJoshua Grisham * Platform driver
134256f529ceSJoshua Grisham */
134356f529ceSJoshua Grisham
galaxybook_probe(struct platform_device * pdev)134456f529ceSJoshua Grisham static int galaxybook_probe(struct platform_device *pdev)
134556f529ceSJoshua Grisham {
134656f529ceSJoshua Grisham struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
134756f529ceSJoshua Grisham struct samsung_galaxybook *galaxybook;
134856f529ceSJoshua Grisham int err;
134956f529ceSJoshua Grisham
135056f529ceSJoshua Grisham if (!adev)
135156f529ceSJoshua Grisham return -ENODEV;
135256f529ceSJoshua Grisham
135356f529ceSJoshua Grisham galaxybook = devm_kzalloc(&pdev->dev, sizeof(*galaxybook), GFP_KERNEL);
135456f529ceSJoshua Grisham if (!galaxybook)
135556f529ceSJoshua Grisham return -ENOMEM;
135656f529ceSJoshua Grisham
135756f529ceSJoshua Grisham galaxybook->platform = pdev;
135856f529ceSJoshua Grisham galaxybook->acpi = adev;
135956f529ceSJoshua Grisham
136056f529ceSJoshua Grisham /*
136156f529ceSJoshua Grisham * Features must be enabled and initialized in the following order to
136256f529ceSJoshua Grisham * avoid failures seen on certain devices:
136356f529ceSJoshua Grisham * - GB_SASB_POWER_MANAGEMENT (including performance mode)
136456f529ceSJoshua Grisham * - GB_SASB_KBD_BACKLIGHT
136556f529ceSJoshua Grisham * - GB_SASB_BLOCK_RECORDING (as part of fw_attrs init)
136656f529ceSJoshua Grisham */
136756f529ceSJoshua Grisham
136856f529ceSJoshua Grisham err = galaxybook_acpi_init(galaxybook);
136956f529ceSJoshua Grisham if (err)
137056f529ceSJoshua Grisham return dev_err_probe(&galaxybook->platform->dev, err,
137156f529ceSJoshua Grisham "failed to initialize ACPI device\n");
137256f529ceSJoshua Grisham
137356f529ceSJoshua Grisham err = galaxybook_platform_profile_init(galaxybook);
137456f529ceSJoshua Grisham if (!err)
137556f529ceSJoshua Grisham galaxybook->has_performance_mode = true;
137656f529ceSJoshua Grisham else if (err != GB_NOT_SUPPORTED)
137756f529ceSJoshua Grisham return dev_err_probe(&galaxybook->platform->dev, err,
137856f529ceSJoshua Grisham "failed to initialize platform profile\n");
137956f529ceSJoshua Grisham
138056f529ceSJoshua Grisham err = galaxybook_battery_threshold_init(galaxybook);
138156f529ceSJoshua Grisham if (err)
138256f529ceSJoshua Grisham return dev_err_probe(&galaxybook->platform->dev, err,
138356f529ceSJoshua Grisham "failed to initialize battery threshold\n");
138456f529ceSJoshua Grisham
138556f529ceSJoshua Grisham err = galaxybook_kbd_backlight_init(galaxybook);
138656f529ceSJoshua Grisham if (!err)
138756f529ceSJoshua Grisham galaxybook->has_kbd_backlight = true;
138856f529ceSJoshua Grisham else if (err != GB_NOT_SUPPORTED)
138956f529ceSJoshua Grisham return dev_err_probe(&galaxybook->platform->dev, err,
139056f529ceSJoshua Grisham "failed to initialize kbd_backlight\n");
139156f529ceSJoshua Grisham
139256f529ceSJoshua Grisham err = galaxybook_fw_attrs_init(galaxybook);
139356f529ceSJoshua Grisham if (err)
139456f529ceSJoshua Grisham return dev_err_probe(&galaxybook->platform->dev, err,
139556f529ceSJoshua Grisham "failed to initialize firmware-attributes\n");
139656f529ceSJoshua Grisham
139756f529ceSJoshua Grisham err = galaxybook_i8042_filter_install(galaxybook);
139856f529ceSJoshua Grisham if (err)
139956f529ceSJoshua Grisham return dev_err_probe(&galaxybook->platform->dev, err,
140056f529ceSJoshua Grisham "failed to initialize i8042_filter\n");
140156f529ceSJoshua Grisham
140256f529ceSJoshua Grisham return 0;
140356f529ceSJoshua Grisham }
140456f529ceSJoshua Grisham
140556f529ceSJoshua Grisham static const struct acpi_device_id galaxybook_device_ids[] = {
1406*afbdc4bbSJoshua Grisham { "SAM0426" },
140756f529ceSJoshua Grisham { "SAM0427" },
140856f529ceSJoshua Grisham { "SAM0428" },
140956f529ceSJoshua Grisham { "SAM0429" },
141056f529ceSJoshua Grisham { "SAM0430" },
141156f529ceSJoshua Grisham {}
141256f529ceSJoshua Grisham };
141356f529ceSJoshua Grisham MODULE_DEVICE_TABLE(acpi, galaxybook_device_ids);
141456f529ceSJoshua Grisham
141556f529ceSJoshua Grisham static struct platform_driver galaxybook_platform_driver = {
141656f529ceSJoshua Grisham .driver = {
141756f529ceSJoshua Grisham .name = DRIVER_NAME,
141856f529ceSJoshua Grisham .acpi_match_table = galaxybook_device_ids,
141956f529ceSJoshua Grisham },
142056f529ceSJoshua Grisham .probe = galaxybook_probe,
142156f529ceSJoshua Grisham };
142256f529ceSJoshua Grisham module_platform_driver(galaxybook_platform_driver);
142356f529ceSJoshua Grisham
142456f529ceSJoshua Grisham MODULE_AUTHOR("Joshua Grisham <josh@joshuagrisham.com>");
142556f529ceSJoshua Grisham MODULE_DESCRIPTION("Samsung Galaxy Book driver");
142656f529ceSJoshua Grisham MODULE_LICENSE("GPL");
1427