zephyr/drivers/shared_irq/shared_irq.c
Dmitriy Korovkin f1420515a7 irq: Add flags to IRQ_CONNECT_STATIC() macro and irq_connect() function
Flags allow passing IRQ triggering option for x86 architecture.
Each platform defines flags for a particular device and then
device driver uses them when registers the interrupt handler.

The change in API means that device drivers and sample
applications need to use the new API.

IRQ triggering configuration is now handled by device drivers
by using flags passed to interrupt registering API:
IRQ_CONNECT_STATIC() or irq_connect()

Change-Id: Ibc4312ea2b4032a2efc5b913c6389f780a2a11d1
Signed-off-by: Dmitriy Korovkin <dmitriy.korovkin@windriver.com>
2016-02-05 20:24:44 -05:00

197 lines
5.2 KiB
C

/*
* Copyright (c) 2015 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <nanokernel.h>
#include <device.h>
#include <shared_irq.h>
#include <init.h>
#include <board.h>
#include <sys_io.h>
/**
* @brief Register a device ISR
* @param dev Pointer to device structure for SHARED_IRQ driver instance.
* @param isr_func Pointer to the ISR function for the device.
* @param isr_dev Pointer to the device that will service the interrupt.
*/
static int isr_register(struct device *dev, isr_t isr_func,
struct device *isr_dev)
{
struct shared_irq_runtime *clients = dev->driver_data;
struct shared_irq_config *config = dev->config->config_info;
uint32_t i;
for (i = 0; i < config->client_count; i++) {
if (!clients->client[i].isr_dev) {
clients->client[i].isr_dev = isr_dev;
clients->client[i].isr_func = isr_func;
return DEV_OK;
}
}
return DEV_FAIL;
}
/**
* @brief Enable ISR for device
* @param dev Pointer to device structure for SHARED_IRQ driver instance.
* @param isr_dev Pointer to the device that will service the interrupt.
*/
static inline int enable(struct device *dev, struct device *isr_dev)
{
struct shared_irq_runtime *clients = dev->driver_data;
struct shared_irq_config *config = dev->config->config_info;
uint32_t i;
for (i = 0; i < config->client_count; i++) {
if (clients->client[i].isr_dev == isr_dev) {
clients->client[i].enabled = 1;
irq_enable(config->irq_num);
return DEV_OK;
}
}
return DEV_FAIL;
}
static int last_enabled_isr(struct shared_irq_runtime *clients, int count)
{
uint32_t i;
for (i = 0; i < count; i++) {
if (clients->client[i].enabled) {
return 0;
}
}
return 1;
}
/**
* @brief Disable ISR for device
* @param dev Pointer to device structure for SHARED_IRQ driver instance.
* @param isr_dev Pointer to the device that will service the interrupt.
*/
static inline int disable(struct device *dev, struct device *isr_dev)
{
struct shared_irq_runtime *clients = dev->driver_data;
struct shared_irq_config *config = dev->config->config_info;
uint32_t i;
for (i = 0; i < config->client_count; i++) {
if (clients->client[i].isr_dev == isr_dev) {
clients->client[i].enabled = 0;
if (last_enabled_isr(clients, config->client_count)) {
irq_disable(config->irq_num);
}
return DEV_OK;
}
}
return DEV_FAIL;
}
void shared_irq_isr(struct device *dev)
{
struct shared_irq_runtime *clients = dev->driver_data;
struct shared_irq_config *config = dev->config->config_info;
uint32_t i;
for (i = 0; i < config->client_count; i++) {
if (clients->client[i].isr_dev) {
clients->client[i].isr_func(clients->client[i].isr_dev);
}
}
}
static struct shared_irq_driver_api api_funcs = {
.isr_register = isr_register,
.enable = enable,
.disable = disable,
};
int shared_irq_initialize(struct device *dev)
{
struct shared_irq_config *config = dev->config->config_info;
dev->driver_api = &api_funcs;
config->config(dev);
return 0;
}
#if CONFIG_SHARED_IRQ_0
void shared_irq_config_0_irq(struct device *port);
struct shared_irq_config shared_irq_config_0 = {
.irq_num = CONFIG_SHARED_IRQ_0_IRQ,
.client_count = CONFIG_SHARED_IRQ_NUM_CLIENTS,
.config = shared_irq_config_0_irq
};
struct shared_irq_runtime shared_irq_0_runtime;
DECLARE_DEVICE_INIT_CONFIG(shared_irq_0, CONFIG_SHARED_IRQ_0_NAME,
shared_irq_initialize, &shared_irq_config_0);
pre_kernel_early_init(shared_irq_0, &shared_irq_0_runtime);
IRQ_CONNECT_STATIC(shared_irq_0, CONFIG_SHARED_IRQ_0_IRQ,
CONFIG_SHARED_IRQ_0_PRI, shared_irq_isr_0, 0,
SHARED_IRQ_0_FLAGS);
void shared_irq_config_0_irq(struct device *port)
{
struct shared_irq_config *config = port->config->config_info;
IRQ_CONFIG(shared_irq_0, config->irq_num, 0);
}
void shared_irq_isr_0(void *unused)
{
shared_irq_isr(&__initconfig_shared_irq_0);
}
#endif /* CONFIG_SHARED_IRQ_0 */
#if CONFIG_SHARED_IRQ_1
void shared_irq_config_1_irq(struct device *port);
struct shared_irq_config shared_irq_config_1 = {
.irq_num = CONFIG_SHARED_IRQ_1_IRQ,
.client_count = CONFIG_SHARED_IRQ_NUM_CLIENTS,
.config = shared_irq_config_1_irq
};
struct shared_irq_runtime shared_irq_1_runtime;
DECLARE_DEVICE_INIT_CONFIG(shared_irq_1, CONFIG_SHARED_IRQ_1_NAME,
shared_irq_initialize, &shared_irq_config_1);
pre_kernel_early_init(shared_irq_1, &shared_irq_1_runtime);
IRQ_CONNECT_STATIC(shared_irq_1, CONFIG_SHARED_IRQ_1_IRQ,
CONFIG_SHARED_IRQ_1_PRI, shared_irq_isr_1, 0,
SHARED_IRQ_1_FLAGS);
void shared_irq_config_1_irq(struct device *port)
{
struct shared_irq_config *config = port->config->config_info;
IRQ_CONFIG(shared_irq_1, config->irq_num, 0);
}
void shared_irq_isr_1(void *unused)
{
shared_irq_isr(&__initconfig_shared_irq_1);
}
#endif /* CONFIG_SHARED_IRQ_1 */