/*
 * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <assert.h>
#include <inttypes.h>
#include <stdint.h>

#include <drivers/spi_mem.h>
#include <lib/utils_def.h>
#include <libfdt.h>

#define SPI_MEM_DEFAULT_SPEED_HZ 100000U

/*
 * struct spi_slave - Representation of a SPI slave.
 *
 * @max_hz:		Maximum speed for this slave in Hertz.
 * @cs:			ID of the chip select connected to the slave.
 * @mode:		SPI mode to use for this slave (see SPI mode flags).
 * @ops:		Ops defined by the bus.
 */
struct spi_slave {
	unsigned int max_hz;
	unsigned int cs;
	unsigned int mode;
	const struct spi_bus_ops *ops;
};

static struct spi_slave spi_slave;

static bool spi_mem_check_buswidth_req(uint8_t buswidth, bool tx)
{
	switch (buswidth) {
	case 1U:
		return true;

	case 2U:
		if ((tx && (spi_slave.mode & (SPI_TX_DUAL | SPI_TX_QUAD)) !=
		     0U) ||
		    (!tx && (spi_slave.mode & (SPI_RX_DUAL | SPI_RX_QUAD)) !=
		     0U)) {
			return true;
		}
		break;

	case 4U:
		if ((tx && (spi_slave.mode & SPI_TX_QUAD) != 0U) ||
		    (!tx && (spi_slave.mode & SPI_RX_QUAD) != 0U)) {
			return true;
		}
		break;

	default:
		break;
	}

	return false;
}

static bool spi_mem_supports_op(const struct spi_mem_op *op)
{
	if (!spi_mem_check_buswidth_req(op->cmd.buswidth, true)) {
		return false;
	}

	if ((op->addr.nbytes != 0U) &&
	    !spi_mem_check_buswidth_req(op->addr.buswidth, true)) {
		return false;
	}

	if ((op->dummy.nbytes != 0U) &&
	    !spi_mem_check_buswidth_req(op->dummy.buswidth, true)) {
		return false;
	}

	if ((op->data.nbytes != 0U) &&
	    !spi_mem_check_buswidth_req(op->data.buswidth,
				       op->data.dir == SPI_MEM_DATA_OUT)) {
		return false;
	}

	return true;
}

static int spi_mem_set_speed_mode(void)
{
	const struct spi_bus_ops *ops = spi_slave.ops;
	int ret;

	ret = ops->set_speed(spi_slave.max_hz);
	if (ret != 0) {
		VERBOSE("Cannot set speed (err=%d)\n", ret);
		return ret;
	}

	ret = ops->set_mode(spi_slave.mode);
	if (ret != 0) {
		VERBOSE("Cannot set mode (err=%d)\n", ret);
		return ret;
	}

	return 0;
}

static int spi_mem_check_bus_ops(const struct spi_bus_ops *ops)
{
	bool error = false;

	if (ops->claim_bus == NULL) {
		VERBOSE("Ops claim bus is not defined\n");
		error = true;
	}

	if (ops->release_bus == NULL) {
		VERBOSE("Ops release bus is not defined\n");
		error = true;
	}

	if (ops->exec_op == NULL) {
		VERBOSE("Ops exec op is not defined\n");
		error = true;
	}

	if (ops->set_speed == NULL) {
		VERBOSE("Ops set speed is not defined\n");
		error = true;
	}

	if (ops->set_mode == NULL) {
		VERBOSE("Ops set mode is not defined\n");
		error = true;
	}

	return error ? -EINVAL : 0;
}

/*
 * spi_mem_exec_op() - Execute a memory operation.
 * @op: The memory operation to execute.
 *
 * This function first checks that @op is supported and then tries to execute
 * it.
 *
 * Return: 0 in case of success, a negative error code otherwise.
 */
int spi_mem_exec_op(const struct spi_mem_op *op)
{
	const struct spi_bus_ops *ops = spi_slave.ops;
	int ret;

	VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addqr:%" PRIx64 " len:%x\n",
		__func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
		op->dummy.buswidth, op->data.buswidth,
		op->addr.val, op->data.nbytes);

	if (!spi_mem_supports_op(op)) {
		WARN("Error in spi_mem_support\n");
		return -ENOTSUP;
	}

	ret = ops->claim_bus(spi_slave.cs);
	if (ret != 0) {
		WARN("Error claim_bus\n");
		return ret;
	}

	ret = ops->exec_op(op);

	ops->release_bus();

	return ret;
}

/*
 * spi_mem_init_slave() - SPI slave device initialization.
 * @fdt: Pointer to the device tree blob.
 * @bus_node: Offset of the bus node.
 * @ops: The SPI bus ops defined.
 *
 * This function first checks that @ops are supported and then tries to find
 * a SPI slave device.
 *
 * Return: 0 in case of success, a negative error code otherwise.
 */
int spi_mem_init_slave(void *fdt, int bus_node, const struct spi_bus_ops *ops)
{
	int ret;
	int mode = 0;
	int nchips = 0;
	int bus_subnode = 0;
	const fdt32_t *cuint = NULL;

	ret = spi_mem_check_bus_ops(ops);
	if (ret != 0) {
		return ret;
	}

	fdt_for_each_subnode(bus_subnode, fdt, bus_node) {
		nchips++;
	}

	if (nchips != 1) {
		ERROR("Only one SPI device is currently supported\n");
		return -EINVAL;
	}

	fdt_for_each_subnode(bus_subnode, fdt, bus_node) {
		/* Get chip select */
		cuint = fdt_getprop(fdt, bus_subnode, "reg", NULL);
		if (cuint == NULL) {
			ERROR("Chip select not well defined\n");
			return -EINVAL;
		}
		spi_slave.cs = fdt32_to_cpu(*cuint);

		/* Get max slave frequency */
		spi_slave.max_hz = SPI_MEM_DEFAULT_SPEED_HZ;
		cuint = fdt_getprop(fdt, bus_subnode,
				    "spi-max-frequency", NULL);
		if (cuint != NULL) {
			spi_slave.max_hz = fdt32_to_cpu(*cuint);
		}

		/* Get mode */
		if ((fdt_getprop(fdt, bus_subnode, "spi-cpol", NULL)) != NULL) {
			mode |= SPI_CPOL;
		}
		if ((fdt_getprop(fdt, bus_subnode, "spi-cpha", NULL)) != NULL) {
			mode |= SPI_CPHA;
		}
		if ((fdt_getprop(fdt, bus_subnode, "spi-cs-high", NULL)) !=
		    NULL) {
			mode |= SPI_CS_HIGH;
		}
		if ((fdt_getprop(fdt, bus_subnode, "spi-3wire", NULL)) !=
		    NULL) {
			mode |= SPI_3WIRE;
		}
		if ((fdt_getprop(fdt, bus_subnode, "spi-half-duplex", NULL)) !=
		    NULL) {
			mode |= SPI_PREAMBLE;
		}

		/* Get dual/quad mode */
		cuint = fdt_getprop(fdt, bus_subnode, "spi-tx-bus-width", NULL);
		if (cuint != NULL) {
			switch (fdt32_to_cpu(*cuint)) {
			case 1U:
				break;
			case 2U:
				mode |= SPI_TX_DUAL;
				break;
			case 4U:
				mode |= SPI_TX_QUAD;
				break;
			default:
				WARN("spi-tx-bus-width %u not supported\n",
				     fdt32_to_cpu(*cuint));
				return -EINVAL;
			}
		}

		cuint = fdt_getprop(fdt, bus_subnode, "spi-rx-bus-width", NULL);
		if (cuint != NULL) {
			switch (fdt32_to_cpu(*cuint)) {
			case 1U:
				break;
			case 2U:
				mode |= SPI_RX_DUAL;
				break;
			case 4U:
				mode |= SPI_RX_QUAD;
				break;
			default:
				WARN("spi-rx-bus-width %u not supported\n",
				     fdt32_to_cpu(*cuint));
				return -EINVAL;
			}
		}

		spi_slave.mode = mode;
		spi_slave.ops = ops;
	}

	return spi_mem_set_speed_mode();
}
