You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
4.6 KiB
190 lines
4.6 KiB
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/spi/spidev.h>
|
|
|
|
#include "spi.h"
|
|
|
|
uint8_t spi_write_data(handle_t *handle, uint8_t *buffer, int length)
|
|
{
|
|
spi_handle_t *spi_handle = (spi_handle_t *)handle;
|
|
struct spi_ioc_transfer xfer =
|
|
{
|
|
.len = length + 1,
|
|
.tx_buf = (unsigned long)buffer,
|
|
.rx_buf = (unsigned long)buffer,
|
|
.cs_change = 1,
|
|
};
|
|
|
|
buffer[length] = checksum(handle, buffer, length);
|
|
|
|
if (ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer) >= 0)
|
|
return buffer[length];
|
|
else
|
|
return CMD_NACK;
|
|
}
|
|
|
|
uint8_t spi_write_cmd(handle_t *handle, uint8_t cmd)
|
|
{
|
|
spi_handle_t *spi_handle = (spi_handle_t *)handle;
|
|
uint8_t buffer[] =
|
|
{
|
|
CMD_SOF,
|
|
cmd,
|
|
~cmd
|
|
};
|
|
struct spi_ioc_transfer xfer =
|
|
{
|
|
.len = sizeof(buffer),
|
|
.tx_buf = (unsigned long)buffer,
|
|
.rx_buf = (unsigned long)buffer,
|
|
.cs_change = 1,
|
|
};
|
|
|
|
if (ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer) >= 0)
|
|
return CMD_ACK;
|
|
else
|
|
return CMD_NACK;
|
|
}
|
|
|
|
uint8_t spi_read_data(handle_t *handle, uint8_t *data, int length)
|
|
{
|
|
spi_handle_t *spi_handle = (spi_handle_t *)handle;
|
|
uint8_t buffer[] =
|
|
{
|
|
0x00
|
|
};
|
|
struct spi_ioc_transfer xfer[] =
|
|
{
|
|
{
|
|
.len = sizeof(buffer),
|
|
.tx_buf = (unsigned long)buffer,
|
|
.rx_buf = (unsigned long)buffer,
|
|
},
|
|
{
|
|
.len = length,
|
|
.tx_buf = (unsigned long)data,
|
|
.rx_buf = (unsigned long)data,
|
|
.cs_change = 1,
|
|
}
|
|
};
|
|
|
|
if (ioctl(spi_handle->fd, SPI_IOC_MESSAGE(2), xfer) >= 0)
|
|
return CMD_ACK;
|
|
else
|
|
return CMD_NACK;
|
|
}
|
|
|
|
uint8_t spi_read_ack(handle_t *handle)
|
|
{
|
|
spi_handle_t *spi_handle = (spi_handle_t *)handle;
|
|
uint16_t timeout = 65535;
|
|
uint8_t ret;
|
|
uint8_t buffer[] =
|
|
{
|
|
0x00,
|
|
};
|
|
struct spi_ioc_transfer xfer =
|
|
{
|
|
.len = sizeof(buffer),
|
|
.tx_buf = (unsigned long)buffer,
|
|
.rx_buf = (unsigned long)buffer,
|
|
.cs_change = 1,
|
|
};
|
|
|
|
if (ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer) >= 0) {
|
|
do {
|
|
ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer);
|
|
timeout --;
|
|
} while (buffer[0] != CMD_ACK && buffer[0] != CMD_NACK && timeout > 0);
|
|
|
|
if (buffer[0] != CMD_ACK && buffer[0] != CMD_NACK && timeout == 0)
|
|
ret = CMD_NACK;
|
|
else
|
|
ret = buffer[0];
|
|
ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer);
|
|
|
|
return ret;
|
|
} else {
|
|
return CMD_NACK;
|
|
}
|
|
}
|
|
|
|
uint8_t spi_sync(handle_t *handle)
|
|
{
|
|
spi_handle_t *spi_handle = (spi_handle_t *)handle;
|
|
uint8_t buffer[] =
|
|
{
|
|
CMD_SOF,
|
|
};
|
|
struct spi_ioc_transfer xfer =
|
|
{
|
|
.len = sizeof(buffer),
|
|
.tx_buf = (unsigned long)buffer,
|
|
.rx_buf = (unsigned long)buffer,
|
|
.cs_change = 1,
|
|
};
|
|
|
|
if (ioctl(spi_handle->fd, SPI_IOC_MESSAGE(1), &xfer) >= 0)
|
|
return handle->read_ack(handle);
|
|
else
|
|
return CMD_NACK;
|
|
}
|
|
|
|
int spi_init(handle_t *handle)
|
|
{
|
|
spi_handle_t *spi_handle = (spi_handle_t *)handle;
|
|
uint8_t tmp8;
|
|
uint32_t tmp32;
|
|
|
|
handle->cmd_erase = CMD_ERASE;
|
|
handle->cmd_read_memory = CMD_READ_MEMORY;
|
|
handle->cmd_write_memory = CMD_WRITE_MEMORY;
|
|
|
|
handle->no_extra_sync = 0;
|
|
|
|
handle->write_data = spi_write_data;
|
|
handle->write_cmd = spi_write_cmd;
|
|
handle->read_data = spi_read_data;
|
|
handle->read_ack = spi_read_ack;
|
|
|
|
tmp8 = SPI_MODE_0;
|
|
if (ioctl(spi_handle->fd, SPI_IOC_WR_MODE, &tmp8) < 0) {
|
|
perror("Error setting mode");
|
|
return -1;
|
|
}
|
|
|
|
tmp32 = 8000000;
|
|
if (ioctl(spi_handle->fd, SPI_IOC_WR_MAX_SPEED_HZ, &tmp32) < 0) {
|
|
perror("Error setting speed");
|
|
return -1;
|
|
}
|
|
|
|
tmp8 = 8;
|
|
if (ioctl(spi_handle->fd, SPI_IOC_WR_BITS_PER_WORD, &tmp8) < 0) {
|
|
perror("Error setting bits per word");
|
|
return -1;
|
|
}
|
|
|
|
if (spi_sync(handle) == CMD_ACK)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|