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
24uint8_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
43uint8_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
66uint8_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
94uint8_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
129uint8_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
150int 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