rt-thread-official/bsp/raspberry-pi/raspi3-64/driver/drv_spi.c

288 lines
7.6 KiB
C
Raw Normal View History

2020-01-10 10:38:21 +08:00
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-07-29 zdzn first version
*/
#include "drv_spi.h"
2020-03-13 21:16:42 +08:00
#include "raspi.h"
2020-01-10 10:38:21 +08:00
#ifdef RT_USING_SPI
2020-03-13 21:16:42 +08:00
#define RPI_CORE_CLK_HZ 250000000
2020-01-10 10:38:21 +08:00
#define BSP_SPI_MAX_HZ (30* 1000 *1000)
#define SPITIMEOUT 0x0FFF
2020-03-13 21:16:42 +08:00
void spi_gpio_write(rt_uint8_t pin, rt_uint8_t val)
2020-01-10 10:38:21 +08:00
{
2020-03-13 21:16:42 +08:00
if (val)
BCM283X_GPIO_GPSET((pin / 32)) = 1 << (pin % 32);
else
BCM283X_GPIO_GPCLR((pin / 32)) = 1 << (pin % 32);
}
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
struct raspi_spi_hw_config
2020-01-10 10:38:21 +08:00
{
2020-03-13 21:16:42 +08:00
rt_uint8_t spi_num;
raspi_gpio_pin sclk_pin;
raspi_pin_select sclk_mode;
raspi_gpio_pin mosi_pin;
raspi_pin_select mosi_mode;
raspi_gpio_pin miso_pin;
raspi_pin_select miso_mode;
#if defined (BSP_USING_SPI0_DEVICE0) || defined (BSP_USING_SPI1_DEVICE0)
raspi_gpio_pin ce0_pin;
raspi_pin_select ce0_mode;
#endif
#if defined (BSP_USING_SPI0_DEVICE1) || defined (BSP_USING_SPI1_DEVICE1)
raspi_gpio_pin ce1_pin;
raspi_pin_select ce1_mode;
#endif
#if defined (BSP_USING_SPI1_DEVICE2)
raspi_gpio_pin ce2_pin;
raspi_pin_select ce2_mode;
#endif
2020-01-10 10:38:21 +08:00
};
2020-03-13 21:16:42 +08:00
struct raspi_spi_device
2020-01-10 10:38:21 +08:00
{
char *device_name;
struct rt_spi_bus *spi_bus;
2020-03-13 21:16:42 +08:00
struct rt_spi_device *spi_device;
raspi_gpio_pin cs_pin;
2020-01-10 10:38:21 +08:00
};
2020-03-13 21:16:42 +08:00
static rt_err_t raspi_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg)
2020-01-10 10:38:21 +08:00
{
2020-03-13 21:16:42 +08:00
RT_ASSERT(cfg != RT_NULL);
RT_ASSERT(device != RT_NULL);
rt_uint16_t divider;
2020-01-10 10:38:21 +08:00
// spi clear fifo
2020-03-13 21:16:42 +08:00
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= BCM283X_SPI0_CS_CLEAR;
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
if (cfg->mode & RT_SPI_CPOL)
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= BCM283X_SPI0_CS_CPOL;
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
if (cfg->mode & RT_SPI_CPHA)
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= BCM283X_SPI0_CS_CPHA;
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
if (cfg->mode & RT_SPI_CS_HIGH)
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= BCM283X_SPI0_CS_CSPOL;
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
//set clk
if (cfg->max_hz > BSP_SPI_MAX_HZ)
2020-01-10 10:38:21 +08:00
cfg->max_hz = BSP_SPI_MAX_HZ;
2020-03-13 21:16:42 +08:00
divider = (rt_uint16_t) ((rt_uint32_t) RPI_CORE_CLK_HZ / cfg->max_hz);
divider &= 0xFFFE;
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
BCM283X_SPI0_CLK(BCM283X_SPI0_BASE) = divider;
2020-01-10 10:38:21 +08:00
return RT_EOK;
}
2020-03-13 21:16:42 +08:00
rt_uint8_t correct_order(rt_uint8_t b, rt_uint8_t flag)
2020-01-10 10:38:21 +08:00
{
2020-03-13 21:16:42 +08:00
if (flag)
return raspi_byte_reverse_table[b];
2020-01-10 10:38:21 +08:00
else
return b;
}
2020-03-13 21:16:42 +08:00
static rt_err_t spi_transfernb(rt_uint8_t* tbuf, rt_uint8_t* rbuf, rt_uint32_t len, rt_uint8_t flag)
2020-01-10 10:38:21 +08:00
{
rt_uint32_t TXCnt=0;
rt_uint32_t RXCnt=0;
/* Clear TX and RX fifos */
2020-03-13 21:16:42 +08:00
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= (BCM283X_SPI0_CS_CLEAR & BCM283X_SPI0_CS_CLEAR);
2020-01-10 10:38:21 +08:00
/* Set TA = 1 */
2020-03-13 21:16:42 +08:00
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= (BCM283X_SPI0_CS_TA & BCM283X_SPI0_CS_TA);
2020-01-10 10:38:21 +08:00
/* Use the FIFO's to reduce the interbyte times */
while ((TXCnt < len) || (RXCnt < len))
{
/* TX fifo not full, so add some more bytes */
2020-03-13 21:16:42 +08:00
while (((BCM283X_SPI0_CS(BCM283X_SPI0_BASE) & BCM283X_SPI0_CS_TXD)) && (TXCnt < len))
2020-01-10 10:38:21 +08:00
{
2020-03-13 21:16:42 +08:00
BCM283X_SPI0_FIFO(BCM283X_SPI0_BASE) = correct_order(tbuf[TXCnt],flag);
2020-01-10 10:38:21 +08:00
TXCnt++;
}
/* Rx fifo not empty, so get the next received bytes */
2020-03-13 21:16:42 +08:00
while (((BCM283X_SPI0_CS(BCM283X_SPI0_BASE) & BCM283X_SPI0_CS_RXD)) && (RXCnt < len))
2020-01-10 10:38:21 +08:00
{
2020-03-13 21:16:42 +08:00
rbuf[RXCnt] = correct_order(BCM283X_SPI0_FIFO(BCM283X_SPI0_BASE),flag);
2020-01-10 10:38:21 +08:00
RXCnt++;
}
}
/* Wait for DONE to be set */
2020-03-13 21:16:42 +08:00
while (!(BCM283X_SPI0_CS(BCM283X_SPI0_BASE) & BCM283X_SPI0_CS_DONE));
2020-01-10 10:38:21 +08:00
/* Set TA = 0, and also set the barrier */
2020-03-13 21:16:42 +08:00
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= (0 & BCM283X_SPI0_CS_TA);
2020-01-10 10:38:21 +08:00
return RT_EOK;
}
static rt_uint32_t raspi_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
2020-03-13 21:16:42 +08:00
2020-01-10 10:38:21 +08:00
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
2020-03-13 21:16:42 +08:00
RT_ASSERT(device->parent.user_data != RT_NULL);
2020-01-10 10:38:21 +08:00
RT_ASSERT(message->send_buf != RT_NULL || message->recv_buf != RT_NULL);
2020-03-13 21:16:42 +08:00
rt_err_t res;
rt_uint8_t flag;
struct rt_spi_configuration config = device->config;
raspi_gpio_pin cs_pin = (raspi_gpio_pin)device->parent.user_data;
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
if (config.mode & RT_SPI_MSB)
flag = 0;
2020-01-10 10:38:21 +08:00
else
2020-03-13 21:16:42 +08:00
flag = 1;
if (message->cs_take);
// (config.mode & RT_SPI_CS_HIGH)?
// spi_gpio_write(cs_pin, 1):
// spi_gpio_write(cs_pin, 0);
/* deal data */
res = spi_transfernb((rt_uint8_t *)message->send_buf, (rt_uint8_t *)message->recv_buf,
(rt_int32_t)message->length, flag);
if (message->cs_release)
(config.mode & RT_SPI_CS_HIGH)?
spi_gpio_write(cs_pin, 0):
spi_gpio_write(cs_pin, 1);
if (res != RT_EOK)
return RT_ERROR;
2020-01-10 10:38:21 +08:00
return message->length;
}
2020-03-13 21:16:42 +08:00
rt_err_t raspi_spi_bus_attach_device(const char *bus_name, struct raspi_spi_device *device)
2020-01-10 10:38:21 +08:00
{
rt_err_t ret;
2020-03-13 21:16:42 +08:00
RT_ASSERT(device != RT_NULL);
ret = rt_spi_bus_attach_device(device->spi_device, device->device_name, bus_name, (void *)(device->cs_pin));
2020-01-10 10:38:21 +08:00
return ret;
}
2020-03-13 21:16:42 +08:00
rt_err_t raspi_spi_hw_init(struct raspi_spi_hw_config *hwcfg)
2020-01-10 10:38:21 +08:00
{
2020-03-13 21:16:42 +08:00
GPIO_FSEL(hwcfg->sclk_pin, hwcfg->sclk_mode);
GPIO_FSEL(hwcfg->miso_pin, hwcfg->miso_mode);
GPIO_FSEL(hwcfg->mosi_pin, hwcfg->mosi_mode);
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
#if defined (BSP_USING_SPI0_DEVICE0)
GPIO_FSEL(hwcfg->ce0_pin, hwcfg->ce0_mode);
#endif
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
#if defined (BSP_USING_SPI0_DEVICE1)
GPIO_FSEL(hwcfg->ce1_pin, hwcfg->ce1_mode);
#endif
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) = 0;
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) = BCM283X_SPI0_CS_CLEAR;
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
//enable chip select
#if defined (BSP_USING_SPI0_DEVICE0)
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= 0;
#endif
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
#if defined (BSP_USING_SPI0_DEVICE1)
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= 0x2;
#endif
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
#if defined (BSP_USING_SPI0_DEVICE0) && defined (BSP_USING_SPI0_DEVICE1)
BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= BCM283X_SPI0_CS_CS;
#endif
2020-01-10 10:38:21 +08:00
return RT_EOK;
}
2020-03-13 21:16:42 +08:00
static struct rt_spi_ops raspi_spi_ops =
2020-01-10 10:38:21 +08:00
{
.configure = raspi_spi_configure,
.xfer = raspi_spi_xfer
};
2020-03-13 21:16:42 +08:00
#if defined (BSP_USING_SPI0_BUS)
#define SPI0_BUS_NAME "spi0"
#define SPI0_DEVICE0_NAME "spi0.0"
#define SPI0_DEVICE1_NAME "spi0.1"
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
struct rt_spi_bus spi0_bus;
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
#if defined (BSP_USING_SPI0_DEVICE0)
struct rt_spi_device spi0_device0;
2020-01-10 10:38:21 +08:00
#endif
2020-03-13 21:16:42 +08:00
#if defined (BSP_USING_SPI0_DEVICE1)
static struct rt_spi_device spi0_device1;
#endif
2020-01-10 10:38:21 +08:00
2020-03-13 21:16:42 +08:00
struct raspi_spi_hw_config raspi_spi0_hw =
2020-01-10 10:38:21 +08:00
{
2020-03-13 21:16:42 +08:00
.spi_num = 0,
.sclk_pin = RPI_GPIO_P1_23,
2020-01-10 10:38:21 +08:00
.sclk_mode = BCM283X_GPIO_FSEL_ALT0,
2020-03-13 21:16:42 +08:00
.mosi_pin = RPI_GPIO_P1_19,
2020-01-10 10:38:21 +08:00
.mosi_mode = BCM283X_GPIO_FSEL_ALT0,
2020-03-13 21:16:42 +08:00
.miso_pin = RPI_GPIO_P1_21,
2020-01-10 10:38:21 +08:00
.miso_mode = BCM283X_GPIO_FSEL_ALT0,
2020-03-13 21:16:42 +08:00
#if defined (BSP_USING_SPI0_DEVICE0)
.ce0_pin = RPI_GPIO_P1_24,
.ce0_mode = BCM283X_GPIO_FSEL_ALT0,
#endif
#if defined (BSP_USING_SPI0_DEVICE1)
.ce1_pin = RPI_GPIO_P1_26,
.ce1_mode = BCM283X_GPIO_FSEL_ALT0,
#endif
2020-01-10 10:38:21 +08:00
};
#endif
2020-03-13 21:16:42 +08:00
int rt_hw_spi_init(void)
2020-01-10 10:38:21 +08:00
{
2020-03-13 21:16:42 +08:00
#if defined (BSP_USING_SPI0_BUS)
raspi_spi_hw_init(&raspi_spi0_hw);
rt_spi_bus_register(&spi0_bus, SPI0_BUS_NAME, &raspi_spi_ops);
#if defined (BSP_USING_SPI0_DEVICE0)
struct raspi_spi_device raspi_spi0_device0 =
{
.device_name = SPI0_DEVICE0_NAME,
.spi_bus = &spi0_bus,
.spi_device = &spi0_device0,
.cs_pin = raspi_spi0_hw.ce0_pin,
};
raspi_spi_bus_attach_device(SPI0_BUS_NAME, &raspi_spi0_device0);
2020-01-10 10:38:21 +08:00
#endif
2020-03-13 21:16:42 +08:00
#if defined (BSP_USING_SPI0_DEVICE1)
struct raspi_spi_device raspi_spi0_device1 =
{
.device_name = SPI0_DEVICE1_NAME,
.spi_bus = &spi0_bus,
.spi_device = &spi0_device1,
.cs_pin = raspi_spi0_hw.ce1_pin,
};
raspi_spi_bus_attach_device(SPI0_BUS_NAME, &raspi_spi0_device1);
#endif
#endif
2020-01-10 10:38:21 +08:00
return RT_EOK;
}
2020-03-13 21:16:42 +08:00
INIT_DEVICE_EXPORT(rt_hw_spi_init);
2020-01-10 10:38:21 +08:00
#endif