-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The QN908x has four FLEXCOMM interfaces that support a subset of UART, SPI or I2C each one. This patch adds generic support for dealing with the FLEXCOMM initialization and interrupts and adds a driver for RX/TX support in UART. With this patch is now possible to use a shell on the device over UART.
- Loading branch information
Showing
8 changed files
with
606 additions
and
5 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,67 @@ | ||
/* | ||
* Copyright (C) 2020 iosabi | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser General | ||
* Public License v2.1. See the file LICENSE in the top level directory for more | ||
* details. | ||
*/ | ||
|
||
/** | ||
* @ingroup cpu_qn908x | ||
* | ||
* @{ | ||
* | ||
* @file | ||
* @brief Flexcomm interface functions. | ||
* | ||
* The FLEXCOMM blocks can operate in different modes such as UART, SPI and I2C, | ||
* but not all modules support all modes. These functions allow to initialize | ||
* and configure the FLEXCOMM, as well as route back the ISRs to the | ||
* corresponding module. | ||
* | ||
* @author iosabi <iosabi@protonmail.com> | ||
*/ | ||
|
||
#ifndef FLEXCOMM_H | ||
#define FLEXCOMM_H | ||
|
||
#include <stdint.h> | ||
#include "periph_cpu.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** | ||
* @brief Flexcomm PSELID values | ||
* | ||
* This value identifies the current function of a FLEXCOMM module. | ||
*/ | ||
typedef enum { | ||
FLEXCOMM_ID_UART = 1, /**< UART mode. */ | ||
FLEXCOMM_ID_SPI = 2, /**< SPI mode. */ | ||
FLEXCOMM_ID_I2C = 3, /**< I2C mode. */ | ||
} flexcom_pselid_t; | ||
|
||
/** | ||
* @brief Initialize a flexcomm module to operate as the selected mode. | ||
* | ||
* @returns -1 in case of error, otherwise returns the number of flexcomm | ||
* instance initialized, such as 2 for FLEXCOMM2. | ||
*/ | ||
int flexcomm_init(FLEXCOMM_Type *dev, flexcom_pselid_t mode); | ||
|
||
/** | ||
* @brief Obtain the flexcomm block number (0-based) from the address. | ||
* | ||
* For example, the flexcomm block number of FLEXCOMM2, the pointer to the | ||
* FLEXCOMM_Type block is 2. If an invalid address is passed returns -1. | ||
*/ | ||
int flexcomm_instance_from_addr(FLEXCOMM_Type *dev); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* FLEXCOMM_H */ | ||
/** @} */ |
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,145 @@ | ||
/* | ||
* Copyright (C) 2020 iosabi | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser General | ||
* Public License v2.1. See the file LICENSE in the top level directory for more | ||
* details. | ||
*/ | ||
|
||
/** | ||
* @ingroup cpu_qn908x | ||
* | ||
* @{ | ||
* | ||
* @file | ||
* @brief Flexcomm interrupt dispatch. | ||
* | ||
* @author iosabi <iosabi@protonmail.com> | ||
* | ||
* @} | ||
*/ | ||
|
||
#include <stdint.h> | ||
#include "cpu.h" | ||
#include "periph_conf.h" | ||
#include "vectors_qn908x.h" | ||
#include "flexcomm.h" | ||
|
||
#include "vendor/drivers/fsl_clock.h" | ||
|
||
#include "debug.h" | ||
|
||
int flexcomm_init(FLEXCOMM_Type *dev, flexcom_pselid_t mode) | ||
{ | ||
static const clock_ip_name_t flexcomm_clocks[] = FLEXCOMM_CLOCKS; | ||
int flexcomm_num = flexcomm_instance_from_addr(dev); | ||
|
||
if (flexcomm_num < 0 || flexcomm_num >= (int)ARRAY_SIZE(flexcomm_clocks)) { | ||
DEBUG("Invalid flexcomm_num: %d\n", flexcomm_num); | ||
return -1; | ||
} | ||
CLOCK_EnableClock(flexcomm_clocks[flexcomm_num]); | ||
/* Reset the flexcomm. */ | ||
SYSCON->RST_SW_SET = 1u << flexcomm_num; | ||
SYSCON->RST_SW_CLR = 1u << flexcomm_num; | ||
|
||
/* Check that the mode is present in the FLEXCOMM. | ||
* Bits 4, 5 and 6 tell whether the UART, SPI and I2C respectively are | ||
* present. */ | ||
if ((dev->PSELID & (1u << (mode + 3))) == 0) { | ||
DEBUG("Mode %d not present in FLEXCOMM%d\n", (int)mode, flexcomm_num); | ||
return -1; | ||
} | ||
|
||
/* This also locks the peripheral so it can't be changed until device or | ||
* peripheral is reset. */ | ||
dev->PSELID = (dev->PSELID & ~FLEXCOMM_PSELID_PERSEL_MASK) | | ||
FLEXCOMM_PSELID_LOCK_MASK | | ||
FLEXCOMM_PSELID_PERSEL(mode); | ||
return flexcomm_num; | ||
} | ||
|
||
int flexcomm_instance_from_addr(FLEXCOMM_Type *dev) | ||
{ | ||
static const FLEXCOMM_Type *flexcomm_addrs[] = FLEXCOMM_BASE_PTRS; | ||
|
||
for (uint8_t i = 0; i < ARRAY_SIZE(flexcomm_addrs); i++) { | ||
if (flexcomm_addrs[i] == dev) { | ||
return i; | ||
} | ||
} | ||
DEBUG("Invalid FLEXCOMM address.\n"); | ||
return -1; | ||
} | ||
|
||
#ifdef MODULE_PERIPH_UART | ||
extern void isr_flexcomm_uart(USART_Type *dev, uint32_t flexcomm_num); | ||
#endif /* MODULE_PERIPH_UART */ | ||
|
||
#ifdef MODULE_PERIPH_SPI | ||
extern void isr_flexcomm_spi(SPI_Type *dev, uint32_t flexcomm_num); | ||
#endif /* MODULE_PERIPH_SPI */ | ||
|
||
#ifdef MODULE_PERIPH_I2C | ||
extern void isr_flexcomm_i2c(I2C_Type *dev, uint32_t flexcomm_num); | ||
#endif /* MODULE_PERIPH_I2C */ | ||
|
||
/** | ||
* @brief General Flexcomm interrupt handler dispatch. | ||
* | ||
* The driver that should get an interrupt from the flexcomm depends on the | ||
* currently configured one, which can be obtained from the PSELID. | ||
*/ | ||
static void isr_flexcomm(void *flexcomm, uint32_t flexcomm_num) | ||
{ | ||
switch (((FLEXCOMM_Type *)flexcomm)->PSELID & FLEXCOMM_PSELID_PERSEL_MASK) { | ||
#ifdef MODULE_PERIPH_UART | ||
case FLEXCOMM_ID_UART: | ||
isr_flexcomm_uart((USART_Type *)(flexcomm), flexcomm_num); | ||
return; | ||
break; | ||
#endif /* MODULE_PERIPH_UART */ | ||
#ifdef MODULE_PERIPH_SPI | ||
case FLEXCOMM_ID_SPI: | ||
isr_flexcomm_spi((SPI_Type *)(flexcomm), flexcomm_num); | ||
return; | ||
break; | ||
#endif /* MODULE_PERIPH_SPI */ | ||
#ifdef MODULE_PERIPH_I2C | ||
case FLEXCOMM_ID_I2C: | ||
isr_flexcomm_i2c((I2C_Type *)(flexcomm), flexcomm_num); | ||
return; | ||
break; | ||
#endif /* MODULE_PERIPH_I2C */ | ||
default: | ||
cortexm_isr_end(); | ||
} | ||
} | ||
|
||
#ifdef FLEXCOMM0 | ||
void isr_flexcomm0(void) | ||
{ | ||
isr_flexcomm(FLEXCOMM0, 0); | ||
} | ||
#endif /* FLEXCOMM0 */ | ||
|
||
#ifdef FLEXCOMM1 | ||
void isr_flexcomm1(void) | ||
{ | ||
isr_flexcomm(FLEXCOMM1, 1); | ||
} | ||
#endif /* FLEXCOMM1 */ | ||
|
||
#ifdef FLEXCOMM2 | ||
void isr_flexcomm2(void) | ||
{ | ||
isr_flexcomm(FLEXCOMM2, 2); | ||
} | ||
#endif /* FLEXCOMM2 */ | ||
|
||
#ifdef FLEXCOMM3 | ||
void isr_flexcomm3(void) | ||
{ | ||
isr_flexcomm(FLEXCOMM3, 3); | ||
} | ||
#endif /* FLEXCOMM3 */ |
Oops, something went wrong.