exynos-linux-stable/drivers/sensorhub/brcm/ssp_spi.c
FAROVITUS 2b92eefa41 import G965FXXU7DTAA OSRC
*First release for Android (Q).

Signed-off-by: FAROVITUS <farovitus@gmail.com>
2020-02-04 13:50:09 +02:00

252 lines
4.7 KiB
C

/*
* driver for Android SensorHub SPI
*
* Copyright (c) 2013, Samsung Electronics. All rights reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
#if defined(DEBUG_SSP_SPI)
#define ssp_log(fmt, arg...) \
pr_err("[%s:%d] " fmt,\
__func__, __LINE__, ##arg)
#else
#define ssp_log(fmt, arg...)
#endif
/* If AP can't change the endian to BIG */
/* for s5c73m ISP, this option must is required.*/
/* This option depends on SPI_DMA_MODE */
/* in camera driver file*/
/*#define CHANGE_ENDIAN */
int ssp_spi_write_sync(struct spi_device *spi, const u8 *addr, const int len)
{
int ret;
#if defined(CHANGE_ENDIAN)
u8 buf[8] = {0};
#endif
struct spi_message msg;
struct spi_transfer xfer = {
.len = len,
#if !defined(CHANGE_ENDIAN)
.tx_buf = addr,
/*QCTK ALRAN QUP_CONFIG 0-4 bits BIG ENDIAN*/
.bits_per_word = 8,
#else
.tx_buf = buf,
#endif
};
#if defined(CHANGE_ENDIAN)
buf[0] = addr[3];
buf[1] = addr[2];
buf[2] = addr[1];
buf[3] = addr[0];
buf[4] = addr[7];
buf[5] = addr[6];
buf[6] = addr[5];
buf[7] = addr[4];
#endif
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
ret = spi_sync(spi, &msg);
if (ret < 0)
ssp_log("error %d\n", ret);
return ret;
}
int ssp_spi_read_sync(struct spi_device *spi, u8 *in_buf, size_t len)
{
int ret;
u8 read_out_buf[2];
struct spi_message msg;
struct spi_transfer xfer = {
.tx_buf = read_out_buf,
.rx_buf = in_buf,
.len = len,
.cs_change = 0,
};
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
ret = spi_sync(spi, &msg);
if (ret < 0)
ssp_log("%s - error %d\n",
__func__, ret);
return ret;
}
int ssp_spi_sync(struct spi_device *spi, u8 *out_buf,
size_t out_len, u8 *in_buf)
{
int ret;
struct spi_message msg;
struct spi_transfer xfer = {
.tx_buf = out_buf,
.rx_buf = in_buf,
.len = out_len,
.cs_change = 0,
};
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
ret = spi_sync(spi, &msg);
ssp_log("%s - received %d\n", __func__, xfer.len);
if (ret < 0)
ssp_log("%s - error %d\n",
__func__, ret);
return ret;
}
unsigned int g_flag_spirecv;
void ssp_spi_async_complete(void *context)
{
g_flag_spirecv = 1;
}
int ssp_spi_async(struct spi_device *spi, u8 *out_buf,
size_t out_len, u8 *in_buf)
{
int ret;
struct spi_message msg;
struct spi_transfer xfer = {
.tx_buf = out_buf,
.rx_buf = in_buf,
.len = out_len,
.cs_change = 0,
};
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
msg.complete = ssp_spi_async_complete;
ret = spi_async(spi, &msg);
if (ret < 0)
ssp_log("%s - error %d\n",
__func__, ret);
return ret;
}
int ssp_spi_read(struct spi_device *spi, u8 *buf, size_t len, const int rxSize)
{
int k;
int ret = 0;
u8 temp_buf[4] = {0};
u32 count = len/rxSize;
u32 extra = len%rxSize;
for (k = 0; k < count; k++) {
ret = ssp_spi_read_sync(spi, &buf[rxSize*k], rxSize);
if (ret < 0) {
ssp_log("%s - error %d\n",
__func__, ret);
return -EINVAL;
}
}
if (extra != 0) {
ret = ssp_spi_read_sync(spi, &buf[rxSize*k], extra);
if (ret < 0) {
ssp_log("%s - error %d\n",
__func__, ret);
return -EINVAL;
}
}
for (k = 0; k < len-3; k += 4) {
memcpy(temp_buf, (char *)&buf[k], sizeof(temp_buf));
buf[k] = temp_buf[3];
buf[k+1] = temp_buf[2];
buf[k+2] = temp_buf[1];
buf[k+3] = temp_buf[0];
}
return 0;
}
int ssp_spi_write(struct spi_device *spi, const u8 *addr,
const int len, const int txSize)
{
int i, j = 0;
int ret = 0;
u8 paddingData[8];
u32 count = len/txSize;
u32 extra = len%txSize;
ssp_log("Entered\n");
ssp_log("count = %d extra = %d\n", count, extra);
memset(paddingData, 0, sizeof(paddingData));
for (i = 0 ; i < count ; i++) {
ret = ssp_spi_write_sync(spi, &addr[j], txSize);
j += txSize;
if (ret < 0) {
ssp_log("failed to write ssp_spi_write_sync\n");
goto exit_err;
}
ssp_log("Delay!!!\n");
msleep(50);
}
if (extra) {
ret = ssp_spi_write_sync(spi, &addr[j], extra);
if (ret < 0) {
ssp_log("failed to write ssp_spi_write_sync\n");
goto exit_err;
}
}
for (i = 0; i < 4; i++) {
memset(paddingData, 0, sizeof(paddingData));
ret = ssp_spi_write_sync(spi, paddingData, 8);
if (ret < 0) {
ssp_log("failed to write ssp_spi_write_sync\n");
goto exit_err;
}
}
ssp_log("Finish!!\n");
exit_err:
return ret;
}