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