tsif: Improve workaround for DMA bug
During tsif stress tests it was reported that the dma flush caused by
calling action_close() is sometimes unrecoverable. The root cause is
stopping the tsif while a read by the dma of the tsif FIFO is in
progress. The previous workaround relied on closing the tsif GPIOs
to stop incoming data to the tsif, then add a delay to allow the
dma to complete all outstanding transactions. A customer still reported
seeing the dma issue. The reason the issue was still happening is due to
the call of gpio API (request/free) which was done on pins not configured
to act as GPIOs. Doing so caused tsif interface not to be closed properly.
Per gpio-mux documentation, pins with function configured as non-gpio
may suffer from un-expected behavior when calling gpio API, these calls
were removed. The delay after closing tsif interface was enlarged to better
cope with low bitrate streams.
Change-Id: I67828c9ad946072a2a925a1d55f35c730a52170c
Signed-off-by: Hamad Kadmany <hkadmany@codeaurora.org>
diff --git a/drivers/misc/tsif.c b/drivers/misc/tsif.c
index 7e59c98..1ff4468 100644
--- a/drivers/misc/tsif.c
+++ b/drivers/misc/tsif.c
@@ -32,7 +32,6 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h> /* kfree, kzalloc */
#include <linux/gpio.h>
-
#include <mach/dma.h>
#include <mach/msm_tsif.h>
@@ -273,36 +272,6 @@
/* ===clocks end=== */
/* ===gpio begin=== */
-static void tsif_gpios_free(const struct msm_gpio *table, int size)
-{
- int i;
- const struct msm_gpio *g;
- for (i = size-1; i >= 0; i--) {
- g = table + i;
- gpio_free(GPIO_PIN(g->gpio_cfg));
- }
-}
-
-static int tsif_gpios_request(const struct msm_gpio *table, int size)
-{
- int rc;
- int i;
- const struct msm_gpio *g;
- for (i = 0; i < size; i++) {
- g = table + i;
- rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
- if (rc) {
- pr_err("gpio_request(%d) <%s> failed: %d\n",
- GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
- goto err;
- }
- }
- return 0;
-err:
- tsif_gpios_free(table, i);
- return rc;
-}
-
static int tsif_gpios_disable(const struct msm_gpio *table, int size)
{
int rc = 0;
@@ -357,19 +326,14 @@
static int tsif_gpios_request_enable(const struct msm_gpio *table, int size)
{
- int rc = tsif_gpios_request(table, size);
- if (rc)
- return rc;
+ int rc;
rc = tsif_gpios_enable(table, size);
- if (rc)
- tsif_gpios_free(table, size);
return rc;
}
static void tsif_gpios_disable_free(const struct msm_gpio *table, int size)
{
tsif_gpios_disable(table, size);
- tsif_gpios_free(table, size);
}
static int tsif_start_gpios(struct msm_tsif_device *tsif_device)
@@ -1029,6 +993,7 @@
struct msm_tsif_platform_data *pdata =
tsif_device->pdev->dev.platform_data;
+
dev_info(&tsif_device->pdev->dev, "%s\n", __func__);
if (tsif_device->state != tsif_state_stopped)
return -EAGAIN;
@@ -1039,14 +1004,6 @@
}
tsif_device->state = tsif_state_running;
- /* make sure the GPIO's are set up */
- rc = tsif_start_gpios(tsif_device);
- if (rc) {
- dev_err(&tsif_device->pdev->dev, "failed to start GPIOs\n");
- tsif_dma_exit(tsif_device);
- return rc;
- }
-
/*
* DMA should be scheduled prior to TSIF hardware initialization,
* otherwise "bus error" will be reported by Data Mover
@@ -1062,9 +1019,20 @@
rc = tsif_start_hw(tsif_device);
if (rc) {
dev_err(&tsif_device->pdev->dev, "Unable to start HW\n");
- tsif_stop_gpios(tsif_device);
tsif_dma_exit(tsif_device);
tsif_clock(tsif_device, 0);
+ disable_irq(tsif_device->irq);
+ return rc;
+ }
+
+ /* make sure the GPIO's are set up */
+ rc = tsif_start_gpios(tsif_device);
+ if (rc) {
+ dev_err(&tsif_device->pdev->dev, "failed to start GPIOs\n");
+ tsif_stop_hw(tsif_device);
+ tsif_dma_exit(tsif_device);
+ tsif_clock(tsif_device, 0);
+ disable_irq(tsif_device->irq);
return rc;
}
@@ -1073,11 +1041,16 @@
dev_err(&tsif_device->pdev->dev,
"Runtime PM: Unable to wake up the device, rc = %d\n",
result);
+ tsif_stop_gpios(tsif_device);
+ tsif_stop_hw(tsif_device);
+ tsif_dma_exit(tsif_device);
+ tsif_clock(tsif_device, 0);
+ disable_irq(tsif_device->irq);
return result;
}
wake_lock(&tsif_device->wake_lock);
- return rc;
+ return 0;
}
static int action_close(struct msm_tsif_device *tsif_device)
@@ -1094,7 +1067,7 @@
* there are any outstanding reads on the bus, and if we
* stop the TSIF too quickly, it can cause a bus error.
*/
- msleep(100);
+ msleep(250);
/* now we can stop the core */
tsif_stop_hw(tsif_device);