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.

506 lines
15 KiB

/*
* Copyright (c) Hisilicon Technologies Co., Ltd.. 2021-2021. All rights reserved.
* Description: loopback test for spi.
* Author: Hisilicon
* Create: 2021-11-08
*/
/********************************************************************************************/
/* Includes */
/********************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include "drv_dev_ext.h"
#include "drv_ioctl_spi.h"
#include "uapi_spi.h"
#include "uapi_system.h"
/********************************************************************************************/
/* Defines */
/********************************************************************************************/
#define sample_spi_check_param(ret, errno, cmd, param, fmt, ...) do { \
if ((param)) { \
printf("[error] "); \
printf((fmt), ##__VA_ARGS__); \
printf("\n"); \
(ret) = (errno); \
cmd; \
} \
} while (0)
#define sample_spi_func_call(ret, func, cmd) do { \
(ret) = (func); \
if ((ret) != TD_SUCCESS) { \
printf("failed!\n"); \
cmd; \
} \
} while (0)
#define sample_spi_mutex_lock(mutex) pthread_mutex_lock(mutex)
#define sample_spi_mutex_unlock(mutex) pthread_mutex_unlock(mutex)
/********************************************************************************************/
/* Enums */
/********************************************************************************************/
typedef enum {
SAMPLE_SPI_DEV_0 = 0,
SAMPLE_SPI_DEV_1 = 1,
SAMPLE_SPI_DEV_2 = 2,
SAMPLE_SPI_DEV_3 = 3,
SAMPLE_SPI_DEV_MAX
} sample_spi_device;
typedef enum {
SAMPLE_SPI_LOGIC_CS = 0,
SAMPLE_SPI_GPIO_CS = 1,
} sample_spi_config_cs;
typedef enum {
SAMPLE_SPI_FORMAT_MOTO = 0,
SAMPLE_SPI_FORMAT_TI = 1,
SAMPLE_SPI_FORMAT_NM = 2,
SAMPLE_SPI_FORMAT_MAX = 3
} sample_spi_frame_format;
typedef enum {
SAMPLE_SPI_SPO_0 = 0,
SAMPLE_SPI_SPO_1 = 1,
SAMPLE_SPI_SPO_2 = 2,
SAMPLE_SPI_SPO_3 = 3,
} sample_spi_clockout_polarity;
typedef enum {
SAMPLE_SPI_SPH_0 = 0,
SAMPLE_SPI_SPH_1 = 1,
SAMPLE_SPI_SPH_2 = 2,
SAMPLE_SPI_SPH_3 = 3,
} sample_spi_clockout_phase;
/********************************************************************************************/
/* Structures */
/********************************************************************************************/
typedef struct {
sample_spi_clockout_polarity spo;
sample_spi_clockout_phase sph;
} sample_spi_attr_motorola;
typedef struct {
td_bool wait_enable;
td_u32 wait_value;
} sample_spi_attr_national_microwire;
/* SPI additional attribute union */ /* CNcomment: Motorola SPI/NM 协议专有属性 */
typedef union {
sample_spi_attr_motorola motorola;
sample_spi_attr_national_microwire national_microwire;
} sample_spi_attr_ext;
typedef struct {
/* chip select */
sample_spi_device device;
/* cs select */
sample_spi_config_cs cs_cfg;
/* baud rate */
td_u32 baud;
/* frame format */
sample_spi_frame_format frame_format;
/* number of bits per transfer, 4-15bit, value of dss : [4, 15]. */
td_u8 dss;
/* little or big endian */
td_bool is_bigend;
/* addition attr when frame_format is motorola or national_microwire. */
sample_spi_attr_ext ext_attr;
/* loopback mode */
td_bool loopback;
} sample_spi_attr;
/********************************************************************************************/
/* Globals */
/********************************************************************************************/
static td_s32 g_spi_dev_fd = -1;
static pthread_mutex_t g_spi_mutex = PTHREAD_MUTEX_INITIALIZER;
static sample_spi_attr g_attr = {
.device = SAMPLE_SPI_DEV_MAX,
.cs_cfg = SAMPLE_SPI_LOGIC_CS,
.baud = 0x8,
.frame_format = SAMPLE_SPI_FORMAT_MOTO,
.dss = 0x8,
.is_bigend = TD_TRUE,
.loopback = TD_FALSE
};
/********************************************************************************************
Function Implementation
********************************************************************************************/
static td_s32 sample_spi_check_attr(const sample_spi_attr *attr)
{
if (attr == TD_NULL) {
soc_log_err("attr is null!\n");
return SOC_ERR_SPI_NULL_PTR;
}
if (attr->device >= SAMPLE_SPI_DEV_MAX) {
soc_log_err("invalid device id %d\n", attr->device);
return SOC_ERR_SPI_INVALID_PARA;
}
if ((attr->cs_cfg != SAMPLE_SPI_LOGIC_CS) &&
(attr->cs_cfg != SAMPLE_SPI_GPIO_CS)) {
soc_log_err("invalid cs cfg %d\n", attr->cs_cfg);
return SOC_ERR_SPI_INVALID_PARA;
}
if (attr->frame_format >= SAMPLE_SPI_FORMAT_MAX) {
soc_log_err("invalid frame format %d\n", attr->frame_format);
return SOC_ERR_SPI_INVALID_PARA;
}
/* dss is between 4 and 15 */
if ((attr->dss < 4) || (attr->dss > 15)) {
soc_log_err("invalid dss %d\n", attr->dss);
return SOC_ERR_SPI_INVALID_PARA;
}
if ((attr->is_bigend != TD_TRUE) &&
(attr->is_bigend != TD_FALSE)) {
soc_log_err("invalid bigend %d\n", attr->is_bigend);
return SOC_ERR_SPI_INVALID_PARA;
}
return TD_SUCCESS;
}
static td_s32 sample_spi_check_open(td_void)
{
td_s32 ret = TD_SUCCESS;
td_s32 ret1;
ret1 = sample_spi_mutex_lock(&g_spi_mutex);
if (ret1 != 0) {
soc_log_err("spi lock failed! ret = 0x%x\n", ret1);
goto out;
}
if (g_spi_dev_fd < 0) {
soc_log_err("spi is not opened!\n");
ret = SOC_ERR_SPI_NOT_INIT;
goto unlock;
}
unlock:
ret1 = sample_spi_mutex_unlock(&g_spi_mutex);
if (ret1 != 0) {
soc_log_err("spi unlock failed! ret = 0x%x\n", ret1);
goto out;
}
out:
return (ret != TD_SUCCESS) ? ret : ((ret1 != 0) ? ret1 : ret);
}
static td_s32 sample_spi_set_fform(sample_spi_device device, const sample_spi_attr *attr)
{
td_s32 ret;
sample_spi_attr tmp_attr = {0};
spi_fform_s fform = {0};
tmp_attr = *attr;
fform.dev_id = device;
fform.mode = tmp_attr.frame_format;
fform.spo = tmp_attr.ext_attr.motorola.spo;
fform.sph = tmp_attr.ext_attr.motorola.sph;
fform.dss = tmp_attr.dss;
fform.cscfg = tmp_attr.cs_cfg;
ret = ioctl(g_spi_dev_fd, CMD_SPI_SET_ATTR, &fform);
if (ret != 0) {
soc_log_err("set frame failed! ret = 0x%x\n", ret);
return ret;
}
return ret;
}
static td_s32 sample_spi_set_blend(sample_spi_device device, const sample_spi_attr *attr)
{
td_s32 ret;
sample_spi_attr tmp_attr = {0};
spi_blend_s bigend = {0};
tmp_attr = *attr;
bigend.dev_id = device;
bigend.set_bend = tmp_attr.is_bigend;
ret = ioctl(g_spi_dev_fd, CMD_SPI_SET_BLEND, &bigend);
if (ret != 0) {
soc_log_err("set big-litten endian failed! ret = 0x%x\n", ret);
return ret;
}
return ret;
}
static td_s32 sample_spi_set_loopback(sample_spi_device device, const sample_spi_attr *attr)
{
td_s32 ret;
sample_spi_attr tmp_attr = {0};
spi_loop_s loopback = {0};
tmp_attr = *attr;
loopback.dev_id = device;
loopback.set_loop = (td_u8)tmp_attr.loopback;
ret = ioctl(g_spi_dev_fd, CMD_SPI_SET_LOOP, &loopback);
if (ret != 0) {
soc_log_err("set loopback mode failed!\n");
return ret;
}
return ret;
}
static td_s32 sample_spi_loopback(sample_spi_device device,
const td_u8 *write, td_u32 write_count,
td_u8 *read, td_u32 read_count)
{
td_s32 ret;
spi_dataex_s data = {0};
data.dev_id = device;
data.s_data = (td_u8 *)write;
data.s_data_cnt = write_count;
data.r_data = read;
data.r_data_cnt = read_count;
ret = ioctl(g_spi_dev_fd, CMD_SPI_RW_LOOP, &data);
if (ret != 0) {
soc_log_err("spi loopback failed! ret = 0x%x\n", ret);
return ret;
}
return ret;
}
static td_s32 sample_spi_init(td_void)
{
return TD_SUCCESS;
}
static td_s32 sample_spi_deinit(td_void)
{
return TD_SUCCESS;
}
static td_s32 sample_spi_open(sample_spi_device device)
{
td_s32 ret;
if (device >= SAMPLE_SPI_DEV_MAX) {
soc_log_err("[spi_open] invalid device %d\n", device);
ret = SOC_ERR_SPI_INVALID_PARA;
goto out;
}
ret = sample_spi_mutex_lock(&g_spi_mutex);
if (ret != 0) {
soc_log_err("spi lock failed! ret = 0x%x\n", ret);
goto out;
}
if (g_spi_dev_fd > 0) {
ret = TD_SUCCESS;
goto unlock;
}
g_spi_dev_fd = open("/dev/" SOC_DEV_SPI_NAME, O_RDWR, 0);
if (g_spi_dev_fd < 0) {
soc_log_fatal("open spi failed!\n");
ret = SOC_ERR_SPI_OPEN_ERR;
goto unlock;
}
ret = ioctl(g_spi_dev_fd, CMD_SPI_OPEN, device);
if (ret != 0) {
soc_log_err("open spi failed! ret = 0x%x\n", ret);
ret = SOC_ERR_SPI_OPEN_ERR;
goto unlock;
}
unlock:
ret = sample_spi_mutex_unlock(&g_spi_mutex);
if (ret != 0) {
soc_log_err("spi unlock failed! ret = 0x%x\n", ret);
goto out;
}
out:
return ret;
}
static td_s32 sample_spi_close(sample_spi_device device)
{
td_s32 ret;
if (device >= SAMPLE_SPI_DEV_MAX) {
soc_log_err("[spi_close] invalid device %d\n", device);
ret = SOC_ERR_SPI_INVALID_PARA;
goto out;
}
ret = sample_spi_mutex_lock(&g_spi_mutex);
if (ret != 0) {
soc_log_err("spi lock failed! ret = 0x%x\n", ret);
goto out;
}
if (g_spi_dev_fd < 0) {
ret = TD_SUCCESS;
goto unlock;
}
ret = ioctl(g_spi_dev_fd, CMD_SPI_CLOSE, device);
if (ret != 0) {
soc_log_err("close spi failed! ret = 0x%x\n", ret);
ret = SOC_ERR_SPI_CLOSE_ERR;
goto unlock;
}
ret = close(g_spi_dev_fd);
if (ret != 0) {
soc_log_err("close spi failed! ret = 0x%x\n", ret);
ret = SOC_ERR_SPI_CLOSE_ERR;
goto unlock;
}
g_spi_dev_fd = -1;
unlock:
ret = sample_spi_mutex_unlock(&g_spi_mutex);
if (ret != 0) {
soc_log_err("spi unlock failed! ret = 0x%x\n", ret);
goto out;
}
out:
return ret;
}
static td_s32 sample_spi_set_attr(sample_spi_device device)
{
td_s32 ret;
g_attr.device = device;
if (device >= SAMPLE_SPI_DEV_MAX) {
soc_log_err("invalid device %d\n", device);
return SOC_ERR_SPI_INVALID_PARA;
}
ret = sample_spi_check_attr(&g_attr);
if (ret != TD_SUCCESS) {
soc_log_err("sample_spi_check_attr failed! ret = 0x%x\n", ret);
return ret;
}
ret = sample_spi_check_open();
if (ret != TD_SUCCESS) {
soc_log_err("sample_spi_check_open failed! ret = 0x%x\n", ret);
return ret;
}
ret = sample_spi_set_fform(device, &g_attr);
if (ret != TD_SUCCESS) {
soc_log_err("sample_spi_set_fform failed! ret = 0x%x\n", ret);
return ret;
}
ret = sample_spi_set_blend(device, &g_attr);
if (ret != TD_SUCCESS) {
soc_log_err("sample_spi_set_blend failed! ret = 0x%x\n", ret);
return ret;
}
return ret;
}
static td_void sample_spi_help(td_void)
{
printf("Usage: sample_spi_loopback spi_channel data_num byte0 [... byten]\n");
}
static td_s32 sample_spi_get_param(td_s32 argc, td_char **argv, td_u32 *spi_num, td_u32 *data_num)
{
td_s32 ret = TD_SUCCESS;
sample_spi_check_param(ret, TD_FAILURE, goto help, argc < 0x3, "arg must be bigger than 3");
sample_spi_check_param(ret, TD_FAILURE, goto help, argv == TD_NULL, "argv is null");
sample_spi_check_param(ret, TD_FAILURE, goto help, spi_num == TD_NULL, "spi_num is null");
sample_spi_check_param(ret, TD_FAILURE, goto help, data_num == TD_NULL, "data_num is null");
*spi_num = (td_u32)strtoul(argv[0x1], TD_NULL, 0);
sample_spi_check_param(ret, TD_FAILURE, goto help, *spi_num >= UAPI_SPI_DEV_MAX,
"spi num must be less than %d", UAPI_SPI_DEV_MAX);
*data_num = (td_u32)strtoul(argv[0x2], TD_NULL, 0);
sample_spi_check_param(ret, TD_FAILURE, goto help, *data_num == 0, "data number is 0!");
sample_spi_check_param(ret, TD_FAILURE, goto help, (*data_num + 0x3) > (td_u32)argc,
"data number do not match the following data");
help:
sample_spi_help();
return ret;
}
td_s32 main(td_s32 argc, td_char **argv)
{
td_s32 ret, ret1, i;
td_u8 *send_data = TD_NULL;
td_u8 *recv_data = TD_NULL;
td_u32 spi_num, data_num, loop;
sample_spi_func_call(ret, sample_spi_get_param(argc, argv, &spi_num, &data_num), goto out);
send_data = (td_u8 *)malloc(data_num);
sample_spi_check_param(ret, TD_FAILURE, goto out, send_data == TD_NULL, "Allocate send data failed!");
recv_data = (td_u8 *)malloc(data_num);
sample_spi_check_param(ret, TD_FAILURE, goto free_s_data, recv_data == TD_NULL, "Allocate recv data failed!");
sample_spi_func_call(ret, uapi_sys_init(), goto free_r_data);
sample_spi_func_call(ret, sample_spi_init(), goto sys_deinit);
sample_spi_func_call(ret, sample_spi_open(spi_num), goto spi_deinit);
sample_spi_func_call(ret, sample_spi_set_attr(spi_num), goto spi_close);
for (loop = 0; loop < data_num; loop++) {
send_data[loop] = (td_u8)strtoul(argv[loop + 0x3], TD_NULL, 0);
}
g_attr.loopback = TD_TRUE;
sample_spi_func_call(ret, sample_spi_set_loopback(spi_num, &g_attr), goto spi_close);
sample_spi_func_call(ret, sample_spi_loopback(spi_num, send_data, data_num, recv_data, data_num), goto spi_close);
printf("spi read: ");
for (i = 0; i < data_num; i++) {
printf("0x%x ", recv_data[i]);
}
printf("\n");
spi_close:
sample_spi_func_call(ret1, sample_spi_close(spi_num), goto spi_deinit);
spi_deinit:
sample_spi_func_call(ret1, sample_spi_deinit(), goto sys_deinit);
sys_deinit:
sample_spi_func_call(ret1, uapi_sys_deinit(), goto free_r_data);
free_r_data:
free(recv_data);
recv_data = TD_NULL;
free_s_data:
free(send_data);
send_data = TD_NULL;
out:
return ret;
}