1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <sys/ioctl.h>
20 #include <linux/spi/spidev.h>
21
22 #include "spi.h"
23
spi_write_data(handle_t * handle,uint8_t * buffer,int length)24 uint8_t spi_write_data(handle_t *handle, uint8_t *buffer, int length)
25 {
26 spi_handle_t *spi_handle = (spi_handle_t *)handle;
27 struct spi_ioc_transfer xfer =
28 {
29 .len = length + 1,
30 .tx_buf = (unsigned long)buffer,
31 .rx_buf = (unsigned long)buffer,
32 .cs_change = 1,
33 };
34
35 buffer[length] = checksum(handle, buffer, length);
36
37 if (ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer) >= 0)
38 return buffer[length];
39 else
40 return CMD_NACK;
41 }
42
spi_write_cmd(handle_t * handle,uint8_t cmd)43 uint8_t spi_write_cmd(handle_t *handle, uint8_t cmd)
44 {
45 spi_handle_t *spi_handle = (spi_handle_t *)handle;
46 uint8_t buffer[] =
47 {
48 CMD_SOF,
49 cmd,
50 ~cmd
51 };
52 struct spi_ioc_transfer xfer =
53 {
54 .len = sizeof(buffer),
55 .tx_buf = (unsigned long)buffer,
56 .rx_buf = (unsigned long)buffer,
57 .cs_change = 1,
58 };
59
60 if (ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer) >= 0)
61 return CMD_ACK;
62 else
63 return CMD_NACK;
64 }
65
spi_read_data(handle_t * handle,uint8_t * data,int length)66 uint8_t spi_read_data(handle_t *handle, uint8_t *data, int length)
67 {
68 spi_handle_t *spi_handle = (spi_handle_t *)handle;
69 uint8_t buffer[] =
70 {
71 0x00
72 };
73 struct spi_ioc_transfer xfer[] =
74 {
75 {
76 .len = sizeof(buffer),
77 .tx_buf = (unsigned long)buffer,
78 .rx_buf = (unsigned long)buffer,
79 },
80 {
81 .len = length,
82 .tx_buf = (unsigned long)data,
83 .rx_buf = (unsigned long)data,
84 .cs_change = 1,
85 }
86 };
87
88 if (ioctl(spi_handle->fd, SPI_IOC_MESSAGE(2), xfer) >= 0)
89 return CMD_ACK;
90 else
91 return CMD_NACK;
92 }
93
spi_read_ack(handle_t * handle)94 uint8_t spi_read_ack(handle_t *handle)
95 {
96 spi_handle_t *spi_handle = (spi_handle_t *)handle;
97 uint16_t timeout = 65535;
98 uint8_t ret;
99 uint8_t buffer[] =
100 {
101 0x00,
102 };
103 struct spi_ioc_transfer xfer =
104 {
105 .len = sizeof(buffer),
106 .tx_buf = (unsigned long)buffer,
107 .rx_buf = (unsigned long)buffer,
108 .cs_change = 1,
109 };
110
111 if (ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer) >= 0) {
112 do {
113 ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer);
114 timeout --;
115 } while (buffer[0] != CMD_ACK && buffer[0] != CMD_NACK && timeout > 0);
116
117 if (buffer[0] != CMD_ACK && buffer[0] != CMD_NACK && timeout == 0)
118 ret = CMD_NACK;
119 else
120 ret = buffer[0];
121 ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer);
122
123 return ret;
124 } else {
125 return CMD_NACK;
126 }
127 }
128
spi_sync(handle_t * handle)129 uint8_t spi_sync(handle_t *handle)
130 {
131 spi_handle_t *spi_handle = (spi_handle_t *)handle;
132 uint8_t buffer[] =
133 {
134 CMD_SOF,
135 };
136 struct spi_ioc_transfer xfer =
137 {
138 .len = sizeof(buffer),
139 .tx_buf = (unsigned long)buffer,
140 .rx_buf = (unsigned long)buffer,
141 .cs_change = 1,
142 };
143
144 if (ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer) >= 0)
145 return handle->read_ack(handle);
146 else
147 return CMD_NACK;
148 }
149
spi_init(handle_t * handle)150 int spi_init(handle_t *handle)
151 {
152 spi_handle_t *spi_handle = (spi_handle_t *)handle;
153 uint8_t tmp8;
154 uint32_t tmp32;
155
156 handle->cmd_erase = CMD_ERASE;
157 handle->cmd_read_memory = CMD_READ_MEMORY;
158 handle->cmd_write_memory = CMD_WRITE_MEMORY;
159
160 handle->write_data = spi_write_data;
161 handle->write_cmd = spi_write_cmd;
162 handle->read_data = spi_read_data;
163 handle->read_ack = spi_read_ack;
164
165 tmp8 = SPI_MODE_0;
166 if (ioctl(spi_handle->fd, SPI_IOC_WR_MODE, &tmp8) < 0) {
167 perror("Error setting mode");
168 return -1;
169 }
170
171 tmp32 = 8000000;
172 if (ioctl(spi_handle->fd, SPI_IOC_WR_MAX_SPEED_HZ, &tmp32) < 0) {
173 perror("Error setting speed");
174 return -1;
175 }
176
177 tmp8 = 8;
178 if (ioctl(spi_handle->fd, SPI_IOC_WR_BITS_PER_WORD, &tmp8) < 0) {
179 perror("Error setting bits per word");
180 return -1;
181 }
182
183 if (spi_sync(handle) == CMD_ACK)
184 return 0;
185 else
186 return -1;
187 }
188