14e67e6cbSYasunari Takiguchi // SPDX-License-Identifier: GPL-2.0
24e67e6cbSYasunari Takiguchi /*
34e67e6cbSYasunari Takiguchi  * cxd2880_spi_device.c
44e67e6cbSYasunari Takiguchi  * Sony CXD2880 DVB-T2/T tuner + demodulator driver
54e67e6cbSYasunari Takiguchi  * SPI access functions
64e67e6cbSYasunari Takiguchi  *
74e67e6cbSYasunari Takiguchi  * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
84e67e6cbSYasunari Takiguchi  */
94e67e6cbSYasunari Takiguchi 
104e67e6cbSYasunari Takiguchi #include <linux/spi/spi.h>
114e67e6cbSYasunari Takiguchi 
124e67e6cbSYasunari Takiguchi #include "cxd2880_spi_device.h"
134e67e6cbSYasunari Takiguchi 
cxd2880_spi_device_write(struct cxd2880_spi * spi,const u8 * data,u32 size)144e67e6cbSYasunari Takiguchi static int cxd2880_spi_device_write(struct cxd2880_spi *spi,
154e67e6cbSYasunari Takiguchi 				    const u8 *data, u32 size)
164e67e6cbSYasunari Takiguchi {
174e67e6cbSYasunari Takiguchi 	struct cxd2880_spi_device *spi_device = NULL;
184e67e6cbSYasunari Takiguchi 	struct spi_message msg;
194e67e6cbSYasunari Takiguchi 	struct spi_transfer tx;
204e67e6cbSYasunari Takiguchi 	int result = 0;
214e67e6cbSYasunari Takiguchi 
224e67e6cbSYasunari Takiguchi 	if (!spi || !spi->user || !data || size == 0)
234e67e6cbSYasunari Takiguchi 		return -EINVAL;
244e67e6cbSYasunari Takiguchi 
254e67e6cbSYasunari Takiguchi 	spi_device = spi->user;
264e67e6cbSYasunari Takiguchi 
274e67e6cbSYasunari Takiguchi 	memset(&tx, 0, sizeof(tx));
284e67e6cbSYasunari Takiguchi 	tx.tx_buf = data;
294e67e6cbSYasunari Takiguchi 	tx.len = size;
304e67e6cbSYasunari Takiguchi 
314e67e6cbSYasunari Takiguchi 	spi_message_init(&msg);
324e67e6cbSYasunari Takiguchi 	spi_message_add_tail(&tx, &msg);
334e67e6cbSYasunari Takiguchi 	result = spi_sync(spi_device->spi, &msg);
344e67e6cbSYasunari Takiguchi 
354e67e6cbSYasunari Takiguchi 	if (result < 0)
364e67e6cbSYasunari Takiguchi 		return -EIO;
374e67e6cbSYasunari Takiguchi 
384e67e6cbSYasunari Takiguchi 	return 0;
394e67e6cbSYasunari Takiguchi }
404e67e6cbSYasunari Takiguchi 
cxd2880_spi_device_write_read(struct cxd2880_spi * spi,const u8 * tx_data,u32 tx_size,u8 * rx_data,u32 rx_size)414e67e6cbSYasunari Takiguchi static int cxd2880_spi_device_write_read(struct cxd2880_spi *spi,
424e67e6cbSYasunari Takiguchi 					 const u8 *tx_data,
434e67e6cbSYasunari Takiguchi 					 u32 tx_size,
444e67e6cbSYasunari Takiguchi 					 u8 *rx_data,
454e67e6cbSYasunari Takiguchi 					 u32 rx_size)
464e67e6cbSYasunari Takiguchi {
474e67e6cbSYasunari Takiguchi 	struct cxd2880_spi_device *spi_device = NULL;
484e67e6cbSYasunari Takiguchi 	int result = 0;
494e67e6cbSYasunari Takiguchi 
504e67e6cbSYasunari Takiguchi 	if (!spi || !spi->user || !tx_data ||
514e67e6cbSYasunari Takiguchi 	    !tx_size || !rx_data || !rx_size)
524e67e6cbSYasunari Takiguchi 		return -EINVAL;
534e67e6cbSYasunari Takiguchi 
544e67e6cbSYasunari Takiguchi 	spi_device = spi->user;
554e67e6cbSYasunari Takiguchi 
564e67e6cbSYasunari Takiguchi 	result = spi_write_then_read(spi_device->spi, tx_data,
574e67e6cbSYasunari Takiguchi 				     tx_size, rx_data, rx_size);
584e67e6cbSYasunari Takiguchi 	if (result < 0)
594e67e6cbSYasunari Takiguchi 		return -EIO;
604e67e6cbSYasunari Takiguchi 
614e67e6cbSYasunari Takiguchi 	return 0;
624e67e6cbSYasunari Takiguchi }
634e67e6cbSYasunari Takiguchi 
644e67e6cbSYasunari Takiguchi int
cxd2880_spi_device_initialize(struct cxd2880_spi_device * spi_device,enum cxd2880_spi_mode mode,u32 speed_hz)654e67e6cbSYasunari Takiguchi cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
664e67e6cbSYasunari Takiguchi 			      enum cxd2880_spi_mode mode,
674e67e6cbSYasunari Takiguchi 			      u32 speed_hz)
684e67e6cbSYasunari Takiguchi {
694e67e6cbSYasunari Takiguchi 	int result = 0;
704e67e6cbSYasunari Takiguchi 	struct spi_device *spi = spi_device->spi;
714e67e6cbSYasunari Takiguchi 
724e67e6cbSYasunari Takiguchi 	switch (mode) {
734e67e6cbSYasunari Takiguchi 	case CXD2880_SPI_MODE_0:
744e67e6cbSYasunari Takiguchi 		spi->mode = SPI_MODE_0;
754e67e6cbSYasunari Takiguchi 		break;
764e67e6cbSYasunari Takiguchi 	case CXD2880_SPI_MODE_1:
774e67e6cbSYasunari Takiguchi 		spi->mode = SPI_MODE_1;
784e67e6cbSYasunari Takiguchi 		break;
794e67e6cbSYasunari Takiguchi 	case CXD2880_SPI_MODE_2:
804e67e6cbSYasunari Takiguchi 		spi->mode = SPI_MODE_2;
814e67e6cbSYasunari Takiguchi 		break;
824e67e6cbSYasunari Takiguchi 	case CXD2880_SPI_MODE_3:
834e67e6cbSYasunari Takiguchi 		spi->mode = SPI_MODE_3;
844e67e6cbSYasunari Takiguchi 		break;
854e67e6cbSYasunari Takiguchi 	default:
864e67e6cbSYasunari Takiguchi 		return -EINVAL;
874e67e6cbSYasunari Takiguchi 	}
884e67e6cbSYasunari Takiguchi 
894e67e6cbSYasunari Takiguchi 	spi->max_speed_hz = speed_hz;
904e67e6cbSYasunari Takiguchi 	spi->bits_per_word = 8;
914e67e6cbSYasunari Takiguchi 	result = spi_setup(spi);
924e67e6cbSYasunari Takiguchi 	if (result != 0) {
934e67e6cbSYasunari Takiguchi 		pr_err("spi_setup failed %d\n", result);
944e67e6cbSYasunari Takiguchi 		return -EINVAL;
954e67e6cbSYasunari Takiguchi 	}
964e67e6cbSYasunari Takiguchi 
974e67e6cbSYasunari Takiguchi 	return 0;
984e67e6cbSYasunari Takiguchi }
994e67e6cbSYasunari Takiguchi 
cxd2880_spi_device_create_spi(struct cxd2880_spi * spi,struct cxd2880_spi_device * spi_device)1004e67e6cbSYasunari Takiguchi int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
1014e67e6cbSYasunari Takiguchi 				  struct cxd2880_spi_device *spi_device)
1024e67e6cbSYasunari Takiguchi {
1034e67e6cbSYasunari Takiguchi 	if (!spi || !spi_device)
1044e67e6cbSYasunari Takiguchi 		return -EINVAL;
1054e67e6cbSYasunari Takiguchi 
1064e67e6cbSYasunari Takiguchi 	spi->read = NULL;
1074e67e6cbSYasunari Takiguchi 	spi->write = cxd2880_spi_device_write;
1084e67e6cbSYasunari Takiguchi 	spi->write_read = cxd2880_spi_device_write_read;
1094e67e6cbSYasunari Takiguchi 	spi->flags = 0;
1104e67e6cbSYasunari Takiguchi 	spi->user = spi_device;
1114e67e6cbSYasunari Takiguchi 
1124e67e6cbSYasunari Takiguchi 	return 0;
1134e67e6cbSYasunari Takiguchi }
114