blob: e89dbb47d5bb8d508afc23ebc0b1b3bebb917e6d [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;
45 return DEV_OK;
46 }
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);
66 return DEV_OK;
67 }
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 }
100 return DEV_OK;
101 }
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;
131 config->config(dev);
132
133 return 0;
134}
135
136#if CONFIG_SHARED_IRQ_0
137void shared_irq_config_0_irq(struct device *port);
138
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
147DECLARE_DEVICE_INIT_CONFIG(shared_irq_0, CONFIG_SHARED_IRQ_0_NAME,
148 shared_irq_initialize, &shared_irq_config_0);
Dmitriy Korovkin57f27412015-10-26 15:56:02 -0400149SYS_DEFINE_DEVICE(shared_irq_0, &shared_irq_0_runtime, SECONDARY,
150 CONFIG_SHARED_IRQ_INIT_PRIORITY);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700151
Daniel Leung8effb4f2015-12-10 09:52:56 -0800152#if defined(CONFIG_IOAPIC)
153#if defined(CONFIG_SHARED_IRQ_0)
154 #if defined(CONFIG_SHARED_IRQ_0_FALLING_EDGE)
155 #define SHARED_IRQ_0_FLAGS (IOAPIC_EDGE | IOAPIC_LOW)
156 #elif defined(CONFIG_SHARED_IRQ_0_RISING_EDGE)
157 #define SHARED_IRQ_0_FLAGS (IOAPIC_EDGE | IOAPIC_HIGH)
158 #elif defined(CONFIG_SHARED_IRQ_0_LEVEL_HIGH)
159 #define SHARED_IRQ_0_FLAGS (IOAPIC_LEVEL | IOAPIC_HIGH)
160 #elif defined(CONFIG_SHARED_IRQ_0_LEVEL_LOW)
161 #define SHARED_IRQ_0_FLAGS (IOAPIC_LEVEL | IOAPIC_LOW)
162 #endif
163#endif /* CONFIG_SHARED_IRQ_0 */
164#else
165 #define SHARED_IRQ_0_FLAGS 0
166#endif /* CONFIG_IOAPIC */
167
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700168IRQ_CONNECT_STATIC(shared_irq_0, CONFIG_SHARED_IRQ_0_IRQ,
Dmitriy Korovkinf1420512015-11-02 18:06:08 -0500169 CONFIG_SHARED_IRQ_0_PRI, shared_irq_isr_0, 0,
170 SHARED_IRQ_0_FLAGS);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700171
172void shared_irq_config_0_irq(struct device *port)
173{
174 struct shared_irq_config *config = port->config->config_info;
175
Juan Manuel Cruzbc1a79c2015-11-30 11:21:13 -0600176 IRQ_CONFIG(shared_irq_0, config->irq_num);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700177}
178
179void shared_irq_isr_0(void *unused)
180{
Allan Stephens7b006062015-10-14 09:17:38 -0400181 shared_irq_isr(&__initconfig_shared_irq_0);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700182}
183
184#endif /* CONFIG_SHARED_IRQ_0 */
185
186#if CONFIG_SHARED_IRQ_1
187void shared_irq_config_1_irq(struct device *port);
188
189struct shared_irq_config shared_irq_config_1 = {
190 .irq_num = CONFIG_SHARED_IRQ_1_IRQ,
191 .client_count = CONFIG_SHARED_IRQ_NUM_CLIENTS,
192 .config = shared_irq_config_1_irq
193};
194
195struct shared_irq_runtime shared_irq_1_runtime;
196
197DECLARE_DEVICE_INIT_CONFIG(shared_irq_1, CONFIG_SHARED_IRQ_1_NAME,
198 shared_irq_initialize, &shared_irq_config_1);
Dmitriy Korovkin57f27412015-10-26 15:56:02 -0400199SYS_DEFINE_DEVICE(shared_irq_1, &shared_irq_1_runtime, SECONDARY,
200 CONFIG_SHARED_IRQ_INIT_PRIORITY);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700201
Daniel Leung8effb4f2015-12-10 09:52:56 -0800202#if defined(CONFIG_IOAPIC)
203#if defined(CONFIG_SHARED_IRQ_1)
204 #if defined(CONFIG_SHARED_IRQ_1_FALLING_EDGE)
205 #define SHARED_IRQ_1_FLAGS (IOAPIC_EDGE | IOAPIC_LOW)
206 #elif defined(CONFIG_SHARED_IRQ_1_RISING_EDGE)
207 #define SHARED_IRQ_1_FLAGS (IOAPIC_EDGE | IOAPIC_HIGH)
208 #elif defined(CONFIG_SHARED_IRQ_1_LEVEL_HIGH)
209 #define SHARED_IRQ_1_FLAGS (IOAPIC_LEVEL | IOAPIC_HIGH)
210 #elif defined(CONFIG_SHARED_IRQ_1_LEVEL_LOW)
211 #define SHARED_IRQ_1_FLAGS (IOAPIC_LEVEL | IOAPIC_LOW)
212 #endif
213#endif /* CONFIG_SHARED_IRQ_1 */
214#else
215 #define SHARED_IRQ_1_FLAGS 0
216#endif /* CONFIG_IOAPIC */
217
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700218IRQ_CONNECT_STATIC(shared_irq_1, CONFIG_SHARED_IRQ_1_IRQ,
Dmitriy Korovkinf1420512015-11-02 18:06:08 -0500219 CONFIG_SHARED_IRQ_1_PRI, shared_irq_isr_1, 0,
220 SHARED_IRQ_1_FLAGS);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700221
222void shared_irq_config_1_irq(struct device *port)
223{
224 struct shared_irq_config *config = port->config->config_info;
225
Juan Manuel Cruzbc1a79c2015-11-30 11:21:13 -0600226 IRQ_CONFIG(shared_irq_1, config->irq_num);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700227}
228
229void shared_irq_isr_1(void *unused)
230{
Allan Stephens7b006062015-10-14 09:17:38 -0400231 shared_irq_isr(&__initconfig_shared_irq_1);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700232}
233
234#endif /* CONFIG_SHARED_IRQ_1 */
235