Initial import of NFC GNSS SDK project

This commit is contained in:
chenjintao
2026-09-15 16:10:12 +08:00
commit 2746cc3d4e
3070 changed files with 892062 additions and 0 deletions
+613
View File
@@ -0,0 +1,613 @@
/*========================================================================================================================
Copyright (c) 2022 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
========================================================================================================================*/
/*=================================================================
EDIT HISTORY FOR MODULE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
WHEN WHO WHAT, WHERE, WHY
------------ ------- -------------------------------------------------------------------------------
2022/04/26 Fias.fan 此文件用于LCD的SPI驱动,不建议客户改动,且要注意不同LCD的驱动时序有差别
==========================================================================================================================*/
#include "common.h"
#include "bsp.h"
#include "mfpr_api.h"
#include "quec_ssp_lcd.h"
#include "quec_spi_drv.h"
#include "quec_startup_gpio.h"
//此延时函数,用于LCD-spi相关的延时
static __inline void uudelay(int us)
{
volatile uint32_t i;
for(i=0; i<us*100;i++)
i = i+1;
}
static __inline void mdelay(int ms){
volatile uint32_t i;
for(i=0; i<ms;i++)
uudelay(10);
}
struct s_spi_ctx g_spi_ctx;
void spi_uninit(struct s_spi_ctx *spi_ctx)
{
//ToDo...
}
struct s_spi_ctx* spi_init(uint32_t sclk, struct spi_info *info, int32_t work_mode)
{
int dividor=0;
struct s_spi_ctx *spi_ctx = &g_spi_ctx;
int reg = 0;
LCDLOGI("spi_init +++\r\n");
if(info == NULL || info->timing == NULL){
LCDLOGE("ERROR: spi_init, Invalid param!\r\n");
return NULL;
}
if(LCD_WORK_MODE_INTERRUPT == work_mode)
{
LCDLOGW("WARNING: spi_init, no interrupt mode supported! change to polling mode!\r\n");
work_mode = LCD_WORK_MODE_POLLING;
}
if((info->format != SPI_FORMAT_RGB565) &&
(info->format != SPI_FORMAT_RGB666) && (info->data_lane_num == 1))
{
LCDLOGE("ERROR: spi_init, Format error!\r\n");
return NULL;
}
spi_ctx->cur_path = 0;
spi_ctx->cur_cs = 0;
spi_ctx->sclk = sclk;
spi_ctx->info.line_num = info->line_num;
spi_ctx->info.interface_id = info->interface_id;
spi_ctx->info.data_lane_num = info->data_lane_num;
spi_ctx->info.format = info->format;
spi_ctx->info.device_id = info->device_id;
spi_ctx->info.sample_edge = info->sample_edge;
spi_ctx->info.force_cs = info->force_cs;
spi_ctx->info.endian = info->endian;
spi_ctx->info.timing = info->timing;
spi_ctx->work_mode = work_mode;
spi_ctx->status = SPI_STATUS_INIT;
spi_lcd_init();
LCDLOGI("spi_init ----\r\n");
return spi_ctx;
}
int spi_update(struct s_spi_ctx *spi_ctx, int32_t work_mode)
{
LCDLOGI("spi_update +++\r\n");
if(LCD_WORK_MODE_INTERRUPT == work_mode){
LCDLOGW("WARNING: spi_init, no interrupt mode supported! change to polling mode!\r\n");
work_mode = LCD_WORK_MODE_POLLING;
}
spi_ctx->work_mode = work_mode;
LCDLOGI("spi_update ----\r\n");
return 0;
}
int spi_write_cmd(struct s_spi_ctx *spi_ctx, uint32_t cmd, uint32_t bits)
{
if(NULL == spi_ctx || bits > 32 || 0 == bits){
LCDLOGE("ERROR: spi_write_cmd, Invalid param\r\n");
return -1;
}
if(SPI_STATUS_INIT != spi_ctx->status){
LCDLOGE("ERROR: spi_write_cmd, Invalid mcu status\r\n");
return -1;
}
if((spi_ctx->info.force_cs == 1) && (spi_ctx->cur_cs == 0)){
LCDLOGE("ERROR: spi_write_cmd, Invalid CS status\r\n");
return -1;
}
if (4 == spi_ctx->info.line_num)
{
quec_gpio_set_value(LCD_SPI_RS, 0);
}
quec_gpio_set_value(LCD_SPI_CS, 0);
ssp_write_cmd_data_to_LCD(0, cmd, bits, spi_ctx->info.line_num);
mdelay(5);//20231026 Increase the delay ,slow down cs pull up speed to ensure successful LCD register initialization
quec_gpio_set_value(LCD_SPI_CS, 1);
return 0;
}
int spi_write_data(struct s_spi_ctx *spi_ctx, uint32_t data, uint32_t bits)
{
if(NULL == spi_ctx || bits > 32 || 0 == bits){
LCDLOGE("ERROR: spi_write_data, Invalid param\r\n");
return -1;
}
if(SPI_STATUS_INIT != spi_ctx->status){
LCDLOGE("ERROR: spi_write_data, Invalid mcu status\r\n");
return -1;
}
if((spi_ctx->info.force_cs == 1) && (spi_ctx->cur_cs == 0)){
LCDLOGE("ERROR: spi_write_data, Invalid CS status\r\n");
return -1;
}
if (4 == spi_ctx->info.line_num)
{
quec_gpio_set_value(LCD_SPI_RS, 1);
}
quec_gpio_set_value(LCD_SPI_CS, 0);
ssp_write_cmd_data_to_LCD(1, data, bits, spi_ctx->info.line_num);
mdelay(5);//20231026 Increase the delay ,slow down cs pull up speed to ensure successful LCD register initialization
quec_gpio_set_value(LCD_SPI_CS, 1);
return 0;
}
int spi_read_data(struct s_spi_ctx *spi_ctx, uint32_t cmd, uint32_t cmd_bits,
uint32_t *data, uint32_t data_bits)
{
uint32_t value_and = 0;
value_and = (1 << data_bits) - 1;
if(NULL == spi_ctx || cmd_bits > 32 || data_bits > 32){
LCDLOGE("ERROR: spi_read_data, Invalid param\r\n");
return -1;
}
if(SPI_STATUS_INIT != spi_ctx->status){
LCDLOGE("ERROR: spi_read_data, Invalid mcu status\r\n");
return -1;
}
if((spi_ctx->info.force_cs == 1) && (spi_ctx->cur_cs == 0)){
LCDLOGE("ERROR: spi_read_data, Invalid CS status\r\n");
return -1;
}
if (4 == spi_ctx->info.line_num)
{
quec_gpio_set_value(LCD_SPI_RS, 0);
}
quec_gpio_set_value(LCD_SPI_CS, 0);
ssp_write_cmd_data_to_LCD(0, cmd, cmd_bits, spi_ctx->info.line_num);
mdelay(10);//延时的时间的长短的依据是什么?
ssp_read_data_from_LCD(data, data_bits);
quec_gpio_set_value(LCD_SPI_CS, 1);
return 0;
}
/* 2021-01-27 added for CraneM & CraneL*/
#define TX_FIFO_INT_EN (0x1<<3) //SSP_INT_EN[3]
#define RX_FIFO_INT_EN (0x1<<2) //SSP_INT_EN[2]
#define TIMEOUT_EN (0x1<<1) //SSP_INT_EN[1]
#define PERI_TRAIL_EN (0x1<<0) //SSP_INT_EN[0]
#define SSPSFRM_M (0x0<<4) //SSP_TOP_CTRL[4]
#define SSPSCLK_M (0x0<<3) //SSP_TOP_CTRL[3]
#define FRF_SPI (0x0<<1) //SSP_TOP_CTRL[2:1]
#define SSP_FORMAT FRF_SPI
#define RX_AUTO_FULL_CTRL_EN (0x1<<17) //SSP_FIFO_CTRL[17]
#define FIFO_UNPACKING (0x0<<16) //SSP_FIFO_CTRL[16]
#define RX_THRES_7 (0x7<<5) //SSP_FIFO_CTRL[9:5]
#define TX_THRES_7 (0x7<<0) //SSP_FIFO_CTRL[4:0]
#define SSE_EN (0x1<<0) //SSP_TOP_CTRL[0]
#define SSP0_BASE_ADDRESS 0xD401B000
#define APB_SSP0_CLK_RST 0xd401501c
#define SSP2_BASE_ADDRESS 0xD401C000
#define APB_SSP2_CLK_RST 0xd401504c
#define DW_9BITS (0x8 << 5)
#define SSP_DATAR 0x10
#define SSP_STATUS 0x14
static __inline void reg_write(uint32_t reg, uint32_t val)
{
(*(volatile unsigned long *)(reg)) = val;
}
static __inline void ssp0_reg_write(uint32_t reg, uint32_t val)
{
reg_write(SSP0_BASE_ADDRESS + reg, val);
}
static __inline uint32_t ssp0_reg_read(uint32_t reg)
{
return (*(volatile uint32_t *)(SSP0_BASE_ADDRESS + reg));
}
static __inline void ssp2_reg_write(uint32_t reg, uint32_t val)
{
reg_write(SSP2_BASE_ADDRESS + reg, val);
}
static __inline uint32_t ssp2_reg_read(uint32_t reg)
{
return (*(volatile uint32_t *)(SSP2_BASE_ADDRESS + reg));
}
void spi_dump(void)
{
UINT32 i = 0;
#ifdef _QUEC_LCD_SSP0_ //打开宏则选用SSP0通道
for ( i = 0; i < 12; i++) {
LCDLOGE("---SSP0 start dump---\r\n");
LCDLOGE("SSPI0 offset: 0x%x, value:0x%lx\r\n", i * 4, ssp0_reg_read(i * 4));
}
LCDLOGE("SPS0 offset: 0x54, value:0x%lx\r\n", ssp0_reg_read(0x54));
LCDLOGE("---SSP0 dump end---\r\n");
#elif defined _QUEC_LCD_SSP2_ //默认选用SSP2通道
for ( i = 0; i < 12; i++) {
LCDLOGE("---SSP2 start dump---\r\n");
LCDLOGE("SSPI2 offset: 0x%x, value:0x%lx\r\n", i * 4, ssp2_reg_read(i * 4));
}
LCDLOGE("SPS2 offset: 0x54, value:0x%lx\r\n", ssp2_reg_read(0x54));
LCDLOGE("---SSP2 dump end---\r\n");
#endif
}
void spi_set_clk_rate(unsigned int clk_dev)
{
if (clk_dev >= SPI_CLK_LIMIT) {
LCDLOGE("[Error]: not supported spi clk\r\n");
return;
}
#ifdef _QUEC_LCD_SSP0_ //打开宏则选用SSP0通道
reg_write(APB_SSP0_CLK_RST, 0x3 | (clk_dev << 4));
#elif defined _QUEC_LCD_SSP2_ //默认选用SSP2通道
reg_write(APB_SSP2_CLK_RST, 0x3 | (clk_dev << 4));
#endif
}
int quec_lcd_spi_cs_init(GPIO_PIN_NUMBER_E gpio_pin)
{
if(CHIP_IS_CRANEM || CHIP_IS_CRANEL||CHIP_IS_CRANELRH)
{
ql_gpio_init(gpio_pin,PIN_DIRECTION_OUT,PIN_PULL_DISABLE,PIN_LEVEL_HIGH); //CS--默认状态为高
LCDLOGI("quec_lcd_spi_cs_init GPIO(%d)\r\n",gpio_pin);
return 0;
}
//使用LCD-SPi控制器控制CS引脚
//ToDo
}
void spi_lcd_init(void)
{
uint32_t ssp_top_cfg=0, ssp_fifo_cfg=0;
uint32_t ssp_int_en_cfg=0, ssp_to_cfg=0;
//ToDo----SPI pin的初始化 ?
if(CHIP_IS_CRANEL||CHIP_IS_CRANELRH) //Fias 2022-04-25 EC600M GPIO配置
{
quec_lcd_spi_cs_init(LCD_SPI_CS); //CS
//600MCN_XX
#if defined (__QUECTEL_PROJECT_EC600MCN_XX__) \
|| defined (__QUECTEL_PROJECT_EC600MCN_LA__) || defined (__QUECTEL_PROJECT_EC600MCN_LE__) \
|| defined (__QUECTEL_PROJECT_EC600MCN_LC__)|| defined (__QUECTEL_PROJECT_EC600MCN_LF__)\
|| defined (__QUECTEL_PROJECT_EC600MCN_MC__)
quec_set_gpio_mfprReg(LCD_SPI_CLK,(MFP_PULL_HIGH|MFP_DRIVE_MEDIUM|MFP_AF1)); //CLK
quec_set_gpio_mfprReg(LCD_SPI_DOUT,(MFP_PULL_HIGH|MFP_DRIVE_MEDIUM|MFP_AF1)); //TX
//800MCN_XX
#elif defined (__QUECTEL_PROJECT_EC800MCN_XX__) \
|| defined(__QUECTEL_PROJECT_EC800MCN_GA__) || defined (__QUECTEL_PROJECT_EC800MCN_LA__)\
|| defined (__QUECTEL_PROJECT_EG810MCN_GA__)|| defined (__QUECTEL_PROJECT_EC800MCN_CC__) \
|| defined (__QUECTEL_PROJECT_EC800MCN_NC__)|| defined (__QUECTEL_PROJECT_EC800MCN_MC__)\
|| defined (__QUECTEL_PROJECT_EC800MCN_LF__)|| defined (__QUECTEL_PROJECT_EG810MCN_LA__)\
|| defined (__QUECTEL_PROJECT_EG800PCN_LA__)
quec_set_gpio_mfprReg(LCD_SPI_CLK,(MFP_PULL_HIGH|MFP_DRIVE_MEDIUM|MFP_AF2)); //CLK
quec_set_gpio_mfprReg(LCD_SPI_DOUT,(MFP_PULL_HIGH|MFP_DRIVE_MEDIUM|MFP_AF2)); //TX
//800AK
#elif defined (__QUECTEL_PROJECT_EG800AKCN_XX__)
quec_set_gpio_mfprReg(LCD_SPI_CLK,(MFP_PULL_HIGH|MFP_DRIVE_MEDIUM|MFP_AF1)); //CLK
quec_set_gpio_mfprReg(LCD_SPI_DOUT,(MFP_PULL_HIGH|MFP_DRIVE_MEDIUM|MFP_AF1)); //TX
#else
LCDLOGI("Please configure the project\n");
#endif
}
#ifdef _QUEC_LCD_SSP0_
reg_write(APB_SSP0_CLK_RST, 0x7);
#elif defined _QUEC_LCD_SSP2_ //默认选用SSP2通道
reg_write(APB_SSP2_CLK_RST, 0x7);
#endif
spi_set_clk_rate(LCD_SCLK_READ_FREQ);
ssp_top_cfg = 0x4d00;
ssp_to_cfg = 0x200;
ssp_fifo_cfg = 0x200e7;
ssp_int_en_cfg = 0xf;
#ifdef _QUEC_LCD_SSP0_ //打开宏则选用SSP0通道
ssp0_reg_write(0, ssp_top_cfg);
ssp0_reg_write(0x4, ssp_fifo_cfg);
ssp0_reg_write(0x8, ssp_int_en_cfg);
ssp0_reg_write(0xc, ssp_to_cfg);
ssp0_reg_write(0, ssp_top_cfg | 0x1);
#elif defined _QUEC_LCD_SSP2_ //默认选用SSP2通道
ssp2_reg_write(0, ssp_top_cfg);
ssp2_reg_write(0x4, ssp_fifo_cfg);
ssp2_reg_write(0x8, ssp_int_en_cfg);
ssp2_reg_write(0xc, ssp_to_cfg);
ssp2_reg_write(0, ssp_top_cfg | 0x1);
#endif
}
void ssp_write_cmd_data_to_LCD(uint32_t cmd, uint32_t data,uint32_t data_bits,uint16_t line_num)
{
int reg=0;
if ((data_bits < 1) || (data_bits > 31)) {
LCDLOGE("[Error]: not supported spi data bits\r\n");
return;
}
#ifdef _QUEC_LCD_SSP0_ //打开宏则选用SSP0通道
ssp0_reg_write(0x54, 0x5);
reg = ssp0_reg_read(0) & ~(0x1f << 5);
if (line_num == 3) {
ssp0_reg_write(0, reg | (data_bits << 5));//9 bits
if (!cmd)
ssp0_reg_write(SSP_DATAR, data);
else
ssp0_reg_write(SSP_DATAR, (1 << data_bits) | data);
} else if (line_num == 4) {
ssp0_reg_write(0, reg | ((data_bits - 1) << 5));
ssp0_reg_write(SSP_DATAR, data);
} else
{
LCDLOGE("[ERROR]: not supported spi line number_ssp0_reg!\r\n");
}
mdelay(1);
#elif defined _QUEC_LCD_SSP2_ //默认选用SSP2通道
ssp2_reg_write(0x54, 0x5);
reg = ssp2_reg_read(0) & ~(0x1f << 5);
if (line_num == 3)
{
ssp2_reg_write(0, reg | (data_bits << 5));//9 bits
if (!cmd)
ssp2_reg_write(SSP_DATAR, data);
else
ssp2_reg_write(SSP_DATAR, (1 << data_bits) | data);
}
else if (line_num == 4)
{
ssp2_reg_write(0, reg | ((data_bits - 1) << 5));
ssp2_reg_write(SSP_DATAR, data);
}
else
LCDLOGE("[ERROR]: not supported spi line number!\r\n");
mdelay(1);
#endif
}
void ssp_write_data_to_LCD_Gram(uint16_t* data, uint32_t sum_pixel,uint32_t data_bits, uint16_t line_num)
{
int i=0, cnt=0, reg=0;
if ((data_bits < 1) || (data_bits > 31)) {
LCDLOGE("[Error]: not supported spi data bits\r\n");
return;
}
#ifdef _QUEC_LCD_SSP0_ //打开宏则选用SSP0通道
ssp0_reg_write(0x54, 0x5);
reg = ssp0_reg_read(0) & ~(0x1f << 5);
if (line_num == 3) {
ssp0_reg_write(0, reg | (8 << 5));
} else if (line_num == 4) {
ssp0_reg_write(0, reg | ((data_bits -1) << 5));
}
for (i = 0; i < sum_pixel; i++)
{
cnt = 0;
/* wait for TX not full *///只有当Tx fifo不为满状态才可以继续向Fifo里写数据
while (!(ssp0_reg_read(SSP_STATUS) & (0x1 << 6))) {
if (cnt ++ > 1000000) {
LCDLOGE("ERROR: spi write byte error_ssp0_reg!\r\n");
return;
}
}
if (line_num == 3)
{
if ((data_bits == 16) || (data_bits == 8))
{
ssp0_reg_write(SSP_DATAR, (1 << 8) | (*(data + i) >> 8));
cnt = 0;
while (!(ssp0_reg_read(SSP_STATUS) & (0x1 << 6))) {
if (cnt ++ > 1000000) {
LCDLOGE("ERROR: spi write byte error_ssp0_reg!\r\n");
return;
}
}
ssp0_reg_write(SSP_DATAR, (0x1 << 8) | (*(data + i) & 0xff));
} else
LCDLOGE("spi write byte not support length_ssp0_reg!\r\n");
}
else if (line_num == 4)
{
ssp0_reg_write(SSP_DATAR, *(data + i));
}
else
{
LCDLOGE("ERROR: spi line number error_ssp0_reg!\r\n");
return;
}
}
#elif defined _QUEC_LCD_SSP2_ //默认选用SSP2通道
ssp2_reg_write(0x54, 0x5);
reg = ssp2_reg_read(0) & ~(0x1f << 5);
if (line_num == 3) {
ssp2_reg_write(0, reg | (8 << 5));
} else if (line_num == 4) {
ssp2_reg_write(0, reg | ((data_bits -1) << 5));
}
for (i = 0; i < sum_pixel; i++) {
cnt = 0;
/* wait for TX not full */
while (!(ssp2_reg_read(SSP_STATUS) & (0x1 << 6))) {
if (cnt ++ > 1000000) {
LCDLOGE("ERROR: spi write byte error!\r\n");
return;
}
}
if (line_num == 3) {
if ((data_bits == 16) || (data_bits == 8)) {
ssp2_reg_write(SSP_DATAR, (1 << 8) | (*(data + i) >> 8));
cnt = 0;
while (!(ssp2_reg_read(SSP_STATUS) & (0x1 << 6))) {
if (cnt ++ > 1000000) {
LCDLOGE("ERROR: spi write byte error!\r\n");
return;
}
}
ssp2_reg_write(SSP_DATAR, (0x1 << 8) | (*(data + i) & 0xff));
} else
LCDLOGE("spi write byte not support length!\r\n");
} else if (line_num == 4) {
ssp2_reg_write(SSP_DATAR, *(data + i));
} else {
LCDLOGE("ERROR: spi line number error!\r\n");
return;
}
}
#endif
}
void ssp_read_data_from_LCD(uint32_t *data, uint32_t data_bits)
{
int reg = 0;
int status = 0;
#ifdef _QUEC_LCD_SSP0_ //打开宏则选用SSP0通道
reg = ssp0_reg_read(0) & ~(0x1f << 5);
if ((data_bits < 1) || (data_bits > 31)) {
LCDLOGE("[Error]: not supported spi data bits_ssp0_reg\r\n");
return;
}
if (data_bits > 8)
ssp0_reg_write(0, reg | (data_bits << 5));
else
ssp0_reg_write(0, reg | ((data_bits -1) << 5)); //8 bit
ssp0_reg_write(0x54, 0x7);
ssp0_reg_write(SSP_DATAR, 0x0);
while (((status = ssp0_reg_read(SSP_STATUS)) & (0x1 << 14)) == 0);
*data = ssp0_reg_read(SSP_DATAR);
#elif defined _QUEC_LCD_SSP2_ //默认选用SSP2通道
reg = ssp2_reg_read(0) & ~(0x1f << 5);
if ((data_bits < 1) || (data_bits > 31)) {
LCDLOGE("[Error]: not supported spi data bits\r\n");
return;
}
if (data_bits > 8)
ssp2_reg_write(0, reg | (data_bits << 5));
else
ssp2_reg_write(0, reg | ((data_bits -1) << 5)); //8 bit
ssp2_reg_write(0x54, 0x7);
ssp2_reg_write(SSP_DATAR, 0x0);
while (((status = ssp2_reg_read(SSP_STATUS)) & (0x1 << 14)) == 0);
*data = ssp2_reg_read(SSP_DATAR);
#endif
}
void wait_ssp_write_data_to_LCD_complete(void)
{
int cnt = 0;
#ifdef _QUEC_LCD_SSP0_ //打开宏则选用SSP0通道
/* wait for TX empty */
while ((ssp0_reg_read(SSP_STATUS) & 0xfc0) != 0x40) {
if (cnt++ > 1000000) {
uudelay(1);//20231026Improve the timeout detection time
LCDLOGE("ERROR: spi write byte error_ssp0_reg!\r\n");
return;
}
}
#elif defined _QUEC_LCD_SSP2_ //默认选用SSP2通道
/* wait for TX empty */
while ((ssp2_reg_read(SSP_STATUS) & 0xfc0) != 0x40) {
if (cnt++ > 1000000) {
uudelay(1);//20231026Improve the timeout detection time
LCDLOGE("ERROR: spi write byte error!\r\n");
return;
}
}
#endif
}