^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Samsung Laptop driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2009,2011 Novell Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/leds.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/rfkill.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/efi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/suspend.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <acpi/video.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * This driver is needed because a number of Samsung laptops do not hook
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * their control settings through ACPI. So we have to poke around in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * BIOS to do things like brightness values, and "special" key controls.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * We have 0 - 8 as valid brightness levels. The specs say that level 0 should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * be reserved by the BIOS (which really doesn't make much sense), we tell
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define MAX_BRIGHT 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define SABI_IFACE_MAIN 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define SABI_IFACE_SUB 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define SABI_IFACE_COMPLETE 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define SABI_IFACE_DATA 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define WL_STATUS_WLAN 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define WL_STATUS_BT 0x2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /* Structure get/set data using sabi */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct sabi_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) u32 d0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) u32 d1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) u16 d2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u8 d3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) u8 data[11];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct sabi_header_offsets {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u8 port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) u8 re_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) u8 iface_func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u8 en_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) u8 data_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u8 data_segment;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct sabi_commands {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * Brightness is 0 - 8, as described above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * Value 0 is for the BIOS to use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u16 get_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u16 set_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * first byte:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * 0x00 - wireless is off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * 0x01 - wireless is on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * second byte:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * 0x02 - 3G is off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * 0x03 - 3G is on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * TODO, verify 3G is correct, that doesn't seem right...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) u16 get_wireless_button;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u16 set_wireless_button;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* 0 is off, 1 is on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u16 get_backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) u16 set_backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * 0x80 or 0x00 - no action
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * 0x81 - recovery key pressed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u16 get_recovery_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) u16 set_recovery_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * on seclinux: 0 is low, 1 is high,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * on swsmi: 0 is normal, 1 is silent, 2 is turbo
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) u16 get_performance_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) u16 set_performance_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* 0x80 is off, 0x81 is on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) u16 get_battery_life_extender;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) u16 set_battery_life_extender;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /* 0x80 is off, 0x81 is on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) u16 get_usb_charge;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) u16 set_usb_charge;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* the first byte is for bluetooth and the third one is for wlan */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) u16 get_wireless_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) u16 set_wireless_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* 0x80 is off, 0x81 is on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) u16 get_lid_handling;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) u16 set_lid_handling;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /* 0x81 to read, (0x82 | level << 8) to set, 0xaabb to enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) u16 kbd_backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * Tell the BIOS that Linux is running on this machine.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * 81 is on, 80 is off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) u16 set_linux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) struct sabi_performance_level {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) u16 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct sabi_config {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int sabi_version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) const char *test_string;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) u16 main_function;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) const struct sabi_header_offsets header_offsets;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) const struct sabi_commands commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) const struct sabi_performance_level performance_levels[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) u8 min_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) u8 max_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static const struct sabi_config sabi_configs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* I don't know if it is really 2, but it it is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * less than 3 anyway */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .sabi_version = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .test_string = "SECLINUX",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .main_function = 0x4c49,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .header_offsets = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .port = 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .re_mem = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .iface_func = 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .en_mem = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .data_offset = 0x05,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) .data_segment = 0x07,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .commands = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .get_brightness = 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .set_brightness = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .get_wireless_button = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .set_wireless_button = 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .get_backlight = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .set_backlight = 0x05,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) .get_recovery_mode = 0x06,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) .set_recovery_mode = 0x07,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) .get_performance_level = 0x08,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) .set_performance_level = 0x09,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .get_battery_life_extender = 0xFFFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .set_battery_life_extender = 0xFFFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .get_usb_charge = 0xFFFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .set_usb_charge = 0xFFFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .get_wireless_status = 0xFFFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .set_wireless_status = 0xFFFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) .get_lid_handling = 0xFFFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) .set_lid_handling = 0xFFFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .kbd_backlight = 0xFFFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .set_linux = 0x0a,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) .performance_levels = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) .name = "silent",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) .value = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) .name = "normal",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) .value = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) .min_brightness = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) .max_brightness = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) .sabi_version = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .test_string = "SwSmi@",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .main_function = 0x5843,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .header_offsets = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) .port = 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) .re_mem = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) .iface_func = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .en_mem = 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) .data_offset = 0x05,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) .data_segment = 0x07,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) .commands = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) .get_brightness = 0x10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .set_brightness = 0x11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) .get_wireless_button = 0x12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) .set_wireless_button = 0x13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) .get_backlight = 0x2d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .set_backlight = 0x2e,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) .get_recovery_mode = 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) .set_recovery_mode = 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .get_performance_level = 0x31,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .set_performance_level = 0x32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) .get_battery_life_extender = 0x65,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) .set_battery_life_extender = 0x66,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) .get_usb_charge = 0x67,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) .set_usb_charge = 0x68,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) .get_wireless_status = 0x69,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) .set_wireless_status = 0x6a,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) .get_lid_handling = 0x6d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) .set_lid_handling = 0x6e,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) .kbd_backlight = 0x78,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) .set_linux = 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) .performance_levels = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) .name = "normal",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) .value = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .name = "silent",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) .value = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) .name = "overclock",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) .value = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) .min_brightness = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) .max_brightness = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * samsung-laptop/ - debugfs root directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) * f0000_segment - dump f0000 segment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * command - current command
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) * data - current data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) * d0, d1, d2, d3 - data fields
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * call - call SABI using command and data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * This allow to call arbitrary sabi commands wihout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * modifying the driver at all.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * For example, setting the keyboard backlight brightness to 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) * echo 0x78 > command
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) * echo 0x0582 > d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) * echo 0 > d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) * echo 0 > d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) * echo 0 > d3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) * cat call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) struct samsung_laptop_debug {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) struct dentry *root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) u16 command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) struct debugfs_blob_wrapper f0000_wrapper;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) struct debugfs_blob_wrapper data_wrapper;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) struct debugfs_blob_wrapper sdiag_wrapper;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) struct samsung_laptop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) struct samsung_rfkill {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) struct samsung_laptop *samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) struct rfkill *rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) enum rfkill_type type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) struct samsung_laptop {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) const struct sabi_config *config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) void __iomem *sabi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) void __iomem *sabi_iface;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) void __iomem *f0000_segment;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) struct mutex sabi_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) struct platform_device *platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) struct backlight_device *backlight_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) struct samsung_rfkill wlan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) struct samsung_rfkill bluetooth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) struct led_classdev kbd_led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) int kbd_led_wk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) struct workqueue_struct *led_workqueue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) struct work_struct kbd_led_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) struct samsung_laptop_debug debug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct samsung_quirks *quirks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct notifier_block pm_nb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) bool handle_backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) bool has_stepping_quirk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) char sdiag[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) struct samsung_quirks {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) bool broken_acpi_video;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) bool four_kbd_backlight_levels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) bool enable_kbd_backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) bool use_native_backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) bool lid_handling;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) static struct samsung_quirks samsung_unknown = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) static struct samsung_quirks samsung_broken_acpi_video = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) .broken_acpi_video = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) static struct samsung_quirks samsung_use_native_backlight = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) .use_native_backlight = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) static struct samsung_quirks samsung_np740u3e = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) .four_kbd_backlight_levels = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) .enable_kbd_backlight = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static struct samsung_quirks samsung_lid_handling = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) .lid_handling = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) static bool force;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) module_param(force, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) MODULE_PARM_DESC(force,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) "Disable the DMI check and forces the driver to be loaded");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) static bool debug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) module_param(debug, bool, S_IRUGO | S_IWUSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) MODULE_PARM_DESC(debug, "Debug enabled or not");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) static int sabi_command(struct samsung_laptop *samsung, u16 command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) struct sabi_data *in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) struct sabi_data *out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) const struct sabi_config *config = samsung->config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) u16 port = readw(samsung->sabi + config->header_offsets.port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) u8 complete, iface_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) mutex_lock(&samsung->sabi_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (debug) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) pr_info("SABI command:0x%04x "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) "data:{0x%08x, 0x%08x, 0x%04x, 0x%02x}",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) command, in->d0, in->d1, in->d2, in->d3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) pr_info("SABI command:0x%04x", command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /* enable memory to be able to write to it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) outb(readb(samsung->sabi + config->header_offsets.en_mem), port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) /* write out the command */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) writew(config->main_function, samsung->sabi_iface + SABI_IFACE_MAIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) writew(command, samsung->sabi_iface + SABI_IFACE_SUB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) writeb(0, samsung->sabi_iface + SABI_IFACE_COMPLETE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (in) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) writel(in->d0, samsung->sabi_iface + SABI_IFACE_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) writel(in->d1, samsung->sabi_iface + SABI_IFACE_DATA + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) writew(in->d2, samsung->sabi_iface + SABI_IFACE_DATA + 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) writeb(in->d3, samsung->sabi_iface + SABI_IFACE_DATA + 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) outb(readb(samsung->sabi + config->header_offsets.iface_func), port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) /* write protect memory to make it safe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) outb(readb(samsung->sabi + config->header_offsets.re_mem), port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /* see if the command actually succeeded */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) complete = readb(samsung->sabi_iface + SABI_IFACE_COMPLETE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) iface_data = readb(samsung->sabi_iface + SABI_IFACE_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) /* iface_data = 0xFF happens when a command is not known
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * so we only add a warning in debug mode since we will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * probably issue some unknown command at startup to find
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * out which features are supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (complete != 0xaa || (iface_data == 0xff && debug))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) pr_warn("SABI command 0x%04x failed with"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) " completion flag 0x%02x and interface data 0x%02x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) command, complete, iface_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (complete != 0xaa || iface_data == 0xff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (out) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) out->d0 = readl(samsung->sabi_iface + SABI_IFACE_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) out->d1 = readl(samsung->sabi_iface + SABI_IFACE_DATA + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) out->d2 = readw(samsung->sabi_iface + SABI_IFACE_DATA + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) out->d3 = readb(samsung->sabi_iface + SABI_IFACE_DATA + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (debug && out) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) pr_info("SABI return data:{0x%08x, 0x%08x, 0x%04x, 0x%02x}",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) out->d0, out->d1, out->d2, out->d3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) mutex_unlock(&samsung->sabi_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) /* simple wrappers usable with most commands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) static int sabi_set_commandb(struct samsung_laptop *samsung,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) u16 command, u8 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) struct sabi_data in = { { { .d0 = 0, .d1 = 0, .d2 = 0, .d3 = 0 } } };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) in.data[0] = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return sabi_command(samsung, command, &in, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) static int read_brightness(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) const struct sabi_config *config = samsung->config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) struct sabi_data sretval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) int user_brightness = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) retval = sabi_command(samsung, commands->get_brightness,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) NULL, &sretval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) user_brightness = sretval.data[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (user_brightness > config->min_brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) user_brightness -= config->min_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) user_brightness = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) return user_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) static void set_brightness(struct samsung_laptop *samsung, u8 user_brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) const struct sabi_config *config = samsung->config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) u8 user_level = user_brightness + config->min_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (samsung->has_stepping_quirk && user_level != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) * short circuit if the specified level is what's already set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) * to prevent the screen from flickering needlessly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (user_brightness == read_brightness(samsung))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) sabi_set_commandb(samsung, commands->set_brightness, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) sabi_set_commandb(samsung, commands->set_brightness, user_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) static int get_brightness(struct backlight_device *bd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) struct samsung_laptop *samsung = bl_get_data(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) return read_brightness(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) static void check_for_stepping_quirk(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) int initial_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) int check_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) int orig_level = read_brightness(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) * Some laptops exhibit the strange behaviour of stepping toward
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) * (rather than setting) the brightness except when changing to/from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) * brightness level 0. This behaviour is checked for here and worked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) * around in set_brightness.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) if (orig_level == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) set_brightness(samsung, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) initial_level = read_brightness(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (initial_level <= 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) check_level = initial_level + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) check_level = initial_level - 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) samsung->has_stepping_quirk = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) set_brightness(samsung, check_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (read_brightness(samsung) != check_level) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) samsung->has_stepping_quirk = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) pr_info("enabled workaround for brightness stepping quirk\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) set_brightness(samsung, orig_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) static int update_status(struct backlight_device *bd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) struct samsung_laptop *samsung = bl_get_data(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) set_brightness(samsung, bd->props.brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) if (bd->props.power == FB_BLANK_UNBLANK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) sabi_set_commandb(samsung, commands->set_backlight, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) sabi_set_commandb(samsung, commands->set_backlight, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) static const struct backlight_ops backlight_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) .get_brightness = get_brightness,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) .update_status = update_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static int seclinux_rfkill_set(void *data, bool blocked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) struct samsung_rfkill *srfkill = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) struct samsung_laptop *samsung = srfkill->samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) return sabi_set_commandb(samsung, commands->set_wireless_button,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) !blocked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) static const struct rfkill_ops seclinux_rfkill_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) .set_block = seclinux_rfkill_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) static int swsmi_wireless_status(struct samsung_laptop *samsung,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) struct sabi_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return sabi_command(samsung, commands->get_wireless_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) NULL, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) static int swsmi_rfkill_set(void *priv, bool blocked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) struct samsung_rfkill *srfkill = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) struct samsung_laptop *samsung = srfkill->samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) ret = swsmi_wireless_status(samsung, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) /* Don't set the state for non-present devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) for (i = 0; i < 4; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (data.data[i] == 0x02)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) data.data[1] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (srfkill->type == RFKILL_TYPE_WLAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) data.data[WL_STATUS_WLAN] = !blocked;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) else if (srfkill->type == RFKILL_TYPE_BLUETOOTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) data.data[WL_STATUS_BT] = !blocked;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) return sabi_command(samsung, commands->set_wireless_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) &data, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) static void swsmi_rfkill_query(struct rfkill *rfkill, void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) struct samsung_rfkill *srfkill = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) struct samsung_laptop *samsung = srfkill->samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) ret = swsmi_wireless_status(samsung, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) if (srfkill->type == RFKILL_TYPE_WLAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) ret = data.data[WL_STATUS_WLAN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) else if (srfkill->type == RFKILL_TYPE_BLUETOOTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) ret = data.data[WL_STATUS_BT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) return ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) rfkill_set_sw_state(rfkill, !ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) static const struct rfkill_ops swsmi_rfkill_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) .set_block = swsmi_rfkill_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) .query = swsmi_rfkill_query,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) static ssize_t get_performance_level(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) struct samsung_laptop *samsung = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) const struct sabi_config *config = samsung->config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) const struct sabi_commands *commands = &config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) struct sabi_data sretval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) /* Read the state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) retval = sabi_command(samsung, commands->get_performance_level,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) NULL, &sretval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) /* The logic is backwards, yeah, lots of fun... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) for (i = 0; config->performance_levels[i].name; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (sretval.data[0] == config->performance_levels[i].value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) return sprintf(buf, "%s\n", config->performance_levels[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) return sprintf(buf, "%s\n", "unknown");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) static ssize_t set_performance_level(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) struct device_attribute *attr, const char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) struct samsung_laptop *samsung = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) const struct sabi_config *config = samsung->config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) const struct sabi_commands *commands = &config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) if (count < 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) for (i = 0; config->performance_levels[i].name; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) const struct sabi_performance_level *level =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) &config->performance_levels[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) if (!strncasecmp(level->name, buf, strlen(level->name))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) sabi_set_commandb(samsung,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) commands->set_performance_level,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) level->value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) if (!config->performance_levels[i].name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) get_performance_level, set_performance_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) static int read_battery_life_extender(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) if (commands->get_battery_life_extender == 0xFFFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) memset(&data, 0, sizeof(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) data.data[0] = 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) retval = sabi_command(samsung, commands->get_battery_life_extender,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) &data, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) if (data.data[0] != 0 && data.data[0] != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) return data.data[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) static int write_battery_life_extender(struct samsung_laptop *samsung,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) int enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) memset(&data, 0, sizeof(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) data.data[0] = 0x80 | enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) return sabi_command(samsung, commands->set_battery_life_extender,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) &data, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) static ssize_t get_battery_life_extender(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) struct samsung_laptop *samsung = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) ret = read_battery_life_extender(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) return sprintf(buf, "%d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) static ssize_t set_battery_life_extender(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) struct samsung_laptop *samsung = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) int ret, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) if (!count || kstrtoint(buf, 0, &value) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) ret = write_battery_life_extender(samsung, !!value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) static DEVICE_ATTR(battery_life_extender, S_IWUSR | S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) get_battery_life_extender, set_battery_life_extender);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) static int read_usb_charge(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) if (commands->get_usb_charge == 0xFFFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) memset(&data, 0, sizeof(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) data.data[0] = 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) retval = sabi_command(samsung, commands->get_usb_charge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) &data, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) if (data.data[0] != 0 && data.data[0] != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) return data.data[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) static int write_usb_charge(struct samsung_laptop *samsung,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) int enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) memset(&data, 0, sizeof(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) data.data[0] = 0x80 | enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) return sabi_command(samsung, commands->set_usb_charge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) &data, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) static ssize_t get_usb_charge(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) struct samsung_laptop *samsung = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) ret = read_usb_charge(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) return sprintf(buf, "%d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) static ssize_t set_usb_charge(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) struct samsung_laptop *samsung = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) int ret, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (!count || kstrtoint(buf, 0, &value) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) ret = write_usb_charge(samsung, !!value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) get_usb_charge, set_usb_charge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) static int read_lid_handling(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) if (commands->get_lid_handling == 0xFFFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) memset(&data, 0, sizeof(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) retval = sabi_command(samsung, commands->get_lid_handling,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) &data, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) return data.data[0] & 0x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) static int write_lid_handling(struct samsung_laptop *samsung,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) int enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) memset(&data, 0, sizeof(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) data.data[0] = 0x80 | enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) return sabi_command(samsung, commands->set_lid_handling,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) &data, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) static ssize_t get_lid_handling(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) struct samsung_laptop *samsung = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) ret = read_lid_handling(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) return sprintf(buf, "%d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) static ssize_t set_lid_handling(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) struct samsung_laptop *samsung = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) int ret, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) if (!count || kstrtoint(buf, 0, &value) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) ret = write_lid_handling(samsung, !!value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) static DEVICE_ATTR(lid_handling, S_IWUSR | S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) get_lid_handling, set_lid_handling);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) static struct attribute *platform_attributes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) &dev_attr_performance_level.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) &dev_attr_battery_life_extender.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) &dev_attr_usb_charge.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) &dev_attr_lid_handling.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) static int find_signature(void __iomem *memcheck, const char *testStr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) int loca;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) for (loca = 0; loca < 0xffff; loca++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) char temp = readb(memcheck + loca);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) if (temp == testStr[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) if (i == strlen(testStr)-1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) ++i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) return loca;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) static void samsung_rfkill_exit(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) if (samsung->wlan.rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) rfkill_unregister(samsung->wlan.rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) rfkill_destroy(samsung->wlan.rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) samsung->wlan.rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) if (samsung->bluetooth.rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) rfkill_unregister(samsung->bluetooth.rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) rfkill_destroy(samsung->bluetooth.rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) samsung->bluetooth.rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) static int samsung_new_rfkill(struct samsung_laptop *samsung,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) struct samsung_rfkill *arfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) const char *name, enum rfkill_type type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) const struct rfkill_ops *ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) int blocked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) struct rfkill **rfkill = &arfkill->rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) arfkill->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) arfkill->samsung = samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) *rfkill = rfkill_alloc(name, &samsung->platform_device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) type, ops, arfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) if (!*rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) if (blocked != -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) rfkill_init_sw_state(*rfkill, blocked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) ret = rfkill_register(*rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) rfkill_destroy(*rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) *rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) static int __init samsung_rfkill_init_seclinux(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) return samsung_new_rfkill(samsung, &samsung->wlan, "samsung-wlan",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) RFKILL_TYPE_WLAN, &seclinux_rfkill_ops, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) static int __init samsung_rfkill_init_swsmi(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) ret = swsmi_wireless_status(samsung, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) /* Some swsmi laptops use the old seclinux way to control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) * wireless devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) if (ret == -EINVAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) ret = samsung_rfkill_init_seclinux(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) /* 0x02 seems to mean that the device is no present/available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) if (data.data[WL_STATUS_WLAN] != 0x02)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) ret = samsung_new_rfkill(samsung, &samsung->wlan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) "samsung-wlan",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) RFKILL_TYPE_WLAN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) &swsmi_rfkill_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) !data.data[WL_STATUS_WLAN]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) if (data.data[WL_STATUS_BT] != 0x02)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) ret = samsung_new_rfkill(samsung, &samsung->bluetooth,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) "samsung-bluetooth",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) RFKILL_TYPE_BLUETOOTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) &swsmi_rfkill_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) !data.data[WL_STATUS_BT]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) samsung_rfkill_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) static int __init samsung_rfkill_init(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) if (samsung->config->sabi_version == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) return samsung_rfkill_init_seclinux(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) if (samsung->config->sabi_version == 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) return samsung_rfkill_init_swsmi(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) static void samsung_lid_handling_exit(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) if (samsung->quirks->lid_handling)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) write_lid_handling(samsung, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) static int __init samsung_lid_handling_init(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) if (samsung->quirks->lid_handling)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) retval = write_lid_handling(samsung, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) static int kbd_backlight_enable(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) if (commands->kbd_backlight == 0xFFFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) memset(&data, 0, sizeof(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) data.d0 = 0xaabb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) retval = sabi_command(samsung, commands->kbd_backlight,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) &data, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) if (data.d0 != 0xccdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) static int kbd_backlight_read(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) memset(&data, 0, sizeof(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) data.data[0] = 0x81;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) retval = sabi_command(samsung, commands->kbd_backlight,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) &data, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) return data.data[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) static int kbd_backlight_write(struct samsung_laptop *samsung, int brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) const struct sabi_commands *commands = &samsung->config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) struct sabi_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) memset(&data, 0, sizeof(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) data.d0 = 0x82 | ((brightness & 0xFF) << 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) return sabi_command(samsung, commands->kbd_backlight,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) &data, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) static void kbd_led_update(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) struct samsung_laptop *samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) samsung = container_of(work, struct samsung_laptop, kbd_led_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) kbd_backlight_write(samsung, samsung->kbd_led_wk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) static void kbd_led_set(struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) enum led_brightness value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) struct samsung_laptop *samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) samsung = container_of(led_cdev, struct samsung_laptop, kbd_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) if (value > samsung->kbd_led.max_brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) value = samsung->kbd_led.max_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) else if (value < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) samsung->kbd_led_wk = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) queue_work(samsung->led_workqueue, &samsung->kbd_led_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) struct samsung_laptop *samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) samsung = container_of(led_cdev, struct samsung_laptop, kbd_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) return kbd_backlight_read(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) static void samsung_leds_exit(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) led_classdev_unregister(&samsung->kbd_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) if (samsung->led_workqueue)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) destroy_workqueue(samsung->led_workqueue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) static int __init samsung_leds_init(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) samsung->led_workqueue = create_singlethread_workqueue("led_workqueue");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) if (!samsung->led_workqueue)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) if (kbd_backlight_enable(samsung) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) INIT_WORK(&samsung->kbd_led_work, kbd_led_update);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) samsung->kbd_led.name = "samsung::kbd_backlight";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) samsung->kbd_led.brightness_set = kbd_led_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) samsung->kbd_led.brightness_get = kbd_led_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) samsung->kbd_led.max_brightness = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) if (samsung->quirks->four_kbd_backlight_levels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) samsung->kbd_led.max_brightness = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) ret = led_classdev_register(&samsung->platform_device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) &samsung->kbd_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) samsung_leds_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) static void samsung_backlight_exit(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) if (samsung->backlight_device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) backlight_device_unregister(samsung->backlight_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) samsung->backlight_device = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) static int __init samsung_backlight_init(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) struct backlight_device *bd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) struct backlight_properties props;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) if (!samsung->handle_backlight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) memset(&props, 0, sizeof(struct backlight_properties));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) props.type = BACKLIGHT_PLATFORM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) props.max_brightness = samsung->config->max_brightness -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) samsung->config->min_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) bd = backlight_device_register("samsung",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) &samsung->platform_device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) samsung, &backlight_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) &props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) if (IS_ERR(bd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) return PTR_ERR(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) samsung->backlight_device = bd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) samsung->backlight_device->props.brightness = read_brightness(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) samsung->backlight_device->props.power = FB_BLANK_UNBLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) backlight_update_status(samsung->backlight_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) struct attribute *attr, int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) struct device *dev = container_of(kobj, struct device, kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) struct samsung_laptop *samsung = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) bool ok = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) if (attr == &dev_attr_performance_level.attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) ok = !!samsung->config->performance_levels[0].name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) if (attr == &dev_attr_battery_life_extender.attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) ok = !!(read_battery_life_extender(samsung) >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) if (attr == &dev_attr_usb_charge.attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) ok = !!(read_usb_charge(samsung) >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) if (attr == &dev_attr_lid_handling.attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) ok = !!(read_lid_handling(samsung) >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) return ok ? attr->mode : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) static const struct attribute_group platform_attribute_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) .is_visible = samsung_sysfs_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) .attrs = platform_attributes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) static void samsung_sysfs_exit(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) struct platform_device *device = samsung->platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) static int __init samsung_sysfs_init(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) struct platform_device *device = samsung->platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) static int samsung_laptop_call_show(struct seq_file *m, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) struct samsung_laptop *samsung = m->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) struct sabi_data *sdata = &samsung->debug.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) seq_printf(m, "SABI 0x%04x {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) samsung->debug.command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) sdata->d0, sdata->d1, sdata->d2, sdata->d3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) ret = sabi_command(samsung, samsung->debug.command, sdata, sdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) seq_printf(m, "SABI command 0x%04x failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) samsung->debug.command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) seq_printf(m, "SABI {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) sdata->d0, sdata->d1, sdata->d2, sdata->d3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) DEFINE_SHOW_ATTRIBUTE(samsung_laptop_call);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) static void samsung_debugfs_exit(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) debugfs_remove_recursive(samsung->debug.root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) static void samsung_debugfs_init(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) struct dentry *root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) root = debugfs_create_dir("samsung-laptop", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) samsung->debug.root = root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) samsung->debug.f0000_wrapper.data = samsung->f0000_segment;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) samsung->debug.f0000_wrapper.size = 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) samsung->debug.data_wrapper.data = &samsung->debug.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) samsung->debug.data_wrapper.size = sizeof(samsung->debug.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) samsung->debug.sdiag_wrapper.data = samsung->sdiag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) samsung->debug.sdiag_wrapper.size = strlen(samsung->sdiag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) debugfs_create_u16("command", S_IRUGO | S_IWUSR, root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) &samsung->debug.command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) debugfs_create_u32("d0", S_IRUGO | S_IWUSR, root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) &samsung->debug.data.d0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) debugfs_create_u32("d1", S_IRUGO | S_IWUSR, root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) &samsung->debug.data.d1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) debugfs_create_u16("d2", S_IRUGO | S_IWUSR, root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) &samsung->debug.data.d2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) debugfs_create_u8("d3", S_IRUGO | S_IWUSR, root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) &samsung->debug.data.d3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) debugfs_create_blob("data", S_IRUGO | S_IWUSR, root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) &samsung->debug.data_wrapper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) debugfs_create_blob("f0000_segment", S_IRUSR | S_IWUSR, root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) &samsung->debug.f0000_wrapper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) debugfs_create_file("call", S_IFREG | S_IRUGO, root, samsung,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) &samsung_laptop_call_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) debugfs_create_blob("sdiag", S_IRUGO | S_IWUSR, root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) &samsung->debug.sdiag_wrapper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) static void samsung_sabi_exit(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) const struct sabi_config *config = samsung->config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) /* Turn off "Linux" mode in the BIOS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) if (config && config->commands.set_linux != 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) sabi_set_commandb(samsung, config->commands.set_linux, 0x80);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) if (samsung->sabi_iface) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) iounmap(samsung->sabi_iface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) samsung->sabi_iface = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) if (samsung->f0000_segment) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) iounmap(samsung->f0000_segment);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) samsung->f0000_segment = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) samsung->config = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) static __init void samsung_sabi_infos(struct samsung_laptop *samsung, int loca,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) unsigned int ifaceP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) const struct sabi_config *config = samsung->config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) printk(KERN_DEBUG "This computer supports SABI==%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) loca + 0xf0000 - 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) printk(KERN_DEBUG "SABI header:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) readw(samsung->sabi + config->header_offsets.port));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) readb(samsung->sabi + config->header_offsets.iface_func));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) readb(samsung->sabi + config->header_offsets.en_mem));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) readb(samsung->sabi + config->header_offsets.re_mem));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) readw(samsung->sabi + config->header_offsets.data_offset));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) readw(samsung->sabi + config->header_offsets.data_segment));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) printk(KERN_DEBUG " SABI pointer = 0x%08x\n", ifaceP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) static void __init samsung_sabi_diag(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) int loca = find_signature(samsung->f0000_segment, "SDiaG@");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) if (loca == 0xffff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) return ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) /* Example:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) * Ident: @SDiaG@686XX-N90X3A/966-SEC-07HL-S90X3A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) * Product name: 90X3A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) * BIOS Version: 07HL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) loca += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) for (i = 0; loca < 0xffff && i < sizeof(samsung->sdiag) - 1; loca++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) char temp = readb(samsung->f0000_segment + loca);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) if (isalnum(temp) || temp == '/' || temp == '-')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) samsung->sdiag[i++] = temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) break ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) if (debug && samsung->sdiag[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) pr_info("sdiag: %s", samsung->sdiag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) static int __init samsung_sabi_init(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) const struct sabi_config *config = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) const struct sabi_commands *commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) unsigned int ifaceP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) int loca = 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) samsung->f0000_segment = ioremap(0xf0000, 0xffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) if (!samsung->f0000_segment) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) if (debug || force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) pr_err("Can't map the segment at 0xf0000\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) samsung_sabi_diag(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) /* Try to find one of the signatures in memory to find the header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) for (i = 0; sabi_configs[i].test_string != NULL; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) samsung->config = &sabi_configs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) loca = find_signature(samsung->f0000_segment,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) samsung->config->test_string);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) if (loca != 0xffff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) if (loca == 0xffff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) if (debug || force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) pr_err("This computer does not support SABI\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) config = samsung->config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) commands = &config->commands;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) /* point to the SMI port Number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) loca += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) samsung->sabi = (samsung->f0000_segment + loca);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) /* Get a pointer to the SABI Interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) ifaceP = (readw(samsung->sabi + config->header_offsets.data_segment) & 0x0ffff) << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) ifaceP += readw(samsung->sabi + config->header_offsets.data_offset) & 0x0ffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) samsung_sabi_infos(samsung, loca, ifaceP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) samsung->sabi_iface = ioremap(ifaceP, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) if (!samsung->sabi_iface) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) pr_err("Can't remap %x\n", ifaceP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) /* Turn on "Linux" mode in the BIOS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) if (commands->set_linux != 0xff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) int retval = sabi_set_commandb(samsung,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) commands->set_linux, 0x81);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) pr_warn("Linux mode was not set!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) /* Check for stepping quirk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) if (samsung->handle_backlight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) check_for_stepping_quirk(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) pr_info("detected SABI interface: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) samsung->config->test_string);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) samsung_sabi_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) static void samsung_platform_exit(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) if (samsung->platform_device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) platform_device_unregister(samsung->platform_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) samsung->platform_device = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) static int samsung_pm_notification(struct notifier_block *nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) unsigned long val, void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) struct samsung_laptop *samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) samsung = container_of(nb, struct samsung_laptop, pm_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) if (val == PM_POST_HIBERNATION &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) samsung->quirks->enable_kbd_backlight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) kbd_backlight_enable(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) if (val == PM_POST_HIBERNATION && samsung->quirks->lid_handling)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) write_lid_handling(samsung, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) static int __init samsung_platform_init(struct samsung_laptop *samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) struct platform_device *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) pdev = platform_device_register_simple("samsung", -1, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) if (IS_ERR(pdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) return PTR_ERR(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) samsung->platform_device = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) platform_set_drvdata(samsung->platform_device, samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) static struct samsung_quirks *quirks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) static int __init samsung_dmi_matched(const struct dmi_system_id *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) quirks = d->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) static const struct dmi_system_id samsung_dmi_table[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) DMI_MATCH(DMI_SYS_VENDOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) DMI_MATCH(DMI_SYS_VENDOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) DMI_MATCH(DMI_SYS_VENDOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) DMI_MATCH(DMI_SYS_VENDOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) /* DMI ids for laptops with bad Chassis Type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) .ident = "R40/R41",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) DMI_MATCH(DMI_PRODUCT_NAME, "R40/R41"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) DMI_MATCH(DMI_BOARD_NAME, "R40/R41"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) /* Specific DMI ids for laptop with quirks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) .callback = samsung_dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) .ident = "N150P",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) DMI_MATCH(DMI_BOARD_NAME, "N150P"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) .driver_data = &samsung_use_native_backlight,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) .callback = samsung_dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) .ident = "N145P/N250P/N260P",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) .driver_data = &samsung_use_native_backlight,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) .callback = samsung_dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) .ident = "N150/N210/N220",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) .driver_data = &samsung_broken_acpi_video,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) .callback = samsung_dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) .ident = "NF110/NF210/NF310",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) .driver_data = &samsung_broken_acpi_video,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) .callback = samsung_dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) .ident = "X360",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) DMI_MATCH(DMI_BOARD_NAME, "X360"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) .driver_data = &samsung_broken_acpi_video,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) .callback = samsung_dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) .ident = "N250P",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) DMI_MATCH(DMI_BOARD_NAME, "N250P"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) .driver_data = &samsung_use_native_backlight,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) .callback = samsung_dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) .ident = "NC210",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) .driver_data = &samsung_broken_acpi_video,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) .callback = samsung_dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) .ident = "730U3E/740U3E",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) .driver_data = &samsung_np740u3e,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) .callback = samsung_dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) .ident = "300V3Z/300V4Z/300V5Z",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) DMI_MATCH(DMI_PRODUCT_NAME, "300V3Z/300V4Z/300V5Z"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) .driver_data = &samsung_lid_handling,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) static struct platform_device *samsung_platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) static int __init samsung_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) struct samsung_laptop *samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) if (efi_enabled(EFI_BOOT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) quirks = &samsung_unknown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) if (!force && !dmi_check_system(samsung_dmi_table))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) samsung = kzalloc(sizeof(*samsung), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) if (!samsung)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) mutex_init(&samsung->sabi_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) samsung->handle_backlight = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) samsung->quirks = quirks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) #ifdef CONFIG_ACPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) if (samsung->quirks->broken_acpi_video)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) if (samsung->quirks->use_native_backlight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) acpi_video_set_dmi_backlight_type(acpi_backlight_native);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) samsung->handle_backlight = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) ret = samsung_platform_init(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) goto error_platform;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) ret = samsung_sabi_init(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) goto error_sabi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) ret = samsung_sysfs_init(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) goto error_sysfs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) ret = samsung_backlight_init(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) goto error_backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) ret = samsung_rfkill_init(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) goto error_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) ret = samsung_leds_init(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) goto error_leds;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) ret = samsung_lid_handling_init(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) goto error_lid_handling;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) samsung_debugfs_init(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) samsung->pm_nb.notifier_call = samsung_pm_notification;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) register_pm_notifier(&samsung->pm_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) samsung_platform_device = samsung->platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) error_lid_handling:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) samsung_leds_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) error_leds:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) samsung_rfkill_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) error_rfkill:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) samsung_backlight_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) error_backlight:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) samsung_sysfs_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) error_sysfs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) samsung_sabi_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) error_sabi:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) samsung_platform_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) error_platform:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) kfree(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) static void __exit samsung_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) struct samsung_laptop *samsung;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) samsung = platform_get_drvdata(samsung_platform_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) unregister_pm_notifier(&samsung->pm_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) samsung_debugfs_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) samsung_lid_handling_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) samsung_leds_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) samsung_rfkill_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) samsung_backlight_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) samsung_sysfs_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) samsung_sabi_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) samsung_platform_exit(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) kfree(samsung);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) samsung_platform_device = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) module_init(samsung_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) module_exit(samsung_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) MODULE_DESCRIPTION("Samsung Backlight driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) MODULE_LICENSE("GPL");