Skip to content

Commit d74da84

Browse files
committed
Merge tag 'platform-drivers-x86-v6.11-3' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver fixes from Ilpo Järvinen: "While the ideapad concurrency fix itself is relatively straightforward, it required moving code around and adding a bit of supporting infrastructure to have a clean inter-driver interface. This shows up in the diffstats. - ideapad-laptop / lenovo-ymc: Protect VPC calls with a mutex - amd/pmf: Query HPD data also when ALS is disabled" * tag 'platform-drivers-x86-v6.11-3' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: platform/x86: ideapad-laptop: add a mutex to synchronize VPC commands platform/x86: ideapad-laptop: move ymc_trigger_ec from lenovo-ymc platform/x86: ideapad-laptop: introduce a generic notification chain platform/x86/amd/pmf: Fix to Update HPD Data When ALS is Disabled
2 parents a1460e4 + 7cc06e7 commit d74da84

File tree

5 files changed

+155
-95
lines changed

5 files changed

+155
-95
lines changed

drivers/platform/x86/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ config LENOVO_YMC
477477
tristate "Lenovo Yoga Tablet Mode Control"
478478
depends on ACPI_WMI
479479
depends on INPUT
480+
depends on IDEAPAD_LAPTOP
480481
select INPUT_SPARSEKMAP
481482
help
482483
This driver maps the Tablet Mode Control switch to SW_TABLET_MODE input

drivers/platform/x86/amd/pmf/spc.c

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -150,36 +150,26 @@ static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_
150150
return 0;
151151
}
152152

153-
static int amd_pmf_get_sensor_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
153+
static void amd_pmf_get_sensor_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
154154
{
155155
struct amd_sfh_info sfh_info;
156-
int ret;
156+
157+
/* Get the latest information from SFH */
158+
in->ev_info.user_present = false;
157159

158160
/* Get ALS data */
159-
ret = amd_get_sfh_info(&sfh_info, MT_ALS);
160-
if (!ret)
161+
if (!amd_get_sfh_info(&sfh_info, MT_ALS))
161162
in->ev_info.ambient_light = sfh_info.ambient_light;
162163
else
163-
return ret;
164+
dev_dbg(dev->dev, "ALS is not enabled/detected\n");
164165

165166
/* get HPD data */
166-
ret = amd_get_sfh_info(&sfh_info, MT_HPD);
167-
if (ret)
168-
return ret;
169-
170-
switch (sfh_info.user_present) {
171-
case SFH_NOT_DETECTED:
172-
in->ev_info.user_present = 0xff; /* assume no sensors connected */
173-
break;
174-
case SFH_USER_PRESENT:
175-
in->ev_info.user_present = 1;
176-
break;
177-
case SFH_USER_AWAY:
178-
in->ev_info.user_present = 0;
179-
break;
167+
if (!amd_get_sfh_info(&sfh_info, MT_HPD)) {
168+
if (sfh_info.user_present == SFH_USER_PRESENT)
169+
in->ev_info.user_present = true;
170+
} else {
171+
dev_dbg(dev->dev, "HPD is not enabled/detected\n");
180172
}
181-
182-
return 0;
183173
}
184174

185175
void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)

drivers/platform/x86/ideapad-laptop.c

Lines changed: 132 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ struct ideapad_rfk_priv {
126126

127127
struct ideapad_private {
128128
struct acpi_device *adev;
129+
struct mutex vpc_mutex; /* protects the VPC calls */
129130
struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
130131
struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
131132
struct platform_device *platform_device;
@@ -146,6 +147,7 @@ struct ideapad_private {
146147
bool touchpad_ctrl_via_ec : 1;
147148
bool ctrl_ps2_aux_port : 1;
148149
bool usb_charging : 1;
150+
bool ymc_ec_trigger : 1;
149151
} features;
150152
struct {
151153
bool initialized;
@@ -194,6 +196,12 @@ MODULE_PARM_DESC(touchpad_ctrl_via_ec,
194196
"Enable registering a 'touchpad' sysfs-attribute which can be used to manually "
195197
"tell the EC to enable/disable the touchpad. This may not work on all models.");
196198

199+
static bool ymc_ec_trigger __read_mostly;
200+
module_param(ymc_ec_trigger, bool, 0444);
201+
MODULE_PARM_DESC(ymc_ec_trigger,
202+
"Enable EC triggering work-around to force emitting tablet mode events. "
203+
"If you need this please report this to: [email protected]");
204+
197205
/*
198206
* shared data
199207
*/
@@ -294,6 +302,8 @@ static int debugfs_status_show(struct seq_file *s, void *data)
294302
struct ideapad_private *priv = s->private;
295303
unsigned long value;
296304

305+
guard(mutex)(&priv->vpc_mutex);
306+
297307
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
298308
seq_printf(s, "Backlight max: %lu\n", value);
299309
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
@@ -412,7 +422,8 @@ static ssize_t camera_power_show(struct device *dev,
412422
unsigned long result;
413423
int err;
414424

415-
err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
425+
scoped_guard(mutex, &priv->vpc_mutex)
426+
err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
416427
if (err)
417428
return err;
418429

@@ -431,7 +442,8 @@ static ssize_t camera_power_store(struct device *dev,
431442
if (err)
432443
return err;
433444

434-
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
445+
scoped_guard(mutex, &priv->vpc_mutex)
446+
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
435447
if (err)
436448
return err;
437449

@@ -484,7 +496,8 @@ static ssize_t fan_mode_show(struct device *dev,
484496
unsigned long result;
485497
int err;
486498

487-
err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
499+
scoped_guard(mutex, &priv->vpc_mutex)
500+
err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
488501
if (err)
489502
return err;
490503

@@ -506,7 +519,8 @@ static ssize_t fan_mode_store(struct device *dev,
506519
if (state > 4 || state == 3)
507520
return -EINVAL;
508521

509-
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
522+
scoped_guard(mutex, &priv->vpc_mutex)
523+
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
510524
if (err)
511525
return err;
512526

@@ -591,7 +605,8 @@ static ssize_t touchpad_show(struct device *dev,
591605
unsigned long result;
592606
int err;
593607

594-
err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
608+
scoped_guard(mutex, &priv->vpc_mutex)
609+
err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
595610
if (err)
596611
return err;
597612

@@ -612,7 +627,8 @@ static ssize_t touchpad_store(struct device *dev,
612627
if (err)
613628
return err;
614629

615-
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
630+
scoped_guard(mutex, &priv->vpc_mutex)
631+
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
616632
if (err)
617633
return err;
618634

@@ -1005,6 +1021,8 @@ static int ideapad_rfk_set(void *data, bool blocked)
10051021
struct ideapad_rfk_priv *priv = data;
10061022
int opcode = ideapad_rfk_data[priv->dev].opcode;
10071023

1024+
guard(mutex)(&priv->priv->vpc_mutex);
1025+
10081026
return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
10091027
}
10101028

@@ -1018,6 +1036,8 @@ static void ideapad_sync_rfk_state(struct ideapad_private *priv)
10181036
int i;
10191037

10201038
if (priv->features.hw_rfkill_switch) {
1039+
guard(mutex)(&priv->vpc_mutex);
1040+
10211041
if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
10221042
return;
10231043
hw_blocked = !hw_blocked;
@@ -1191,8 +1211,9 @@ static void ideapad_input_novokey(struct ideapad_private *priv)
11911211
{
11921212
unsigned long long_pressed;
11931213

1194-
if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
1195-
return;
1214+
scoped_guard(mutex, &priv->vpc_mutex)
1215+
if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
1216+
return;
11961217

11971218
if (long_pressed)
11981219
ideapad_input_report(priv, 17);
@@ -1204,8 +1225,9 @@ static void ideapad_check_special_buttons(struct ideapad_private *priv)
12041225
{
12051226
unsigned long bit, value;
12061227

1207-
if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
1208-
return;
1228+
scoped_guard(mutex, &priv->vpc_mutex)
1229+
if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
1230+
return;
12091231

12101232
for_each_set_bit (bit, &value, 16) {
12111233
switch (bit) {
@@ -1238,6 +1260,8 @@ static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
12381260
unsigned long now;
12391261
int err;
12401262

1263+
guard(mutex)(&priv->vpc_mutex);
1264+
12411265
err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
12421266
if (err)
12431267
return err;
@@ -1250,6 +1274,8 @@ static int ideapad_backlight_update_status(struct backlight_device *blightdev)
12501274
struct ideapad_private *priv = bl_get_data(blightdev);
12511275
int err;
12521276

1277+
guard(mutex)(&priv->vpc_mutex);
1278+
12531279
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL,
12541280
blightdev->props.brightness);
12551281
if (err)
@@ -1327,6 +1353,8 @@ static void ideapad_backlight_notify_power(struct ideapad_private *priv)
13271353
if (!blightdev)
13281354
return;
13291355

1356+
guard(mutex)(&priv->vpc_mutex);
1357+
13301358
if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
13311359
return;
13321360

@@ -1339,7 +1367,8 @@ static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
13391367

13401368
/* if we control brightness via acpi video driver */
13411369
if (!priv->blightdev)
1342-
read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1370+
scoped_guard(mutex, &priv->vpc_mutex)
1371+
read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
13431372
else
13441373
backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
13451374
}
@@ -1564,7 +1593,8 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_
15641593
int ret;
15651594

15661595
/* Without reading from EC touchpad LED doesn't switch state */
1567-
ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
1596+
scoped_guard(mutex, &priv->vpc_mutex)
1597+
ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
15681598
if (ret)
15691599
return;
15701600

@@ -1592,16 +1622,92 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_
15921622
priv->r_touchpad_val = value;
15931623
}
15941624

1625+
static const struct dmi_system_id ymc_ec_trigger_quirk_dmi_table[] = {
1626+
{
1627+
/* Lenovo Yoga 7 14ARB7 */
1628+
.matches = {
1629+
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1630+
DMI_MATCH(DMI_PRODUCT_NAME, "82QF"),
1631+
},
1632+
},
1633+
{
1634+
/* Lenovo Yoga 7 14ACN6 */
1635+
.matches = {
1636+
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1637+
DMI_MATCH(DMI_PRODUCT_NAME, "82N7"),
1638+
},
1639+
},
1640+
{ }
1641+
};
1642+
1643+
static void ideapad_laptop_trigger_ec(void)
1644+
{
1645+
struct ideapad_private *priv;
1646+
int ret;
1647+
1648+
guard(mutex)(&ideapad_shared_mutex);
1649+
1650+
priv = ideapad_shared;
1651+
if (!priv)
1652+
return;
1653+
1654+
if (!priv->features.ymc_ec_trigger)
1655+
return;
1656+
1657+
scoped_guard(mutex, &priv->vpc_mutex)
1658+
ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_YMC, 1);
1659+
if (ret)
1660+
dev_warn(&priv->platform_device->dev, "Could not write YMC: %d\n", ret);
1661+
}
1662+
1663+
static int ideapad_laptop_nb_notify(struct notifier_block *nb,
1664+
unsigned long action, void *data)
1665+
{
1666+
switch (action) {
1667+
case IDEAPAD_LAPTOP_YMC_EVENT:
1668+
ideapad_laptop_trigger_ec();
1669+
break;
1670+
}
1671+
1672+
return 0;
1673+
}
1674+
1675+
static struct notifier_block ideapad_laptop_notifier = {
1676+
.notifier_call = ideapad_laptop_nb_notify,
1677+
};
1678+
1679+
static BLOCKING_NOTIFIER_HEAD(ideapad_laptop_chain_head);
1680+
1681+
int ideapad_laptop_register_notifier(struct notifier_block *nb)
1682+
{
1683+
return blocking_notifier_chain_register(&ideapad_laptop_chain_head, nb);
1684+
}
1685+
EXPORT_SYMBOL_NS_GPL(ideapad_laptop_register_notifier, IDEAPAD_LAPTOP);
1686+
1687+
int ideapad_laptop_unregister_notifier(struct notifier_block *nb)
1688+
{
1689+
return blocking_notifier_chain_unregister(&ideapad_laptop_chain_head, nb);
1690+
}
1691+
EXPORT_SYMBOL_NS_GPL(ideapad_laptop_unregister_notifier, IDEAPAD_LAPTOP);
1692+
1693+
void ideapad_laptop_call_notifier(unsigned long action, void *data)
1694+
{
1695+
blocking_notifier_call_chain(&ideapad_laptop_chain_head, action, data);
1696+
}
1697+
EXPORT_SYMBOL_NS_GPL(ideapad_laptop_call_notifier, IDEAPAD_LAPTOP);
1698+
15951699
static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
15961700
{
15971701
struct ideapad_private *priv = data;
15981702
unsigned long vpc1, vpc2, bit;
15991703

1600-
if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
1601-
return;
1704+
scoped_guard(mutex, &priv->vpc_mutex) {
1705+
if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
1706+
return;
16021707

1603-
if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
1604-
return;
1708+
if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
1709+
return;
1710+
}
16051711

16061712
vpc1 = (vpc2 << 8) | vpc1;
16071713

@@ -1728,6 +1834,8 @@ static void ideapad_check_features(struct ideapad_private *priv)
17281834
priv->features.ctrl_ps2_aux_port =
17291835
ctrl_ps2_aux_port || dmi_check_system(ctrl_ps2_aux_port_list);
17301836
priv->features.touchpad_ctrl_via_ec = touchpad_ctrl_via_ec;
1837+
priv->features.ymc_ec_trigger =
1838+
ymc_ec_trigger || dmi_check_system(ymc_ec_trigger_quirk_dmi_table);
17311839

17321840
if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
17331841
priv->features.fan_mode = true;
@@ -1906,6 +2014,10 @@ static int ideapad_acpi_add(struct platform_device *pdev)
19062014
priv->adev = adev;
19072015
priv->platform_device = pdev;
19082016

2017+
err = devm_mutex_init(&pdev->dev, &priv->vpc_mutex);
2018+
if (err)
2019+
return err;
2020+
19092021
ideapad_check_features(priv);
19102022

19112023
err = ideapad_sysfs_init(priv);
@@ -1974,6 +2086,8 @@ static int ideapad_acpi_add(struct platform_device *pdev)
19742086
if (err)
19752087
goto shared_init_failed;
19762088

2089+
ideapad_laptop_register_notifier(&ideapad_laptop_notifier);
2090+
19772091
return 0;
19782092

19792093
shared_init_failed:
@@ -2006,6 +2120,8 @@ static void ideapad_acpi_remove(struct platform_device *pdev)
20062120
struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
20072121
int i;
20082122

2123+
ideapad_laptop_unregister_notifier(&ideapad_laptop_notifier);
2124+
20092125
ideapad_shared_exit(priv);
20102126

20112127
acpi_remove_notify_handler(priv->adev->handle,

drivers/platform/x86/ideapad-laptop.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@
1212
#include <linux/acpi.h>
1313
#include <linux/jiffies.h>
1414
#include <linux/errno.h>
15+
#include <linux/notifier.h>
16+
17+
enum ideapad_laptop_notifier_actions {
18+
IDEAPAD_LAPTOP_YMC_EVENT,
19+
};
20+
21+
int ideapad_laptop_register_notifier(struct notifier_block *nb);
22+
int ideapad_laptop_unregister_notifier(struct notifier_block *nb);
23+
void ideapad_laptop_call_notifier(unsigned long action, void *data);
1524

1625
enum {
1726
VPCCMD_R_VPC1 = 0x10,

0 commit comments

Comments
 (0)