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 | |