318 lines
8.0 KiB
C
318 lines
8.0 KiB
C
#include <rtdevice.h>
|
|
#include "gtypes.h"
|
|
#include "gd_spi.h"
|
|
#include "drv_ssi.h"
|
|
#include "platform.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* local defines */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* local data types */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* local data */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* local functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
static void *gk_get_spi_dev_pri_data(struct rt_spi_device *device)
|
|
{
|
|
return device->parent.user_data;
|
|
}
|
|
|
|
static rt_err_t gk_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
|
|
{
|
|
struct gk_spi_slave_info *spi_slave;
|
|
struct gk_spi_controller *spi_control;
|
|
GD_SPI_OPEN_PARAMS_S openParamsP;
|
|
rt_uint32_t spi_hz;
|
|
rt_int32_t ret;
|
|
rt_uint8_t data_width = 8,polarity;
|
|
|
|
if(!device || !configuration)
|
|
{
|
|
rt_kprintf("%s,%d,param wrong!\n",__FUNCTION__,__LINE__);
|
|
return RT_ERROR;
|
|
}
|
|
|
|
spi_slave = (struct gk_spi_slave_info *)gk_get_spi_dev_pri_data(device);
|
|
spi_control = spi_slave->control;
|
|
|
|
rt_sem_take(&spi_control->xfer_lock, RT_WAITING_FOREVER);
|
|
|
|
if(spi_slave->spihandle > 0)
|
|
{
|
|
GD_SPI_Close(&spi_slave->spihandle);
|
|
spi_slave->spihandle = -1;
|
|
}
|
|
|
|
openParamsP.spi = spi_control->id;
|
|
openParamsP.slave = spi_slave->id;
|
|
openParamsP.csgpio = spi_slave->cs_pin;
|
|
openParamsP.used_irq = 1;
|
|
|
|
if (configuration->max_hz > GD_SPI_FREQ_81M)
|
|
spi_hz = GD_SPI_FREQ_81M;
|
|
else
|
|
spi_hz = configuration->max_hz;
|
|
|
|
openParamsP.baudrate = spi_hz;
|
|
|
|
/* CPOL */
|
|
if (configuration->mode & RT_SPI_CPOL && configuration->mode & RT_SPI_CPHA)
|
|
{
|
|
polarity = SPI_POLARITY_MODE3;
|
|
}
|
|
else if(configuration->mode & RT_SPI_CPOL && !configuration->mode & RT_SPI_CPHA)
|
|
{
|
|
polarity = SPI_POLARITY_MODE2;
|
|
}
|
|
else if(!configuration->mode & RT_SPI_CPOL && configuration->mode & RT_SPI_CPHA)
|
|
{
|
|
polarity = SPI_POLARITY_MODE1;
|
|
}
|
|
else
|
|
polarity = SPI_POLARITY_MODE0;
|
|
|
|
openParamsP.polarity = polarity;
|
|
|
|
ret = GD_SPI_Open(&openParamsP,&(spi_slave->spihandle));
|
|
if(ret != GD_OK)
|
|
{
|
|
rt_kprintf("GD_SPI_Open failed!\n");
|
|
rt_sem_release(&spi_control->xfer_lock);
|
|
return RT_ERROR;
|
|
}
|
|
|
|
/* data_width */
|
|
if (configuration->data_width <= 8)
|
|
{
|
|
data_width = 8;
|
|
}
|
|
else if (configuration->data_width <= 16)
|
|
{
|
|
|
|
data_width = 16;
|
|
}
|
|
|
|
ret = GD_SPI_SetDatFormat(spi_slave->spihandle, data_width);;
|
|
if(ret != GD_OK)
|
|
{
|
|
rt_kprintf("GD_SPI_SetDatFormat failed!\n");
|
|
rt_sem_release(&spi_control->xfer_lock);
|
|
return RT_ERROR;
|
|
}
|
|
|
|
rt_sem_release(&spi_control->xfer_lock);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_uint32_t gk_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
|
|
{
|
|
struct gk_spi_slave_info *spi_slave;
|
|
struct gk_spi_controller *spi_control;
|
|
GERR ret = GD_OK;
|
|
|
|
if(!device || !message)
|
|
{
|
|
rt_kprintf("%s,%d,param wrong!\n",__FUNCTION__,__LINE__);
|
|
return 0;
|
|
}
|
|
|
|
spi_slave = (struct gk_spi_slave_info *)gk_get_spi_dev_pri_data(device);
|
|
|
|
if(!spi_slave)
|
|
{
|
|
rt_kprintf("%s,%d,param wrong!\n",__FUNCTION__,__LINE__);
|
|
return 0;
|
|
}
|
|
|
|
spi_control = spi_slave->control;
|
|
|
|
if(spi_slave->spihandle < 0)
|
|
{
|
|
rt_kprintf("%s,%d,spi channel not configured!\n",__FUNCTION__,__LINE__);
|
|
return 0;
|
|
}
|
|
|
|
if(!message)
|
|
{
|
|
rt_kprintf("%s,%d,params wrong!\n",__FUNCTION__,__LINE__);
|
|
return 0;
|
|
}
|
|
|
|
rt_sem_take(&spi_control->xfer_lock, RT_WAITING_FOREVER);
|
|
|
|
if(message->cs_take)
|
|
GD_SPI_GetDevice(spi_slave->spihandle);
|
|
|
|
if(message->recv_buf && message->send_buf)
|
|
ret = GD_SPI_WriteThenReadBytes(spi_slave->spihandle,(rt_uint8_t *)message->send_buf,message->length,
|
|
(rt_uint8_t *)message->recv_buf,message->length);
|
|
else if(message->send_buf && !message->recv_buf)
|
|
ret = GD_SPI_WriteBytes(spi_slave->spihandle,(rt_uint8_t *)message->send_buf,message->length);
|
|
else if(!message->send_buf && message->recv_buf)
|
|
ret = GD_SPI_WriteThenReadBytes(spi_slave->spihandle,NULL,0,(rt_uint8_t *)message->recv_buf,message->length);
|
|
|
|
|
|
if(message->cs_release)
|
|
GD_SPI_ReleaseDevice(spi_slave->spihandle);
|
|
|
|
rt_sem_release(&spi_control->xfer_lock);
|
|
|
|
|
|
if(ret != GD_OK)
|
|
{
|
|
rt_kprintf("%s,%d,transfer error!\n",__FUNCTION__,__LINE__);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return message->length;
|
|
}
|
|
|
|
}
|
|
|
|
static struct rt_spi_ops gk_spi_ops = {
|
|
|
|
.configure = gk_spi_configure, .xfer = gk_spi_xfer,
|
|
|
|
};
|
|
|
|
int gk_spi_probe(void *priv_data)
|
|
{
|
|
int ret,i;
|
|
char spi_dev_name[20] = {0};
|
|
char spi_bus_name[20] = {0};
|
|
char spi_lock_name[20] = {0};
|
|
struct gk_spi_controller *spi_control;
|
|
struct gk_spi_controller_data *spi_controller_data = (struct gk_spi_controller_data *)priv_data;
|
|
struct gk_spi_slave_info **control_slave;
|
|
struct gk_spi_slave_info *spi_slave,*next_slave;
|
|
|
|
if (!spi_controller_data)
|
|
{
|
|
rt_kprintf("%s,%d input param wrong!\n",__FUNCTION__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
spi_control = (struct gk_spi_controller *)rt_malloc(sizeof(struct gk_spi_controller));
|
|
if (!spi_control)
|
|
{
|
|
rt_kprintf("%s,%d malloc failed!\n",__FUNCTION__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
rt_memset(spi_control, 0, sizeof(struct gk_spi_controller));
|
|
|
|
spi_control->id = spi_controller_data->id;
|
|
|
|
rt_sprintf(spi_lock_name, "%s%d", "spi_lock", spi_control->id);
|
|
rt_sprintf(spi_bus_name, "%s%d", "spi_bus", spi_control->id);
|
|
|
|
rt_sem_init(&spi_control->xfer_lock, spi_lock_name, 1, RT_IPC_FLAG_FIFO);
|
|
|
|
ret = rt_spi_bus_register(&spi_control->spi_bus, spi_bus_name, &gk_spi_ops);
|
|
|
|
control_slave = &spi_control->spi_slave;
|
|
|
|
for (i = 0; i < spi_controller_data->total_slave; i++)
|
|
{
|
|
spi_slave = (struct gk_spi_slave_info *)rt_malloc(sizeof(struct gk_spi_slave_info));
|
|
if (!spi_slave)
|
|
{
|
|
rt_kprintf("%s,%d malloc failed!\n",__FUNCTION__,__LINE__);
|
|
goto exit;
|
|
}
|
|
rt_memset(spi_slave, 0, sizeof(struct gk_spi_slave_info));
|
|
|
|
spi_slave->id = i;
|
|
spi_slave->control = spi_control;
|
|
spi_slave->cs_pin = spi_controller_data->slave_cs_pin[i];
|
|
spi_slave->spihandle = -1;
|
|
|
|
rt_sprintf(spi_dev_name, "%s%d%s%d", "ssi", spi_control->id, "_", spi_slave->id);
|
|
|
|
*control_slave = spi_slave;
|
|
control_slave = &spi_slave->next;
|
|
|
|
ret = rt_spi_bus_attach_device(&spi_slave->spi_device, spi_dev_name,spi_bus_name, spi_slave);
|
|
if (ret != RT_EOK)
|
|
{
|
|
rt_kprintf("register dev to bus failed...\n");
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
spi_controller_data->control = spi_control;
|
|
|
|
GD_SPI_Init();
|
|
|
|
return RT_EOK;
|
|
|
|
exit:
|
|
|
|
spi_slave = spi_control->spi_slave;
|
|
while (spi_slave != RT_NULL)
|
|
{
|
|
next_slave = spi_slave->next;
|
|
rt_free(spi_slave);
|
|
spi_slave = next_slave;
|
|
}
|
|
|
|
rt_sem_detach(&spi_control->xfer_lock);
|
|
|
|
rt_free(spi_control);
|
|
|
|
return RT_ERROR;
|
|
}
|
|
|
|
int gk_spi_exit(void *priv_data)
|
|
{
|
|
|
|
struct gk_spi_controller *spi_control;
|
|
struct gk_spi_controller_data *plat_data;
|
|
struct gk_spi_slave_info *spi_slave;
|
|
struct gk_spi_slave_info *next_slave;
|
|
|
|
plat_data = (struct gk_spi_controller_data *)priv_data;
|
|
spi_control = plat_data->control;
|
|
spi_slave = spi_control->spi_slave;
|
|
|
|
while (spi_slave != RT_NULL)
|
|
{
|
|
next_slave = spi_slave->next;
|
|
rt_free(spi_slave);
|
|
spi_slave = next_slave;
|
|
}
|
|
|
|
rt_sem_detach(&spi_control->xfer_lock);
|
|
|
|
rt_free(spi_control);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
struct gk_platform_driver gk_spi_driver_ops = {
|
|
|
|
.name = "spi", .probe = gk_spi_probe, .remove = gk_spi_exit,
|
|
|
|
};
|
|
|
|
void rt_hw_spi_init(void)
|
|
{
|
|
|
|
gk_platform_driver_init(&gk_spi_driver_ops);
|
|
}
|
|
|