blob: 054518f06cc9cd848e21482db1b4332283c54a85 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* This file is part of the QM35 UCI stack for linux.
*
* Copyright (c) 2021 Qorvo US, Inc.
*
* This software is provided under the GNU General Public License, version 2
* (GPLv2), as well as under a Qorvo commercial license.
*
* You may choose to use this software under the terms of the GPLv2 License,
* version 2 ("GPLv2"), as published by the Free Software Foundation.
* You should have received a copy of the GPLv2 along with this program. If
* not, see <http://www.gnu.org/licenses/>.
*
* This program is distributed under the GPLv2 in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GPLv2 for more
* details.
*
* If you cannot meet the requirements of the GPLv2, you may not use this
* software for any purpose without first obtaining a commercial license from
* Qorvo.
* Please contact Qorvo to inquire about licensing terms.
*
* QM35 UCI over HSSPI protocol
*/
#include <linux/bitfield.h>
#include <linux/interrupt.h>
#include <linux/ioctl.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/spi/spi.h>
#include <linux/spinlock.h>
#include <linux/miscdevice.h>
#include <linux/poll.h>
#include <linux/uaccess.h>
#include <linux/firmware.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
#ifdef CONFIG_QM35_DEBOUNCE_TIME_US
#include <linux/ktime.h>
#endif
#include <qmrom.h>
#include <qmrom_spi.h>
#include <qmrom_log.h>
#include <spi_rom_protocol.h>
#include "qm35.h"
#include "uci_ioctls.h"
#include "hsspi.h"
#include "hsspi_uci.h"
#include "hsspi_test.h"
#define QM35_REGULATOR_DELAY_US 1000
#define QMROM_RETRIES 10
#define REGULATORS_ENABLED(x) (x->vdd1 || x->vdd2 || x->vdd3 || x->vdd4)
#ifndef NO_UWB_HAL
#define NO_UWB_HAL false
#endif
static int qm_firmware_load(struct qm35_ctx *qm35_hdl);
static void qm35_regulators_set(struct qm35_ctx *qm35_hdl, bool on);
static const struct file_operations uci_fops;
static const struct of_device_id qm35_dt_ids[] = {
{ .compatible = "qorvo,qm35" },
{},
};
MODULE_DEVICE_TABLE(of, qm35_dt_ids);
static bool flash_on_probe = false;
module_param(flash_on_probe, bool, 0444);
MODULE_PARM_DESC(flash_on_probe, "Flash during the module probe");
static int spi_speed_hz;
module_param(spi_speed_hz, int, 0444);
MODULE_PARM_DESC(spi_speed_hz, "SPI speed (if not set use DTS's one)");
static char *fwname = NULL;
module_param(fwname, charp, 0444);
MODULE_PARM_DESC(fwname, "Use fwname as firmware binary to flash QM35");
static bool wake_use_wakeup = true;
module_param(wake_use_wakeup, bool, 0444);
MODULE_PARM_DESC(wake_use_wakeup, "Use wakeup pin to wake up QM35");
static bool wake_use_csn = false;
module_param(wake_use_csn, bool, 0444);
MODULE_PARM_DESC(wake_use_csn, "Use HSSPI CSn pin to wake up QM35");
static bool wake_on_ssirq = true;
module_param(wake_on_ssirq, bool, 0644);
MODULE_PARM_DESC(wake_on_ssirq,
"Allow QM35 to wakeup the platform using ss_irq");
int trace_spi_xfers;
module_param(trace_spi_xfers, int, 0444);
MODULE_PARM_DESC(trace_spi_xfers, "Trace all the SPI transfers");
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");
int log_qm_traces = 1;
module_param(log_qm_traces, int, 0444);
MODULE_PARM_DESC(log_qm_traces, "Logs the QM35 traces in the kernel messages");
static uint8_t qm_soc_id[ROM_SOC_ID_LEN];
static uint16_t qm_dev_id;
/*
* uci_open() : open operation for uci device
*
*/
static int uci_open(struct inode *inode, struct file *file)
{
struct miscdevice *uci_dev = file->private_data;
struct qm35_ctx *qm35_hdl =
container_of(uci_dev, struct qm35_ctx, uci_dev);
return hsspi_register(&qm35_hdl->hsspi, &qm35_hdl->uci_layer.hlayer);
}
/*
* uci_ioctl() - ioctl operation for uci device.
*
*/
static long uci_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
void __user *argp = (void __user *)args;
struct miscdevice *uci_dev = filp->private_data;
struct qm35_ctx *qm35_hdl =
container_of(uci_dev, struct qm35_ctx, uci_dev);
int ret;
switch (cmd) {
case QM35_CTRL_GET_STATE: {
return copy_to_user(argp, &qm35_hdl->state,
sizeof(qm35_hdl->state)) ?
-EFAULT :
0;
}
case QM35_CTRL_RESET: {
qm35_hsspi_stop(qm35_hdl);
ret = qm35_reset(qm35_hdl, QM_RESET_LOW_MS, true);
msleep(QM_BOOT_MS);
qm35_hsspi_start(qm35_hdl);
if (ret)
return ret;
return copy_to_user(argp, &qm35_hdl->state,
sizeof(qm35_hdl->state)) ?
-EFAULT :
0;
}
case QM35_CTRL_FW_UPLOAD: {
qm35_hsspi_stop(qm35_hdl);
ret = qm_firmware_load(qm35_hdl);
msleep(QM_BOOT_MS);
qm35_hsspi_start(qm35_hdl);
if (ret)
return ret;
return copy_to_user(argp, &qm35_hdl->state,
sizeof(qm35_hdl->state)) ?
-EFAULT :
0;
}
case QM35_CTRL_POWER: {
unsigned int on;
ret = get_user(on, (unsigned int __user *)argp);
if (ret)
return ret;
qm35_hsspi_stop(qm35_hdl);
if (REGULATORS_ENABLED(qm35_hdl))
qm35_regulators_set(qm35_hdl, on);
/*
* Always reset QM as regulators could be shared with
* other devices and power may not be controlled as
* expected
*/
qm35_reset(qm35_hdl, QM_RESET_LOW_MS, on);
msleep(QM_BOOT_MS);
/* If reset or power on */
if (!REGULATORS_ENABLED(qm35_hdl) ||
(REGULATORS_ENABLED(qm35_hdl) && on))
qm35_hsspi_start(qm35_hdl);
return 0;
}
default:
dev_err(&qm35_hdl->spi->dev, "unknown ioctl %x to %s device\n",
cmd, qm35_hdl->uci_dev.name);
return -EINVAL;
}
}
/*
* uci_release() - release operation for uci device.
*
*/
static int uci_release(struct inode *inode, struct file *filp)
{
struct miscdevice *uci_dev = filp->private_data;
struct qm35_ctx *qm35_hdl =
container_of(uci_dev, struct qm35_ctx, uci_dev);
hsspi_unregister(&qm35_hdl->hsspi, &qm35_hdl->uci_layer.hlayer);
return 0;
}
static ssize_t uci_read(struct file *filp, char __user *buf, size_t len,
loff_t *off)
{
struct miscdevice *uci_dev = filp->private_data;
struct qm35_ctx *qm35_hdl =
container_of(uci_dev, struct qm35_ctx, uci_dev);
struct uci_packet *p;
int ret;
p = uci_layer_read(&qm35_hdl->uci_layer, len,
filp->f_flags & O_NONBLOCK);
if (IS_ERR(p))
return PTR_ERR(p);
ret = copy_to_user(buf, p->data, p->length);
if (!ret)
ret = p->length;
uci_packet_free(p);
return ret;
}
static ssize_t uci_write(struct file *filp, const char __user *buf, size_t len,
loff_t *off)
{
struct miscdevice *uci_dev = filp->private_data;
struct qm35_ctx *qm35_hdl =
container_of(uci_dev, struct qm35_ctx, uci_dev);
struct uci_packet *p;
DECLARE_COMPLETION_ONSTACK(comp);
int ret;
p = uci_packet_alloc(len);
if (!p)
return -ENOMEM;
p->write_done = &comp;
if (copy_from_user(p->data, buf, len)) {
ret = -EFAULT;
goto free;
}
ret = hsspi_send(&qm35_hdl->hsspi, &qm35_hdl->uci_layer.hlayer,
&p->blk);
if (ret)
goto free;
wait_for_completion(&comp);
ret = p->status ? p->status : len;
free:
uci_packet_free(p);
return ret;
}
static __poll_t uci_poll(struct file *filp, struct poll_table_struct *wait)
{
struct miscdevice *uci_dev = filp->private_data;
struct qm35_ctx *qm35_ctx =
container_of(uci_dev, struct qm35_ctx, uci_dev);
__poll_t mask = 0;
poll_wait(filp, &qm35_ctx->uci_layer.wq, wait);
if (uci_layer_has_data_available(&qm35_ctx->uci_layer))
mask |= EPOLLIN;
return mask;
}
static const struct file_operations uci_fops = {
.owner = THIS_MODULE,
.open = uci_open,
.release = uci_release,
.unlocked_ioctl = uci_ioctl,
.read = uci_read,
.write = uci_write,
.poll = uci_poll,
};
static irqreturn_t qm35_irq_handler(int irq, void *qm35_ctx)
{
struct qm35_ctx *qm35_hdl = qm35_ctx;
spin_lock(&qm35_hdl->lock);
qm35_hdl->state = QM35_CTRL_STATE_READY;
spin_unlock(&qm35_hdl->lock);
disable_irq_nosync(irq);
hsspi_set_output_data_waiting(&qm35_hdl->hsspi);
return IRQ_HANDLED;
}
static void reenable_ss_irq(struct hsspi *hsspi)
{
struct qm35_ctx *qm35_hdl = container_of(hsspi, struct qm35_ctx, hsspi);
enable_irq(qm35_hdl->spi->irq);
}
static irqreturn_t qm35_ss_rdy_handler(int irq, void *data)
{
struct qm35_ctx *qm35_hdl = data;
#ifdef CONFIG_QM35_DEBOUNCE_TIME_US
static ktime_t old_time;
ktime_t current_time;
current_time = ktime_get();
if (ktime_after(ktime_add(old_time,
CONFIG_QM35_DEBOUNCE_TIME_US * 1000),
current_time))
return IRQ_HANDLED;
old_time = current_time;
#endif
/* Should be low already but in case we just woke up QM */
if (wake_use_csn)
gpiod_set_value(qm35_hdl->gpio_csn, 0);
if (wake_use_wakeup)
gpiod_set_value(qm35_hdl->gpio_wakeup, 0);
hsspi_clear_spi_slave_busy(&qm35_hdl->hsspi);
hsspi_set_spi_slave_ready(&qm35_hdl->hsspi);
return IRQ_HANDLED;
}
static void qm35_wakeup(struct hsspi *hsspi)
{
struct qm35_ctx *qm35_hdl = container_of(hsspi, struct qm35_ctx, hsspi);
if (wake_use_csn)
gpiod_set_value(qm35_hdl->gpio_csn, 1);
if (wake_use_wakeup)
gpiod_set_value(qm35_hdl->gpio_wakeup, 1);
/* The wake up will be cleared only when ss-rdy is raised again */
}
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, true);
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_clear_spi_slave_ready(&qm35_hdl->hsspi);
if (qm35_hdl->hsspi.waiting_ss_rdy)
qm35_wakeup(&qm35_hdl->hsspi);
return IRQ_HANDLED;
}
void qm35_hsspi_start(struct qm35_ctx *qm35_hdl)
{
int irq;
/* nothing to do as HSSPI is already started */
if (qm35_hdl->hsspi.state == HSSPI_RUNNING)
return;
irq = gpiod_to_irq(qm35_hdl->gpio_ss_rdy);
if (irq >= 0) {
enable_irq(irq);
#ifdef CONFIG_QM35_RISING_IRQ_NOT_TRIGGERED
/* Some IRQ controller will trigger a rising edge if
* the gpio is high when enabling the IRQ, some will
* not (RPI board for example). In the second case we
* can miss an event depending on if the level rise
* before or after enable_irq. Besides, the handler
* can also run *after* hsspi_start, breaking the
* hsspi thread with a false information. So let's
* sleep and force the SS_READY bit after.
*/
if (gpiod_get_value(qm35_hdl->gpio_ss_rdy))
hsspi_set_spi_slave_ready(&qm35_hdl->hsspi);
#endif
}
hsspi_start(&qm35_hdl->hsspi);
}
void qm35_hsspi_stop(struct qm35_ctx *qm35_hdl)
{
int irq;
/* nothing to do as HSSPI is already stopped */
if (qm35_hdl->hsspi.state == HSSPI_STOPPED)
return;
hsspi_stop(&qm35_hdl->hsspi);
irq = gpiod_to_irq(qm35_hdl->gpio_ss_rdy);
if (irq >= 0) {
disable_irq_nosync(irq);
clear_bit(HSSPI_FLAGS_SS_READY, qm35_hdl->hsspi.flags);
}
}
int qm35_reset_sync(struct qm35_ctx *qm35_hdl)
{
int ret;
qm35_hsspi_stop(qm35_hdl);
ret = qm35_reset(qm35_hdl, QM_RESET_LOW_MS, true);
msleep(QM_BOOT_MS);
qm35_hsspi_start(qm35_hdl);
return ret;
}
static int qm_firmware_flashing(void *handle, struct qmrom_handle *h,
bool use_prod_fw)
{
struct qm35_ctx *qm35_hdl = (struct qm35_ctx *)handle;
struct spi_device *spi = qm35_hdl->spi;
const struct firmware *fw;
int ret = 0;
fw = qmrom_spi_get_firmware(&spi->dev, h, use_prod_fw);
if (fw == NULL) {
dev_err(&spi->dev, "Firmware file not present!\n");
return -1;
}
ret = qmrom_flash_fw(h, fw);
dev_dbg(&spi->dev, "Return qmrom_flash_fw = %d!\n", ret);
qmrom_spi_release_firmware(fw);
return ret;
}
static int qm_firmware_load(struct qm35_ctx *qm35_hdl)
{
struct spi_device *spi = qm35_hdl->spi;
unsigned int state = qm35_get_state(qm35_hdl);
struct qmrom_handle *h;
int ret;
qm35_set_state(qm35_hdl, QM35_CTRL_STATE_FW_DOWNLOADING);
qmrom_set_log_device(&spi->dev, LOG_WARN);
h = qmrom_init(&spi->dev, qm35_hdl, qm35_hdl->gpio_ss_rdy,
qmrom_retries, qmrom_spi_reset_device);
if (!h) {
pr_err("qmrom_init failed\n");
ret = -1;
goto out;
}
dev_info(&spi->dev, " chip_ver: %x\n", h->chip_rev);
dev_info(&spi->dev, " dev_id: deca%04x\n", h->device_version);
if (h->chip_rev != CHIP_REVISION_A0) {
dev_info(&spi->dev, " soc_id: %*phN\n", ROM_SOC_ID_LEN,
h->soc_id);
dev_info(&spi->dev, " uuid: %*phN\n", ROM_UUID_LEN,
h->uuid);
dev_info(&spi->dev, " lcs_state: %u\n", h->lcs_state);
memcpy(&qm_dev_id, &h->device_version, sizeof(qm_dev_id));
memcpy(qm_soc_id, h->soc_id, ROM_SOC_ID_LEN);
debug_soc_info_available(&qm35_hdl->debug);
} else {
dev_dbg(&spi->dev,
"SoC info not supported on chip revision A0\n");
}
dev_dbg(&spi->dev, "Starting device flashing!\n");
ret = qm_firmware_flashing(qm35_hdl, h, true);
if (ret) {
qmrom_reboot_bootloader(h);
ret = qm_firmware_flashing(qm35_hdl, h, false);
}
if (ret)
dev_err(&spi->dev, "Firmware download failed with %d!\n", ret);
else
dev_info(&spi->dev, "Device flashing completed!\n");
out:
qm35_set_state(qm35_hdl, state);
return ret;
}
int qm_get_dev_id(struct qm35_ctx *qm35_hdl, uint16_t *dev_id)
{
memcpy(dev_id, &qm_dev_id, sizeof(qm_dev_id));
return 0;
}
int qm_get_soc_id(struct qm35_ctx *qm35_hdl, uint8_t *soc_id)
{
memcpy(soc_id, qm_soc_id, ROM_SOC_ID_LEN);
return 0;
}
/**
* hsspi_irqs_setup() - setup all irqs needed by HSSPI
* @qm35_ctx: pointer to &struct qm35_ctx
*
* SS_IRQ
* ------
*
* If `ss-irq-gpios` exists in the DTS, it is used. If not, it's using
* the `interrupts` definition from the SPI device.
*
* SS_READY
* --------
*
* The `ss-ready-gpios` is mandatory. It is used by the FW to signal
* the driver that it can handle a SPI transaction.
*
* Return: 0 if no error, -errno otherwise
*/
static int hsspi_irqs_setup(struct qm35_ctx *qm35_ctx)
{
int ret;
unsigned long ss_irqflags;
/* Get READY GPIO */
qm35_ctx->gpio_ss_rdy =
devm_gpiod_get(&qm35_ctx->spi->dev, "ss-ready", GPIOD_IN);
if (IS_ERR(qm35_ctx->gpio_ss_rdy))
return PTR_ERR(qm35_ctx->gpio_ss_rdy);
ret = devm_request_irq(&qm35_ctx->spi->dev,
gpiod_to_irq(qm35_ctx->gpio_ss_rdy),
&qm35_ss_rdy_handler, IRQF_TRIGGER_RISING,
"hsspi-ss-rdy", qm35_ctx);
if (ret)
return ret;
/* get SS_IRQ GPIO */
qm35_ctx->gpio_ss_irq = devm_gpiod_get_optional(&qm35_ctx->spi->dev,
"ss-irq", GPIOD_IN);
if (qm35_ctx->gpio_ss_irq) {
if (IS_ERR(qm35_ctx->gpio_ss_irq))
return PTR_ERR(qm35_ctx->gpio_ss_irq);
qm35_ctx->spi->irq = gpiod_to_irq(qm35_ctx->gpio_ss_irq);
ss_irqflags = IRQF_TRIGGER_HIGH;
} else {
ss_irqflags = irq_get_trigger_type(qm35_ctx->spi->irq);
}
if (wake_on_ssirq) {
ret = enable_irq_wake(qm35_ctx->spi->irq);
if (ret) {
return ret;
}
}
qm35_ctx->hsspi.odw_cleared = reenable_ss_irq;
qm35_ctx->hsspi.wakeup = qm35_wakeup;
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, "hsspi-ss-irq",
qm35_ctx);
if (ret)
return ret;
/* Get exton */
qm35_ctx->gpio_exton =
devm_gpiod_get_optional(&qm35_ctx->spi->dev, "exton", GPIOD_IN);
if (qm35_ctx->gpio_exton) {
if (IS_ERR(qm35_ctx->gpio_exton))
return PTR_ERR(qm35_ctx->gpio_exton);
ret = devm_request_irq(&qm35_ctx->spi->dev,
gpiod_to_irq(qm35_ctx->gpio_exton),
&qm35_exton_handler,
IRQF_TRIGGER_FALLING, "hsspi-exton",
qm35_ctx);
if (ret)
return ret;
if (!gpiod_get_value(qm35_ctx->gpio_exton))
hsspi_clear_spi_slave_ready(&qm35_ctx->hsspi);
}
/* Get spi csn */
if (wake_use_csn) {
qm35_ctx->gpio_csn = devm_gpiod_get(&qm35_ctx->spi->dev, "csn",
GPIOD_OUT_HIGH);
if (IS_ERR(qm35_ctx->gpio_csn))
return PTR_ERR(qm35_ctx->gpio_csn);
}
/* Get wakeup */
if (wake_use_wakeup) {
qm35_ctx->gpio_wakeup = devm_gpiod_get(&qm35_ctx->spi->dev,
"wakeup", GPIOD_OUT_LOW);
if (IS_ERR(qm35_ctx->gpio_wakeup))
return PTR_ERR(qm35_ctx->gpio_wakeup);
}
return 0;
}
static int qm35_regulator_set_one(struct regulator *reg, bool on)
{
if (!reg)
return 0;
return on ? regulator_enable(reg) : regulator_disable(reg);
}
static void qm35_regulators_set(struct qm35_ctx *qm35_hdl, bool on)
{
static const char *str_fmt = "failed to %s %s regulator: %d\n";
struct device *dev = &qm35_hdl->spi->dev;
const char *on_str = on ? "enable" : "disable";
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;
qm35_hdl->regulators_enabled = on;
spin_unlock(&qm35_hdl->lock);
/* nothing to do we are already in the desired state */
if (is_enabled == on)
return;
ret = qm35_regulator_set_one(qm35_hdl->vdd1, on);
if (ret)
dev_err(dev, str_fmt, on_str, "vdd1", ret);
ret = qm35_regulator_set_one(qm35_hdl->vdd2, on);
if (ret)
dev_err(dev, str_fmt, on_str, "vdd2", ret);
ret = qm35_regulator_set_one(qm35_hdl->vdd3, on);
if (ret)
dev_err(dev, str_fmt, on_str, "vdd3", ret);
ret = qm35_regulator_set_one(qm35_hdl->vdd4, on);
if (ret)
dev_err(dev, str_fmt, on_str, "vdd4", ret);
/* wait for regulator stabilization */
usleep_range(QM35_REGULATOR_DELAY_US, QM35_REGULATOR_DELAY_US + 100);
}
static void qm35_regulators_setup_one(struct regulator **reg,
struct device *dev, const char *name)
{
static const char *str_fmt =
"%s regulator not defined in device tree: %d\n";
struct regulator *tmp;
tmp = devm_regulator_get_optional(dev, name);
if (IS_ERR(tmp)) {
dev_notice(dev, str_fmt, name, PTR_ERR(tmp));
tmp = NULL;
}
*reg = tmp;
}
static void qm35_regulators_setup(struct qm35_ctx *qm35_hdl)
{
struct device *dev = &qm35_hdl->spi->dev;
qm35_regulators_setup_one(&qm35_hdl->vdd1, dev, "qm35-vdd1");
qm35_regulators_setup_one(&qm35_hdl->vdd2, dev, "qm35-vdd2");
qm35_regulators_setup_one(&qm35_hdl->vdd3, dev, "qm35-vdd3");
qm35_regulators_setup_one(&qm35_hdl->vdd4, dev, "qm35-vdd4");
qm35_hdl->regulators_enabled = false;
qm35_hdl->state = QM35_CTRL_STATE_RESET;
}
static int qm35_probe(struct spi_device *spi)
{
struct qm35_ctx *qm35_ctx;
struct miscdevice *uci_misc;
int ret = 0;
if (fwname) {
qmrom_set_fwname(fwname);
}
if (spi_speed_hz) {
spi->max_speed_hz = spi_speed_hz;
ret = spi_setup(spi);
if (ret) {
dev_err(&spi->dev,
"spi_setup: requested spi speed=%d ret=%d\n",
spi_speed_hz, ret);
return ret;
}
}
qm35_ctx = devm_kzalloc(&spi->dev, sizeof(*qm35_ctx), GFP_KERNEL);
if (!qm35_ctx)
return -ENOMEM;
qm35_ctx->spi = spi;
qm35_ctx->log_qm_traces = log_qm_traces;
spin_lock_init(&qm35_ctx->lock);
spi_set_drvdata(spi, qm35_ctx);
qm35_ctx->gpio_reset =
devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(qm35_ctx->gpio_reset)) {
ret = PTR_ERR(qm35_ctx->gpio_reset);
return ret;
}
qm35_regulators_setup(qm35_ctx);
uci_misc = &qm35_ctx->uci_dev;
uci_misc->minor = MISC_DYNAMIC_MINOR;
uci_misc->name = UCI_DEV_NAME;
uci_misc->fops = &uci_fops;
uci_misc->parent = &spi->dev;
/* we need the debugfs root initialized here to be able
* to display the soc info populated if flash_on_probe
* is set for chips different than A0
*/
ret = debug_init_root(&qm35_ctx->debug, NULL);
if (ret) {
debug_deinit(&qm35_ctx->debug);
goto poweroff;
}
ret = hsspi_init(&qm35_ctx->hsspi, spi);
if (ret)
goto poweroff;
ret = uci_layer_init(&qm35_ctx->uci_layer);
if (ret)
goto hsspi_deinit;
ret = debug_init(&qm35_ctx->debug);
if (ret)
goto uci_layer_deinit;
ret = hsspi_test_init(&qm35_ctx->hsspi);
if (ret)
goto debug_deinit;
ret = coredump_layer_init(&qm35_ctx->coredump_layer, &qm35_ctx->debug);
if (ret)
goto hsspi_test_deinit;
ret = log_layer_init(&qm35_ctx->log_layer, &qm35_ctx->debug);
if (ret)
goto coredump_layer_deinit;
ret = hsspi_register(&qm35_ctx->hsspi,
&qm35_ctx->coredump_layer.hlayer);
if (ret)
goto log_layer_deinit;
ret = hsspi_register(&qm35_ctx->hsspi, &qm35_ctx->log_layer.hlayer);
if (ret)
goto coredump_layer_unregister;
msleep(QM_BOOT_MS);
ret = hsspi_irqs_setup(qm35_ctx);
if (ret)
goto log_layer_unregister;
if (flash_on_probe) {
qm35_regulators_set(qm35_ctx, true);
ret = qm_firmware_load(qm35_ctx);
qm35_regulators_set(qm35_ctx, false);
if (ret)
goto log_layer_unregister;
}
hsspi_set_gpios(&qm35_ctx->hsspi, qm35_ctx->gpio_ss_rdy,
qm35_ctx->gpio_exton);
if (!NO_UWB_HAL) {
/* If regulators not available, QM is powered on */
if (!REGULATORS_ENABLED(qm35_ctx))
hsspi_start(&qm35_ctx->hsspi);
} else {
qm35_regulators_set(qm35_ctx, true);
usleep_range(100000, 100000);
hsspi_start(&qm35_ctx->hsspi);
}
ret = misc_register(&qm35_ctx->uci_dev);
if (ret) {
dev_err(&spi->dev, "Failed to register uci device\n");
goto log_layer_unregister;
}
dev_info(&spi->dev, "Registered: [%s] misc device\n", uci_misc->name);
dev_info(&spi->dev, "QM35 spi driver version " DRV_VERSION " probed\n");
return 0;
log_layer_unregister:
hsspi_unregister(&qm35_ctx->hsspi, &qm35_ctx->log_layer.hlayer);
coredump_layer_unregister:
hsspi_unregister(&qm35_ctx->hsspi, &qm35_ctx->coredump_layer.hlayer);
log_layer_deinit:
log_layer_deinit(&qm35_ctx->log_layer);
coredump_layer_deinit:
coredump_layer_deinit(&qm35_ctx->coredump_layer);
hsspi_test_deinit:
hsspi_test_deinit(&qm35_ctx->hsspi);
debug_deinit:
debug_deinit(&qm35_ctx->debug);
uci_layer_deinit:
uci_layer_deinit(&qm35_ctx->uci_layer);
hsspi_deinit:
hsspi_deinit(&qm35_ctx->hsspi);
poweroff:
qm35_regulators_set(qm35_ctx, false);
return ret;
}
static int qm35_remove(struct spi_device *spi)
{
struct qm35_ctx *qm35_hdl = spi_get_drvdata(spi);
misc_deregister(&qm35_hdl->uci_dev);
hsspi_stop(&qm35_hdl->hsspi);
hsspi_unregister(&qm35_hdl->hsspi, &qm35_hdl->log_layer.hlayer);
hsspi_unregister(&qm35_hdl->hsspi, &qm35_hdl->coredump_layer.hlayer);
log_layer_deinit(&qm35_hdl->log_layer);
coredump_layer_deinit(&qm35_hdl->coredump_layer);
hsspi_test_deinit(&qm35_hdl->hsspi);
debug_deinit(&qm35_hdl->debug);
uci_layer_deinit(&qm35_hdl->uci_layer);
hsspi_deinit(&qm35_hdl->hsspi);
qm35_regulators_set(qm35_hdl, false);
dev_info(&spi->dev, "Deregistered: [%s] misc device\n",
qm35_hdl->uci_dev.name);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int qm35_pm_suspend(struct device *dev)
{
struct qm35_ctx *qm35_hdl = dev_get_drvdata(dev);
qm35_hsspi_stop(qm35_hdl);
return 0;
}
static int qm35_pm_resume(struct device *dev)
{
struct qm35_ctx *qm35_hdl = dev_get_drvdata(dev);
qm35_hsspi_start(qm35_hdl);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(qm35_spi_ops, qm35_pm_suspend, qm35_pm_resume);
#define pm_sleep_ptr(_ptr) (IS_ENABLED(CONFIG_PM_SLEEP) ? (_ptr) : NULL)
static struct spi_driver qm35_spi_driver = {
.driver = {
.name = "qm35",
.of_match_table = of_match_ptr(qm35_dt_ids),
.pm = pm_sleep_ptr(&qm35_spi_ops),
},
.probe = qm35_probe,
.remove = qm35_remove,
};
module_spi_driver(qm35_spi_driver);
MODULE_AUTHOR("Qorvo US, Inc.");
MODULE_DESCRIPTION("QM35 SPI device interface");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);