summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2019-09-03 14:02:24 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2019-09-03 14:02:24 -0700
commit34b6804ae9302ce8b1f48391cd45110ac723172a (patch)
tree771eacbe6c27b611830584384e3b6cfcc40f04d2 /drivers/platform
parent8d75d72e2e260adf92e63ff5a830b4905e34135f (diff)
parent9ea2de0a4e7b4cd918a38c8e5f7198c5ce77702f (diff)
Merge "msm: Add ipc router config in Makefile and Kconfig"
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/msm/qcn/qcn_sdio.c85
1 files changed, 71 insertions, 14 deletions
diff --git a/drivers/platform/msm/qcn/qcn_sdio.c b/drivers/platform/msm/qcn/qcn_sdio.c
index 18bca8b2e13c..f926b660876c 100644
--- a/drivers/platform/msm/qcn/qcn_sdio.c
+++ b/drivers/platform/msm/qcn/qcn_sdio.c
@@ -22,6 +22,7 @@
#include <linux/mmc/sd.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
+#include <linux/kthread.h>
#include "qcn_sdio.h"
static bool tx_dump;
@@ -33,6 +34,19 @@ module_param(rx_dump, bool, S_IRUGO | S_IWUSR | S_IWGRP);
static int dump_len = 32;
module_param(dump_len, int, S_IRUGO | S_IWUSR | S_IWGRP);
+static bool retune;
+module_param(retune, bool, S_IRUGO | S_IWUSR | S_IWGRP);
+
+/* driver_state :
+ * QCN_SDIO_SW_RESET = 0,
+ * QCN_SDIO_SW_PBL,
+ * QCN_SDIO_SW_SBL,
+ * QCN_SDIO_SW_RDDM,
+ * QCN_SDIO_SW_MROM,
+*/
+static int driver_state;
+module_param(driver_state, int, S_IRUGO | S_IRUSR | S_IRGRP);
+
static struct mmc_host *current_host;
#define HEX_DUMP(mode, buf, len) \
@@ -65,7 +79,9 @@ struct completion client_probe_complete;
static struct mutex lock;
static struct list_head cinfo_head;
static atomic_t status;
+static atomic_t xport_status;
static spinlock_t async_lock;
+static struct task_struct *reset_task;
static int qcn_create_sysfs(struct device *dev);
@@ -133,6 +149,18 @@ static void qcn_sdio_free_rw_req(struct qcn_sdio_rw_info *rw_req)
spin_unlock(&sdio_ctxt->lock_free_q);
}
+static void qcn_sdio_purge_rw_buff(void)
+{
+ struct qcn_sdio_rw_info *rw_req = NULL;
+
+ while (!list_empty(&sdio_ctxt->rw_wait_q)) {
+ rw_req = list_first_entry(&sdio_ctxt->rw_wait_q,
+ struct qcn_sdio_rw_info, list);
+ list_del(&rw_req->list);
+ qcn_sdio_free_rw_req(rw_req);
+ }
+}
+
void qcn_sdio_client_probe_complete(int id)
{
complete(&client_probe_complete);
@@ -441,6 +469,7 @@ int qcn_sw_mode_change(enum qcn_sdio_sw_mode mode)
pr_err("Invalid mode\n");
}
+ driver_state = mode;
sdio_ctxt->curr_sw_mode = mode;
return 0;
}
@@ -513,13 +542,35 @@ static int qcn_read_meta_info(void)
return ret;
}
+static int reset_thread(void *data)
+{
+ qcn_sdio_purge_rw_buff();
+ qcn_sdio_card_state(false);
+ qcn_sdio_card_state(true);
+ kthread_stop(reset_task);
+ reset_task = NULL;
+
+ return 0;
+}
+
static void qcn_sdio_irq_handler(struct sdio_func *func)
{
u8 data = 0;
-
+ int ret = 0;
sdio_claim_host(sdio_ctxt->func);
- data = sdio_readb(sdio_ctxt->func, SDIO_QCN_IRQ_STATUS, NULL);
+ data = sdio_readb(sdio_ctxt->func, SDIO_QCN_IRQ_STATUS, &ret);
+ if (ret) {
+ sdio_release_host(sdio_ctxt->func);
+
+ pr_err("%s: IRQ status read error ret = %d\n", __func__, ret);
+
+ reset_task = kthread_run(reset_thread, NULL, "qcn_reset");
+ if (IS_ERR(reset_task))
+ pr_err("Failed to run qcn_reset thread\n");
+
+ return;
+ }
sdio_release_host(sdio_ctxt->func);
if (data & SDIO_QCN_IRQ_CRQ_READY_MASK) {
@@ -591,18 +642,6 @@ static int qcn_sdio_recv_buff(u32 cid, void *buff, size_t len)
return ret;
}
-static void qcn_sdio_purge_rw_buff(void)
-{
- struct qcn_sdio_rw_info *rw_req = NULL;
-
- while (!list_empty(&sdio_ctxt->rw_wait_q)) {
- rw_req = list_first_entry(&sdio_ctxt->rw_wait_q,
- struct qcn_sdio_rw_info, list);
- list_del(&rw_req->list);
- qcn_sdio_free_rw_req(rw_req);
- }
-}
-
static void qcn_sdio_rw_work(struct work_struct *work)
{
int ret = 0;
@@ -709,6 +748,13 @@ int qcn_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
current_host = func->card->host;
+ if (!retune) {
+ pr_debug("%s Probing driver with retune disabled\n", __func__);
+ mmc_retune_disable(current_host);
+ }
+
+ atomic_set(&xport_status, 1);
+
return 0;
err:
kfree(sdio_ctxt);
@@ -721,6 +767,7 @@ static void qcn_sdio_remove(struct sdio_func *func)
struct qcn_sdio_client_info *cinfo = NULL;
struct qcn_sdio_ch_info *ch_info = NULL;
+ atomic_set(&xport_status, 0);
sdio_claim_host(sdio_ctxt->func);
qcn_enable_async_irq(false);
sdio_release_host(sdio_ctxt->func);
@@ -750,6 +797,7 @@ static void qcn_sdio_remove(struct sdio_func *func)
kfree(sdio_ctxt);
sdio_ctxt = NULL;
+ mmc_retune_enable(current_host);
}
static const struct sdio_device_id qcn_sdio_devices[] = {
@@ -1027,6 +1075,9 @@ int sdio_al_queue_transfer_async(struct sdio_al_channel_handle *handle,
struct qcn_sdio_rw_info *rw_req = NULL;
u32 cid = QCN_SDIO_CH_MAX;
+ if (!atomic_read(&xport_status))
+ return -ENODEV;
+
if (!handle) {
pr_err("%s: Error: Invalid Param\n", __func__);
return -EINVAL;
@@ -1071,6 +1122,9 @@ int sdio_al_queue_transfer(struct sdio_al_channel_handle *ch_handle,
int ret = 0;
u32 cid = QCN_SDIO_CH_MAX;
+ if (!atomic_read(&xport_status))
+ return -ENODEV;
+
if (!ch_handle) {
pr_err("%s: SDIO: Invalid Param\n", __func__);
return -EINVAL;
@@ -1118,6 +1172,9 @@ int sdio_al_meta_transfer(struct sdio_al_channel_handle *handle,
u32 cid = QCN_SDIO_CH_MAX;
u8 event = 0;
+ if (!atomic_read(&xport_status))
+ return -ENODEV;
+
if (!handle)
return -EINVAL;