forked from RT-Thread/rt-thread
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[bsp][CV1800B] add SPI driver for CV1800B
Signed-off-by: Jingbao Qiu <[email protected]>
- Loading branch information
1 parent
d856f77
commit c24280f
Showing
6 changed files
with
404 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
/* | ||
* Copyright (c) 2006-2023, RT-Thread Development Team | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Change Logs: | ||
* Date Author Notes | ||
* 2024-03-28 qiujingbao first version | ||
*/ | ||
|
||
#include "drv_spi.h" | ||
#ifdef RT_USING_SPI | ||
|
||
#define DBG_TAG "drv.spi" | ||
#define DBG_LVL DBG_INFO | ||
#include <rtdbg.h> | ||
|
||
static struct cv1800_spi cv1800_spi_obj[] = | ||
{ | ||
#ifdef BSP_USING_SPI | ||
{ | ||
.spi_id = SPI2, | ||
.device_name = "spi2", | ||
.fifo_len = SPI_TXFTLR, | ||
}, | ||
#endif | ||
}; | ||
|
||
static struct spi_regs *get_spi_base(uint8_t spi_id) | ||
{ | ||
struct spi_regs *spi_base = NULL; | ||
|
||
switch (spi_id) | ||
{ | ||
case SPI0: | ||
spi_base = (struct spi_regs *)SPI0_BASE; | ||
break; | ||
case SPI1: | ||
spi_base = (struct spi_regs *)SPI1_BASE; | ||
break; | ||
case SPI2: | ||
spi_base = (struct spi_regs *)SPI2_BASE; | ||
break; | ||
case SPI3: | ||
spi_base = (struct spi_regs *)SPI3_BASE; | ||
break; | ||
} | ||
|
||
return spi_base; | ||
} | ||
|
||
static rt_err_t drv_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration) | ||
{ | ||
rt_err_t ret = RT_EOK; | ||
struct cv1800_spi *spi_dev = RT_NULL; | ||
uint32_t mode; | ||
|
||
spi_dev = (struct cv1800_spi *)(device->bus->parent.user_data); | ||
|
||
spi_dev->data_width = configuration->data_width; | ||
|
||
/* disable spi */ | ||
spi_enable(spi_dev->reg, 0); | ||
|
||
/* clear irq */ | ||
spi_clear_irq(spi_dev->reg, SPI_IRQ_MSAK); | ||
|
||
/* set clk */ | ||
ret = spi_set_frequency(spi_dev->reg, configuration->max_hz); | ||
if (ret) | ||
return ret; | ||
|
||
/* set mode */ | ||
ret = gen_spi_mode(configuration, &mode); | ||
if (ret) | ||
return ret; | ||
|
||
spi_set_mode(spi_dev->reg, mode); | ||
|
||
/* set cs */ | ||
spi_enable_cs(spi_dev->reg, 0x1); | ||
|
||
spi_enable(spi_dev->reg, 0x1); | ||
|
||
mode = mmio_read_32((uintptr_t)&spi_dev->reg->spi_ctrl0); | ||
LOG_D("mode: %x", mode); | ||
mode = mmio_read_32((uintptr_t)&spi_dev->reg->spi_baudr); | ||
LOG_D("spi_baudr: %x", mode); | ||
|
||
return ret; | ||
} | ||
|
||
int hw_spi_recv(struct cv1800_spi *dev) { | ||
uint32_t rever; | ||
uint32_t tem; | ||
int ret; | ||
|
||
rever = mmio_read_32((uintptr_t)&dev->reg->spi_rxflr); | ||
ret = (int)rever; | ||
|
||
while (rever) | ||
{ | ||
tem = mmio_read_32((uintptr_t)&dev->reg->spi_dr); | ||
|
||
if (dev->recv_buf < dev->recv_end) | ||
{ | ||
if (dev->data_width == 8) | ||
*(uint8_t *)(dev->recv_buf) = tem; | ||
else | ||
*(uint16_t *)(dev->recv_buf) = tem; | ||
} | ||
else | ||
{ | ||
return 0; | ||
} | ||
|
||
rever--; | ||
dev->recv_buf += dev->data_width >> 3; | ||
} | ||
return ret; | ||
} | ||
|
||
int hw_spi_send(struct cv1800_spi *dev) { | ||
uint32_t txflr; | ||
uint32_t max; | ||
uint16_t value; | ||
|
||
txflr = mmio_read_32((uintptr_t)&dev->reg->spi_txflr); | ||
max = dev->fifo_len - txflr; | ||
|
||
while (max) | ||
{ | ||
if (dev->send_end - dev->send_buf) | ||
{ | ||
if (dev->data_width == 8) | ||
value = *(uint8_t *)(dev->send_buf); | ||
else | ||
value = *(uint16_t *)(dev->send_buf); | ||
} | ||
else | ||
{ | ||
return 0; | ||
} | ||
|
||
mmio_write_32((uintptr_t)&dev->reg->spi_dr, value); | ||
dev->send_buf += dev->data_width >> 3; | ||
max--; | ||
} | ||
|
||
return 0; | ||
} | ||
static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message) { | ||
int ret = 0; | ||
struct cv1800_spi *spi_dev; | ||
|
||
RT_ASSERT(device != RT_NULL); | ||
RT_ASSERT(device->bus != RT_NULL); | ||
RT_ASSERT(message != RT_NULL); | ||
|
||
spi_dev = (struct cv1800_spi *)(device->bus->parent.user_data); | ||
|
||
if (message->send_buf != RT_NULL) | ||
{ | ||
spi_dev->send_buf = message->send_buf; | ||
spi_dev->send_end = (void *)((uint8_t *)spi_dev->send_buf + message->length); | ||
} | ||
|
||
if (message->recv_buf != RT_NULL) | ||
{ | ||
spi_dev->recv_buf = message->recv_buf; | ||
spi_dev->recv_end = (void *)((uint8_t *)spi_dev->recv_buf + message->length); | ||
} | ||
|
||
/* if user use their cs */ | ||
if (message->cs_take && device->cs_pin != PIN_NONE) | ||
rt_pin_write(device->cs_pin, PIN_LOW); | ||
|
||
if (message->send_buf) | ||
{ | ||
while (spi_dev->send_buf != spi_dev->send_end) | ||
{ | ||
hw_spi_send(spi_dev); | ||
} | ||
|
||
/* wait for complete */ | ||
while (mmio_read_32((uintptr_t)&spi_dev->reg->spi_txflr)) {} | ||
|
||
ret = message->length; | ||
} | ||
|
||
if (message->recv_buf) | ||
{ | ||
while (spi_dev->recv_buf != spi_dev->recv_end) | ||
{ | ||
hw_spi_recv(spi_dev); | ||
} | ||
|
||
ret = message->length; | ||
} | ||
|
||
if (message->cs_release && device->cs_pin != PIN_NONE) | ||
rt_pin_write(device->cs_pin, PIN_HIGH); | ||
|
||
return ret; | ||
} | ||
|
||
const static struct rt_spi_ops drv_spi_ops = | ||
{ | ||
drv_spi_configure, | ||
spixfer, | ||
}; | ||
|
||
int rt_hw_spi_init(void) | ||
{ | ||
rt_err_t ret = RT_EOK; | ||
struct spi_regs *reg = NULL; | ||
|
||
for (rt_size_t i = 0; i < sizeof(cv1800_spi_obj) / sizeof(struct cv1800_spi); i++) { | ||
/* set reg base addr */ | ||
reg = get_spi_base(cv1800_spi_obj[i].spi_id); | ||
if (!reg) | ||
return -RT_ERROR; | ||
|
||
cv1800_spi_obj[i].reg = reg; | ||
cv1800_spi_obj[i].spi_bus.parent.user_data = &cv1800_spi_obj[i]; | ||
|
||
/* register spix bus */ | ||
ret = rt_spi_bus_register(&cv1800_spi_obj[i].spi_bus, cv1800_spi_obj[i].device_name, &drv_spi_ops); | ||
} | ||
|
||
return ret; | ||
} | ||
INIT_BOARD_EXPORT(rt_hw_spi_init); | ||
|
||
#endif /* RT_USING_SPI */ |
Oops, something went wrong.