blob: c57c84927ba5540bc553db600ae667411d03ad3f [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 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 xfer_ongoing;
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__