// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_devio_spi.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * I/O interface via SPI * * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #include "cxd2880_devio_spi.h" #define BURST_WRITE_MAX 128 static int cxd2880_io_spi_read_reg(struct cxd2880_io *io, enum cxd2880_io_tgt tgt, u8 sub_address, u8 *data, u32 size) { int ret; struct cxd2880_spi *spi = NULL; u8 send_data[6]; u8 *read_data_top = data; if (!io || !io->if_object || !data) return -EINVAL; if (sub_address + size > 0x100) return -EINVAL; spi = io->if_object; if (tgt == CXD2880_IO_TGT_SYS) send_data[0] = 0x0b; else send_data[0] = 0x0a; send_data[3] = 0; send_data[4] = 0; send_data[5] = 0; while (size > 0) { send_data[1] = sub_address; if (size > 255) send_data[2] = 255; else send_data[2] = size; ret = spi->write_read(spi, send_data, sizeof(send_data), read_data_top, send_data[2]); if (ret) return ret; sub_address += send_data[2]; read_data_top += send_data[2]; size -= send_data[2]; } return ret; } static int cxd2880_io_spi_write_reg(struct cxd2880_io *io, enum cxd2880_io_tgt tgt, u8 sub_address, const u8 *data, u32 size) { int ret; struct cxd2880_spi *spi = NULL; u8 send_data[BURST_WRITE_MAX + 4]; const u8 *write_data_top = data; if (!io || !io->if_object || !data) return -EINVAL; if (size > BURST_WRITE_MAX) return -EINVAL; if (sub_address + size > 0x100) return -EINVAL; spi = io->if_object; if (tgt == CXD2880_IO_TGT_SYS) send_data[0] = 0x0f; else send_data[0] = 0x0e; while (size > 0) { send_data[1] = sub_address; if (size > 255) send_data[2] = 255; else send_data[2] = size; memcpy(&send_data[3], write_data_top, send_data[2]); if (tgt == CXD2880_IO_TGT_SYS) { send_data[3 + send_data[2]] = 0x00; ret = spi->write(spi, send_data, send_data[2] + 4); } else { ret = spi->write(spi, send_data, send_data[2] + 3); } if (ret) return ret; sub_address += send_data[2]; write_data_top += send_data[2]; size -= send_data[2]; } return ret; } int cxd2880_io_spi_create(struct cxd2880_io *io, struct cxd2880_spi *spi, u8 slave_select) { if (!io || !spi) return -EINVAL; io->read_regs = cxd2880_io_spi_read_reg; io->write_regs = cxd2880_io_spi_write_reg; io->write_reg = cxd2880_io_common_write_one_reg; io->if_object = spi; io->i2c_address_sys = 0; io->i2c_address_demod = 0; io->slave_select = slave_select; return 0; }