root/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
// SPDX-License-Identifier: GPL-2.0
/*
 * cxd2880_spi_device.c
 * Sony CXD2880 DVB-T2/T tuner + demodulator driver
 * SPI access functions
 *
 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
 */

#include <linux/spi/spi.h>

#include "cxd2880_spi_device.h"

static int cxd2880_spi_device_write(struct cxd2880_spi *spi,
                                    const u8 *data, u32 size)
{
        struct cxd2880_spi_device *spi_device = NULL;
        struct spi_message msg;
        struct spi_transfer tx;
        int result = 0;

        if (!spi || !spi->user || !data || size == 0)
                return -EINVAL;

        spi_device = spi->user;

        memset(&tx, 0, sizeof(tx));
        tx.tx_buf = data;
        tx.len = size;

        spi_message_init(&msg);
        spi_message_add_tail(&tx, &msg);
        result = spi_sync(spi_device->spi, &msg);

        if (result < 0)
                return -EIO;

        return 0;
}

static int cxd2880_spi_device_write_read(struct cxd2880_spi *spi,
                                         const u8 *tx_data,
                                         u32 tx_size,
                                         u8 *rx_data,
                                         u32 rx_size)
{
        struct cxd2880_spi_device *spi_device = NULL;
        int result = 0;

        if (!spi || !spi->user || !tx_data ||
            !tx_size || !rx_data || !rx_size)
                return -EINVAL;

        spi_device = spi->user;

        result = spi_write_then_read(spi_device->spi, tx_data,
                                     tx_size, rx_data, rx_size);
        if (result < 0)
                return -EIO;

        return 0;
}

int
cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
                              enum cxd2880_spi_mode mode,
                              u32 speed_hz)
{
        int result = 0;
        struct spi_device *spi = spi_device->spi;

        switch (mode) {
        case CXD2880_SPI_MODE_0:
                spi->mode = SPI_MODE_0;
                break;
        case CXD2880_SPI_MODE_1:
                spi->mode = SPI_MODE_1;
                break;
        case CXD2880_SPI_MODE_2:
                spi->mode = SPI_MODE_2;
                break;
        case CXD2880_SPI_MODE_3:
                spi->mode = SPI_MODE_3;
                break;
        default:
                return -EINVAL;
        }

        spi->max_speed_hz = speed_hz;
        spi->bits_per_word = 8;
        result = spi_setup(spi);
        if (result != 0) {
                pr_err("spi_setup failed %d\n", result);
                return -EINVAL;
        }

        return 0;
}

int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
                                  struct cxd2880_spi_device *spi_device)
{
        if (!spi || !spi_device)
                return -EINVAL;

        spi->read = NULL;
        spi->write = cxd2880_spi_device_write;
        spi->write_read = cxd2880_spi_device_write_read;
        spi->flags = 0;
        spi->user = spi_device;

        return 0;
}