1// SPDX-License-Identifier: GPL-2.0
2/*
3 * cxd2880_spi_device.c
4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver
5 * SPI access functions
6 *
7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
8 */
9
10#include <linux/spi/spi.h>
11
12#include "cxd2880_spi_device.h"
13
14static int cxd2880_spi_device_write(struct cxd2880_spi *spi,
15				    const u8 *data, u32 size)
16{
17	struct cxd2880_spi_device *spi_device = NULL;
18	struct spi_message msg;
19	struct spi_transfer tx;
20	int result = 0;
21
22	if (!spi || !spi->user || !data || size == 0)
23		return -EINVAL;
24
25	spi_device = spi->user;
26
27	memset(&tx, 0, sizeof(tx));
28	tx.tx_buf = data;
29	tx.len = size;
30
31	spi_message_init(&msg);
32	spi_message_add_tail(&tx, &msg);
33	result = spi_sync(spi_device->spi, &msg);
34
35	if (result < 0)
36		return -EIO;
37
38	return 0;
39}
40
41static int cxd2880_spi_device_write_read(struct cxd2880_spi *spi,
42					 const u8 *tx_data,
43					 u32 tx_size,
44					 u8 *rx_data,
45					 u32 rx_size)
46{
47	struct cxd2880_spi_device *spi_device = NULL;
48	int result = 0;
49
50	if (!spi || !spi->user || !tx_data ||
51	    !tx_size || !rx_data || !rx_size)
52		return -EINVAL;
53
54	spi_device = spi->user;
55
56	result = spi_write_then_read(spi_device->spi, tx_data,
57				     tx_size, rx_data, rx_size);
58	if (result < 0)
59		return -EIO;
60
61	return 0;
62}
63
64int
65cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
66			      enum cxd2880_spi_mode mode,
67			      u32 speed_hz)
68{
69	int result = 0;
70	struct spi_device *spi = spi_device->spi;
71
72	switch (mode) {
73	case CXD2880_SPI_MODE_0:
74		spi->mode = SPI_MODE_0;
75		break;
76	case CXD2880_SPI_MODE_1:
77		spi->mode = SPI_MODE_1;
78		break;
79	case CXD2880_SPI_MODE_2:
80		spi->mode = SPI_MODE_2;
81		break;
82	case CXD2880_SPI_MODE_3:
83		spi->mode = SPI_MODE_3;
84		break;
85	default:
86		return -EINVAL;
87	}
88
89	spi->max_speed_hz = speed_hz;
90	spi->bits_per_word = 8;
91	result = spi_setup(spi);
92	if (result != 0) {
93		pr_err("spi_setup failed %d\n", result);
94		return -EINVAL;
95	}
96
97	return 0;
98}
99
100int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
101				  struct cxd2880_spi_device *spi_device)
102{
103	if (!spi || !spi_device)
104		return -EINVAL;
105
106	spi->read = NULL;
107	spi->write = cxd2880_spi_device_write;
108	spi->write_read = cxd2880_spi_device_write_read;
109	spi->flags = 0;
110	spi->user = spi_device;
111
112	return 0;
113}
114