summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Liu <victorliu@google.com>2024-03-13 19:57:59 +0000
committerAndroid Partner Code Review <android-gerrit-partner@google.com>2024-03-13 19:57:59 +0000
commit9bdbec4725f4fdfd6c36d3292db778ba249d3fca (patch)
tree0e931433b7d4f8d384439fd69de31e6512765f6f
parentd28772fb6f9a4bc2932238c3d0710002b4a9f690 (diff)
parent491a32b27dcad89bbf92dc15a67741a48c4c74fc (diff)
downloadqm35-android-gs-shusky-5.15-android15-beta.tar.gz
-rw-r--r--qm35s/hsspi.c41
-rw-r--r--qm35s/hsspi.h13
-rw-r--r--qm35s/qm35-spi.c19
-rw-r--r--qm35s/qm35.h2
-rw-r--r--qm35s/qmrom_spi.c12
5 files changed, 73 insertions, 14 deletions
diff --git a/qm35s/hsspi.c b/qm35s/hsspi.c
index 44589fd..52c6908 100644
--- a/qm35s/hsspi.c
+++ b/qm35s/hsspi.c
@@ -141,9 +141,27 @@ static bool is_txrx_waiting(struct hsspi *hsspi)
static int hsspi_wait_ss_ready(struct hsspi *hsspi)
{
int ret;
+ unsigned long flags;
hsspi->waiting_ss_rdy = true;
+ /**
+ * The following block allows to handle the case where
+ * the HSSPI_FLAGS_SS_READY is set but the SOC went into
+ * sleep (S3 or S4) and the exton interrupt has not been
+ * caught yet.
+ *
+ * In that case, the SOC is not ready and this function
+ * would return 0 immediately leading to a potential
+ * comms issue if we initiate the transfer when the SOC
+ * is preparing its SPI xfer.
+ *
+ * So, if this happens, HSSPI_FLAGS_SS_BUSY will be low
+ * and depending on the ss-rdy gpio state, we know if
+ * the SOC is ready. If not, we'll wait for the timeout
+ * (and wake the SOC if necessary before waiting).
+ */
+ spin_lock_irqsave(&hsspi->flags_lock, flags);
if (!test_bit(HSSPI_FLAGS_SS_BUSY, hsspi->flags)) {
/* The ss_ready went low, so the fw is not busy anymore,
* if the ss_ready is high, we can proceed, else,
@@ -151,9 +169,12 @@ static int hsspi_wait_ss_ready(struct hsspi *hsspi)
* we need to wait for it to be ready again.
*/
clear_bit(HSSPI_FLAGS_SS_READY, hsspi->flags);
+ spin_unlock_irqrestore(&hsspi->flags_lock, flags);
if (gpiod_get_value(hsspi->gpio_ss_rdy)) {
return 0;
}
+ } else {
+ spin_unlock_irqrestore(&hsspi->flags_lock, flags);
}
/* Check if the QM went to sleep and wake it up if it did */
@@ -507,6 +528,7 @@ int hsspi_init(struct hsspi *hsspi, struct spi_device *spi)
memset(hsspi, 0, sizeof(*hsspi));
spin_lock_init(&hsspi->lock);
+ spin_lock_init(&hsspi->flags_lock);
INIT_LIST_HEAD(&hsspi->work_list);
hsspi->state = HSSPI_STOPPED;
@@ -636,11 +658,6 @@ int hsspi_unregister(struct hsspi *hsspi, struct hsspi_layer *layer)
return 0;
}
-void hsspi_clear_spi_slave_busy(struct hsspi *hsspi)
-{
- clear_bit(HSSPI_FLAGS_SS_BUSY, hsspi->flags);
-}
-
void hsspi_set_spi_slave_busy(struct hsspi *hsspi)
{
set_bit(HSSPI_FLAGS_SS_BUSY, hsspi->flags);
@@ -648,7 +665,21 @@ void hsspi_set_spi_slave_busy(struct hsspi *hsspi)
void hsspi_set_spi_slave_ready(struct hsspi *hsspi)
{
+ unsigned long flags;
+ spin_lock_irqsave(&hsspi->flags_lock, flags);
+ clear_bit(HSSPI_FLAGS_SS_BUSY, hsspi->flags);
+ set_bit(HSSPI_FLAGS_SS_READY, hsspi->flags);
+ spin_unlock_irqrestore(&hsspi->flags_lock, flags);
+
+ wake_up_interruptible(&hsspi->wq_ready);
+}
+
+void hsspi_set_spi_slave_ready_irq(struct hsspi *hsspi)
+{
+ spin_lock(&hsspi->flags_lock);
+ clear_bit(HSSPI_FLAGS_SS_BUSY, hsspi->flags);
set_bit(HSSPI_FLAGS_SS_READY, hsspi->flags);
+ spin_unlock(&hsspi->flags_lock);
wake_up_interruptible(&hsspi->wq_ready);
}
diff --git a/qm35s/hsspi.h b/qm35s/hsspi.h
index 9cb62cc..4919e01 100644
--- a/qm35s/hsspi.h
+++ b/qm35s/hsspi.h
@@ -147,6 +147,7 @@ enum hsspi_state {
*/
struct hsspi {
spinlock_t lock; /* protect work_list, layers and state */
+ spinlock_t flags_lock; /* protect flags */
struct list_head work_list;
struct hsspi_layer *layers[UL_MAX_IDX];
enum hsspi_state state;
@@ -229,12 +230,22 @@ int hsspi_unregister(struct hsspi *hsspi, struct hsspi_layer *layer);
* hsspi_set_spi_slave_ready() - tell the hsspi that the ss_ready is active
* @hsspi: pointer to a &struct hsspi
*
- * This function is called in the ss_ready irq handler. It notices the
+ * This function is called in the driver's init. It notices the
* HSSPI driver that the QM is ready for transfer.
*/
void hsspi_set_spi_slave_ready(struct hsspi *hsspi);
/**
+ * hsspi_set_spi_slave_ready_irq() - tell the hsspi that the ss_ready is active
+ * in irq context,
+ * @hsspi: pointer to a &struct hsspi
+ *
+ * This function is called in the ss_ready irq handler. It notices the
+ * HSSPI driver that the QM is ready for transfer.
+ */
+void hsspi_set_spi_slave_ready_irq(struct hsspi *hsspi);
+
+/**
* hsspi_clear_spi_slave_ready() - tell the hsspi that the ss_ready has
* been lowered meaning that the fw is busy or asleep,
* @hsspi: pointer to a &struct hsspi
diff --git a/qm35s/qm35-spi.c b/qm35s/qm35-spi.c
index 49063f1..ca0a533 100644
--- a/qm35s/qm35-spi.c
+++ b/qm35s/qm35-spi.c
@@ -215,6 +215,13 @@ static long uci_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
qm35_hsspi_stop(qm35_hdl);
+ if (NO_UWB_HAL) {
+ on = true;
+ dev_warn(
+ &qm35_hdl->spi->dev,
+ "qm35_regulators_set always ON due to NO_UWB_HAL");
+ }
+
if (REGULATORS_ENABLED(qm35_hdl))
qm35_regulators_set(qm35_hdl, on);
@@ -384,10 +391,11 @@ static irqreturn_t qm35_ss_rdy_handler(int irq, void *data)
gpiod_set_value(qm35_hdl->gpio_wakeup, 0);
if (!qm35_hdl->flashing) {
- hsspi_clear_spi_slave_busy(&qm35_hdl->hsspi);
- hsspi_set_spi_slave_ready(&qm35_hdl->hsspi);
+ hsspi_set_spi_slave_ready_irq(&qm35_hdl->hsspi);
} else {
+ spin_lock(&qm35_hdl->lock);
qm35_hdl->qmrom_qm_ready = true;
+ spin_unlock(&qm35_hdl->lock);
wake_up_interruptible(&qm35_hdl->qmrom_wq_ready);
}
@@ -834,11 +842,6 @@ static void qm35_regulators_set(struct qm35_ctx *qm35_hdl, bool on)
bool is_enabled;
int ret;
- if (NO_UWB_HAL) {
- on = true;
- on_str = "enable";
- }
-
spin_lock(&qm35_hdl->lock);
is_enabled = qm35_hdl->regulators_enabled;
@@ -1013,6 +1016,8 @@ static int qm35_probe(struct spi_device *spi)
} else {
qm35_regulators_set(qm35_ctx, true);
usleep_range(100000, 100000);
+ qm35_reset(qm35_ctx, QM_RESET_LOW_MS, true);
+ msleep(QM_BOOT_MS);
qm35_hsspi_start(qm35_ctx);
}
diff --git a/qm35s/qm35.h b/qm35s/qm35.h
index 128da99..22be3d9 100644
--- a/qm35s/qm35.h
+++ b/qm35s/qm35.h
@@ -28,7 +28,7 @@
#define QM_BOOT_MS 450
#define QM_BEFORE_RESET_MS 450
-#define DRV_VERSION "7.2.7-rc3"
+#define DRV_VERSION "7.2.9-rc1"
struct regulator;
diff --git a/qm35s/qmrom_spi.c b/qm35s/qmrom_spi.c
index 99d2584..babf7e2 100644
--- a/qm35s/qmrom_spi.c
+++ b/qm35s/qmrom_spi.c
@@ -167,6 +167,18 @@ void qmrom_spi_release_firmware(const struct firmware *fw)
int qmrom_spi_wait_for_ready_line(void *handle, unsigned int timeout_ms)
{
struct qm35_ctx *qm35_ctx = (struct qm35_ctx *)handle;
+ unsigned long flags;
+ spin_lock_irqsave(&qm35_ctx->lock, flags);
+ if (gpiod_get_value(qm35_ctx->gpio_ss_rdy) == 0 &&
+ qm35_ctx->qmrom_qm_ready) {
+ /*
+ * qmrom_qm_ready should be cleared if ready line is low
+ * did we run into a glitch on ss-rdy? or did the soc
+ * crash?
+ */
+ qm35_ctx->qmrom_qm_ready = false;
+ }
+ spin_unlock_irqrestore(&qm35_ctx->lock, flags);
wait_event_interruptible_timeout(qm35_ctx->qmrom_wq_ready,
qm35_ctx->qmrom_qm_ready,