zephyr/drivers/dma/dmamux_stm32.c
Martí Bolívar 7e0eed9235 devicetree: allow access to all nodes
Usually, we want to operate only on "available" device
nodes ("available" means "status is okay and a matching binding is
found"), but that's not true in all cases.

Sometimes we want to operate on special nodes without matching
bindings, such as those describing memory.

To handle the distinction, change various additional devicetree APIs
making it clear that they operate only on available device nodes,
adjusting gen_defines and devicetree.h implementation details
accordingly:

- emit macros for all existing nodes in gen_defines.py, regardless
  of status or matching binding
- rename DT_NUM_INST to DT_NUM_INST_STATUS_OKAY
- rename DT_NODE_HAS_COMPAT to DT_NODE_HAS_COMPAT_STATUS_OKAY
- rename DT_INST_FOREACH to DT_INST_FOREACH_STATUS_OKAY
- rename DT_ANY_INST_ON_BUS to DT_ANY_INST_ON_BUS_STATUS_OKAY
- rewrite DT_HAS_NODE_STATUS_OKAY in terms of a new DT_NODE_HAS_STATUS
- resurrect DT_HAS_NODE in the form of DT_NODE_EXISTS
- remove DT_COMPAT_ON_BUS as a public API
- use the new default_prop_types edtlib parameter

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-05-08 19:37:18 -05:00

216 lines
5.6 KiB
C

/*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Common part of DMAMUX drivers for stm32.
* @note api functions named dmamux_stm32_
* are calling the dma_stm32 corresponding function
* implemented in dma_stm32.c
*/
#include <soc.h>
#include <init.h>
#include <drivers/dma.h>
#include <drivers/clock_control.h>
#include <drivers/clock_control/stm32_clock_control.h>
#include "dmamux_stm32.h"
#include "dma_stm32.h"
#include <logging/log.h>
LOG_MODULE_REGISTER(dmamux_stm32, CONFIG_DMA_LOG_LEVEL);
#define DT_DRV_COMPAT st_stm32_dmamux
int dmamux_stm32_configure(struct device *dev, u32_t id,
struct dma_config *config)
{
/* device is the dmamux, id is the dmamux channel from 0 */
struct dmamux_stm32_data *data = dev->driver_data;
const struct dmamux_stm32_config *dev_config =
dev->config_info;
/*
* request line ID for this mux channel is stored
* in the dma_slot parameter
*/
int request_id = config->dma_slot;
if (request_id >= dev_config->req_nb + dev_config->gen_nb) {
LOG_ERR("request ID %d is too big.", request_id);
return -EINVAL;
}
/* check if this channel is valid */
if (id >= dev_config->channel_nb) {
LOG_ERR("channel ID %d is too big.", id);
return -EINVAL;
}
/*
* Also configures the corresponding dma channel
* instance is given by the dev_dma
* stream is given by the index i
* config is directly this dma_config
*/
/*
* This dmamux channel 'id' is now used for this peripheral request
* It gives this mux request ID to the dma through the config.dma_slot
*/
if (dma_stm32_configure(data->mux_channels[id].dev_dma,
data->mux_channels[id].dma_id, config) != 0) {
LOG_ERR("cannot configure the dmamux.");
return -EINVAL;
}
/* set the Request Line ID to this dmamux channel i */
DMAMUX_Channel_TypeDef *dmamux =
(DMAMUX_Channel_TypeDef *)dev_config->base;
LL_DMAMUX_SetRequestID(dmamux, id, request_id);
return 0;
}
int dmamux_stm32_start(struct device *dev, u32_t id)
{
const struct dmamux_stm32_config *dev_config =
dev->config_info;
struct dmamux_stm32_data *data = dev->driver_data;
/* check if this channel is valid */
if (id >= dev_config->channel_nb) {
LOG_ERR("channel ID %d is too big.", id);
return -EINVAL;
}
if (dma_stm32_start(data->mux_channels[id].dev_dma,
data->mux_channels[id].dma_id) != 0) {
LOG_ERR("cannot start the dmamux channel %d.", id);
return -EINVAL;
}
return 0;
}
int dmamux_stm32_stop(struct device *dev, u32_t id)
{
const struct dmamux_stm32_config *dev_config =
dev->config_info;
struct dmamux_stm32_data *data = dev->driver_data;
/* check if this channel is valid */
if (id >= dev_config->channel_nb) {
LOG_ERR("channel ID %d is too big.", id);
return -EINVAL;
}
if (dma_stm32_stop(data->mux_channels[id].dev_dma,
data->mux_channels[id].dma_id) != 0) {
LOG_ERR("cannot stop the dmamux channel %d.", id);
return -EINVAL;
}
return 0;
}
int dmamux_stm32_reload(struct device *dev, u32_t id,
u32_t src, u32_t dst, size_t size)
{
const struct dmamux_stm32_config *dev_config =
dev->config_info;
struct dmamux_stm32_data *data = dev->driver_data;
/* check if this channel is valid */
if (id >= dev_config->channel_nb) {
LOG_ERR("channel ID %d is too big.", id);
return -EINVAL;
}
if (dma_stm32_reload(data->mux_channels[id].dev_dma,
data->mux_channels[id].dma_id,
src, dst, size) != 0) {
LOG_ERR("cannot reload the dmamux channel %d.", id);
return -EINVAL;
}
return 0;
}
static int dmamux_stm32_init(struct device *dev)
{
struct dmamux_stm32_data *data = dev->driver_data;
const struct dmamux_stm32_config *config =
dev->config_info;
struct device *clk =
device_get_binding(STM32_CLOCK_CONTROL_NAME);
if (clock_control_on(clk,
(clock_control_subsys_t *) &config->pclken) != 0) {
LOG_ERR("clock op failed\n");
return -EIO;
}
int size_stream =
sizeof(struct dmamux_stm32_channel) * config->channel_nb;
data->mux_channels = k_malloc(size_stream);
if (!data->mux_channels) {
LOG_ERR("HEAP_MEM_POOL_SIZE is too small");
return -ENOMEM;
}
for (int i = 0; i < config->channel_nb; i++) {
/*
* associates the dmamux channel
* to the corresponding dma stream
*/
if (i < config->channel_nb / 2) {
data->mux_channels[i].dev_dma =
device_get_binding((const char *)"DMA_1");
/* dma 1 channels from 1 to N */
data->mux_channels[i].dma_id = i + 1;
} else {
data->mux_channels[i].dev_dma =
device_get_binding((const char *)"DMA_2");
data->mux_channels[i].dma_id =
/* dma 2 channels from 1 to N */
i - config->channel_nb / 2 + 1;
}
}
return 0;
}
static const struct dma_driver_api dma_funcs = {
.reload = dmamux_stm32_reload,
.config = dmamux_stm32_configure,
.start = dmamux_stm32_start,
.stop = dmamux_stm32_stop,
};
#define DMAMUX_INIT(index) \
\
const struct dmamux_stm32_config dmamux_stm32_config_##index = {\
.pclken = { .bus = DT_INST_CLOCKS_CELL(index, bus), \
.enr = DT_INST_CLOCKS_CELL(index, bits) }, \
.base = DT_INST_REG_ADDR(index), \
.channel_nb = DT_INST_PROP(index, dma_channels), \
.gen_nb = DT_INST_PROP(index, dma_generators), \
.req_nb = DT_INST_PROP(index, dma_requests), \
}; \
\
static struct dmamux_stm32_data dmamux_stm32_data_##index = { \
.mux_channels = NULL, \
}; \
\
DEVICE_AND_API_INIT(dmamux_##index, DT_INST_LABEL(index), \
&dmamux_stm32_init, \
&dmamux_stm32_data_##index, &dmamux_stm32_config_##index,\
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,\
&dma_funcs);
DT_INST_FOREACH_STATUS_OKAY(DMAMUX_INIT)