blob: 181186d9eddde7e849bbf159bdfa3df51909167f [file] [log] [blame]
Dirk Brandewie002c53b2015-09-29 08:42:22 -07001/*
2 * Copyright (c) 2015 Intel Corporation.
3 *
Javier B Perez Hernandezf7fffae2015-10-06 11:00:37 -05004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Dirk Brandewie002c53b2015-09-29 08:42:22 -07007 *
Javier B Perez Hernandezf7fffae2015-10-06 11:00:37 -05008 * http://www.apache.org/licenses/LICENSE-2.0
Dirk Brandewie002c53b2015-09-29 08:42:22 -07009 *
Javier B Perez Hernandezf7fffae2015-10-06 11:00:37 -050010 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Dirk Brandewie002c53b2015-09-29 08:42:22 -070015 */
16
17#include <nanokernel.h>
18#include <device.h>
19#include <shared_irq.h>
20#include <init.h>
21#include <board.h>
22#include <sys_io.h>
23
Daniel Leung8effb4f2015-12-10 09:52:56 -080024#ifdef CONFIG_IOAPIC
25#include <drivers/ioapic.h>
26#endif
27
Dirk Brandewie002c53b2015-09-29 08:42:22 -070028/**
29 * @brief Register a device ISR
30 * @param dev Pointer to device structure for SHARED_IRQ driver instance.
31 * @param isr_func Pointer to the ISR function for the device.
32 * @param isr_dev Pointer to the device that will service the interrupt.
33 */
34static int isr_register(struct device *dev, isr_t isr_func,
35 struct device *isr_dev)
36{
37 struct shared_irq_runtime *clients = dev->driver_data;
38 struct shared_irq_config *config = dev->config->config_info;
39 uint32_t i;
40
41 for (i = 0; i < config->client_count; i++) {
42 if (!clients->client[i].isr_dev) {
43 clients->client[i].isr_dev = isr_dev;
44 clients->client[i].isr_func = isr_func;
Andre Guedes024cfe72016-03-09 14:01:20 -030045 return 0;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070046 }
47 }
48 return DEV_FAIL;
49}
50
51/**
52 * @brief Enable ISR for device
53 * @param dev Pointer to device structure for SHARED_IRQ driver instance.
54 * @param isr_dev Pointer to the device that will service the interrupt.
55 */
56static inline int enable(struct device *dev, struct device *isr_dev)
57{
58 struct shared_irq_runtime *clients = dev->driver_data;
59 struct shared_irq_config *config = dev->config->config_info;
60 uint32_t i;
61
62 for (i = 0; i < config->client_count; i++) {
63 if (clients->client[i].isr_dev == isr_dev) {
64 clients->client[i].enabled = 1;
65 irq_enable(config->irq_num);
Andre Guedes024cfe72016-03-09 14:01:20 -030066 return 0;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070067 }
68 }
69 return DEV_FAIL;
70}
71
72static int last_enabled_isr(struct shared_irq_runtime *clients, int count)
73{
74 uint32_t i;
75
76 for (i = 0; i < count; i++) {
77 if (clients->client[i].enabled) {
78 return 0;
79 }
80 }
81 return 1;
82}
83/**
84 * @brief Disable ISR for device
85 * @param dev Pointer to device structure for SHARED_IRQ driver instance.
86 * @param isr_dev Pointer to the device that will service the interrupt.
87 */
88static inline int disable(struct device *dev, struct device *isr_dev)
89{
90 struct shared_irq_runtime *clients = dev->driver_data;
91 struct shared_irq_config *config = dev->config->config_info;
92 uint32_t i;
93
94 for (i = 0; i < config->client_count; i++) {
95 if (clients->client[i].isr_dev == isr_dev) {
96 clients->client[i].enabled = 0;
97 if (last_enabled_isr(clients, config->client_count)) {
98 irq_disable(config->irq_num);
99 }
Andre Guedes024cfe72016-03-09 14:01:20 -0300100 return 0;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700101 }
102 }
103 return DEV_FAIL;
104}
105
106void shared_irq_isr(struct device *dev)
107{
108 struct shared_irq_runtime *clients = dev->driver_data;
109 struct shared_irq_config *config = dev->config->config_info;
110 uint32_t i;
111
112 for (i = 0; i < config->client_count; i++) {
113 if (clients->client[i].isr_dev) {
114 clients->client[i].isr_func(clients->client[i].isr_dev);
115 }
116 }
117}
118
119static struct shared_irq_driver_api api_funcs = {
120 .isr_register = isr_register,
121 .enable = enable,
122 .disable = disable,
123};
124
125
126int shared_irq_initialize(struct device *dev)
127{
128 struct shared_irq_config *config = dev->config->config_info;
129
130 dev->driver_api = &api_funcs;
Andrew Boied9cfbd52016-01-08 00:46:14 -0800131 config->config();
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700132
133 return 0;
134}
135
136#if CONFIG_SHARED_IRQ_0
Andrew Boied9cfbd52016-01-08 00:46:14 -0800137void shared_irq_config_0_irq(void);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700138
139struct shared_irq_config shared_irq_config_0 = {
140 .irq_num = CONFIG_SHARED_IRQ_0_IRQ,
141 .client_count = CONFIG_SHARED_IRQ_NUM_CLIENTS,
142 .config = shared_irq_config_0_irq
143};
144
145struct shared_irq_runtime shared_irq_0_runtime;
146
Benjamin Walshd340d4c2016-01-28 14:48:47 -0500147DEVICE_INIT(shared_irq_0, CONFIG_SHARED_IRQ_0_NAME, shared_irq_initialize,
148 &shared_irq_0_runtime, &shared_irq_config_0,
149 SECONDARY, CONFIG_SHARED_IRQ_INIT_PRIORITY);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700150
Daniel Leung8effb4f2015-12-10 09:52:56 -0800151#if defined(CONFIG_IOAPIC)
152#if defined(CONFIG_SHARED_IRQ_0)
153 #if defined(CONFIG_SHARED_IRQ_0_FALLING_EDGE)
154 #define SHARED_IRQ_0_FLAGS (IOAPIC_EDGE | IOAPIC_LOW)
155 #elif defined(CONFIG_SHARED_IRQ_0_RISING_EDGE)
156 #define SHARED_IRQ_0_FLAGS (IOAPIC_EDGE | IOAPIC_HIGH)
157 #elif defined(CONFIG_SHARED_IRQ_0_LEVEL_HIGH)
158 #define SHARED_IRQ_0_FLAGS (IOAPIC_LEVEL | IOAPIC_HIGH)
159 #elif defined(CONFIG_SHARED_IRQ_0_LEVEL_LOW)
160 #define SHARED_IRQ_0_FLAGS (IOAPIC_LEVEL | IOAPIC_LOW)
161 #endif
162#endif /* CONFIG_SHARED_IRQ_0 */
163#else
164 #define SHARED_IRQ_0_FLAGS 0
165#endif /* CONFIG_IOAPIC */
166
Andrew Boied9cfbd52016-01-08 00:46:14 -0800167void shared_irq_config_0_irq(void)
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700168{
Andrew Boie897ffae2016-01-27 10:07:31 -0800169 IRQ_CONNECT(CONFIG_SHARED_IRQ_0_IRQ, CONFIG_SHARED_IRQ_0_PRI,
Benjamin Walsh2c1a95a2016-01-26 16:42:29 -0500170 shared_irq_isr, DEVICE_GET(shared_irq_0),
Andrew Boied9cfbd52016-01-08 00:46:14 -0800171 SHARED_IRQ_0_FLAGS);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700172}
173
174#endif /* CONFIG_SHARED_IRQ_0 */
175
176#if CONFIG_SHARED_IRQ_1
Andrew Boied9cfbd52016-01-08 00:46:14 -0800177void shared_irq_config_1_irq(void);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700178
179struct shared_irq_config shared_irq_config_1 = {
180 .irq_num = CONFIG_SHARED_IRQ_1_IRQ,
181 .client_count = CONFIG_SHARED_IRQ_NUM_CLIENTS,
182 .config = shared_irq_config_1_irq
183};
184
185struct shared_irq_runtime shared_irq_1_runtime;
186
Benjamin Walshd340d4c2016-01-28 14:48:47 -0500187DEVICE_INIT(shared_irq_1, CONFIG_SHARED_IRQ_1_NAME, shared_irq_initialize,
188 &shared_irq_1_runtime, &shared_irq_config_1,
189 SECONDARY, CONFIG_SHARED_IRQ_INIT_PRIORITY);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700190
Daniel Leung8effb4f2015-12-10 09:52:56 -0800191#if defined(CONFIG_IOAPIC)
192#if defined(CONFIG_SHARED_IRQ_1)
193 #if defined(CONFIG_SHARED_IRQ_1_FALLING_EDGE)
194 #define SHARED_IRQ_1_FLAGS (IOAPIC_EDGE | IOAPIC_LOW)
195 #elif defined(CONFIG_SHARED_IRQ_1_RISING_EDGE)
196 #define SHARED_IRQ_1_FLAGS (IOAPIC_EDGE | IOAPIC_HIGH)
197 #elif defined(CONFIG_SHARED_IRQ_1_LEVEL_HIGH)
198 #define SHARED_IRQ_1_FLAGS (IOAPIC_LEVEL | IOAPIC_HIGH)
199 #elif defined(CONFIG_SHARED_IRQ_1_LEVEL_LOW)
200 #define SHARED_IRQ_1_FLAGS (IOAPIC_LEVEL | IOAPIC_LOW)
201 #endif
202#endif /* CONFIG_SHARED_IRQ_1 */
203#else
204 #define SHARED_IRQ_1_FLAGS 0
205#endif /* CONFIG_IOAPIC */
206
Andrew Boied9cfbd52016-01-08 00:46:14 -0800207void shared_irq_config_1_irq(void)
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700208{
Andrew Boie897ffae2016-01-27 10:07:31 -0800209 IRQ_CONNECT(CONFIG_SHARED_IRQ_1_IRQ, CONFIG_SHARED_IRQ_1_PRI,
Benjamin Walsh2c1a95a2016-01-26 16:42:29 -0500210 shared_irq_isr, DEVICE_GET(shared_irq_1),
Andrew Boied9cfbd52016-01-08 00:46:14 -0800211 SHARED_IRQ_1_FLAGS);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700212}
213
214#endif /* CONFIG_SHARED_IRQ_1 */
215