diff options
Diffstat (limited to 'qm35s/hsspi.h')
-rw-r--r-- | qm35s/hsspi.h | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/qm35s/hsspi.h b/qm35s/hsspi.h new file mode 100644 index 0000000..9cb62cc --- /dev/null +++ b/qm35s/hsspi.h @@ -0,0 +1,327 @@ +/* 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 HSSPI Protocol + */ + +#ifndef __HSSPI_H__ +#define __HSSPI_H__ + +#include <linux/gpio.h> +#include <linux/kthread.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/spi/spi.h> +#include <linux/wait.h> + +enum { UL_RESERVED, + UL_BOOT_FLASH, + UL_UCI_APP, + UL_COREDUMP, + UL_LOG, + UL_TEST_HSSPI, + UL_MAX_IDX }; + +struct stc_header { + u8 flags; + u8 ul; + u16 length; +} __packed; + +enum hsspi_work_type { + HSSPI_WORK_TX = 0, + HSSPI_WORK_COMPLETION, +}; + +/** + * struct hsspi_block - Memory block used by the HSSPI. + * @data: pointer to some memory + * @length: requested length of the data + * @size: size of the data (could be greater than length) + * + * This structure represents the memory used by the HSSPI driver for + * sending or receiving message. Upper layer must provides the HSSPI + * driver a way to allocate such structure for reception and uses this + * structure for sending function. + * + * The goal here is to prevent useless copy. + */ +struct hsspi_block { + void *data; + u16 length; + u16 size; +}; + +struct hsspi_layer; + +/** + * struct hsspi_layer_ops - Upper layer operations. + * + * @registered: Called when this upper layer is registered. + * @unregistered: Called when unregistered. + * + * @get: Called when the HSSPI driver need some memory for + * reception. This &struct hsspi_block will be give back to the upper + * layer in the received callback. + * + * @received: Called when the HSSPI driver received some data for this + * upper layer. In case of error, status is used to notify the upper + * layer. + * + * @sent: Called when a &struct hsspi_block is sent by the HSSPI + * driver. In case of error, status is used to notify the upper layer. + * + * Operation needed to be implemented by an upper layer. All ops are + * called by the HSSPI driver and are mandatory. + */ +struct hsspi_layer_ops { + int (*registered)(struct hsspi_layer *upper_layer); + void (*unregistered)(struct hsspi_layer *upper_layer); + + struct hsspi_block *(*get)(struct hsspi_layer *upper_layer, u16 length); + void (*received)(struct hsspi_layer *upper_layer, + struct hsspi_block *blk, int status); + void (*sent)(struct hsspi_layer *upper_layer, struct hsspi_block *blk, + int status); +}; + +/** + * struct hsspi_layer - HSSPI upper layer. + * @name: Name of this upper layer. + * @id: id (ul used in the STC header) of this upper layer + * @ops: &struct hsspi_layer_ops + * + * Basic upper layer structure. Inherit from it to implement a + * concrete upper layer. + */ +struct hsspi_layer { + char *name; + u8 id; + const struct hsspi_layer_ops *ops; +}; + +enum hsspi_flags { + HSSPI_FLAGS_SS_IRQ = 0, + HSSPI_FLAGS_SS_READY = 1, + HSSPI_FLAGS_SS_BUSY = 2, + HSSPI_FLAGS_MAX = 3, +}; + +enum hsspi_state { + HSSPI_RUNNING = 0, + HSSPI_ERROR = 1, + HSSPI_STOPPED = 2, +}; + +/** + * struct hsspi - HSSPI driver. + * + * Some things need to be refine: + * 1. a better way to disable/enable ss_irq or ss_ready GPIOs + * 2. be able to change spi speed on the fly (for flashing purpose) + * + * Actually this structure should be abstract. + * + */ +struct hsspi { + spinlock_t lock; /* protect work_list, layers and state */ + struct list_head work_list; + struct hsspi_layer *layers[UL_MAX_IDX]; + enum hsspi_state state; + + DECLARE_BITMAP(flags, HSSPI_FLAGS_MAX); + struct wait_queue_head wq; + struct wait_queue_head wq_ready; + struct task_struct *thread; + + // re-enable SS_IRQ + void (*odw_cleared)(struct hsspi *hsspi); + + // wakeup QM35 + void (*wakeup)(struct hsspi *hsspi); + + // reset QM35 + void (*reset_qm35)(struct hsspi *hsspi); + + struct spi_device *spi; + + struct stc_header *host, *soc; + ktime_t next_cs_active_time; + + struct gpio_desc *gpio_ss_rdy; + struct gpio_desc *gpio_exton; + + volatile bool waiting_ss_rdy; +}; + +/** + * hsspi_init() - Initialiaze the HSSPI + * @hsspi: pointer to a &struct hsspi + * @spi: pointer to the &struct spi_device used by the HSSPI for SPI + * transmission + * + * Initialize the HSSPI structure. + * + * Return: 0 if no error or -errno. + * + */ +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 + * @hsspi: pointer to a &struct hsspi + * + * Deinitialize the HSSPI structure. + * + * Return: 0 if no error or -errno + */ +int hsspi_deinit(struct hsspi *hsspi); + +/** + * hsspi_register() - Register an upper layer + * @hsspi: pointer to a &struct hsspi + * @layer: pointer to a &struct hsspi_layer + * + * Register an upper layer. + * + * Return: 0 if no error or -errno. + * + */ +int hsspi_register(struct hsspi *hsspi, struct hsspi_layer *layer); + +/** + * hsspi_unregister() - Unregister an upper layer + * @hsspi: pointer to a &struct hsspi + * @layer: pointer to a &struct hsspi_layer + * + * Unregister an upper layer. + * + * Return: 0 if no error or -errno. + * + */ +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 + * HSSPI driver that the QM is ready for transfer. + */ +void hsspi_set_spi_slave_ready(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 + */ +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 ss_ready irq handler. It notices the + * HSSPI driver that the QM has acknowledged the last SPI xfer. + */ +void hsspi_clear_spi_slave_busy(struct hsspi *hsspi); + +/** + * hsspi_set_output_data_waiting() - tell the hsspi that the ss_irq is active + * @hsspi: pointer to a &struct hsspi + * + * This function is called in the ss_irq irq handler. It notices the + * HSSPI dirver that the QM has some date to outpput. + * + * The HSSPI must work with or without the ss_irq gpio. The current + * implementation is far from ideal regarding this requirement. + * + * W/o the gpio we should send repeatly some 0-length write transfer + * in order to check for ODW flag in SOC STC header. + */ +void hsspi_set_output_data_waiting(struct hsspi *hsspi); + +/** + * hsspi_init_block() - allocate a block data that suits HSSPI. + * + * @blk: point to a &struct hsspi_block + * @length: block length + * + * Return: 0 or -ENOMEM on error + */ +int hsspi_init_block(struct hsspi_block *blk, u16 length); + +/** + * hsspi_deinit_block() - deallocate a block data. + * + * @blk: point to a &struct hsspi_block + * + */ +void hsspi_deinit_block(struct hsspi_block *blk); + +/** + * hsspi_send() - send a &struct hsspi_block for a &struct hsspi_layer + * layer. + * + * @hsspi: pointer to a &struct hsspi + * @layer: pointer to a &struct hsspi_layer + * @blk: pointer to a &struct hsspi_block + * + * Send the block `blk` of the upper layer `layer` on the `hsspi` + * driver. + * + * Return: 0 if no error or -errno. + * + */ +int hsspi_send(struct hsspi *hsspi, struct hsspi_layer *layer, + struct hsspi_block *blk); + +/** + * hsspi_start() - start the HSSPI + * + * @hsspi: pointer to a &struct hsspi + * + */ +void hsspi_start(struct hsspi *hsspi); + +/** + * hsspi_stop() - stop the HSSPI + * + * @hsspi: pointer to a &struct hsspi + * + */ +void hsspi_stop(struct hsspi *hsspi); + +#endif // __HSSPI_H__ |