mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 06:01:57 +00:00
platform-drivers-x86 for v6.11-3
Fixes: - ideapad-laptop / lenovo-ymc: Protect VPC calls with a mutex - amd/pmf: Query HPD data also when ALS is disabled The following is an automated shortlog grouped by driver: amd/pmf: - Fix to Update HPD Data When ALS is Disabled ideapad-laptop: - add a mutex to synchronize VPC commands - introduce a generic notification chain - move ymc_trigger_ec from lenovo-ymc -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQSCSUwRdwTNL2MhaBlZrE9hU+XOMQUCZrnHXQAKCRBZrE9hU+XO MTcjAP91S8mHmZ81J1029xMC8qKwu4nY1G+bURHphTbqLFTg6gD/XFuqdUKT2n0+ GgGg7FV+GrS8rZT1oqqRI/2OXg2LugU= =1XJi -----END PGP SIGNATURE----- Merge tag 'platform-drivers-x86-v6.11-3' into review-hans Merge 'platform-drivers-x86-v6.11-3' into review-hans to avoid conflicts when merging further ideapad-laptop patches. platform-drivers-x86 for v6.11-3 Fixes: - ideapad-laptop / lenovo-ymc: Protect VPC calls with a mutex - amd/pmf: Query HPD data also when ALS is disabled The following is an automated shortlog grouped by driver: amd/pmf: - Fix to Update HPD Data When ALS is Disabled ideapad-laptop: - add a mutex to synchronize VPC commands - introduce a generic notification chain - move ymc_trigger_ec from lenovo-ymc
This commit is contained in:
commit
d945085a7e
@ -130,12 +130,12 @@ data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
|
||||
|
||||
Due to a peculiarity in how Windows handles the ``CreateByteField()`` ACPI operator (errors only
|
||||
happen when a invalid byte field is ultimately accessed), all methods require a 32 byte input
|
||||
buffer, even if the Binay MOF says otherwise.
|
||||
buffer, even if the Binary MOF says otherwise.
|
||||
|
||||
The input buffer contains a single byte to select the subfeature to be accessed and 31 bytes of
|
||||
input data, the meaning of which depends on the subfeature being accessed.
|
||||
|
||||
The output buffer contains a singe 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.
|
||||
|
||||
WMI method Get_EC()
|
||||
@ -147,7 +147,7 @@ data contains a flag byte and a 28 byte controller firmware version string.
|
||||
The first 4 bits of the flag byte contain the minor version of the embedded controller interface,
|
||||
with the next 2 bits containing the major version of the embedded controller interface.
|
||||
|
||||
The 7th bit signals if the embedded controller page chaged (exact meaning is unknown), and the
|
||||
The 7th bit signals if the embedded controller page changed (exact meaning is unknown), and the
|
||||
last bit signals if the platform is a Tigerlake platform.
|
||||
|
||||
The MSI software seems to only use this interface when the last bit is set.
|
||||
|
@ -477,6 +477,7 @@ config LENOVO_YMC
|
||||
tristate "Lenovo Yoga Tablet Mode Control"
|
||||
depends on ACPI_WMI
|
||||
depends on INPUT
|
||||
depends on IDEAPAD_LAPTOP
|
||||
select INPUT_SPARSEKMAP
|
||||
help
|
||||
This driver maps the Tablet Mode Control switch to SW_TABLET_MODE input
|
||||
|
@ -764,6 +764,7 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
|
||||
case AMD_CPU_ID_CB:
|
||||
case AMD_CPU_ID_PS:
|
||||
case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
|
||||
case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
|
||||
return MSG_OS_HINT_RN;
|
||||
}
|
||||
return -EINVAL;
|
||||
@ -967,6 +968,7 @@ static const struct pci_device_id pmc_pci_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SP) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -67,6 +67,7 @@ void amd_mp2_stb_deinit(struct amd_pmc_dev *dev);
|
||||
#define AMD_CPU_ID_PS 0x14E8
|
||||
#define AMD_CPU_ID_SP 0x14A4
|
||||
#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
|
||||
#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122
|
||||
#define PCI_DEVICE_ID_AMD_MP2_STB 0x172c
|
||||
|
||||
#endif /* PMC_H */
|
||||
|
@ -41,6 +41,7 @@
|
||||
#define AMD_CPU_ID_RMB 0x14b5
|
||||
#define AMD_CPU_ID_PS 0x14e8
|
||||
#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
|
||||
#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122
|
||||
|
||||
#define PMF_MSG_DELAY_MIN_US 50
|
||||
#define RESPONSE_REGISTER_LOOP_MAX 20000
|
||||
@ -249,6 +250,7 @@ static const struct pci_device_id pmf_pci_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RMB) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) },
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -382,6 +384,7 @@ static const struct acpi_device_id amd_pmf_acpi_ids[] = {
|
||||
{"AMDI0102", 0},
|
||||
{"AMDI0103", 0},
|
||||
{"AMDI0105", 0},
|
||||
{"AMDI0107", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, amd_pmf_acpi_ids);
|
||||
|
@ -29,6 +29,14 @@ static const struct dmi_system_id fwbug_list[] = {
|
||||
},
|
||||
.driver_data = &quirk_no_sps_bug,
|
||||
},
|
||||
{
|
||||
.ident = "ROG Ally X",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "RC72LA"),
|
||||
},
|
||||
.driver_data = &quirk_no_sps_bug,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
@ -48,4 +56,3 @@ void amd_pmf_quirks_init(struct amd_pmf_dev *dev)
|
||||
dmi_id->ident);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,36 +150,26 @@ static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_pmf_get_sensor_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
|
||||
static void amd_pmf_get_sensor_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
|
||||
{
|
||||
struct amd_sfh_info sfh_info;
|
||||
int ret;
|
||||
|
||||
/* Get the latest information from SFH */
|
||||
in->ev_info.user_present = false;
|
||||
|
||||
/* Get ALS data */
|
||||
ret = amd_get_sfh_info(&sfh_info, MT_ALS);
|
||||
if (!ret)
|
||||
if (!amd_get_sfh_info(&sfh_info, MT_ALS))
|
||||
in->ev_info.ambient_light = sfh_info.ambient_light;
|
||||
else
|
||||
return ret;
|
||||
dev_dbg(dev->dev, "ALS is not enabled/detected\n");
|
||||
|
||||
/* get HPD data */
|
||||
ret = amd_get_sfh_info(&sfh_info, MT_HPD);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (sfh_info.user_present) {
|
||||
case SFH_NOT_DETECTED:
|
||||
in->ev_info.user_present = 0xff; /* assume no sensors connected */
|
||||
break;
|
||||
case SFH_USER_PRESENT:
|
||||
in->ev_info.user_present = 1;
|
||||
break;
|
||||
case SFH_USER_AWAY:
|
||||
in->ev_info.user_present = 0;
|
||||
break;
|
||||
if (!amd_get_sfh_info(&sfh_info, MT_HPD)) {
|
||||
if (sfh_info.user_present == SFH_USER_PRESENT)
|
||||
in->ev_info.user_present = true;
|
||||
} else {
|
||||
dev_dbg(dev->dev, "HPD is not enabled/detected\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
|
||||
|
@ -125,6 +125,7 @@ struct ideapad_rfk_priv {
|
||||
|
||||
struct ideapad_private {
|
||||
struct acpi_device *adev;
|
||||
struct mutex vpc_mutex; /* protects the VPC calls */
|
||||
struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
|
||||
struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
|
||||
struct platform_device *platform_device;
|
||||
@ -145,6 +146,7 @@ struct ideapad_private {
|
||||
bool touchpad_ctrl_via_ec : 1;
|
||||
bool ctrl_ps2_aux_port : 1;
|
||||
bool usb_charging : 1;
|
||||
bool ymc_ec_trigger : 1;
|
||||
} features;
|
||||
struct {
|
||||
bool initialized;
|
||||
@ -193,6 +195,12 @@ MODULE_PARM_DESC(touchpad_ctrl_via_ec,
|
||||
"Enable registering a 'touchpad' sysfs-attribute which can be used to manually "
|
||||
"tell the EC to enable/disable the touchpad. This may not work on all models.");
|
||||
|
||||
static bool ymc_ec_trigger __read_mostly;
|
||||
module_param(ymc_ec_trigger, bool, 0444);
|
||||
MODULE_PARM_DESC(ymc_ec_trigger,
|
||||
"Enable EC triggering work-around to force emitting tablet mode events. "
|
||||
"If you need this please report this to: platform-driver-x86@vger.kernel.org");
|
||||
|
||||
/*
|
||||
* shared data
|
||||
*/
|
||||
@ -293,6 +301,8 @@ static int debugfs_status_show(struct seq_file *s, void *data)
|
||||
struct ideapad_private *priv = s->private;
|
||||
unsigned long value;
|
||||
|
||||
guard(mutex)(&priv->vpc_mutex);
|
||||
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
|
||||
seq_printf(s, "Backlight max: %lu\n", value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
|
||||
@ -411,7 +421,8 @@ static ssize_t camera_power_show(struct device *dev,
|
||||
unsigned long result;
|
||||
int err;
|
||||
|
||||
err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -430,7 +441,8 @@ static ssize_t camera_power_store(struct device *dev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -483,7 +495,8 @@ static ssize_t fan_mode_show(struct device *dev,
|
||||
unsigned long result;
|
||||
int err;
|
||||
|
||||
err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -505,7 +518,8 @@ static ssize_t fan_mode_store(struct device *dev,
|
||||
if (state > 4 || state == 3)
|
||||
return -EINVAL;
|
||||
|
||||
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -590,7 +604,8 @@ static ssize_t touchpad_show(struct device *dev,
|
||||
unsigned long result;
|
||||
int err;
|
||||
|
||||
err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -611,7 +626,8 @@ static ssize_t touchpad_store(struct device *dev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -1004,6 +1020,8 @@ static int ideapad_rfk_set(void *data, bool blocked)
|
||||
struct ideapad_rfk_priv *priv = data;
|
||||
int opcode = ideapad_rfk_data[priv->dev].opcode;
|
||||
|
||||
guard(mutex)(&priv->priv->vpc_mutex);
|
||||
|
||||
return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
|
||||
}
|
||||
|
||||
@ -1017,6 +1035,8 @@ static void ideapad_sync_rfk_state(struct ideapad_private *priv)
|
||||
int i;
|
||||
|
||||
if (priv->features.hw_rfkill_switch) {
|
||||
guard(mutex)(&priv->vpc_mutex);
|
||||
|
||||
if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
|
||||
return;
|
||||
hw_blocked = !hw_blocked;
|
||||
@ -1190,8 +1210,9 @@ static void ideapad_input_novokey(struct ideapad_private *priv)
|
||||
{
|
||||
unsigned long long_pressed;
|
||||
|
||||
if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
|
||||
return;
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
|
||||
return;
|
||||
|
||||
if (long_pressed)
|
||||
ideapad_input_report(priv, 17);
|
||||
@ -1203,8 +1224,9 @@ static void ideapad_check_special_buttons(struct ideapad_private *priv)
|
||||
{
|
||||
unsigned long bit, value;
|
||||
|
||||
if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
|
||||
return;
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
|
||||
return;
|
||||
|
||||
for_each_set_bit (bit, &value, 16) {
|
||||
switch (bit) {
|
||||
@ -1237,6 +1259,8 @@ static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
|
||||
unsigned long now;
|
||||
int err;
|
||||
|
||||
guard(mutex)(&priv->vpc_mutex);
|
||||
|
||||
err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
|
||||
if (err)
|
||||
return err;
|
||||
@ -1249,6 +1273,8 @@ static int ideapad_backlight_update_status(struct backlight_device *blightdev)
|
||||
struct ideapad_private *priv = bl_get_data(blightdev);
|
||||
int err;
|
||||
|
||||
guard(mutex)(&priv->vpc_mutex);
|
||||
|
||||
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL,
|
||||
blightdev->props.brightness);
|
||||
if (err)
|
||||
@ -1326,6 +1352,8 @@ static void ideapad_backlight_notify_power(struct ideapad_private *priv)
|
||||
if (!blightdev)
|
||||
return;
|
||||
|
||||
guard(mutex)(&priv->vpc_mutex);
|
||||
|
||||
if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
|
||||
return;
|
||||
|
||||
@ -1338,7 +1366,8 @@ static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
|
||||
|
||||
/* if we control brightness via acpi video driver */
|
||||
if (!priv->blightdev)
|
||||
read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
|
||||
else
|
||||
backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
|
||||
}
|
||||
@ -1563,7 +1592,8 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_
|
||||
int ret;
|
||||
|
||||
/* Without reading from EC touchpad LED doesn't switch state */
|
||||
ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
@ -1591,16 +1621,92 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_
|
||||
priv->r_touchpad_val = value;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id ymc_ec_trigger_quirk_dmi_table[] = {
|
||||
{
|
||||
/* Lenovo Yoga 7 14ARB7 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "82QF"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Lenovo Yoga 7 14ACN6 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "82N7"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static void ideapad_laptop_trigger_ec(void)
|
||||
{
|
||||
struct ideapad_private *priv;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&ideapad_shared_mutex);
|
||||
|
||||
priv = ideapad_shared;
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
if (!priv->features.ymc_ec_trigger)
|
||||
return;
|
||||
|
||||
scoped_guard(mutex, &priv->vpc_mutex)
|
||||
ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_YMC, 1);
|
||||
if (ret)
|
||||
dev_warn(&priv->platform_device->dev, "Could not write YMC: %d\n", ret);
|
||||
}
|
||||
|
||||
static int ideapad_laptop_nb_notify(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
switch (action) {
|
||||
case IDEAPAD_LAPTOP_YMC_EVENT:
|
||||
ideapad_laptop_trigger_ec();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block ideapad_laptop_notifier = {
|
||||
.notifier_call = ideapad_laptop_nb_notify,
|
||||
};
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(ideapad_laptop_chain_head);
|
||||
|
||||
int ideapad_laptop_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&ideapad_laptop_chain_head, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ideapad_laptop_register_notifier, IDEAPAD_LAPTOP);
|
||||
|
||||
int ideapad_laptop_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_unregister(&ideapad_laptop_chain_head, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ideapad_laptop_unregister_notifier, IDEAPAD_LAPTOP);
|
||||
|
||||
void ideapad_laptop_call_notifier(unsigned long action, void *data)
|
||||
{
|
||||
blocking_notifier_call_chain(&ideapad_laptop_chain_head, action, data);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ideapad_laptop_call_notifier, IDEAPAD_LAPTOP);
|
||||
|
||||
static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct ideapad_private *priv = data;
|
||||
unsigned long vpc1, vpc2, bit;
|
||||
|
||||
if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
|
||||
return;
|
||||
scoped_guard(mutex, &priv->vpc_mutex) {
|
||||
if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
|
||||
return;
|
||||
|
||||
if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
|
||||
return;
|
||||
if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
|
||||
return;
|
||||
}
|
||||
|
||||
vpc1 = (vpc2 << 8) | vpc1;
|
||||
|
||||
@ -1727,6 +1833,8 @@ static void ideapad_check_features(struct ideapad_private *priv)
|
||||
priv->features.ctrl_ps2_aux_port =
|
||||
ctrl_ps2_aux_port || dmi_check_system(ctrl_ps2_aux_port_list);
|
||||
priv->features.touchpad_ctrl_via_ec = touchpad_ctrl_via_ec;
|
||||
priv->features.ymc_ec_trigger =
|
||||
ymc_ec_trigger || dmi_check_system(ymc_ec_trigger_quirk_dmi_table);
|
||||
|
||||
if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
|
||||
priv->features.fan_mode = true;
|
||||
@ -1905,6 +2013,10 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
||||
priv->adev = adev;
|
||||
priv->platform_device = pdev;
|
||||
|
||||
err = devm_mutex_init(&pdev->dev, &priv->vpc_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ideapad_check_features(priv);
|
||||
|
||||
err = ideapad_sysfs_init(priv);
|
||||
@ -1973,6 +2085,8 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
||||
if (err)
|
||||
goto shared_init_failed;
|
||||
|
||||
ideapad_laptop_register_notifier(&ideapad_laptop_notifier);
|
||||
|
||||
return 0;
|
||||
|
||||
shared_init_failed:
|
||||
@ -2005,6 +2119,8 @@ static void ideapad_acpi_remove(struct platform_device *pdev)
|
||||
struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
|
||||
int i;
|
||||
|
||||
ideapad_laptop_unregister_notifier(&ideapad_laptop_notifier);
|
||||
|
||||
ideapad_shared_exit(priv);
|
||||
|
||||
acpi_remove_notify_handler(priv->adev->handle,
|
||||
|
@ -12,6 +12,15 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
enum ideapad_laptop_notifier_actions {
|
||||
IDEAPAD_LAPTOP_YMC_EVENT,
|
||||
};
|
||||
|
||||
int ideapad_laptop_register_notifier(struct notifier_block *nb);
|
||||
int ideapad_laptop_unregister_notifier(struct notifier_block *nb);
|
||||
void ideapad_laptop_call_notifier(unsigned long action, void *data);
|
||||
|
||||
enum {
|
||||
VPCCMD_R_VPC1 = 0x10,
|
||||
|
@ -229,8 +229,8 @@ static int doscan(void *data)
|
||||
*/
|
||||
static void ifs_test_core(int cpu, struct device *dev)
|
||||
{
|
||||
union ifs_status status = {};
|
||||
union ifs_scan activate;
|
||||
union ifs_status status;
|
||||
unsigned long timeout;
|
||||
struct ifs_data *ifsd;
|
||||
int to_start, to_stop;
|
||||
|
@ -7,11 +7,13 @@
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/suspend.h>
|
||||
#include "../dual_accel_detect.h"
|
||||
@ -66,6 +68,7 @@ static const struct key_entry intel_vbtn_switchmap[] = {
|
||||
};
|
||||
|
||||
struct intel_vbtn_priv {
|
||||
struct mutex mutex; /* Avoid notify_handler() racing with itself */
|
||||
struct input_dev *buttons_dev;
|
||||
struct input_dev *switches_dev;
|
||||
bool dual_accel;
|
||||
@ -155,6 +158,8 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
|
||||
bool autorelease;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&priv->mutex);
|
||||
|
||||
if ((ke = sparse_keymap_entry_from_scancode(priv->buttons_dev, event))) {
|
||||
if (!priv->has_buttons) {
|
||||
dev_warn(&device->dev, "Warning: received 0x%02x button event on a device without buttons, please report this.\n",
|
||||
@ -290,6 +295,10 @@ static int intel_vbtn_probe(struct platform_device *device)
|
||||
return -ENOMEM;
|
||||
dev_set_drvdata(&device->dev, priv);
|
||||
|
||||
err = devm_mutex_init(&device->dev, &priv->mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
priv->dual_accel = dual_accel;
|
||||
priv->has_buttons = has_buttons;
|
||||
priv->has_switches = has_switches;
|
||||
|
@ -20,32 +20,10 @@
|
||||
#define LENOVO_YMC_QUERY_INSTANCE 0
|
||||
#define LENOVO_YMC_QUERY_METHOD 0x01
|
||||
|
||||
static bool ec_trigger __read_mostly;
|
||||
module_param(ec_trigger, bool, 0444);
|
||||
MODULE_PARM_DESC(ec_trigger, "Enable EC triggering work-around to force emitting tablet mode events");
|
||||
|
||||
static bool force;
|
||||
module_param(force, bool, 0444);
|
||||
MODULE_PARM_DESC(force, "Force loading on boards without a convertible DMI chassis-type");
|
||||
|
||||
static const struct dmi_system_id ec_trigger_quirk_dmi_table[] = {
|
||||
{
|
||||
/* Lenovo Yoga 7 14ARB7 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "82QF"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Lenovo Yoga 7 14ACN6 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "82N7"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct dmi_system_id allowed_chasis_types_dmi_table[] = {
|
||||
{
|
||||
.matches = {
|
||||
@ -62,21 +40,8 @@ static const struct dmi_system_id allowed_chasis_types_dmi_table[] = {
|
||||
|
||||
struct lenovo_ymc_private {
|
||||
struct input_dev *input_dev;
|
||||
struct acpi_device *ec_acpi_dev;
|
||||
};
|
||||
|
||||
static void lenovo_ymc_trigger_ec(struct wmi_device *wdev, struct lenovo_ymc_private *priv)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!priv->ec_acpi_dev)
|
||||
return;
|
||||
|
||||
err = write_ec_cmd(priv->ec_acpi_dev->handle, VPCCMD_W_YMC, 1);
|
||||
if (err)
|
||||
dev_warn(&wdev->dev, "Could not write YMC: %d\n", err);
|
||||
}
|
||||
|
||||
static const struct key_entry lenovo_ymc_keymap[] = {
|
||||
/* Laptop */
|
||||
{ KE_SW, 0x01, { .sw = { SW_TABLET_MODE, 0 } } },
|
||||
@ -125,11 +90,9 @@ static void lenovo_ymc_notify(struct wmi_device *wdev, union acpi_object *data)
|
||||
|
||||
free_obj:
|
||||
kfree(obj);
|
||||
lenovo_ymc_trigger_ec(wdev, priv);
|
||||
ideapad_laptop_call_notifier(IDEAPAD_LAPTOP_YMC_EVENT, &code);
|
||||
}
|
||||
|
||||
static void acpi_dev_put_helper(void *p) { acpi_dev_put(p); }
|
||||
|
||||
static int lenovo_ymc_probe(struct wmi_device *wdev, const void *ctx)
|
||||
{
|
||||
struct lenovo_ymc_private *priv;
|
||||
@ -143,29 +106,10 @@ static int lenovo_ymc_probe(struct wmi_device *wdev, const void *ctx)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ec_trigger |= dmi_check_system(ec_trigger_quirk_dmi_table);
|
||||
|
||||
priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ec_trigger) {
|
||||
pr_debug("Lenovo YMC enable EC triggering.\n");
|
||||
priv->ec_acpi_dev = acpi_dev_get_first_match_dev("VPC2004", NULL, -1);
|
||||
|
||||
if (!priv->ec_acpi_dev) {
|
||||
dev_err(&wdev->dev, "Could not find EC ACPI device.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
err = devm_add_action_or_reset(&wdev->dev,
|
||||
acpi_dev_put_helper, priv->ec_acpi_dev);
|
||||
if (err) {
|
||||
dev_err(&wdev->dev,
|
||||
"Could not clean up EC ACPI device: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
input_dev = devm_input_allocate_device(&wdev->dev);
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
@ -192,7 +136,6 @@ static int lenovo_ymc_probe(struct wmi_device *wdev, const void *ctx)
|
||||
dev_set_drvdata(&wdev->dev, priv);
|
||||
|
||||
/* Report the state for the first time on probe */
|
||||
lenovo_ymc_trigger_ec(wdev, priv);
|
||||
lenovo_ymc_notify(wdev, NULL);
|
||||
return 0;
|
||||
}
|
||||
@ -217,3 +160,4 @@ module_wmi_driver(lenovo_ymc_driver);
|
||||
MODULE_AUTHOR("Gergo Koteles <soyer@irl.hu>");
|
||||
MODULE_DESCRIPTION("Lenovo Yoga Mode Control driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(IDEAPAD_LAPTOP);
|
||||
|
Loading…
Reference in New Issue
Block a user