Skip to content

Commit 1369bb5

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 4d765c9 commit 1369bb5

3 files changed

Lines changed: 110 additions & 2 deletions

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
/**
@@ -1038,6 +1042,91 @@ void spihid_apple_core_shutdown(struct spi_device *spi)
10381042
}
10391043
EXPORT_SYMBOL_GPL(spihid_apple_core_shutdown);
10401044

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

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

Lines changed: 17 additions & 2 deletions
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,8 +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,
124-
.owner = THIS_MODULE,
139+
.pm = &spihid_apple_core_pm,
125140
.of_match_table = of_match_ptr(spihid_apple_of_match),
126141
},
127142

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)