diff options
author | Philippe Skowronski <philippe.skowronski@qorvo.com> | 2022-12-16 15:02:03 +0100 |
---|---|---|
committer | Victor Liu <victorliu@google.com> | 2022-12-19 15:26:00 +0000 |
commit | bcc705f6cab9b04de6c28b299b821c6e286c5e4f (patch) | |
tree | b382475cafc666cef49ceaee01d1ef25bcb6f4c8 | |
parent | e2c9ecbfbe750046b838a01c3078cfbc6a20e574 (diff) | |
download | uwb-bcc705f6cab9b04de6c28b299b821c6e286c5e4f.tar.gz |
Revert "Revert "[R-5.2.2] uwb: update qm35 driver to release R5.2.2""
This reverts commit 2f7d8b7fd5a922910a921a33c7c7c1a3d7483504.
Change-Id: Idf3069bcb124b1f5efcaae4f011114ec2fb46ede
Signed-off-by: Philippe Skowronski <philippe.skowronski@qorvo.com>
-rw-r--r-- | hsspi.c | 118 | ||||
-rw-r--r-- | hsspi.h | 45 | ||||
-rw-r--r-- | qm35-spi.c | 26 |
3 files changed, 111 insertions, 78 deletions
@@ -44,7 +44,8 @@ #define STC_SOC_ERR BIT(4) #define SS_READY_TIMEOUT_MS (250) -#define INTER_CS_ACTIVE_TIME_US (10) + +#define MAX_SUCCESSIVE_ERRORS (5) struct hsspi_work { struct list_head list; @@ -133,13 +134,26 @@ static int hsspi_wait_ss_ready(struct hsspi *hsspi) { int ret; + 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, + * either the fw went to sleep or crashed, in any case + * we need to wait for it to be ready again. + */ + clear_bit(HSSPI_FLAGS_SS_READY, hsspi->flags); + if (gpiod_get_value(hsspi->gpio_ss_rdy)) { + return 0; + } + } + ret = wait_event_interruptible_timeout( hsspi->wq_ready, test_and_clear_bit(HSSPI_FLAGS_SS_READY, hsspi->flags), msecs_to_jiffies(SS_READY_TIMEOUT_MS)); if (ret == 0) { - dev_err(&hsspi->spi->dev, "timed out waiting for ss_ready(%d)\n", - test_bit(HSSPI_FLAGS_SS_READY, hsspi->flags)); + dev_warn(&hsspi->spi->dev, + "timed out waiting for ss_ready(%d)\n", + test_bit(HSSPI_FLAGS_SS_READY, hsspi->flags)); return -EAGAIN; } if (ret < 0) { @@ -150,35 +164,6 @@ static int hsspi_wait_ss_ready(struct hsspi *hsspi) } /** - * wait_cs_active_min_interval() - waits the time necessary to respect the - * minimium interval between two chip selects active. - * - * @hsspi: &struct hsspi - */ -static void wait_cs_active_min_interval(struct hsspi *hsspi) -{ - /* The HSSPI chip select shall not be activated too early after - * it was deselected. - */ - ktime_t delta = hsspi->next_cs_active_time - ktime_get(); - if (delta > 0) { - delta = ktime_to_us(delta); - usleep_range(delta, delta); - } -} - -/** - * update_next_cs_interval() - update the next time the chip select - * can be activated. - * - * @hsspi: &struct hsspi - */ -static void update_next_cs_interval(struct hsspi *hsspi) -{ - hsspi->next_cs_active_time = ktime_add(ktime_get(), INTER_CS_ACTIVE_TIME_US); -} - -/** * spi_xfer() - Single SPI transfer * * @hsspi: &struct hsspi @@ -201,34 +186,26 @@ static int spi_xfer(struct hsspi *hsspi, const void *tx, void *rx, .len = length, }, }; - int ret, retry = 20; + int ret, retry = 2; hsspi->soc->flags = 0; hsspi->soc->ul = 0; hsspi->soc->length = 0; - if (hsspi->spi_error) - return hsspi->spi_error; - do { - /* The HSSPI chip select shall not be activated too early after - * it was deselected. - */ - wait_cs_active_min_interval(hsspi); hsspi->wakeup_enter(hsspi); ret = hsspi_wait_ss_ready(hsspi); if (ret < 0) { hsspi->wakeup_release(hsspi); - update_next_cs_interval(hsspi); continue; } if (test_sleep_after_ss_ready_us > 0) usleep_range(test_sleep_after_ss_ready_us, test_sleep_after_ss_ready_us+1); + hsspi_set_spi_slave_busy(hsspi); ret = spi_sync_transfer(hsspi->spi, xfers, length ? 2 : 1); hsspi->wakeup_release(hsspi); - update_next_cs_interval(hsspi); trace_hsspi_spi_xfer(&hsspi->spi->dev, hsspi->host, hsspi->soc, ret); @@ -238,7 +215,9 @@ static int spi_xfer(struct hsspi *hsspi, const void *tx, void *rx, } if (!(hsspi->soc->flags & STC_SOC_RDY)) { - dev_err(&hsspi->spi->dev, "FW not ready (flags 0x%02x)\n", hsspi->soc->flags); + dev_err(&hsspi->spi->dev, + "FW not ready (flags %#02x)\n", + hsspi->soc->flags); ret = -EAGAIN; continue; } @@ -257,8 +236,10 @@ static void check_soc_flag(const struct device *dev, const char *func_name, expected = is_tx ? 0x0 : STC_SOC_OA; - if ((soc_flags & (STC_SOC_ERR|STC_SOC_OA)) != expected) - dev_warn(dev, "%s: bad soc flags 0x%hhx\n", func_name, soc_flags); + if ((soc_flags & (STC_SOC_ERR | STC_SOC_OA)) != expected) { + dev_warn(dev, "%s: bad soc flags %#hhx, expected %#hhx\n", + func_name, soc_flags, expected); + } } /** @@ -382,7 +363,9 @@ static int hsspi_pre_read(struct hsspi *hsspi) static int hsspi_thread_fn(void *data) { struct hsspi *hsspi = data; + static int successive_errors; + successive_errors = 0; while (1) { struct hsspi_work *hw; int ret; @@ -408,7 +391,7 @@ static int hsspi_thread_fn(void *data) } else { dev_err(&hsspi->spi->dev, "unknown hsspi_work type: %d\n", hw->type); - ret = -EINVAL; + continue; } } else /* If there is no work, we are here because @@ -417,11 +400,24 @@ static int hsspi_thread_fn(void *data) ret = hsspi_pre_read(hsspi); if (ret) { - spin_lock(&hsspi->lock); - hsspi->state = HSSPI_ERROR; - spin_unlock(&hsspi->lock); + successive_errors++; - hsspi->spi_error = ret; + if (successive_errors > MAX_SUCCESSIVE_ERRORS) { + dev_err(&hsspi->spi->dev, + "Max successive errors %d reached, likely entered ROM code...\n", + successive_errors); + + /* When the device reboots, the ROM code might raise + * ss_ready; if a SPI transfer is requested, the AP + * will initiate the SPI xfer and the ROM code will + * enter its command mode infinite loop... + * No choice but rebooting the device. + */ + hsspi->reset_qm35(hsspi); + successive_errors = 0; + } + } else { + successive_errors = 0; } } return 0; @@ -436,7 +432,6 @@ int hsspi_init(struct hsspi *hsspi, struct spi_device *spi) hsspi->state = HSSPI_STOPPED; hsspi->spi = spi; - hsspi->spi_error = -EAGAIN; init_waitqueue_head(&hsspi->wq); init_waitqueue_head(&hsspi->wq_ready); @@ -454,6 +449,12 @@ int hsspi_init(struct hsspi *hsspi, struct spi_device *spi) return 0; } +void hsspi_set_gpios(struct hsspi *hsspi, struct gpio_desc *gpio_ss_rdy, struct gpio_desc *gpio_exton) +{ + hsspi->gpio_ss_rdy = gpio_ss_rdy; + hsspi->gpio_exton = gpio_exton; +} + int hsspi_deinit(struct hsspi *hsspi) { int i; @@ -555,18 +556,26 @@ 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); +} + void hsspi_set_spi_slave_ready(struct hsspi *hsspi) { - clear_bit(HSSPI_FLAGS_OFF, hsspi->flags); set_bit(HSSPI_FLAGS_SS_READY, hsspi->flags); wake_up_interruptible(&hsspi->wq_ready); } -void hsspi_set_spi_slave_off(struct hsspi *hsspi) +void hsspi_clear_spi_slave_ready(struct hsspi *hsspi) { clear_bit(HSSPI_FLAGS_SS_READY, hsspi->flags); - set_bit(HSSPI_FLAGS_OFF, hsspi->flags); } void hsspi_set_output_data_waiting(struct hsspi *hsspi) @@ -647,7 +656,6 @@ void hsspi_start(struct hsspi *hsspi) spin_lock(&hsspi->lock); hsspi->state = HSSPI_RUNNING; - hsspi->spi_error = 0; spin_unlock(&hsspi->lock); @@ -127,7 +127,7 @@ struct hsspi_layer { enum hsspi_flags { HSSPI_FLAGS_SS_IRQ = 0, HSSPI_FLAGS_SS_READY = 1, - HSSPI_FLAGS_OFF = 2, + HSSPI_FLAGS_SS_BUSY = 2, HSSPI_FLAGS_MAX = 3, }; @@ -165,11 +165,16 @@ struct hsspi { void (*wakeup_enter)(struct hsspi *hsspi); void (*wakeup_release)(struct hsspi *hsspi); + // reset QM35 + void (*reset_qm35)(struct hsspi *hsspi); + struct spi_device *spi; - int spi_error; struct stc_header *host, *soc; ktime_t next_cs_active_time; + + struct gpio_desc *gpio_ss_rdy; + struct gpio_desc *gpio_exton; }; /** @@ -184,6 +189,8 @@ struct hsspi { * */ int hsspi_init(struct hsspi *hsspi, struct spi_device *spi); +void hsspi_set_gpios(struct hsspi *hsspi, struct gpio_desc *gpio_ss_rdy, + struct gpio_desc *gpio_exton); /** * hsspi_deinit() - Initialiaze the HSSPI @@ -225,28 +232,32 @@ int hsspi_unregister(struct hsspi *hsspi, struct hsspi_layer *layer); * * This function is called in the ss_ready irq handler. It notices the * HSSPI driver that the QM is ready for transfer. - * - * The HSSPI must work with or without the ss_rdy gpio. The current - * implementation is far from ideal regarding this requirement. - * - * W/o the gpio we should send SPI transfer right away and retry it if - * the RDY bit was not present in the SOC STC header. */ void hsspi_set_spi_slave_ready(struct hsspi *hsspi); /** - * hsspi_set_spi_slave_off() - tell the hsspi that qm35 went asleep + * 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 + */ +void hsspi_clear_spi_slave_ready(struct hsspi *hsspi); + +/** + * hsspi_set_spi_slave_busy() - tell the hsspi that the ss_ready has + * not been lowered and raised again meaning that the fw is busy, + * @hsspi: pointer to a &struct hsspi + */ +void hsspi_set_spi_slave_busy(struct hsspi *hsspi); + +/** + * hsspi_clear_spi_slave_busy() - tell the hsspi that the ss_ready has + * been lowered and raised again meaning that the fw is not busy anymore, * @hsspi: pointer to a &struct hsspi * - * This function is called in the exton irq handler. It notices the - * HSSPI driver that the QM went asleep. - * - * The HSSPI must work with or without the exton gpio but the sleep - * states on the qm35 would be affected. - * - * W/o the gpio we will ignore the fact that qm35 might have gone asleep. + * This function is called in the ss_ready irq handler. It notices the + * HSSPI driver that the QM has acknowledged the last SPI xfer. */ -void hsspi_set_spi_slave_off(struct hsspi *hsspi); +void hsspi_clear_spi_slave_busy(struct hsspi *hsspi); /** * hsspi_set_output_data_waiting() - tell the hsspi that the ss_irq is active @@ -97,6 +97,10 @@ int qmrom_retries = QMROM_RETRIES; module_param(qmrom_retries, int, 0444); MODULE_PARM_DESC(qmrom_retries, "QMROM retries"); +int reset_on_error = 1; +module_param(reset_on_error, int, 0444); +MODULE_PARM_DESC(reset_on_error, "Reset the QM35 on successive errors"); + static uint8_t qm_soc_id[ROM_SOC_ID_LEN]; static uint16_t qm_dev_id; @@ -328,6 +332,7 @@ static irqreturn_t qm35_ss_rdy_handler(int irq, void *data) old_time = current_time; #endif + hsspi_clear_spi_slave_busy(&qm35_hdl->hsspi); hsspi_set_spi_slave_ready(&qm35_hdl->hsspi); return IRQ_HANDLED; @@ -355,11 +360,21 @@ static void qm35_wakeup_release(struct hsspi *hsspi) gpiod_set_value(qm35_hdl->gpio_wakeup, 0); } +static void qm35_reset_hook(struct hsspi *hsspi) +{ + struct qm35_ctx *qm35_hdl = + container_of(hsspi, struct qm35_ctx, hsspi); + + if (reset_on_error) + qm35_reset(qm35_hdl, QM_RESET_LOW_MS); + usleep_range(QM_BEFORE_RESET_MS * 1000, QM_BEFORE_RESET_MS * 1000); +} + static irqreturn_t qm35_exton_handler(int irq, void *data) { struct qm35_ctx *qm35_hdl = data; - hsspi_set_spi_slave_off(&qm35_hdl->hsspi); + hsspi_clear_spi_slave_ready(&qm35_hdl->hsspi); return IRQ_HANDLED; } @@ -525,6 +540,7 @@ static int hsspi_irqs_setup(struct qm35_ctx *qm35_ctx) qm35_ctx->hsspi.odw_cleared = reenable_ss_irq; qm35_ctx->hsspi.wakeup_enter = qm35_wakeup_enter; qm35_ctx->hsspi.wakeup_release = qm35_wakeup_release; + qm35_ctx->hsspi.reset_qm35 = qm35_reset_hook; ret = devm_request_irq(&qm35_ctx->spi->dev, qm35_ctx->spi->irq, &qm35_irq_handler, ss_irqflags, @@ -548,7 +564,7 @@ static int hsspi_irqs_setup(struct qm35_ctx *qm35_ctx) return ret; if (!gpiod_get_value(qm35_ctx->gpio_exton)) - hsspi_set_spi_slave_off(&qm35_ctx->hsspi); + hsspi_clear_spi_slave_ready(&qm35_ctx->hsspi); } /* Get spi csn */ @@ -742,12 +758,10 @@ static int qm35_probe(struct spi_device *spi) goto log_layer_unregister; } + hsspi_set_gpios(&qm35_ctx->hsspi, qm35_ctx->gpio_ss_rdy, + qm35_ctx->gpio_exton); hsspi_start(&qm35_ctx->hsspi); - /* we can have missed an edge */ - if (gpiod_get_value(qm35_ctx->gpio_ss_rdy)) - hsspi_set_spi_slave_ready(&qm35_ctx->hsspi); - ret = misc_register(&qm35_ctx->uci_dev); if (ret) { dev_err(&spi->dev, "Failed to register uci device\n"); |