1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * cxd2880_devio_spi.c 4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver 5 * I/O interface via SPI 6 * 7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation 8 */ 9 10 #include "cxd2880_devio_spi.h" 11 12 #define BURST_WRITE_MAX 128 13 14 static int cxd2880_io_spi_read_reg(struct cxd2880_io *io, 15 enum cxd2880_io_tgt tgt, 16 u8 sub_address, u8 *data, 17 u32 size) 18 { 19 int ret = 0; 20 struct cxd2880_spi *spi = NULL; 21 u8 send_data[6]; 22 u8 *read_data_top = data; 23 24 if (!io || !io->if_object || !data) 25 return -EINVAL; 26 27 if (sub_address + size > 0x100) 28 return -EINVAL; 29 30 spi = io->if_object; 31 32 if (tgt == CXD2880_IO_TGT_SYS) 33 send_data[0] = 0x0b; 34 else 35 send_data[0] = 0x0a; 36 37 send_data[3] = 0; 38 send_data[4] = 0; 39 send_data[5] = 0; 40 41 while (size > 0) { 42 send_data[1] = sub_address; 43 if (size > 255) 44 send_data[2] = 255; 45 else 46 send_data[2] = size; 47 48 ret = 49 spi->write_read(spi, send_data, sizeof(send_data), 50 read_data_top, send_data[2]); 51 if (ret) 52 return ret; 53 54 sub_address += send_data[2]; 55 read_data_top += send_data[2]; 56 size -= send_data[2]; 57 } 58 59 return ret; 60 } 61 62 static int cxd2880_io_spi_write_reg(struct cxd2880_io *io, 63 enum cxd2880_io_tgt tgt, 64 u8 sub_address, 65 const u8 *data, u32 size) 66 { 67 int ret = 0; 68 struct cxd2880_spi *spi = NULL; 69 u8 send_data[BURST_WRITE_MAX + 4]; 70 const u8 *write_data_top = data; 71 72 if (!io || !io->if_object || !data) 73 return -EINVAL; 74 75 if (size > BURST_WRITE_MAX) 76 return -EINVAL; 77 78 if (sub_address + size > 0x100) 79 return -EINVAL; 80 81 spi = io->if_object; 82 83 if (tgt == CXD2880_IO_TGT_SYS) 84 send_data[0] = 0x0f; 85 else 86 send_data[0] = 0x0e; 87 88 while (size > 0) { 89 send_data[1] = sub_address; 90 if (size > 255) 91 send_data[2] = 255; 92 else 93 send_data[2] = size; 94 95 memcpy(&send_data[3], write_data_top, send_data[2]); 96 97 if (tgt == CXD2880_IO_TGT_SYS) { 98 send_data[3 + send_data[2]] = 0x00; 99 ret = spi->write(spi, send_data, send_data[2] + 4); 100 } else { 101 ret = spi->write(spi, send_data, send_data[2] + 3); 102 } 103 if (ret) 104 return ret; 105 106 sub_address += send_data[2]; 107 write_data_top += send_data[2]; 108 size -= send_data[2]; 109 } 110 111 return ret; 112 } 113 114 int cxd2880_io_spi_create(struct cxd2880_io *io, 115 struct cxd2880_spi *spi, u8 slave_select) 116 { 117 if (!io || !spi) 118 return -EINVAL; 119 120 io->read_regs = cxd2880_io_spi_read_reg; 121 io->write_regs = cxd2880_io_spi_write_reg; 122 io->write_reg = cxd2880_io_common_write_one_reg; 123 io->if_object = spi; 124 io->i2c_address_sys = 0; 125 io->i2c_address_demod = 0; 126 io->slave_select = slave_select; 127 128 return 0; 129 } 130