blob: 8678e884a29d17fe3f5b8b82b3188a6c5ee0e023 [file] [log] [blame]
Dirk Brandewie002c53b2015-09-29 08:42:22 -07001/*
2 * Copyright (c) 2015 Intel Corporation.
3 *
David B. Kinderac74d8b2017-01-18 17:01:01 -08004 * SPDX-License-Identifier: Apache-2.0
Dirk Brandewie002c53b2015-09-29 08:42:22 -07005 */
6
Kumar Gala67d42d62020-03-25 12:05:44 -05007#define DT_DRV_COMPAT shared_irq
8
Andre Guedes7c956d22016-03-09 14:38:02 -03009#include <errno.h>
10
Flavio Santesb04cdcd2016-12-04 14:59:37 -060011#include <kernel.h>
Dirk Brandewie002c53b2015-09-29 08:42:22 -070012#include <device.h>
13#include <shared_irq.h>
14#include <init.h>
Anas Nashifef281c42019-06-25 12:26:23 -040015#include <sys/sys_io.h>
Dirk Brandewie002c53b2015-09-29 08:42:22 -070016
Daniel Leung8effb4f2015-12-10 09:52:56 -080017#ifdef CONFIG_IOAPIC
Anas Nashif43a49332019-06-21 12:54:15 -040018#include <drivers/interrupt_controller/ioapic.h>
Daniel Leung8effb4f2015-12-10 09:52:56 -080019#endif
20
Henrik Brix Andersene8ffafa2021-04-10 22:18:15 +020021typedef void (*shared_irq_config_irq_t)(void);
22
23struct shared_irq_config {
24 uint32_t irq_num;
25 shared_irq_config_irq_t config;
26 uint32_t client_count;
27};
28
29struct shared_irq_client {
30 const struct device *isr_dev;
31 isr_t isr_func;
32 uint32_t enabled;
33};
34
35struct shared_irq_runtime {
Thomas Strangerdedd4442021-03-28 18:07:56 +020036 struct shared_irq_client *const client;
Henrik Brix Andersene8ffafa2021-04-10 22:18:15 +020037};
38
Dirk Brandewie002c53b2015-09-29 08:42:22 -070039/**
40 * @brief Register a device ISR
41 * @param dev Pointer to device structure for SHARED_IRQ driver instance.
42 * @param isr_func Pointer to the ISR function for the device.
43 * @param isr_dev Pointer to the device that will service the interrupt.
44 */
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020045static int isr_register(const struct device *dev, isr_t isr_func,
46 const struct device *isr_dev)
Dirk Brandewie002c53b2015-09-29 08:42:22 -070047{
Tomasz Bursztyka98d9b012020-05-28 21:23:02 +020048 struct shared_irq_runtime *clients = dev->data;
Tomasz Bursztykaaf6140c2020-05-28 20:44:16 +020049 const struct shared_irq_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -050050 uint32_t i;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070051
Patrik Flykt8ff96b52018-11-29 11:12:22 -080052 for (i = 0U; i < config->client_count; i++) {
Dirk Brandewie002c53b2015-09-29 08:42:22 -070053 if (!clients->client[i].isr_dev) {
54 clients->client[i].isr_dev = isr_dev;
55 clients->client[i].isr_func = isr_func;
Andre Guedes024cfe72016-03-09 14:01:20 -030056 return 0;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070057 }
58 }
Andre Guedes7c956d22016-03-09 14:38:02 -030059 return -EIO;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070060}
61
62/**
63 * @brief Enable ISR for device
64 * @param dev Pointer to device structure for SHARED_IRQ driver instance.
65 * @param isr_dev Pointer to the device that will service the interrupt.
66 */
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020067static inline int enable(const struct device *dev,
68 const struct device *isr_dev)
Dirk Brandewie002c53b2015-09-29 08:42:22 -070069{
Tomasz Bursztyka98d9b012020-05-28 21:23:02 +020070 struct shared_irq_runtime *clients = dev->data;
Tomasz Bursztykaaf6140c2020-05-28 20:44:16 +020071 const struct shared_irq_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -050072 uint32_t i;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070073
Patrik Flykt8ff96b52018-11-29 11:12:22 -080074 for (i = 0U; i < config->client_count; i++) {
Dirk Brandewie002c53b2015-09-29 08:42:22 -070075 if (clients->client[i].isr_dev == isr_dev) {
Patrik Flykt24d71432019-03-26 19:57:45 -060076 clients->client[i].enabled = 1U;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070077 irq_enable(config->irq_num);
Andre Guedes024cfe72016-03-09 14:01:20 -030078 return 0;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070079 }
80 }
Andre Guedes7c956d22016-03-09 14:38:02 -030081 return -EIO;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070082}
83
84static int last_enabled_isr(struct shared_irq_runtime *clients, int count)
85{
Kumar Galaa1b77fd2020-05-27 11:26:57 -050086 uint32_t i;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070087
Patrik Flykt8ff96b52018-11-29 11:12:22 -080088 for (i = 0U; i < count; i++) {
Dirk Brandewie002c53b2015-09-29 08:42:22 -070089 if (clients->client[i].enabled) {
90 return 0;
91 }
92 }
93 return 1;
94}
95/**
96 * @brief Disable ISR for device
97 * @param dev Pointer to device structure for SHARED_IRQ driver instance.
98 * @param isr_dev Pointer to the device that will service the interrupt.
99 */
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200100static inline int disable(const struct device *dev,
101 const struct device *isr_dev)
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700102{
Tomasz Bursztyka98d9b012020-05-28 21:23:02 +0200103 struct shared_irq_runtime *clients = dev->data;
Tomasz Bursztykaaf6140c2020-05-28 20:44:16 +0200104 const struct shared_irq_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500105 uint32_t i;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700106
Patrik Flykt8ff96b52018-11-29 11:12:22 -0800107 for (i = 0U; i < config->client_count; i++) {
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700108 if (clients->client[i].isr_dev == isr_dev) {
Patrik Flykt24d71432019-03-26 19:57:45 -0600109 clients->client[i].enabled = 0U;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700110 if (last_enabled_isr(clients, config->client_count)) {
111 irq_disable(config->irq_num);
112 }
Andre Guedes024cfe72016-03-09 14:01:20 -0300113 return 0;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700114 }
115 }
Andre Guedes7c956d22016-03-09 14:38:02 -0300116 return -EIO;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700117}
118
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200119void shared_irq_isr(const struct device *dev)
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700120{
Tomasz Bursztyka98d9b012020-05-28 21:23:02 +0200121 struct shared_irq_runtime *clients = dev->data;
Tomasz Bursztykaaf6140c2020-05-28 20:44:16 +0200122 const struct shared_irq_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500123 uint32_t i;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700124
Patrik Flykt8ff96b52018-11-29 11:12:22 -0800125 for (i = 0U; i < config->client_count; i++) {
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700126 if (clients->client[i].isr_dev) {
127 clients->client[i].isr_func(clients->client[i].isr_dev);
128 }
129 }
130}
131
Marcus Shawcroft0bac7872016-10-24 08:39:02 +0100132static const struct shared_irq_driver_api api_funcs = {
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700133 .isr_register = isr_register,
134 .enable = enable,
135 .disable = disable,
136};
137
138
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200139int shared_irq_initialize(const struct device *dev)
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700140{
Tomasz Bursztykaaf6140c2020-05-28 20:44:16 +0200141 const struct shared_irq_config *config = dev->config;
Andrew Boied9cfbd52016-01-08 00:46:14 -0800142 config->config();
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700143 return 0;
144}
145
Thomas Strangera0bea082021-03-28 17:27:36 +0200146/*
147 * INST_SUPPORTS_DEP_ORDS_CNT: Counts the number of "elements" in
148 * DT_SUPPORTS_DEP_ORDS(n). There is a comma after each ordinal(inc. the last)
149 * Hence FOR_EACH adds "+1" once too often which has to be subtracted in the end.
150 */
151#define F1(x) 1
152#define INST_SUPPORTS_DEP_ORDS_CNT(n) \
153 (FOR_EACH(F1, (+), DT_INST_SUPPORTS_DEP_ORDS(n)) - 1)
154
Thomas Stranger23982032021-03-28 17:04:43 +0200155#define SHARED_IRQ_CONFIG_FUNC(n) \
156void shared_irq_config_func_##n(void) \
157{ \
158 IRQ_CONNECT(DT_INST_IRQN(n), \
159 DT_INST_IRQ(n, priority), \
160 shared_irq_isr, \
161 DEVICE_DT_INST_GET(n), \
Thomas Stranger8f559a32021-03-28 18:13:37 +0200162 COND_CODE_1(DT_INST_IRQ_HAS_CELL(n, sense), \
163 (DT_INST_IRQ(n, sense)), \
164 (0))); \
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700165}
166
Thomas Stranger23982032021-03-28 17:04:43 +0200167#define SHARED_IRQ_INIT(n) \
168 SHARED_IRQ_CONFIG_FUNC(n) \
Thomas Strangerdedd4442021-03-28 18:07:56 +0200169 struct shared_irq_client clients_##n[INST_SUPPORTS_DEP_ORDS_CNT(n)]; \
170 struct shared_irq_runtime shared_irq_data_##n = { \
171 .client = clients_##n \
172 }; \
Thomas Stranger23982032021-03-28 17:04:43 +0200173 \
174 const struct shared_irq_config shared_irq_config_##n = { \
175 .irq_num = DT_INST_IRQN(n), \
Thomas Strangera0bea082021-03-28 17:27:36 +0200176 .client_count = INST_SUPPORTS_DEP_ORDS_CNT(n), \
Thomas Stranger23982032021-03-28 17:04:43 +0200177 .config = shared_irq_config_func_##n \
178 }; \
179 DEVICE_DT_INST_DEFINE(n, shared_irq_initialize, \
180 NULL, \
181 &shared_irq_data_##n, \
182 &shared_irq_config_##n, POST_KERNEL, \
183 CONFIG_SHARED_IRQ_INIT_PRIORITY, \
184 &api_funcs);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700185
Thomas Stranger23982032021-03-28 17:04:43 +0200186DT_INST_FOREACH_STATUS_OKAY(SHARED_IRQ_INIT)