From 37cb6a2d9d7061578180df498a221225ab59cb22 Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Tue, 6 Dec 2011 15:36:44 -0800 Subject: [PATCH 1/2] mfd: wcd9310: Retry read/write on failure There can be instance that slimbus read or write fails due to slimbus clock not turning back on time. Wait 5ms if driver fails to read/write and retry. Change-Id: I050635b7dad9ad282040f0563d3c44124e1327c7 Signed-off-by: Joonwoo Park --- drivers/mfd/wcd9310-core.c | 44 +++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c index aabc2cc54ce..4b81e9966fa 100644 --- a/drivers/mfd/wcd9310-core.c +++ b/drivers/mfd/wcd9310-core.c @@ -27,6 +27,7 @@ #define TABLA_SLIM_GLA_MAX_RETRIES 5 #define TABLA_REGISTER_START_OFFSET 0x800 +#define TABLA_SLIM_RW_MAX_TRIES 3 #define MAX_TABLA_DEVICE 4 #define TABLA_I2C_MODE 0x03 @@ -183,21 +184,25 @@ static int tabla_slim_read_device(struct tabla *tabla, unsigned short reg, { int ret; struct slim_ele_access msg; + int slim_read_tries = TABLA_SLIM_RW_MAX_TRIES; msg.start_offset = TABLA_REGISTER_START_OFFSET + reg; msg.num_bytes = bytes; msg.comp = NULL; - mutex_lock(&tabla->xfer_lock); - if (interface) - ret = slim_request_val_element(tabla->slim_slave, &msg, dest, - bytes); - else - ret = slim_request_val_element(tabla->slim, &msg, dest, bytes); + while (1) { + mutex_lock(&tabla->xfer_lock); + ret = slim_request_val_element(interface ? + tabla->slim_slave : tabla->slim, + &msg, dest, bytes); + mutex_unlock(&tabla->xfer_lock); + if (likely(ret == 0) || (--slim_read_tries == 0)) + break; + usleep_range(5000, 5000); + } if (ret) - pr_err("%s: Error, Tabla read failed\n", __func__); + pr_err("%s: Error, Tabla read failed (%d)\n", __func__, ret); - mutex_unlock(&tabla->xfer_lock); return ret; } /* Interface specifies whether the write is to the interface or general @@ -208,20 +213,25 @@ static int tabla_slim_write_device(struct tabla *tabla, unsigned short reg, { int ret; struct slim_ele_access msg; + int slim_write_tries = TABLA_SLIM_RW_MAX_TRIES; msg.start_offset = TABLA_REGISTER_START_OFFSET + reg; msg.num_bytes = bytes; msg.comp = NULL; - mutex_lock(&tabla->xfer_lock); - if (interface) - ret = slim_change_val_element(tabla->slim_slave, &msg, src, - bytes); - else - ret = slim_change_val_element(tabla->slim, &msg, src, bytes); - if (ret) - pr_err("%s: Error, Tabla write failed\n", __func__); + while (1) { + mutex_lock(&tabla->xfer_lock); + ret = slim_change_val_element(interface ? + tabla->slim_slave : tabla->slim, + &msg, src, bytes); + mutex_unlock(&tabla->xfer_lock); + if (likely(ret == 0) || (--slim_write_tries == 0)) + break; + usleep_range(5000, 5000); + } + + if (ret) + pr_err("%s: Error, Tabla write failed (%d)\n", __func__, ret); - mutex_unlock(&tabla->xfer_lock); return ret; } From 4669aa3f5dfc3ea594371f317b6a27f80189734f Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Tue, 6 Dec 2011 15:42:05 -0800 Subject: [PATCH 2/2] mfd: wcd9310: Make tabla interrupt line to be wakeable Tabla hardware needs to wake up CPU by interrupt for headset insertion/removal/button press functionalities. Make Tabla's interrupt line as wakeable interrupt so driver gets interrupt while CPU is suspend mode. CRs-Fixed: 318317 Change-Id: Ie42938478ad66cb108a01abea1d0b01df7485e8b Signed-off-by: Joonwoo Park --- drivers/mfd/wcd9310-irq.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/mfd/wcd9310-irq.c b/drivers/mfd/wcd9310-irq.c index 9cc47615083..fef13230286 100644 --- a/drivers/mfd/wcd9310-irq.c +++ b/drivers/mfd/wcd9310-irq.c @@ -189,17 +189,37 @@ int tabla_irq_init(struct tabla *tabla) ret = request_threaded_irq(tabla->irq, NULL, tabla_irq_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "tabla", tabla); - - if (ret != 0) { + if (ret != 0) dev_err(tabla->dev, "Failed to request IRQ %d: %d\n", tabla->irq, ret); - return ret; + else { + ret = enable_irq_wake(tabla->irq); + if (ret == 0) { + ret = device_init_wakeup(tabla->dev, 1); + if (ret) { + dev_err(tabla->dev, "Failed to init device" + "wakeup : %d\n", ret); + disable_irq_wake(tabla->irq); + } + } else + dev_err(tabla->dev, "Failed to set wake interrupt on" + " IRQ %d: %d\n", tabla->irq, ret); + if (ret) + free_irq(tabla->irq, tabla); } - return 0; + + if (ret) + mutex_destroy(&tabla->irq_lock); + + return ret; } + void tabla_irq_exit(struct tabla *tabla) { - if (tabla->irq) + if (tabla->irq) { + disable_irq_wake(tabla->irq); free_irq(tabla->irq, tabla); + device_init_wakeup(tabla->dev, 0); + } mutex_destroy(&tabla->irq_lock); }