3
0
Fork 0
forked from mirrors/linux

Merge branch 'fixes' into for-next

Resolve conflicts in dell/alienware-wmi-wmax and asus-wmi, and enable
applying a few amd/hsmp patches that depend on changes in the fixes
branch.
This commit is contained in:
Ilpo Järvinen 2025-05-12 00:18:11 +03:00
commit 593ee93aa7
No known key found for this signature in database
GPG key ID: 59AC4F6153E5CE31
25 changed files with 384 additions and 131 deletions

View file

@ -138,6 +138,10 @@ input data, the meaning of which depends on the subfeature being accessed.
The output buffer contains a single byte which signals success or failure (``0x00`` on failure) The output buffer contains a single byte which signals success or failure (``0x00`` on failure)
and 31 bytes of output data, the meaning if which depends on the subfeature being accessed. and 31 bytes of output data, the meaning if which depends on the subfeature being accessed.
.. note::
The ACPI control method responsible for handling the WMI method calls is not thread-safe.
This is a firmware bug that needs to be handled inside the driver itself.
WMI method Get_EC() WMI method Get_EC()
------------------- -------------------

View file

@ -333,9 +333,9 @@ static ssize_t secure_boot_fuse_state_show(struct device *dev,
else else
status = valid ? "Invalid" : "Free"; status = valid ? "Invalid" : "Free";
} }
buf_len += sysfs_emit(buf + buf_len, "%d:%s ", key, status); buf_len += sysfs_emit_at(buf, buf_len, "%d:%s ", key, status);
} }
buf_len += sysfs_emit(buf + buf_len, "\n"); buf_len += sysfs_emit_at(buf, buf_len, "\n");
return buf_len; return buf_len;
} }

View file

@ -27,9 +27,8 @@
#include "hsmp.h" #include "hsmp.h"
#define DRIVER_NAME "amd_hsmp" #define DRIVER_NAME "hsmp_acpi"
#define DRIVER_VERSION "2.3" #define DRIVER_VERSION "2.3"
#define ACPI_HSMP_DEVICE_HID "AMDI0097"
/* These are the strings specified in ACPI table */ /* These are the strings specified in ACPI table */
#define MSG_IDOFF_STR "MsgIdOffset" #define MSG_IDOFF_STR "MsgIdOffset"

View file

@ -23,6 +23,7 @@
#define HSMP_CDEV_NAME "hsmp_cdev" #define HSMP_CDEV_NAME "hsmp_cdev"
#define HSMP_DEVNODE_NAME "hsmp" #define HSMP_DEVNODE_NAME "hsmp"
#define ACPI_HSMP_DEVICE_HID "AMDI0097"
struct hsmp_mbaddr_info { struct hsmp_mbaddr_info {
u32 base_addr; u32 base_addr;

View file

@ -11,6 +11,7 @@
#include <asm/amd_hsmp.h> #include <asm/amd_hsmp.h>
#include <linux/acpi.h>
#include <linux/build_bug.h> #include <linux/build_bug.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
@ -266,7 +267,7 @@ static bool legacy_hsmp_support(void)
} }
case 0x1A: case 0x1A:
switch (boot_cpu_data.x86_model) { switch (boot_cpu_data.x86_model) {
case 0x00 ... 0x1F: case 0x00 ... 0x0F:
return true; return true;
default: default:
return false; return false;
@ -288,6 +289,9 @@ static int __init hsmp_plt_init(void)
return ret; return ret;
} }
if (acpi_dev_present(ACPI_HSMP_DEVICE_HID, NULL, -1))
return -ENODEV;
hsmp_pdev = get_hsmp_pdev(); hsmp_pdev = get_hsmp_pdev();
if (!hsmp_pdev) if (!hsmp_pdev)
return -ENOMEM; return -ENOMEM;

View file

@ -217,6 +217,13 @@ static const struct dmi_system_id fwbug_list[] = {
DMI_MATCH(DMI_BIOS_VERSION, "03.05"), DMI_MATCH(DMI_BIOS_VERSION, "03.05"),
} }
}, },
{
.ident = "MECHREVO Wujie 14X (GX4HRXL)",
.driver_data = &quirk_spurious_8042,
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "WUJIE14-GX4HRXL"),
}
},
{} {}
}; };

View file

@ -644,10 +644,9 @@ static void amd_pmc_s2idle_check(void)
struct smu_metrics table; struct smu_metrics table;
int rc; int rc;
/* CZN: Ensure that future s0i3 entry attempts at least 10ms passed */ /* Avoid triggering OVP */
if (pdev->cpu_id == AMD_CPU_ID_CZN && !get_metrics_table(pdev, &table) && if (!get_metrics_table(pdev, &table) && table.s0i3_last_entry_status)
table.s0i3_last_entry_status) msleep(2500);
usleep_range(10000, 20000);
/* Dump the IdleMask before we add to the STB */ /* Dump the IdleMask before we add to the STB */
amd_pmc_idlemask_read(pdev, pdev->dev, NULL); amd_pmc_idlemask_read(pdev, pdev->dev, NULL);

View file

@ -120,9 +120,9 @@ static void amd_pmf_set_automode(struct amd_pmf_dev *dev, int idx,
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pwr_ctrl->sppt_apu_only, NULL); amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pwr_ctrl->sppt_apu_only, NULL);
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pwr_ctrl->stt_min, NULL); amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pwr_ctrl->stt_min, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
pwr_ctrl->stt_skin_temp[STT_TEMP_APU], NULL); fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_APU]), NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
pwr_ctrl->stt_skin_temp[STT_TEMP_HS2], NULL); fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_HS2]), NULL);
if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX)) if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
apmf_update_fan_idx(dev, config_store.mode_set[idx].fan_control.manual, apmf_update_fan_idx(dev, config_store.mode_set[idx].fan_control.manual,

View file

@ -81,10 +81,10 @@ static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx,
amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL); amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL);
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL); amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL);
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL); amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, pc->stt_skin_temp[STT_TEMP_APU], amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
NULL); fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_APU]), NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, pc->stt_skin_temp[STT_TEMP_HS2], amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
NULL); fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_HS2]), NULL);
if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX)) if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
apmf_update_fan_idx(dev, apmf_update_fan_idx(dev,

View file

@ -176,6 +176,20 @@ static void __maybe_unused amd_pmf_dump_registers(struct amd_pmf_dev *dev)
dev_dbg(dev->dev, "AMD_PMF_REGISTER_MESSAGE:%x\n", value); dev_dbg(dev->dev, "AMD_PMF_REGISTER_MESSAGE:%x\n", value);
} }
/**
* fixp_q88_fromint: Convert integer to Q8.8
* @val: input value
*
* Converts an integer into binary fixed point format where 8 bits
* are used for integer and 8 bits are used for the decimal.
*
* Return: unsigned integer converted to Q8.8 format
*/
u32 fixp_q88_fromint(u32 val)
{
return val << 8;
}
int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data) int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data)
{ {
int rc; int rc;

View file

@ -777,6 +777,7 @@ int apmf_install_handler(struct amd_pmf_dev *pmf_dev);
int apmf_os_power_slider_update(struct amd_pmf_dev *dev, u8 flag); int apmf_os_power_slider_update(struct amd_pmf_dev *dev, u8 flag);
int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer); int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer);
int amd_pmf_notify_sbios_heartbeat_event_v2(struct amd_pmf_dev *dev, u8 flag); int amd_pmf_notify_sbios_heartbeat_event_v2(struct amd_pmf_dev *dev, u8 flag);
u32 fixp_q88_fromint(u32 val);
/* SPS Layer */ /* SPS Layer */
int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf); int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf);

View file

@ -198,9 +198,11 @@ static void amd_pmf_update_slider_v2(struct amd_pmf_dev *dev, int idx)
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
apts_config_store.val[idx].stt_min_limit, NULL); apts_config_store.val[idx].stt_min_limit, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
apts_config_store.val[idx].stt_skin_temp_limit_apu, NULL); fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_apu),
NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
apts_config_store.val[idx].stt_skin_temp_limit_hs2, NULL); fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_hs2),
NULL);
} }
void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
@ -217,9 +219,11 @@ void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
config_store.prop[src][idx].stt_min, NULL); config_store.prop[src][idx].stt_min, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL); fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU]),
NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL); fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2]),
NULL);
} else if (op == SLIDER_OP_GET) { } else if (op == SLIDER_OP_GET) {
amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl); amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl);
amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt); amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt);

View file

@ -123,7 +123,8 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_STT_SKINTEMP_APU: case PMF_POLICY_STT_SKINTEMP_APU:
if (dev->prev_data->stt_skintemp_apu != val) { if (dev->prev_data->stt_skintemp_apu != val) {
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, val, NULL); amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
fixp_q88_fromint(val), NULL);
dev_dbg(dev->dev, "update STT_SKINTEMP_APU: %u\n", val); dev_dbg(dev->dev, "update STT_SKINTEMP_APU: %u\n", val);
dev->prev_data->stt_skintemp_apu = val; dev->prev_data->stt_skintemp_apu = val;
} }
@ -131,7 +132,8 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_STT_SKINTEMP_HS2: case PMF_POLICY_STT_SKINTEMP_HS2:
if (dev->prev_data->stt_skintemp_hs2 != val) { if (dev->prev_data->stt_skintemp_hs2 != val) {
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, val, NULL); amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
fixp_q88_fromint(val), NULL);
dev_dbg(dev->dev, "update STT_SKINTEMP_HS2: %u\n", val); dev_dbg(dev->dev, "update STT_SKINTEMP_HS2: %u\n", val);
dev->prev_data->stt_skintemp_hs2 = val; dev->prev_data->stt_skintemp_hs2 = val;
} }
@ -332,6 +334,11 @@ static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev)
return 0; return 0;
} }
static inline bool amd_pmf_pb_valid(struct amd_pmf_dev *dev)
{
return memchr_inv(dev->policy_buf, 0xff, dev->policy_sz);
}
#ifdef CONFIG_AMD_PMF_DEBUG #ifdef CONFIG_AMD_PMF_DEBUG
static void amd_pmf_hex_dump_pb(struct amd_pmf_dev *dev) static void amd_pmf_hex_dump_pb(struct amd_pmf_dev *dev)
{ {
@ -359,12 +366,22 @@ static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf,
dev->policy_buf = new_policy_buf; dev->policy_buf = new_policy_buf;
dev->policy_sz = length; dev->policy_sz = length;
if (!amd_pmf_pb_valid(dev)) {
ret = -EINVAL;
goto cleanup;
}
amd_pmf_hex_dump_pb(dev); amd_pmf_hex_dump_pb(dev);
ret = amd_pmf_start_policy_engine(dev); ret = amd_pmf_start_policy_engine(dev);
if (ret < 0) if (ret < 0)
return ret; goto cleanup;
return length; return length;
cleanup:
kfree(dev->policy_buf);
dev->policy_buf = NULL;
return ret;
} }
static const struct file_operations pb_fops = { static const struct file_operations pb_fops = {
@ -526,6 +543,12 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
memcpy_fromio(dev->policy_buf, dev->policy_base, dev->policy_sz); memcpy_fromio(dev->policy_buf, dev->policy_base, dev->policy_sz);
if (!amd_pmf_pb_valid(dev)) {
dev_info(dev->dev, "No Smart PC policy present\n");
ret = -EINVAL;
goto err_free_policy;
}
amd_pmf_hex_dump_pb(dev); amd_pmf_hex_dump_pb(dev);
dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL); dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL);

View file

@ -426,11 +426,14 @@ static int asus_pega_lucid_set(struct asus_laptop *asus, int unit, bool enable)
static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method) static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method)
{ {
unsigned long long val = (unsigned long long)curr;
acpi_status status;
int i, delta; int i, delta;
unsigned long long val;
for (i = 0; i < PEGA_ACC_RETRIES; i++) {
acpi_evaluate_integer(asus->handle, method, NULL, &val);
for (i = 0; i < PEGA_ACC_RETRIES; i++) {
status = acpi_evaluate_integer(asus->handle, method, NULL, &val);
if (ACPI_FAILURE(status))
continue;
/* The output is noisy. From reading the ASL /* The output is noisy. From reading the ASL
* dissassembly, timeout errors are returned with 1's * dissassembly, timeout errors are returned with 1's
* in the high word, and the lack of locking around * in the high word, and the lack of locking around

View file

@ -305,6 +305,7 @@ struct asus_wmi {
u32 kbd_rgb_dev; u32 kbd_rgb_dev;
bool kbd_rgb_state_available; bool kbd_rgb_state_available;
bool oobe_state_available;
u8 throttle_thermal_policy_mode; u8 throttle_thermal_policy_mode;
u32 throttle_thermal_policy_dev; u32 throttle_thermal_policy_dev;
@ -1868,7 +1869,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
goto error; goto error;
} }
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE)) { if (asus->oobe_state_available) {
/* /*
* Disable OOBE state, so that e.g. the keyboard backlight * Disable OOBE state, so that e.g. the keyboard backlight
* works. * works.
@ -4780,6 +4781,7 @@ static int asus_wmi_add(struct platform_device *pdev)
asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU); asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
asus->oobe_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE);
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE))
asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
@ -4832,7 +4834,8 @@ static int asus_wmi_add(struct platform_device *pdev)
goto fail_leds; goto fail_leds;
asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result); asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result);
if (result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) if ((result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) ==
(ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT))
asus->driver->wlan_ctrl_by_user = 1; asus->driver->wlan_ctrl_by_user = 1;
if (!(asus->driver->wlan_ctrl_by_user && ashs_present())) { if (!(asus->driver->wlan_ctrl_by_user && ashs_present())) {
@ -4997,6 +5000,13 @@ static int asus_hotk_restore(struct device *device)
} }
if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
kbd_led_update(asus); kbd_led_update(asus);
if (asus->oobe_state_available) {
/*
* Disable OOBE state, so that e.g. the keyboard backlight
* works.
*/
asus_wmi_set_devstate(ASUS_WMI_DEVID_OOBE, 1, NULL);
}
if (asus_wmi_has_fnlock_key(asus)) if (asus_wmi_has_fnlock_key(asus))
asus_wmi_fnlock_update(asus); asus_wmi_fnlock_update(asus);

View file

@ -89,12 +89,44 @@ static struct awcc_quirks generic_quirks = {
static struct awcc_quirks empty_quirks; static struct awcc_quirks empty_quirks;
static const struct dmi_system_id awcc_dmi_table[] __initconst = { static const struct dmi_system_id awcc_dmi_table[] __initconst = {
{
.ident = "Alienware Area-51m R2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware Area-51m R2"),
},
.driver_data = &generic_quirks,
},
{
.ident = "Alienware m15 R7",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m15 R7"),
},
.driver_data = &generic_quirks,
},
{
.ident = "Alienware m16 R1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1"),
},
.driver_data = &g_series_quirks,
},
{ {
.ident = "Alienware m16 R1 AMD", .ident = "Alienware m16 R1 AMD",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1 AMD"), DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1 AMD"),
}, },
.driver_data = &g_series_quirks,
},
{
.ident = "Alienware m16 R2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R2"),
},
.driver_data = &generic_quirks, .driver_data = &generic_quirks,
}, },
{ {
@ -121,6 +153,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {
}, },
.driver_data = &generic_quirks, .driver_data = &generic_quirks,
}, },
{
.ident = "Alienware x15 R2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R2"),
},
.driver_data = &generic_quirks,
},
{ {
.ident = "Alienware x17 R2", .ident = "Alienware x17 R2",
.matches = { .matches = {
@ -153,6 +193,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {
}, },
.driver_data = &g_series_quirks, .driver_data = &g_series_quirks,
}, },
{
.ident = "Dell Inc. G16 7630",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Dell G16 7630"),
},
.driver_data = &g_series_quirks,
},
{ {
.ident = "Dell Inc. G3 3500", .ident = "Dell Inc. G3 3500",
.matches = { .matches = {
@ -177,6 +225,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {
}, },
.driver_data = &g_series_quirks, .driver_data = &g_series_quirks,
}, },
{
.ident = "Dell Inc. G5 5505",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "G5 5505"),
},
.driver_data = &g_series_quirks,
},
}; };
enum AWCC_GET_FAN_SENSORS_OPERATIONS { enum AWCC_GET_FAN_SENSORS_OPERATIONS {
@ -1241,14 +1297,14 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices)
for (unsigned int i = 0; i < priv->profile_count; i++) { for (unsigned int i = 0; i < priv->profile_count; i++) {
ret = awcc_op_get_resource_id(priv->wdev, i + offset, &id); ret = awcc_op_get_resource_id(priv->wdev, i + offset, &id);
if (ret == -EIO)
return ret;
/* /*
* Some devices report an incorrect number of thermal profiles * Some devices report an incorrect number of thermal profiles
* so the resource ID list may end prematurely * so the resource ID list may end prematurely
*/ */
if (ret == -EBADRQC) if (ret == -EBADRQC)
break; break;
if (ret)
return ret;
if (!is_awcc_thermal_profile_id(id)) { if (!is_awcc_thermal_profile_id(id)) {
dev_dbg(&priv->wdev->dev, "Unmapped thermal profile ID 0x%02x\n", id); dev_dbg(&priv->wdev->dev, "Unmapped thermal profile ID 0x%02x\n", id);

View file

@ -1294,6 +1294,16 @@ static const struct key_entry ideapad_keymap[] = {
/* Specific to some newer models */ /* Specific to some newer models */
{ KE_KEY, 0x3e | IDEAPAD_WMI_KEY, { KEY_MICMUTE } }, { KE_KEY, 0x3e | IDEAPAD_WMI_KEY, { KEY_MICMUTE } },
{ KE_KEY, 0x3f | IDEAPAD_WMI_KEY, { KEY_RFKILL } }, { KE_KEY, 0x3f | IDEAPAD_WMI_KEY, { KEY_RFKILL } },
/* Star- (User Assignable Key) */
{ KE_KEY, 0x44 | IDEAPAD_WMI_KEY, { KEY_PROG1 } },
/* Eye */
{ KE_KEY, 0x45 | IDEAPAD_WMI_KEY, { KEY_PROG3 } },
/* Performance toggle also Fn+Q, handled inside ideapad_wmi_notify() */
{ KE_KEY, 0x3d | IDEAPAD_WMI_KEY, { KEY_PROG4 } },
/* shift + prtsc */
{ KE_KEY, 0x2d | IDEAPAD_WMI_KEY, { KEY_CUT } },
{ KE_KEY, 0x29 | IDEAPAD_WMI_KEY, { KEY_TOUCHPAD_TOGGLE } },
{ KE_KEY, 0x2a | IDEAPAD_WMI_KEY, { KEY_ROOT_MENU } },
{ KE_END }, { KE_END },
}; };
@ -2080,6 +2090,12 @@ static void ideapad_wmi_notify(struct wmi_device *wdev, union acpi_object *data)
dev_dbg(&wdev->dev, "WMI fn-key event: 0x%llx\n", dev_dbg(&wdev->dev, "WMI fn-key event: 0x%llx\n",
data->integer.value); data->integer.value);
/* performance button triggered by 0x3d */
if (data->integer.value == 0x3d && priv->dytc) {
platform_profile_cycle();
break;
}
/* 0x02 FnLock, 0x03 Esc */ /* 0x02 FnLock, 0x03 Esc */
if (data->integer.value == 0x02 || data->integer.value == 0x03) if (data->integer.value == 0x02 || data->integer.value == 0x03)
ideapad_fn_lock_led_notify(priv, data->integer.value == 0x02); ideapad_fn_lock_led_notify(priv, data->integer.value == 0x02);

View file

@ -44,16 +44,17 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alex Hung"); MODULE_AUTHOR("Alex Hung");
static const struct acpi_device_id intel_hid_ids[] = { static const struct acpi_device_id intel_hid_ids[] = {
{"INT33D5", 0}, { "INT33D5" },
{"INTC1051", 0}, { "INTC1051" },
{"INTC1054", 0}, { "INTC1054" },
{"INTC1070", 0}, { "INTC1070" },
{"INTC1076", 0}, { "INTC1076" },
{"INTC1077", 0}, { "INTC1077" },
{"INTC1078", 0}, { "INTC1078" },
{"INTC107B", 0}, { "INTC107B" },
{"INTC10CB", 0}, { "INTC10CB" },
{"", 0}, { "INTC10CC" },
{ }
}; };
MODULE_DEVICE_TABLE(acpi, intel_hid_ids); MODULE_DEVICE_TABLE(acpi, intel_hid_ids);

View file

@ -146,15 +146,13 @@ static int uncore_event_cpu_online(unsigned int cpu)
{ {
struct uncore_data *data; struct uncore_data *data;
int target; int target;
int ret;
/* Check if there is an online cpu in the package for uncore MSR */ /* Check if there is an online cpu in the package for uncore MSR */
target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu)); target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu));
if (target < nr_cpu_ids) if (target < nr_cpu_ids)
return 0; return 0;
/* Use this CPU on this die as a control CPU */
cpumask_set_cpu(cpu, &uncore_cpu_mask);
data = uncore_get_instance(cpu); data = uncore_get_instance(cpu);
if (!data) if (!data)
return 0; return 0;
@ -163,7 +161,14 @@ static int uncore_event_cpu_online(unsigned int cpu)
data->die_id = topology_die_id(cpu); data->die_id = topology_die_id(cpu);
data->domain_id = UNCORE_DOMAIN_ID_INVALID; data->domain_id = UNCORE_DOMAIN_ID_INVALID;
return uncore_freq_add_entry(data, cpu); ret = uncore_freq_add_entry(data, cpu);
if (ret)
return ret;
/* Use this CPU on this die as a control CPU */
cpumask_set_cpu(cpu, &uncore_cpu_mask);
return 0;
} }
static int uncore_event_cpu_offline(unsigned int cpu) static int uncore_event_cpu_offline(unsigned int cpu)

View file

@ -10,6 +10,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/cleanup.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/device/driver.h> #include <linux/device/driver.h>
@ -17,6 +18,7 @@
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/printk.h> #include <linux/printk.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/types.h> #include <linux/types.h>
@ -76,8 +78,13 @@ enum msi_wmi_platform_method {
MSI_PLATFORM_GET_WMI = 0x1d, MSI_PLATFORM_GET_WMI = 0x1d,
}; };
struct msi_wmi_platform_debugfs_data { struct msi_wmi_platform_data {
struct wmi_device *wdev; struct wmi_device *wdev;
struct mutex wmi_lock; /* Necessary when calling WMI methods */
};
struct msi_wmi_platform_debugfs_data {
struct msi_wmi_platform_data *data;
enum msi_wmi_platform_method method; enum msi_wmi_platform_method method;
struct rw_semaphore buffer_lock; /* Protects debugfs buffer */ struct rw_semaphore buffer_lock; /* Protects debugfs buffer */
size_t length; size_t length;
@ -132,8 +139,9 @@ static int msi_wmi_platform_parse_buffer(union acpi_object *obj, u8 *output, siz
return 0; return 0;
} }
static int msi_wmi_platform_query(struct wmi_device *wdev, enum msi_wmi_platform_method method, static int msi_wmi_platform_query(struct msi_wmi_platform_data *data,
u8 *input, size_t input_length, u8 *output, size_t output_length) enum msi_wmi_platform_method method, u8 *input,
size_t input_length, u8 *output, size_t output_length)
{ {
struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_buffer in = { struct acpi_buffer in = {
@ -147,9 +155,15 @@ static int msi_wmi_platform_query(struct wmi_device *wdev, enum msi_wmi_platform
if (!input_length || !output_length) if (!input_length || !output_length)
return -EINVAL; return -EINVAL;
status = wmidev_evaluate_method(wdev, 0x0, method, &in, &out); /*
if (ACPI_FAILURE(status)) * The ACPI control method responsible for handling the WMI method calls
return -EIO; * is not thread-safe. Because of this we have to do the locking ourself.
*/
scoped_guard(mutex, &data->wmi_lock) {
status = wmidev_evaluate_method(data->wdev, 0x0, method, &in, &out);
if (ACPI_FAILURE(status))
return -EIO;
}
obj = out.pointer; obj = out.pointer;
if (!obj) if (!obj)
@ -170,22 +184,22 @@ static umode_t msi_wmi_platform_is_visible(const void *drvdata, enum hwmon_senso
static int msi_wmi_platform_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, static int msi_wmi_platform_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val) int channel, long *val)
{ {
struct wmi_device *wdev = dev_get_drvdata(dev); struct msi_wmi_platform_data *data = dev_get_drvdata(dev);
u8 input[32] = { 0 }; u8 input[32] = { 0 };
u8 output[32]; u8 output[32];
u16 data; u16 value;
int ret; int ret;
ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_FAN, input, sizeof(input), output, ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_FAN, input, sizeof(input), output,
sizeof(output)); sizeof(output));
if (ret < 0) if (ret < 0)
return ret; return ret;
data = get_unaligned_be16(&output[channel * 2 + 1]); value = get_unaligned_be16(&output[channel * 2 + 1]);
if (!data) if (!value)
*val = 0; *val = 0;
else else
*val = 480000 / data; *val = 480000 / value;
return 0; return 0;
} }
@ -231,7 +245,7 @@ static ssize_t msi_wmi_platform_write(struct file *fp, const char __user *input,
return ret; return ret;
down_write(&data->buffer_lock); down_write(&data->buffer_lock);
ret = msi_wmi_platform_query(data->wdev, data->method, payload, data->length, data->buffer, ret = msi_wmi_platform_query(data->data, data->method, payload, data->length, data->buffer,
data->length); data->length);
up_write(&data->buffer_lock); up_write(&data->buffer_lock);
@ -277,17 +291,17 @@ static void msi_wmi_platform_debugfs_remove(void *data)
debugfs_remove_recursive(dir); debugfs_remove_recursive(dir);
} }
static void msi_wmi_platform_debugfs_add(struct wmi_device *wdev, struct dentry *dir, static void msi_wmi_platform_debugfs_add(struct msi_wmi_platform_data *drvdata, struct dentry *dir,
const char *name, enum msi_wmi_platform_method method) const char *name, enum msi_wmi_platform_method method)
{ {
struct msi_wmi_platform_debugfs_data *data; struct msi_wmi_platform_debugfs_data *data;
struct dentry *entry; struct dentry *entry;
data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL); data = devm_kzalloc(&drvdata->wdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return; return;
data->wdev = wdev; data->data = drvdata;
data->method = method; data->method = method;
init_rwsem(&data->buffer_lock); init_rwsem(&data->buffer_lock);
@ -298,82 +312,82 @@ static void msi_wmi_platform_debugfs_add(struct wmi_device *wdev, struct dentry
entry = debugfs_create_file(name, 0600, dir, data, &msi_wmi_platform_debugfs_fops); entry = debugfs_create_file(name, 0600, dir, data, &msi_wmi_platform_debugfs_fops);
if (IS_ERR(entry)) if (IS_ERR(entry))
devm_kfree(&wdev->dev, data); devm_kfree(&drvdata->wdev->dev, data);
} }
static void msi_wmi_platform_debugfs_init(struct wmi_device *wdev) static void msi_wmi_platform_debugfs_init(struct msi_wmi_platform_data *data)
{ {
struct dentry *dir; struct dentry *dir;
char dir_name[64]; char dir_name[64];
int ret, method; int ret, method;
scnprintf(dir_name, ARRAY_SIZE(dir_name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev)); scnprintf(dir_name, ARRAY_SIZE(dir_name), "%s-%s", DRIVER_NAME, dev_name(&data->wdev->dev));
dir = debugfs_create_dir(dir_name, NULL); dir = debugfs_create_dir(dir_name, NULL);
if (IS_ERR(dir)) if (IS_ERR(dir))
return; return;
ret = devm_add_action_or_reset(&wdev->dev, msi_wmi_platform_debugfs_remove, dir); ret = devm_add_action_or_reset(&data->wdev->dev, msi_wmi_platform_debugfs_remove, dir);
if (ret < 0) if (ret < 0)
return; return;
for (method = MSI_PLATFORM_GET_PACKAGE; method <= MSI_PLATFORM_GET_WMI; method++) for (method = MSI_PLATFORM_GET_PACKAGE; method <= MSI_PLATFORM_GET_WMI; method++)
msi_wmi_platform_debugfs_add(wdev, dir, msi_wmi_platform_debugfs_names[method - 1], msi_wmi_platform_debugfs_add(data, dir, msi_wmi_platform_debugfs_names[method - 1],
method); method);
} }
static int msi_wmi_platform_hwmon_init(struct wmi_device *wdev) static int msi_wmi_platform_hwmon_init(struct msi_wmi_platform_data *data)
{ {
struct device *hdev; struct device *hdev;
hdev = devm_hwmon_device_register_with_info(&wdev->dev, "msi_wmi_platform", wdev, hdev = devm_hwmon_device_register_with_info(&data->wdev->dev, "msi_wmi_platform", data,
&msi_wmi_platform_chip_info, NULL); &msi_wmi_platform_chip_info, NULL);
return PTR_ERR_OR_ZERO(hdev); return PTR_ERR_OR_ZERO(hdev);
} }
static int msi_wmi_platform_ec_init(struct wmi_device *wdev) static int msi_wmi_platform_ec_init(struct msi_wmi_platform_data *data)
{ {
u8 input[32] = { 0 }; u8 input[32] = { 0 };
u8 output[32]; u8 output[32];
u8 flags; u8 flags;
int ret; int ret;
ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_EC, input, sizeof(input), output, ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_EC, input, sizeof(input), output,
sizeof(output)); sizeof(output));
if (ret < 0) if (ret < 0)
return ret; return ret;
flags = output[MSI_PLATFORM_EC_FLAGS_OFFSET]; flags = output[MSI_PLATFORM_EC_FLAGS_OFFSET];
dev_dbg(&wdev->dev, "EC RAM version %lu.%lu\n", dev_dbg(&data->wdev->dev, "EC RAM version %lu.%lu\n",
FIELD_GET(MSI_PLATFORM_EC_MAJOR_MASK, flags), FIELD_GET(MSI_PLATFORM_EC_MAJOR_MASK, flags),
FIELD_GET(MSI_PLATFORM_EC_MINOR_MASK, flags)); FIELD_GET(MSI_PLATFORM_EC_MINOR_MASK, flags));
dev_dbg(&wdev->dev, "EC firmware version %.28s\n", dev_dbg(&data->wdev->dev, "EC firmware version %.28s\n",
&output[MSI_PLATFORM_EC_VERSION_OFFSET]); &output[MSI_PLATFORM_EC_VERSION_OFFSET]);
if (!(flags & MSI_PLATFORM_EC_IS_TIGERLAKE)) { if (!(flags & MSI_PLATFORM_EC_IS_TIGERLAKE)) {
if (!force) if (!force)
return -ENODEV; return -ENODEV;
dev_warn(&wdev->dev, "Loading on a non-Tigerlake platform\n"); dev_warn(&data->wdev->dev, "Loading on a non-Tigerlake platform\n");
} }
return 0; return 0;
} }
static int msi_wmi_platform_init(struct wmi_device *wdev) static int msi_wmi_platform_init(struct msi_wmi_platform_data *data)
{ {
u8 input[32] = { 0 }; u8 input[32] = { 0 };
u8 output[32]; u8 output[32];
int ret; int ret;
ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_WMI, input, sizeof(input), output, ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_WMI, input, sizeof(input), output,
sizeof(output)); sizeof(output));
if (ret < 0) if (ret < 0)
return ret; return ret;
dev_dbg(&wdev->dev, "WMI interface version %u.%u\n", dev_dbg(&data->wdev->dev, "WMI interface version %u.%u\n",
output[MSI_PLATFORM_WMI_MAJOR_OFFSET], output[MSI_PLATFORM_WMI_MAJOR_OFFSET],
output[MSI_PLATFORM_WMI_MINOR_OFFSET]); output[MSI_PLATFORM_WMI_MINOR_OFFSET]);
@ -381,7 +395,8 @@ static int msi_wmi_platform_init(struct wmi_device *wdev)
if (!force) if (!force)
return -ENODEV; return -ENODEV;
dev_warn(&wdev->dev, "Loading despite unsupported WMI interface version (%u.%u)\n", dev_warn(&data->wdev->dev,
"Loading despite unsupported WMI interface version (%u.%u)\n",
output[MSI_PLATFORM_WMI_MAJOR_OFFSET], output[MSI_PLATFORM_WMI_MAJOR_OFFSET],
output[MSI_PLATFORM_WMI_MINOR_OFFSET]); output[MSI_PLATFORM_WMI_MINOR_OFFSET]);
} }
@ -391,19 +406,31 @@ static int msi_wmi_platform_init(struct wmi_device *wdev)
static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context) static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context)
{ {
struct msi_wmi_platform_data *data;
int ret; int ret;
ret = msi_wmi_platform_init(wdev); data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->wdev = wdev;
dev_set_drvdata(&wdev->dev, data);
ret = devm_mutex_init(&wdev->dev, &data->wmi_lock);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = msi_wmi_platform_ec_init(wdev); ret = msi_wmi_platform_init(data);
if (ret < 0) if (ret < 0)
return ret; return ret;
msi_wmi_platform_debugfs_init(wdev); ret = msi_wmi_platform_ec_init(data);
if (ret < 0)
return ret;
return msi_wmi_platform_hwmon_init(wdev); msi_wmi_platform_debugfs_init(data);
return msi_wmi_platform_hwmon_init(data);
} }
static const struct wmi_device_id msi_wmi_platform_id_table[] = { static const struct wmi_device_id msi_wmi_platform_id_table[] = {

View file

@ -11519,6 +11519,8 @@ static int __must_check __init get_thinkpad_model_data(
tp->vendor = PCI_VENDOR_ID_IBM; tp->vendor = PCI_VENDOR_ID_IBM;
else if (dmi_name_in_vendors("LENOVO")) else if (dmi_name_in_vendors("LENOVO"))
tp->vendor = PCI_VENDOR_ID_LENOVO; tp->vendor = PCI_VENDOR_ID_LENOVO;
else if (dmi_name_in_vendors("NEC"))
tp->vendor = PCI_VENDOR_ID_LENOVO;
else else
return 0; return 0;

View file

@ -179,6 +179,18 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
}, },
.driver_data = (void *)&peaq_c1010_info, .driver_data = (void *)&peaq_c1010_info,
}, },
{
/* Vexia Edu Atla 10 tablet 5V version */
.matches = {
/* Having all 3 of these not set is somewhat unique */
DMI_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."),
DMI_MATCH(DMI_BOARD_NAME, "To be filled by O.E.M."),
/* Above strings are too generic, also match on BIOS date */
DMI_MATCH(DMI_BIOS_DATE, "05/14/2015"),
},
.driver_data = (void *)&vexia_edu_atla10_5v_info,
},
{ {
/* Vexia Edu Atla 10 tablet 9V version */ /* Vexia Edu Atla 10 tablet 9V version */
.matches = { .matches = {
@ -187,7 +199,7 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
/* Above strings are too generic, also match on BIOS date */ /* Above strings are too generic, also match on BIOS date */
DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"), DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"),
}, },
.driver_data = (void *)&vexia_edu_atla10_info, .driver_data = (void *)&vexia_edu_atla10_9v_info,
}, },
{ {
/* Whitelabel (sold as various brands) TM800A550L */ /* Whitelabel (sold as various brands) TM800A550L */

View file

@ -599,62 +599,122 @@ const struct x86_dev_info whitelabel_tm800a550l_info __initconst = {
}; };
/* /*
* Vexia EDU ATLA 10 tablet, Android 4.2 / 4.4 + Guadalinex Ubuntu tablet * Vexia EDU ATLA 10 tablet 5V, Android 4.4 + Guadalinex Ubuntu tablet
* distributed to schools in the Spanish Andalucía region. * distributed to schools in the Spanish Andalucía region.
*/ */
static const char * const crystal_cove_pwrsrc_psy[] = { "crystal_cove_pwrsrc" }; static const struct property_entry vexia_edu_atla10_5v_touchscreen_props[] = {
static const struct property_entry vexia_edu_atla10_ulpmc_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", crystal_cove_pwrsrc_psy),
{ }
};
static const struct software_node vexia_edu_atla10_ulpmc_node = {
.properties = vexia_edu_atla10_ulpmc_props,
};
static const char * const vexia_edu_atla10_accel_mount_matrix[] = {
"0", "-1", "0",
"1", "0", "0",
"0", "0", "1"
};
static const struct property_entry vexia_edu_atla10_accel_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_accel_mount_matrix),
{ }
};
static const struct software_node vexia_edu_atla10_accel_node = {
.properties = vexia_edu_atla10_accel_props,
};
static const struct property_entry vexia_edu_atla10_touchscreen_props[] = {
PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000), PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000),
PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120), PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
{ } { }
}; };
static const struct software_node vexia_edu_atla10_touchscreen_node = { static const struct software_node vexia_edu_atla10_5v_touchscreen_node = {
.properties = vexia_edu_atla10_touchscreen_props, .properties = vexia_edu_atla10_5v_touchscreen_props,
}; };
static const struct property_entry vexia_edu_atla10_pmic_props[] = { static const struct x86_i2c_client_info vexia_edu_atla10_5v_i2c_clients[] __initconst = {
{
/* kxcjk1013 accelerometer */
.board_info = {
.type = "kxcjk1013",
.addr = 0x0f,
.dev_name = "kxcjk1013",
},
.adapter_path = "\\_SB_.I2C3",
}, {
/* touchscreen controller */
.board_info = {
.type = "hid-over-i2c",
.addr = 0x38,
.dev_name = "FTSC1000",
.swnode = &vexia_edu_atla10_5v_touchscreen_node,
},
.adapter_path = "\\_SB_.I2C4",
.irq_data = {
.type = X86_ACPI_IRQ_TYPE_APIC,
.index = 0x44,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_HIGH,
},
}
};
static struct gpiod_lookup_table vexia_edu_atla10_5v_ft5416_gpios = {
.dev_id = "i2c-FTSC1000",
.table = {
GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW),
{ }
},
};
static struct gpiod_lookup_table * const vexia_edu_atla10_5v_gpios[] = {
&vexia_edu_atla10_5v_ft5416_gpios,
NULL
};
const struct x86_dev_info vexia_edu_atla10_5v_info __initconst = {
.i2c_client_info = vexia_edu_atla10_5v_i2c_clients,
.i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_5v_i2c_clients),
.gpiod_lookup_tables = vexia_edu_atla10_5v_gpios,
};
/*
* Vexia EDU ATLA 10 tablet 9V, Android 4.2 + Guadalinex Ubuntu tablet
* distributed to schools in the Spanish Andalucía region.
*/
static const char * const crystal_cove_pwrsrc_psy[] = { "crystal_cove_pwrsrc" };
static const struct property_entry vexia_edu_atla10_9v_ulpmc_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", crystal_cove_pwrsrc_psy),
{ }
};
static const struct software_node vexia_edu_atla10_9v_ulpmc_node = {
.properties = vexia_edu_atla10_9v_ulpmc_props,
};
static const char * const vexia_edu_atla10_9v_accel_mount_matrix[] = {
"0", "-1", "0",
"1", "0", "0",
"0", "0", "1"
};
static const struct property_entry vexia_edu_atla10_9v_accel_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_9v_accel_mount_matrix),
{ }
};
static const struct software_node vexia_edu_atla10_9v_accel_node = {
.properties = vexia_edu_atla10_9v_accel_props,
};
static const struct property_entry vexia_edu_atla10_9v_touchscreen_props[] = {
PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000),
PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
{ }
};
static const struct software_node vexia_edu_atla10_9v_touchscreen_node = {
.properties = vexia_edu_atla10_9v_touchscreen_props,
};
static const struct property_entry vexia_edu_atla10_9v_pmic_props[] = {
PROPERTY_ENTRY_BOOL("linux,register-pwrsrc-power_supply"), PROPERTY_ENTRY_BOOL("linux,register-pwrsrc-power_supply"),
{ } { }
}; };
static const struct software_node vexia_edu_atla10_pmic_node = { static const struct software_node vexia_edu_atla10_9v_pmic_node = {
.properties = vexia_edu_atla10_pmic_props, .properties = vexia_edu_atla10_9v_pmic_props,
}; };
static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initconst = { static const struct x86_i2c_client_info vexia_edu_atla10_9v_i2c_clients[] __initconst = {
{ {
/* I2C attached embedded controller, used to access fuel-gauge */ /* I2C attached embedded controller, used to access fuel-gauge */
.board_info = { .board_info = {
.type = "vexia_atla10_ec", .type = "vexia_atla10_ec",
.addr = 0x76, .addr = 0x76,
.dev_name = "ulpmc", .dev_name = "ulpmc",
.swnode = &vexia_edu_atla10_ulpmc_node, .swnode = &vexia_edu_atla10_9v_ulpmc_node,
}, },
.adapter_path = "0000:00:18.1", .adapter_path = "0000:00:18.1",
}, { }, {
@ -679,7 +739,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon
.type = "kxtj21009", .type = "kxtj21009",
.addr = 0x0f, .addr = 0x0f,
.dev_name = "kxtj21009", .dev_name = "kxtj21009",
.swnode = &vexia_edu_atla10_accel_node, .swnode = &vexia_edu_atla10_9v_accel_node,
}, },
.adapter_path = "0000:00:18.5", .adapter_path = "0000:00:18.5",
}, { }, {
@ -688,7 +748,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon
.type = "hid-over-i2c", .type = "hid-over-i2c",
.addr = 0x38, .addr = 0x38,
.dev_name = "FTSC1000", .dev_name = "FTSC1000",
.swnode = &vexia_edu_atla10_touchscreen_node, .swnode = &vexia_edu_atla10_9v_touchscreen_node,
}, },
.adapter_path = "0000:00:18.6", .adapter_path = "0000:00:18.6",
.irq_data = { .irq_data = {
@ -703,7 +763,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon
.type = "intel_soc_pmic_crc", .type = "intel_soc_pmic_crc",
.addr = 0x6e, .addr = 0x6e,
.dev_name = "intel_soc_pmic_crc", .dev_name = "intel_soc_pmic_crc",
.swnode = &vexia_edu_atla10_pmic_node, .swnode = &vexia_edu_atla10_9v_pmic_node,
}, },
.adapter_path = "0000:00:18.7", .adapter_path = "0000:00:18.7",
.irq_data = { .irq_data = {
@ -715,7 +775,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon
} }
}; };
static const struct x86_serdev_info vexia_edu_atla10_serdevs[] __initconst = { static const struct x86_serdev_info vexia_edu_atla10_9v_serdevs[] __initconst = {
{ {
.ctrl.pci.devfn = PCI_DEVFN(0x1e, 3), .ctrl.pci.devfn = PCI_DEVFN(0x1e, 3),
.ctrl_devname = "serial0", .ctrl_devname = "serial0",
@ -723,7 +783,7 @@ static const struct x86_serdev_info vexia_edu_atla10_serdevs[] __initconst = {
}, },
}; };
static struct gpiod_lookup_table vexia_edu_atla10_ft5416_gpios = { static struct gpiod_lookup_table vexia_edu_atla10_9v_ft5416_gpios = {
.dev_id = "i2c-FTSC1000", .dev_id = "i2c-FTSC1000",
.table = { .table = {
GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_LOW), GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_LOW),
@ -731,12 +791,12 @@ static struct gpiod_lookup_table vexia_edu_atla10_ft5416_gpios = {
}, },
}; };
static struct gpiod_lookup_table * const vexia_edu_atla10_gpios[] = { static struct gpiod_lookup_table * const vexia_edu_atla10_9v_gpios[] = {
&vexia_edu_atla10_ft5416_gpios, &vexia_edu_atla10_9v_ft5416_gpios,
NULL NULL
}; };
static int __init vexia_edu_atla10_init(struct device *dev) static int __init vexia_edu_atla10_9v_init(struct device *dev)
{ {
struct pci_dev *pdev; struct pci_dev *pdev;
int ret; int ret;
@ -760,13 +820,13 @@ static int __init vexia_edu_atla10_init(struct device *dev)
return 0; return 0;
} }
const struct x86_dev_info vexia_edu_atla10_info __initconst = { const struct x86_dev_info vexia_edu_atla10_9v_info __initconst = {
.i2c_client_info = vexia_edu_atla10_i2c_clients, .i2c_client_info = vexia_edu_atla10_9v_i2c_clients,
.i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_i2c_clients), .i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_9v_i2c_clients),
.serdev_info = vexia_edu_atla10_serdevs, .serdev_info = vexia_edu_atla10_9v_serdevs,
.serdev_count = ARRAY_SIZE(vexia_edu_atla10_serdevs), .serdev_count = ARRAY_SIZE(vexia_edu_atla10_9v_serdevs),
.gpiod_lookup_tables = vexia_edu_atla10_gpios, .gpiod_lookup_tables = vexia_edu_atla10_9v_gpios,
.init = vexia_edu_atla10_init, .init = vexia_edu_atla10_9v_init,
.use_pci = true, .use_pci = true,
}; };

View file

@ -127,7 +127,8 @@ extern const struct x86_dev_info nextbook_ares8_info;
extern const struct x86_dev_info nextbook_ares8a_info; extern const struct x86_dev_info nextbook_ares8a_info;
extern const struct x86_dev_info peaq_c1010_info; extern const struct x86_dev_info peaq_c1010_info;
extern const struct x86_dev_info whitelabel_tm800a550l_info; extern const struct x86_dev_info whitelabel_tm800a550l_info;
extern const struct x86_dev_info vexia_edu_atla10_info; extern const struct x86_dev_info vexia_edu_atla10_5v_info;
extern const struct x86_dev_info vexia_edu_atla10_9v_info;
extern const struct x86_dev_info xiaomi_mipad2_info; extern const struct x86_dev_info xiaomi_mipad2_info;
extern const struct dmi_system_id x86_android_tablet_ids[]; extern const struct dmi_system_id x86_android_tablet_ids[];

View file

@ -36,6 +36,7 @@ struct pmc_ipc_rbuf {
*/ */
static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf *rbuf) static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf *rbuf)
{ {
#ifdef CONFIG_ACPI
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object params[PMC_IPCS_PARAM_COUNT] = { union acpi_object params[PMC_IPCS_PARAM_COUNT] = {
{.type = ACPI_TYPE_INTEGER,}, {.type = ACPI_TYPE_INTEGER,},
@ -89,6 +90,9 @@ static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
} }
return 0; return 0;
#else
return -ENODEV;
#endif /* CONFIG_ACPI */
} }
#endif /* INTEL_PMC_IPC_H */ #endif /* INTEL_PMC_IPC_H */