diff options
-rw-r--r-- | drivers/modem/m6718_spi/modem_driver.c | 34 | ||||
-rw-r--r-- | drivers/modem/m6718_spi/modem_private.h | 1 | ||||
-rw-r--r-- | drivers/modem/m6718_spi/modem_protocol.h | 2 | ||||
-rw-r--r-- | drivers/modem/m6718_spi/modem_util.h | 4 | ||||
-rw-r--r-- | drivers/modem/m6718_spi/protocol.c | 66 | ||||
-rw-r--r-- | drivers/modem/m6718_spi/statemachine.c | 6 | ||||
-rw-r--r-- | drivers/modem/m6718_spi/util.c | 14 |
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); +} |