imx: Add IMX EPIT driver for i.MX socs
Add shim driver for i.MX EPIT (Enhanced Periodic Interrupt Timer) peripheral which can be used for i.MX6SoloX, i.MX7D and other i.MX socs. Origin: Original Signed-off-by: Stanislav Poboril <stanislav.poboril@nxp.com>
This commit is contained in:
parent
708f08a4be
commit
f51ef0551c
7 changed files with 271 additions and 0 deletions
|
@ -6,6 +6,7 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_TMR_CMSDK_APB counter_tmr_cmsdk_apb.
|
|||
zephyr_library_sources_ifdef(CONFIG_TIMER_TMR_CMSDK_APB timer_tmr_cmsdk_apb.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_COUNTER_DTMR_CMSDK_APB counter_dtmr_cmsdk_apb.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_TIMER_DTMR_CMSDK_APB timer_dtmr_cmsdk_apb.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_COUNTER_IMX_EPIT counter_imx_epit.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_COUNTER_NRF_TIMER counter_nrfx_timer.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_COUNTER_NRF_RTC counter_nrfx_rtc.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_RTC_QMSI counter_rtc_qmsi.c)
|
||||
|
|
|
@ -28,5 +28,6 @@ source "drivers/counter/Kconfig.dtmr_cmsdk_apb"
|
|||
|
||||
source "drivers/counter/Kconfig.nrfx"
|
||||
|
||||
source "drivers/counter/Kconfig.imx_epit"
|
||||
|
||||
endif # COUNTER
|
||||
|
|
26
drivers/counter/Kconfig.imx_epit
Normal file
26
drivers/counter/Kconfig.imx_epit
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Kconfig.imx_epit - IMX EPIT configuration options
|
||||
#
|
||||
# Copyright (c) 2018, NXP
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
config COUNTER_IMX_EPIT
|
||||
bool "IMX EPIT driver"
|
||||
depends on COUNTER && HAS_IMX_EPIT
|
||||
help
|
||||
Enable the IMX EPIT driver.
|
||||
|
||||
if COUNTER_IMX_EPIT
|
||||
|
||||
config COUNTER_IMX_EPIT_1
|
||||
bool "Counter 1"
|
||||
help
|
||||
Enable Counter 1.
|
||||
|
||||
config COUNTER_IMX_EPIT_2
|
||||
bool "Counter 2"
|
||||
help
|
||||
Enable Counter 2.
|
||||
|
||||
endif # COUNTER_IMX_EPIT
|
187
drivers/counter/counter_imx_epit.c
Normal file
187
drivers/counter/counter_imx_epit.c
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <counter.h>
|
||||
#include <device.h>
|
||||
#include "clock_freq.h"
|
||||
#include "epit.h"
|
||||
|
||||
#define COUNTER_MAX_RELOAD 0xFFFFFFFF
|
||||
|
||||
struct imx_epit_config {
|
||||
struct counter_config_info info;
|
||||
EPIT_Type *base;
|
||||
u16_t prescaler;
|
||||
};
|
||||
|
||||
struct imx_epit_data {
|
||||
volatile counter_top_callback_t callback;
|
||||
volatile void *user_data;
|
||||
};
|
||||
|
||||
static inline const struct imx_epit_config *get_epit_config(struct device *dev)
|
||||
{
|
||||
return CONTAINER_OF(dev->config->config_info, struct imx_epit_config,
|
||||
info);
|
||||
}
|
||||
|
||||
static void imx_epit_isr(void *arg)
|
||||
{
|
||||
struct device *dev = (struct device *)arg;
|
||||
EPIT_Type *base = get_epit_config(dev)->base;
|
||||
struct imx_epit_data *driver_data = dev->driver_data;
|
||||
|
||||
EPIT_ClearStatusFlag(base);
|
||||
|
||||
if (driver_data->callback != NULL) {
|
||||
driver_data->callback(dev, (void *)driver_data->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void imx_epit_init(struct device *dev)
|
||||
{
|
||||
struct imx_epit_config *config = (struct imx_epit_config *)
|
||||
get_epit_config(dev);
|
||||
EPIT_Type *base = config->base;
|
||||
epit_init_config_t epit_config = {
|
||||
.freeRun = true,
|
||||
.waitEnable = true,
|
||||
.stopEnable = true,
|
||||
.dbgEnable = true,
|
||||
.enableMode = true
|
||||
};
|
||||
|
||||
/* Adjust frequency in the counter configuration info */
|
||||
config->info.freq = get_epit_clock_freq(base)/(config->prescaler + 1U);
|
||||
|
||||
EPIT_Init(base, &epit_config);
|
||||
}
|
||||
|
||||
static int imx_epit_start(struct device *dev)
|
||||
{
|
||||
EPIT_Type *base = get_epit_config(dev)->base;
|
||||
|
||||
/* Set EPIT clock source */
|
||||
EPIT_SetClockSource(base, epitClockSourcePeriph);
|
||||
|
||||
/* Set prescaler */
|
||||
EPIT_SetPrescaler(base, get_epit_config(dev)->prescaler);
|
||||
|
||||
/* Start the counter */
|
||||
EPIT_Enable(base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_epit_stop(struct device *dev)
|
||||
{
|
||||
EPIT_Type *base = get_epit_config(dev)->base;
|
||||
|
||||
/* Disable EPIT */
|
||||
EPIT_Disable(base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32_t imx_epit_read(struct device *dev)
|
||||
{
|
||||
EPIT_Type *base = get_epit_config(dev)->base;
|
||||
u32_t value;
|
||||
|
||||
value = EPIT_GetCounterLoadValue(base) - EPIT_ReadCounter(base);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int imx_epit_set_top_value(struct device *dev, u32_t ticks,
|
||||
counter_top_callback_t callback,
|
||||
void *user_data)
|
||||
{
|
||||
EPIT_Type *base = get_epit_config(dev)->base;
|
||||
struct imx_epit_data *driver_data = dev->driver_data;
|
||||
|
||||
/* Disable EPIT Output Compare interrupt for consistency */
|
||||
EPIT_SetIntCmd(base, false);
|
||||
|
||||
driver_data->callback = callback;
|
||||
driver_data->user_data = user_data;
|
||||
|
||||
/* Set both reload and counter values to "ticks" */
|
||||
EPIT_SetOverwriteCounter(base, true);
|
||||
EPIT_SetCounterLoadValue(base, ticks);
|
||||
|
||||
if (callback != NULL) {
|
||||
/* (Re)enable EPIT Output Compare interrupt */
|
||||
EPIT_SetIntCmd(base, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32_t imx_epit_get_pending_int(struct device *dev)
|
||||
{
|
||||
EPIT_Type *base = get_epit_config(dev)->base;
|
||||
|
||||
return EPIT_GetStatusFlag(base) ? 1U : 0U;
|
||||
}
|
||||
|
||||
static u32_t imx_epit_get_top_value(struct device *dev)
|
||||
{
|
||||
EPIT_Type *base = get_epit_config(dev)->base;
|
||||
|
||||
return EPIT_GetCounterLoadValue(base);
|
||||
}
|
||||
|
||||
static u32_t imx_epit_get_max_relative_alarm(struct device *dev)
|
||||
{
|
||||
return COUNTER_MAX_RELOAD;
|
||||
}
|
||||
|
||||
static const struct counter_driver_api imx_epit_driver_api = {
|
||||
.start = imx_epit_start,
|
||||
.stop = imx_epit_stop,
|
||||
.read = imx_epit_read,
|
||||
.set_top_value = imx_epit_set_top_value,
|
||||
.get_pending_int = imx_epit_get_pending_int,
|
||||
.get_top_value = imx_epit_get_top_value,
|
||||
.get_max_relative_alarm = imx_epit_get_max_relative_alarm,
|
||||
};
|
||||
|
||||
#define COUNTER_IMX_EPIT_DEVICE(idx) \
|
||||
static int imx_epit_config_func_##idx(struct device *dev); \
|
||||
static const struct imx_epit_config imx_epit_##idx##_config = { \
|
||||
.info = { \
|
||||
.max_top_value = COUNTER_MAX_RELOAD, \
|
||||
.freq = 1U, \
|
||||
.count_up = false, \
|
||||
.channels = 0U, \
|
||||
}, \
|
||||
.base = (EPIT_Type *)DT_COUNTER_IMX_EPIT_##idx##_BASE_ADDRESS, \
|
||||
.prescaler = DT_COUNTER_IMX_EPIT_##idx##_PRESCALER, \
|
||||
}; \
|
||||
static struct imx_epit_data imx_epit_##idx##_data; \
|
||||
DEVICE_AND_API_INIT(epit_##idx, DT_COUNTER_IMX_EPIT_##idx##_LABEL, \
|
||||
&imx_epit_config_func_##idx, \
|
||||
&imx_epit_##idx##_data, &imx_epit_##idx##_config.info, \
|
||||
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&imx_epit_driver_api); \
|
||||
static int imx_epit_config_func_##idx(struct device *dev) \
|
||||
{ \
|
||||
imx_epit_init(dev); \
|
||||
IRQ_CONNECT(DT_COUNTER_IMX_EPIT_##idx##_IRQ, \
|
||||
DT_COUNTER_IMX_EPIT_##idx##_IRQ_PRI, \
|
||||
imx_epit_isr, DEVICE_GET(epit_##idx), 0); \
|
||||
irq_enable(DT_COUNTER_IMX_EPIT_##idx##_IRQ); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COUNTER_IMX_EPIT_1
|
||||
COUNTER_IMX_EPIT_DEVICE(1);
|
||||
#endif /* CONFIG_COUNTER_IMX_EPIT_1 */
|
||||
|
||||
#ifdef CONFIG_COUNTER_IMX_EPIT_2
|
||||
COUNTER_IMX_EPIT_DEVICE(2);
|
||||
#endif /* CONFIG_COUNTER_IMX_EPIT_2 */
|
50
dts/bindings/arm/nxp,imx-epit.yaml
Normal file
50
dts/bindings/arm/nxp,imx-epit.yaml
Normal file
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
# Copyright (c) 2018, NXP
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
---
|
||||
title: IMX EPIT COUNTER
|
||||
version: 0.1
|
||||
|
||||
description: >
|
||||
This binding gives a base representation of the i.MX Enhanced Periodic Interrupt Timer (EPIT)
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
type: string
|
||||
category: required
|
||||
description: compatible strings
|
||||
constraint: "nxp,imx-epit"
|
||||
|
||||
reg:
|
||||
type: array
|
||||
description: mmio register space
|
||||
generation: define
|
||||
category: required
|
||||
|
||||
interrupts:
|
||||
type: array
|
||||
category: required
|
||||
description: required interrupts
|
||||
generation: define
|
||||
|
||||
label:
|
||||
type: string
|
||||
category: required
|
||||
description: Human readable string describing the device (used by Zephyr for API name)
|
||||
generation: define
|
||||
|
||||
prescaler:
|
||||
type: int
|
||||
category: required
|
||||
description: Set the EPIT prescaler between 0 and 4095
|
||||
generation: define
|
||||
|
||||
rdc:
|
||||
type: int
|
||||
category: required
|
||||
description: Set the RDC permission for this peripheral
|
||||
generation: define
|
||||
|
||||
...
|
|
@ -33,4 +33,9 @@ config HAS_IMX_I2C
|
|||
help
|
||||
Set if the I2C module is present in the SoC.
|
||||
|
||||
config HAS_IMX_EPIT
|
||||
bool
|
||||
help
|
||||
Set if the EPIT module is present in the SoC.
|
||||
|
||||
endif # HAS_IMX_HAL
|
||||
|
|
|
@ -14,3 +14,4 @@ zephyr_sources_ifdef(CONFIG_UART_IMX uart_imx.c)
|
|||
zephyr_sources_ifdef(CONFIG_GPIO_IMX gpio_imx.c)
|
||||
zephyr_sources_ifdef(CONFIG_I2C_IMX i2c_imx.c)
|
||||
zephyr_sources_ifdef(CONFIG_IPM_IMX mu_imx.c)
|
||||
zephyr_sources_ifdef(CONFIG_COUNTER_IMX_EPIT epit.c)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue