drivers: mfd: Add NXP LP Flexcomm driver
1. This driver allows to configure the Low Power Flexcomm interface as a UART, SPI or I2C device. 2. Manages the interrupts and dispatches it to the appropriate device driver. 3. A Flexcomm interface can be configured to be used as I2C and UART device. However a SPI device cannot be used concurrently with I2C or UART. Add checks for this feature. Signed-off-by: Mahesh Mahadevan <mahesh.mahadevan@nxp.com>
This commit is contained in:
parent
8c2b55d97d
commit
72fd8d14da
5 changed files with 201 additions and 0 deletions
|
|
@ -9,3 +9,4 @@ zephyr_library_sources_ifdef(CONFIG_MFD_NPM1300 mfd_npm1300.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MFD_AXP192 mfd_axp192.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MFD_AD5592 mfd_ad5592.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NXP_LP_FLEXCOMM mfd_nxp_lp_flexcomm.c)
|
||||
|
|
|
|||
|
|
@ -24,5 +24,6 @@ source "drivers/mfd/Kconfig.max20335"
|
|||
source "drivers/mfd/Kconfig.nct38xx"
|
||||
source "drivers/mfd/Kconfig.npm1300"
|
||||
source "drivers/mfd/Kconfig.npm6001"
|
||||
source "drivers/mfd/Kconfig.lpflexcomm"
|
||||
|
||||
endif # MFD
|
||||
|
|
|
|||
14
drivers/mfd/Kconfig.lpflexcomm
Normal file
14
drivers/mfd/Kconfig.lpflexcomm
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Copyright 2024 NXP
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config NXP_LP_FLEXCOMM
|
||||
bool "Driver for the NXP Low Power FlexComm Interface"
|
||||
default y
|
||||
depends on DT_HAS_NXP_LP_FLEXCOMM_ENABLED
|
||||
help
|
||||
Enabled the Low Power FlexComm shim driver.
|
||||
LP FLexcomm allows enablement of LPUART and LPI2C
|
||||
at the same time with reduced interface. This driver
|
||||
checks concurrent enablement and returns and error for
|
||||
unsupported concurrent enablement.
|
||||
169
drivers/mfd/mfd_nxp_lp_flexcomm.c
Normal file
169
drivers/mfd/mfd_nxp_lp_flexcomm.c
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nxp_lp_flexcomm
|
||||
|
||||
#include <errno.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/irq.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/drivers/mfd/nxp_lp_flexcomm.h>
|
||||
|
||||
LOG_MODULE_REGISTER(mfd_nxp_lp_flexcomm, CONFIG_MFD_LOG_LEVEL);
|
||||
|
||||
struct nxp_lp_flexcomm_child {
|
||||
const struct device *dev;
|
||||
uint8_t periph;
|
||||
child_isr_t lp_flexcomm_child_isr;
|
||||
};
|
||||
|
||||
struct nxp_lp_flexcomm_data {
|
||||
struct nxp_lp_flexcomm_child *children;
|
||||
size_t num_children;
|
||||
};
|
||||
|
||||
struct nxp_lp_flexcomm_config {
|
||||
LP_FLEXCOMM_Type *base;
|
||||
void (*irq_config_func)(const struct device *dev);
|
||||
};
|
||||
|
||||
void nxp_lp_flexcomm_isr(const struct device *dev)
|
||||
{
|
||||
uint32_t interrupt_status;
|
||||
const struct nxp_lp_flexcomm_config *config = dev->config;
|
||||
struct nxp_lp_flexcomm_data *data = dev->data;
|
||||
uint32_t instance = LP_FLEXCOMM_GetInstance(config->base);
|
||||
struct nxp_lp_flexcomm_child *child;
|
||||
|
||||
interrupt_status = LP_FLEXCOMM_GetInterruptStatus(instance);
|
||||
if ((interrupt_status &
|
||||
((uint32_t)kLPFLEXCOMM_I2cSlaveInterruptFlag |
|
||||
(uint32_t)kLPFLEXCOMM_I2cMasterInterruptFlag)) != 0U) {
|
||||
child = &data->children[LP_FLEXCOMM_PERIPH_LPI2C];
|
||||
|
||||
if (child->lp_flexcomm_child_isr != NULL) {
|
||||
child->lp_flexcomm_child_isr(child->dev);
|
||||
}
|
||||
}
|
||||
if ((interrupt_status &
|
||||
((uint32_t)kLPFLEXCOMM_UartRxInterruptFlag |
|
||||
(uint32_t)kLPFLEXCOMM_UartTxInterruptFlag)) != 0U) {
|
||||
child = &data->children[LP_FLEXCOMM_PERIPH_LPUART];
|
||||
|
||||
if (child->lp_flexcomm_child_isr != NULL) {
|
||||
child->lp_flexcomm_child_isr(child->dev);
|
||||
}
|
||||
}
|
||||
if (((interrupt_status &
|
||||
(uint32_t)kLPFLEXCOMM_SpiInterruptFlag)) != 0U) {
|
||||
child = &data->children[LP_FLEXCOMM_PERIPH_LPSPI];
|
||||
|
||||
if (child->lp_flexcomm_child_isr != NULL) {
|
||||
child->lp_flexcomm_child_isr(child->dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nxp_lp_flexcomm_setirqhandler(const struct device *dev, const struct device *child_dev,
|
||||
LP_FLEXCOMM_PERIPH_T periph, child_isr_t handler)
|
||||
{
|
||||
struct nxp_lp_flexcomm_data *data = dev->data;
|
||||
struct nxp_lp_flexcomm_child *child;
|
||||
|
||||
child = &data->children[periph];
|
||||
|
||||
/* Store the interrupt handler and the child device node */
|
||||
child->lp_flexcomm_child_isr = handler;
|
||||
child->dev = child_dev;
|
||||
}
|
||||
|
||||
static int nxp_lp_flexcomm_init(const struct device *dev)
|
||||
{
|
||||
const struct nxp_lp_flexcomm_config *config = dev->config;
|
||||
struct nxp_lp_flexcomm_data *data = dev->data;
|
||||
uint32_t instance;
|
||||
struct nxp_lp_flexcomm_child *child = NULL;
|
||||
bool spi_found = false;
|
||||
bool uart_found = false;
|
||||
bool i2c_found = false;
|
||||
|
||||
for (int i = 1; i < data->num_children; i++) {
|
||||
child = &data->children[i];
|
||||
if (child->periph == LP_FLEXCOMM_PERIPH_LPSPI) {
|
||||
spi_found = true;
|
||||
}
|
||||
if (child->periph == LP_FLEXCOMM_PERIPH_LPI2C) {
|
||||
i2c_found = true;
|
||||
}
|
||||
if (child->periph == LP_FLEXCOMM_PERIPH_LPUART) {
|
||||
uart_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If SPI is enabled with another interface type return an error */
|
||||
if (spi_found && (i2c_found || uart_found)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
instance = LP_FLEXCOMM_GetInstance(config->base);
|
||||
|
||||
if (uart_found && i2c_found) {
|
||||
LP_FLEXCOMM_Init(instance, LP_FLEXCOMM_PERIPH_LPI2CAndLPUART);
|
||||
} else if (uart_found) {
|
||||
LP_FLEXCOMM_Init(instance, LP_FLEXCOMM_PERIPH_LPUART);
|
||||
} else if (i2c_found) {
|
||||
LP_FLEXCOMM_Init(instance, LP_FLEXCOMM_PERIPH_LPI2C);
|
||||
} else if (spi_found) {
|
||||
LP_FLEXCOMM_Init(instance, LP_FLEXCOMM_PERIPH_LPSPI);
|
||||
}
|
||||
|
||||
config->irq_config_func(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MCUX_FLEXCOMM_CHILD_INIT(child_node_id) \
|
||||
[DT_NODE_CHILD_IDX(child_node_id) + 1] = { \
|
||||
.periph = DT_NODE_CHILD_IDX(child_node_id) + 1, \
|
||||
},
|
||||
|
||||
#define NXP_LP_FLEXCOMM_INIT(n) \
|
||||
\
|
||||
static struct nxp_lp_flexcomm_child \
|
||||
nxp_lp_flexcomm_children_##n[LP_FLEXCOMM_PERIPH_LPI2C + 1] = { \
|
||||
DT_INST_FOREACH_CHILD_STATUS_OKAY(n, MCUX_FLEXCOMM_CHILD_INIT) \
|
||||
}; \
|
||||
\
|
||||
static void nxp_lp_flexcomm_config_func_##n(const struct device *dev); \
|
||||
\
|
||||
static const struct nxp_lp_flexcomm_config nxp_lp_flexcomm_config_##n = { \
|
||||
.base = (LP_FLEXCOMM_Type *)DT_INST_REG_ADDR(n), \
|
||||
.irq_config_func = nxp_lp_flexcomm_config_func_##n, \
|
||||
}; \
|
||||
\
|
||||
static struct nxp_lp_flexcomm_data nxp_lp_flexcomm_data_##n = { \
|
||||
.children = nxp_lp_flexcomm_children_##n, \
|
||||
.num_children = ARRAY_SIZE(nxp_lp_flexcomm_children_##n), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(n, \
|
||||
&nxp_lp_flexcomm_init, \
|
||||
NULL, \
|
||||
&nxp_lp_flexcomm_data_##n, \
|
||||
&nxp_lp_flexcomm_config_##n, \
|
||||
PRE_KERNEL_1, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
NULL); \
|
||||
\
|
||||
static void nxp_lp_flexcomm_config_func_##n(const struct device *dev) \
|
||||
{ \
|
||||
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \
|
||||
nxp_lp_flexcomm_isr, DEVICE_DT_INST_GET(n), 0); \
|
||||
irq_enable(DT_INST_IRQN(n)); \
|
||||
}
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(NXP_LP_FLEXCOMM_INIT)
|
||||
16
include/zephyr/drivers/mfd/nxp_lp_flexcomm.h
Normal file
16
include/zephyr/drivers/mfd/nxp_lp_flexcomm.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_DRIVERS_NXP_LP_FLEXCOMM_H_
|
||||
#define ZEPHYR_DRIVERS_NXP_LP_FLEXCOMM_H_
|
||||
|
||||
#include "fsl_lpflexcomm.h"
|
||||
|
||||
typedef void (*child_isr_t)(const struct device *dev);
|
||||
|
||||
void nxp_lp_flexcomm_setirqhandler(const struct device *dev, const struct device *child_dev,
|
||||
LP_FLEXCOMM_PERIPH_T periph, child_isr_t handler);
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_NXP_LP_FLEXCOMM_H_ */
|
||||
Loading…
Reference in a new issue