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 | |
14 | static 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(m: &msg); |
32 | spi_message_add_tail(t: &tx, m: &msg); |
33 | result = spi_sync(spi: spi_device->spi, message: &msg); |
34 | |
35 | if (result < 0) |
36 | return -EIO; |
37 | |
38 | return 0; |
39 | } |
40 | |
41 | static 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: spi_device->spi, txbuf: tx_data, |
57 | n_tx: tx_size, rxbuf: rx_data, n_rx: rx_size); |
58 | if (result < 0) |
59 | return -EIO; |
60 | |
61 | return 0; |
62 | } |
63 | |
64 | int |
65 | cxd2880_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 | |
100 | int 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 | |