Skip to content

Commit 0c27be5

Browse files
committed
HID: transport: spi: Add suspend support
Working suspend and resume. The keyboard can not yet used as wakeup source. Most likely caused by missing irq_set_wake support in the gpio/pinctrl driver. Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 17f9b97 commit 0c27be5

3 files changed

Lines changed: 110 additions & 1 deletion

File tree

drivers/hid/spi-hid/spi-hid-apple-core.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ struct spihid_apple {
115115

116116
/* state tracking flags */
117117
bool status_booted;
118+
119+
#ifdef IRQ_WAKE_SUPPORT
120+
bool irq_wake_enabled;
121+
#endif
118122
};
119123

120124
/**
@@ -1035,6 +1039,91 @@ void spihid_apple_core_shutdown(struct spi_device *spi)
10351039
}
10361040
EXPORT_SYMBOL_GPL(spihid_apple_core_shutdown);
10371041

1042+
#ifdef CONFIG_PM_SLEEP
1043+
static int spihid_apple_core_suspend(struct device *dev)
1044+
{
1045+
int ret;
1046+
#ifdef IRQ_WAKE_SUPPORT
1047+
int wake_status;
1048+
#endif
1049+
struct spihid_apple *spihid = spi_get_drvdata(to_spi_device(dev));
1050+
1051+
if (spihid->tp.hid) {
1052+
ret = hid_driver_suspend(spihid->tp.hid, PMSG_SUSPEND);
1053+
if (ret < 0)
1054+
return ret;
1055+
}
1056+
1057+
if (spihid->kbd.hid) {
1058+
ret = hid_driver_suspend(spihid->kbd.hid, PMSG_SUSPEND);
1059+
if (ret < 0) {
1060+
if (spihid->tp.hid)
1061+
hid_driver_resume(spihid->tp.hid);
1062+
return ret;
1063+
}
1064+
}
1065+
1066+
/* Save some power */
1067+
spihid->ops->disable_irq(spihid->ops);
1068+
1069+
#ifdef IRQ_WAKE_SUPPORT
1070+
if (device_may_wakeup(dev)) {
1071+
wake_status = spihid->ops->enable_irq_wake(spihid->ops);
1072+
if (!wake_status)
1073+
spihid->irq_wake_enabled = true;
1074+
else
1075+
dev_warn(dev, "Failed to enable irq wake: %d\n",
1076+
wake_status);
1077+
} else {
1078+
spihid->ops->power_off(spihid->ops);
1079+
}
1080+
#else
1081+
spihid->ops->power_off(spihid->ops);
1082+
#endif
1083+
1084+
return 0;
1085+
}
1086+
1087+
static int spihid_apple_core_resume(struct device *dev)
1088+
{
1089+
int ret_tp = 0, ret_kbd = 0;
1090+
struct spihid_apple *spihid = spi_get_drvdata(to_spi_device(dev));
1091+
#ifdef IRQ_WAKE_SUPPORT
1092+
int wake_status;
1093+
1094+
if (!device_may_wakeup(dev)) {
1095+
spihid->ops->power_on(spihid->ops);
1096+
} else if (spihid->irq_wake_enabled) {
1097+
wake_status = spihid->ops->disable_irq_wake(spihid->ops);
1098+
if (!wake_status)
1099+
spihid->irq_wake_enabled = false;
1100+
else
1101+
dev_warn(dev, "Failed to disable irq wake: %d\n",
1102+
wake_status);
1103+
}
1104+
#endif
1105+
1106+
spihid->ops->enable_irq(spihid->ops);
1107+
spihid->ops->power_on(spihid->ops);
1108+
1109+
if (spihid->tp.hid)
1110+
ret_tp = hid_driver_reset_resume(spihid->tp.hid);
1111+
if (spihid->kbd.hid)
1112+
ret_kbd = hid_driver_reset_resume(spihid->kbd.hid);
1113+
1114+
if (ret_tp < 0)
1115+
return ret_tp;
1116+
1117+
return ret_kbd;
1118+
}
1119+
#endif
1120+
1121+
const struct dev_pm_ops spihid_apple_core_pm = {
1122+
SET_SYSTEM_SLEEP_PM_OPS(spihid_apple_core_suspend,
1123+
spihid_apple_core_resume)
1124+
};
1125+
EXPORT_SYMBOL_GPL(spihid_apple_core_pm);
1126+
10381127
MODULE_DESCRIPTION("Apple SPI HID transport driver");
10391128
MODULE_AUTHOR("Janne Grunau <j@jannau.net>");
10401129
MODULE_LICENSE("GPL");

drivers/hid/spi-hid/spi-hid-apple-of.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ static int spihid_apple_of_disable_irq(struct spihid_apple_ops *ops)
6565
return 0;
6666
}
6767

68+
static int spihid_apple_of_enable_irq_wake(struct spihid_apple_ops *ops)
69+
{
70+
struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops);
71+
72+
return enable_irq_wake(sh_of->irq);
73+
}
74+
75+
static int spihid_apple_of_disable_irq_wake(struct spihid_apple_ops *ops)
76+
{
77+
struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops);
78+
79+
return disable_irq_wake(sh_of->irq);
80+
}
81+
6882
static int spihid_apple_of_probe(struct spi_device *spi)
6983
{
7084
struct device *dev = &spi->dev;
@@ -79,6 +93,8 @@ static int spihid_apple_of_probe(struct spi_device *spi)
7993
spihid_of->ops.power_off = spihid_apple_of_power_off;
8094
spihid_of->ops.enable_irq = spihid_apple_of_enable_irq;
8195
spihid_of->ops.disable_irq = spihid_apple_of_disable_irq;
96+
spihid_of->ops.enable_irq_wake = spihid_apple_of_enable_irq_wake;
97+
spihid_of->ops.disable_irq_wake = spihid_apple_of_disable_irq_wake;
8298

8399
spihid_of->enable_gpio = devm_gpiod_get_index(dev, "spien", 0, 0);
84100
if (IS_ERR(spihid_of->enable_gpio)) {
@@ -120,7 +136,7 @@ MODULE_DEVICE_TABLE(spi, spihid_apple_of_id);
120136
static struct spi_driver spihid_apple_of_driver = {
121137
.driver = {
122138
.name = "spi-hid-apple-of",
123-
//.pm = &spi_hid_apple_of_pm,
139+
.pm = &spihid_apple_core_pm,
124140
.owner = THIS_MODULE,
125141
.of_match_table = of_match_ptr(spihid_apple_of_match),
126142
},

drivers/hid/spi-hid/spi-hid-apple.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ struct spihid_apple_ops {
2020
int (*power_off)(struct spihid_apple_ops *ops);
2121
int (*enable_irq)(struct spihid_apple_ops *ops);
2222
int (*disable_irq)(struct spihid_apple_ops *ops);
23+
int (*enable_irq_wake)(struct spihid_apple_ops *ops);
24+
int (*disable_irq_wake)(struct spihid_apple_ops *ops);
2325
};
2426

2527
irqreturn_t spihid_apple_core_irq(int irq, void *data);
@@ -28,4 +30,6 @@ int spihid_apple_core_probe(struct spi_device *spi, struct spihid_apple_ops *ops
2830
void spihid_apple_core_remove(struct spi_device *spi);
2931
void spihid_apple_core_shutdown(struct spi_device *spi);
3032

33+
extern const struct dev_pm_ops spihid_apple_core_pm;
34+
3135
#endif /* SPI_HID_APPLE_H */

0 commit comments

Comments
 (0)