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->no_extra_sync = 0;
161 
162     handle->write_data = spi_write_data;
163     handle->write_cmd = spi_write_cmd;
164     handle->read_data = spi_read_data;
165     handle->read_ack = spi_read_ack;
166 
167     tmp8 = SPI_MODE_0;
168     if (ioctl(spi_handle->fd, SPI_IOC_WR_MODE, &tmp8) < 0) {
169         perror("Error setting mode");
170         return -1;
171     }
172 
173     tmp32 = 8000000;
174     if (ioctl(spi_handle->fd, SPI_IOC_WR_MAX_SPEED_HZ, &tmp32) < 0) {
175         perror("Error setting speed");
176         return -1;
177     }
178 
179     tmp8 = 8;
180     if (ioctl(spi_handle->fd, SPI_IOC_WR_BITS_PER_WORD, &tmp8) < 0) {
181         perror("Error setting bits per word");
182         return -1;
183     }
184 
185     if (spi_sync(handle) == CMD_ACK)
186         return 0;
187     else
188         return -1;
189 }
190