blob: 116daf9088fa8ab7fa356fb3017bc786bbb688f1 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <assert.h>
#include <commonlib/helpers.h>
#include <spi-generic.h>
#include <stddef.h>
#include <string.h>
int spi_claim_bus(const struct spi_slave *slave)
{
const struct spi_ctrlr *ctrlr = slave->ctrlr;
if (ctrlr && ctrlr->claim_bus)
return ctrlr->claim_bus(slave);
return 0;
}
void spi_release_bus(const struct spi_slave *slave)
{
const struct spi_ctrlr *ctrlr = slave->ctrlr;
if (ctrlr && ctrlr->release_bus)
ctrlr->release_bus(slave);
}
static int spi_xfer_single_op(const struct spi_slave *slave,
struct spi_op *op)
{
const struct spi_ctrlr *ctrlr = slave->ctrlr;
int ret;
if (!ctrlr || !ctrlr->xfer)
return -1;
ret = ctrlr->xfer(slave, op->dout, op->bytesout, op->din, op->bytesin);
if (ret)
op->status = SPI_OP_FAILURE;
else
op->status = SPI_OP_SUCCESS;
return ret;
}
static int spi_xfer_vector_default(const struct spi_slave *slave,
struct spi_op vectors[], size_t count)
{
size_t i;
int ret;
for (i = 0; i < count; i++) {
ret = spi_xfer_single_op(slave, &vectors[i]);
if (ret)
return ret;
}
return 0;
}
int spi_xfer_vector(const struct spi_slave *slave,
struct spi_op vectors[], size_t count)
{
const struct spi_ctrlr *ctrlr = slave->ctrlr;
if (ctrlr && ctrlr->xfer_vector)
return ctrlr->xfer_vector(slave, vectors, count);
return spi_xfer_vector_default(slave, vectors, count);
}
int spi_xfer(const struct spi_slave *slave, const void *dout, size_t bytesout,
void *din, size_t bytesin)
{
const struct spi_ctrlr *ctrlr = slave->ctrlr;
if (ctrlr && ctrlr->xfer)
return ctrlr->xfer(slave, dout, bytesout, din, bytesin);
return -1;
}
unsigned int spi_crop_chunk(const struct spi_slave *slave, unsigned int cmd_len,
unsigned int buf_len)
{
const struct spi_ctrlr *ctrlr = slave->ctrlr;
unsigned int ctrlr_max;
bool deduct_cmd_len;
bool deduct_opcode_len;
if (!ctrlr)
return 0;
deduct_cmd_len = !!(ctrlr->flags & SPI_CNTRLR_DEDUCT_CMD_LEN);
deduct_opcode_len = !!(ctrlr->flags & SPI_CNTRLR_DEDUCT_OPCODE_LEN);
ctrlr_max = ctrlr->max_xfer_size;
assert (ctrlr_max != 0);
/* Assume opcode is always one byte and deduct it from the cmd_len
as the hardware has a separate register for the opcode. */
if (deduct_opcode_len)
cmd_len--;
if (deduct_cmd_len && (ctrlr_max > cmd_len))
ctrlr_max -= cmd_len;
return MIN(ctrlr_max, buf_len);
}
void __weak spi_init(void)
{
/* Default weak implementation - do nothing. */
}
int spi_setup_slave(unsigned int bus, unsigned int cs, struct spi_slave *slave)
{
size_t i;
memset(slave, 0, sizeof(*slave));
for (i = 0; i < spi_ctrlr_bus_map_count; i++) {
if ((spi_ctrlr_bus_map[i].bus_start <= bus) &&
(spi_ctrlr_bus_map[i].bus_end >= bus)) {
slave->ctrlr = spi_ctrlr_bus_map[i].ctrlr;
break;
}
}
if (slave->ctrlr == NULL) {
printk(BIOS_ERR, "Can't find SPI bus %u\n", bus);
return -1;
}
slave->bus = bus;
slave->cs = cs;
if (slave->ctrlr->setup)
return slave->ctrlr->setup(slave);
return 0;
}