summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Blair <chris.blair@stericsson.com>2012-01-04 16:19:01 +0000
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-06-05 10:40:23 +0200
commit897e9614f89d1f50501b6261ade8837e7d61881b (patch)
treef162168422ecbcaa047f04510c4c69dc350c8cdd
parentb3fed0a70ea154d26733edede211456c873b61a7 (diff)
modem m6718: Handle modem irq before resume
Handles the scenario where the modem wakes up the APE and the modem irq is serviced before the IPC driver is resumed. The event is regsitered and serviced later when the driver resume hook is called. ST-Ericsson ID: 405458 ST-Ericsson FOSS-OUT ID: Trivial ST-Ericsson Linux next: NA Change-Id: I441decea1cbc657e8dc13ca63a3116f50581c6a7 Signed-off-by: Chris Blair <chris.blair@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/44410 Reviewed-by: QATOOLS Reviewed-by: QABUILD Reviewed-by: Rickard EVERTSSON <rickard.evertsson@stericsson.com> Reviewed-by: Linus WALLEIJ <linus.walleij@stericsson.com>
-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);
+}