summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/modem/m6718_spi/modem_driver.c34
-rw-r--r--drivers/modem/m6718_spi/modem_private.h1
-rw-r--r--drivers/modem/m6718_spi/modem_protocol.h2
-rw-r--r--drivers/modem/m6718_spi/modem_util.h4
-rw-r--r--drivers/modem/m6718_spi/protocol.c66
-rw-r--r--drivers/modem/m6718_spi/statemachine.c6
-rw-r--r--drivers/modem/m6718_spi/util.c14
7 files changed, 121 insertions, 6 deletions
diff --git a/drivers/modem/m6718_spi/modem_driver.c b/drivers/modem/m6718_spi/modem_driver.c
index 623a9191d27..8086e97aa7c 100644
--- a/drivers/modem/m6718_spi/modem_driver.c
+++ b/drivers/modem/m6718_spi/modem_driver.c
@@ -214,13 +214,25 @@ static int __exit spi_remove(struct spi_device *sdev)
static int spi_suspend(struct spi_device *sdev, pm_message_t mesg)
{
bool busy;
+ int ret = -EBUSY;
+ dev_dbg(&sdev->dev, "suspend called\n");
busy = modem_protocol_is_busy(sdev);
- dev_dbg(&sdev->dev, "suspend called, protocol busy:%d\n", busy);
- if (!busy)
- return modem_net_suspend(modem_driver_data.ndev);
- else
+ if (busy) {
+ dev_warn(&sdev->dev, "suspend failed (protocol busy)\n");
return -EBUSY;
+ }
+ ret = modem_protocol_suspend(sdev);
+ if (ret) {
+ dev_warn(&sdev->dev, "suspend failed, (protocol suspend))\n");
+ return ret;
+ }
+ ret = modem_net_suspend(modem_driver_data.ndev);
+ if (ret) {
+ dev_warn(&sdev->dev, "suspend failed, (netdev suspend)\n");
+ return ret;
+ }
+ return 0;
}
/**
@@ -229,8 +241,20 @@ static int spi_suspend(struct spi_device *sdev, pm_message_t mesg)
*/
static int spi_resume(struct spi_device *sdev)
{
+ int ret;
+
dev_dbg(&sdev->dev, "resume called\n");
- return modem_net_resume(modem_driver_data.ndev);
+ ret = modem_protocol_resume(sdev);
+ if (ret) {
+ dev_warn(&sdev->dev, "resume failed, (protocol resume))\n");
+ return ret;
+ }
+ ret = modem_net_resume(modem_driver_data.ndev);
+ if (ret) {
+ dev_warn(&sdev->dev, "resume failed, (netdev resume))\n");
+ return ret;
+ }
+ return 0;
}
#endif /* CONFIG_PM */
diff --git a/drivers/modem/m6718_spi/modem_private.h b/drivers/modem/m6718_spi/modem_private.h
index 929cb62d672..10e651c01ea 100644
--- a/drivers/modem/m6718_spi/modem_private.h
+++ b/drivers/modem/m6718_spi/modem_private.h
@@ -49,6 +49,7 @@ struct ipc_tx_queue {
struct ipc_link_context {
struct modem_m6718_spi_link_platform_data *link;
struct spi_device *sdev;
+ atomic_t suspended;
atomic_t gpio_configured;
atomic_t state_int;
spinlock_t sm_lock;
diff --git a/drivers/modem/m6718_spi/modem_protocol.h b/drivers/modem/m6718_spi/modem_protocol.h
index 69511945cb5..751dcba1087 100644
--- a/drivers/modem/m6718_spi/modem_protocol.h
+++ b/drivers/modem/m6718_spi/modem_protocol.h
@@ -18,5 +18,7 @@ int modem_protocol_probe(struct spi_device *sdev);
void modem_protocol_exit(void);
bool modem_protocol_is_busy(struct spi_device *sdev);
bool modem_protocol_channel_is_open(u8 channel);
+int modem_protocol_suspend(struct spi_device *sdev);
+int modem_protocol_resume(struct spi_device *sdev);
#endif /* _MODEM_PROTOCOL_H_ */
diff --git a/drivers/modem/m6718_spi/modem_util.h b/drivers/modem/m6718_spi/modem_util.h
index 3219900a3c8..2d9e2e39abc 100644
--- a/drivers/modem/m6718_spi/modem_util.h
+++ b/drivers/modem/m6718_spi/modem_util.h
@@ -50,4 +50,8 @@ bool ipc_util_link_gpio_request(struct ipc_link_context *context,
bool ipc_util_link_gpio_config(struct ipc_link_context *context);
bool ipc_util_link_gpio_unconfig(struct ipc_link_context *context);
+bool ipc_util_link_is_suspended(struct ipc_link_context *context);
+void ipc_util_suspend_link(struct ipc_link_context *context);
+void ipc_util_resume_link(struct ipc_link_context *context);
+
#endif /* _MODEM_UTIL_H_ */
diff --git a/drivers/modem/m6718_spi/protocol.c b/drivers/modem/m6718_spi/protocol.c
index aa21d4dbcde..fa6b2528dd4 100644
--- a/drivers/modem/m6718_spi/protocol.c
+++ b/drivers/modem/m6718_spi/protocol.c
@@ -196,6 +196,71 @@ bool modem_protocol_is_busy(struct spi_device *sdev)
return false;
}
+int modem_protocol_suspend(struct spi_device *sdev)
+{
+ struct modem_m6718_spi_link_platform_data *link =
+ sdev->dev.platform_data;
+ struct ipc_link_context *context;
+ int link_id;
+
+ if (link == NULL) {
+ /* platform data missing in board config? */
+ dev_err(&sdev->dev, "error: no platform data for link!\n");
+ return -ENODEV;
+ }
+
+ link_id = link->id;
+ context = &l1_context.device_context[link_id];
+
+ if (link_id >= IPC_NBR_SUPPORTED_SPI_LINKS) {
+ dev_err(&sdev->dev,
+ "link %d error: too many links! (max %d)\n",
+ link->id, IPC_NBR_SUPPORTED_SPI_LINKS);
+ return -ENODEV;
+ }
+
+ ipc_util_suspend_link(context);
+ return 0;
+}
+
+int modem_protocol_resume(struct spi_device *sdev)
+{
+ struct modem_m6718_spi_link_platform_data *link =
+ sdev->dev.platform_data;
+ struct ipc_link_context *context;
+ int link_id;
+
+ if (link == NULL) {
+ /* platform data missing in board config? */
+ dev_err(&sdev->dev, "error: no platform data for link!\n");
+ return -ENODEV;
+ }
+
+ link_id = link->id;
+ context = &l1_context.device_context[link_id];
+
+ if (link_id >= IPC_NBR_SUPPORTED_SPI_LINKS) {
+ dev_err(&sdev->dev,
+ "link %d error: too many links! (max %d)\n",
+ link->id, IPC_NBR_SUPPORTED_SPI_LINKS);
+ return -ENODEV;
+ }
+
+ ipc_util_resume_link(context);
+
+ /*
+ * If the resume event was an interrupt from the slave then the event
+ * is pending and we need to service it now.
+ */
+ if (ipc_util_int_is_active(context)) {
+ dev_dbg(&sdev->dev,
+ "link %d: slave-ready is pending after resume\n",
+ link_id);
+ ipc_sm_kick(IPC_SM_RUN_SLAVE_IRQ, context);
+ }
+ return 0;
+}
+
static void spi_tfr_complete(void *context)
{
ipc_sm_kick(IPC_SM_RUN_TFR_COMPLETE,
@@ -306,6 +371,7 @@ int modem_protocol_probe(struct spi_device *sdev)
/* init link context */
context->link = link;
context->sdev = sdev;
+ ipc_util_resume_link(context);
atomic_set(&context->gpio_configured, 0);
atomic_set(&context->state_int,
ipc_util_int_level_inactive(context));
diff --git a/drivers/modem/m6718_spi/statemachine.c b/drivers/modem/m6718_spi/statemachine.c
index a2092cd2f94..a956661c3bf 100644
--- a/drivers/modem/m6718_spi/statemachine.c
+++ b/drivers/modem/m6718_spi/statemachine.c
@@ -1396,7 +1396,11 @@ void ipc_sm_kick(u8 event, struct ipc_link_context *context)
break;
}
- state_machine_run(context, event);
+ if (!ipc_util_link_is_suspended(context))
+ state_machine_run(context, event);
+ else
+ dev_dbg(&sdev->dev,
+ "link %d is suspended, waiting for resume\n", link->id);
spin_unlock_irqrestore(&context->sm_lock, flags);
}
diff --git a/drivers/modem/m6718_spi/util.c b/drivers/modem/m6718_spi/util.c
index 43862baff99..9c89eb9b34a 100644
--- a/drivers/modem/m6718_spi/util.c
+++ b/drivers/modem/m6718_spi/util.c
@@ -266,3 +266,17 @@ bool ipc_util_link_gpio_unconfig(struct ipc_link_context *context)
return true;
}
+bool ipc_util_link_is_suspended(struct ipc_link_context *context)
+{
+ return atomic_read(&context->suspended) == 1;
+}
+
+void ipc_util_suspend_link(struct ipc_link_context *context)
+{
+ atomic_set(&context->suspended, 1);
+}
+
+void ipc_util_resume_link(struct ipc_link_context *context)
+{
+ atomic_set(&context->suspended, 0);
+}