blob: 6717ccd2498591ee7ceb6d135f478d2776270c70 [file] [log] [blame]
Dirk Brandewie002c53b2015-09-29 08:42:22 -07001/*
Navinkumar Balabakthana8490c32023-08-24 06:03:17 +00002 * Copyright (c) 2015 - 2023 Intel Corporation.
Dirk Brandewie002c53b2015-09-29 08:42:22 -07003 *
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
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020011#include <zephyr/kernel.h>
12#include <zephyr/device.h>
13#include <zephyr/shared_irq.h>
14#include <zephyr/init.h>
15#include <zephyr/sys/sys_io.h>
Gerard Marull-Paretas178bdc42022-10-17 10:24:11 +020016#include <zephyr/irq.h>
Dirk Brandewie002c53b2015-09-29 08:42:22 -070017
Daniel Leung8effb4f2015-12-10 09:52:56 -080018#ifdef CONFIG_IOAPIC
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020019#include <zephyr/drivers/interrupt_controller/ioapic.h>
Daniel Leung8effb4f2015-12-10 09:52:56 -080020#endif
21
Henrik Brix Andersene8ffafa2021-04-10 22:18:15 +020022typedef void (*shared_irq_config_irq_t)(void);
23
24struct shared_irq_config {
25 uint32_t irq_num;
26 shared_irq_config_irq_t config;
27 uint32_t client_count;
28};
29
30struct shared_irq_client {
31 const struct device *isr_dev;
32 isr_t isr_func;
33 uint32_t enabled;
34};
35
36struct shared_irq_runtime {
Thomas Strangerdedd4442021-03-28 18:07:56 +020037 struct shared_irq_client *const client;
Henrik Brix Andersene8ffafa2021-04-10 22:18:15 +020038};
39
Dirk Brandewie002c53b2015-09-29 08:42:22 -070040/**
41 * @brief Register a device ISR
42 * @param dev Pointer to device structure for SHARED_IRQ driver instance.
43 * @param isr_func Pointer to the ISR function for the device.
44 * @param isr_dev Pointer to the device that will service the interrupt.
45 */
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020046static int isr_register(const struct device *dev, isr_t isr_func,
47 const struct device *isr_dev)
Dirk Brandewie002c53b2015-09-29 08:42:22 -070048{
Tomasz Bursztyka98d9b012020-05-28 21:23:02 +020049 struct shared_irq_runtime *clients = dev->data;
Tomasz Bursztykaaf6140c2020-05-28 20:44:16 +020050 const struct shared_irq_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -050051 uint32_t i;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070052
Patrik Flykt8ff96b52018-11-29 11:12:22 -080053 for (i = 0U; i < config->client_count; i++) {
Dirk Brandewie002c53b2015-09-29 08:42:22 -070054 if (!clients->client[i].isr_dev) {
55 clients->client[i].isr_dev = isr_dev;
56 clients->client[i].isr_func = isr_func;
Andre Guedes024cfe72016-03-09 14:01:20 -030057 return 0;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070058 }
59 }
Andre Guedes7c956d22016-03-09 14:38:02 -030060 return -EIO;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070061}
62
63/**
64 * @brief Enable ISR for device
65 * @param dev Pointer to device structure for SHARED_IRQ driver instance.
66 * @param isr_dev Pointer to the device that will service the interrupt.
67 */
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020068static inline int enable(const struct device *dev,
69 const struct device *isr_dev)
Dirk Brandewie002c53b2015-09-29 08:42:22 -070070{
Tomasz Bursztyka98d9b012020-05-28 21:23:02 +020071 struct shared_irq_runtime *clients = dev->data;
Tomasz Bursztykaaf6140c2020-05-28 20:44:16 +020072 const struct shared_irq_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -050073 uint32_t i;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070074
Patrik Flykt8ff96b52018-11-29 11:12:22 -080075 for (i = 0U; i < config->client_count; i++) {
Dirk Brandewie002c53b2015-09-29 08:42:22 -070076 if (clients->client[i].isr_dev == isr_dev) {
Patrik Flykt24d71432019-03-26 19:57:45 -060077 clients->client[i].enabled = 1U;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070078 irq_enable(config->irq_num);
Andre Guedes024cfe72016-03-09 14:01:20 -030079 return 0;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070080 }
81 }
Andre Guedes7c956d22016-03-09 14:38:02 -030082 return -EIO;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070083}
84
85static int last_enabled_isr(struct shared_irq_runtime *clients, int count)
86{
Kumar Galaa1b77fd2020-05-27 11:26:57 -050087 uint32_t i;
Dirk Brandewie002c53b2015-09-29 08:42:22 -070088
Patrik Flykt8ff96b52018-11-29 11:12:22 -080089 for (i = 0U; i < count; i++) {
Dirk Brandewie002c53b2015-09-29 08:42:22 -070090 if (clients->client[i].enabled) {
91 return 0;
92 }
93 }
94 return 1;
95}
96/**
97 * @brief Disable ISR for device
98 * @param dev Pointer to device structure for SHARED_IRQ driver instance.
99 * @param isr_dev Pointer to the device that will service the interrupt.
100 */
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200101static inline int disable(const struct device *dev,
102 const struct device *isr_dev)
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700103{
Tomasz Bursztyka98d9b012020-05-28 21:23:02 +0200104 struct shared_irq_runtime *clients = dev->data;
Tomasz Bursztykaaf6140c2020-05-28 20:44:16 +0200105 const struct shared_irq_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500106 uint32_t i;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700107
Patrik Flykt8ff96b52018-11-29 11:12:22 -0800108 for (i = 0U; i < config->client_count; i++) {
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700109 if (clients->client[i].isr_dev == isr_dev) {
Patrik Flykt24d71432019-03-26 19:57:45 -0600110 clients->client[i].enabled = 0U;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700111 if (last_enabled_isr(clients, config->client_count)) {
112 irq_disable(config->irq_num);
113 }
Andre Guedes024cfe72016-03-09 14:01:20 -0300114 return 0;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700115 }
116 }
Andre Guedes7c956d22016-03-09 14:38:02 -0300117 return -EIO;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700118}
119
Yong Cong Sinf6d5c2e2024-09-19 16:54:40 +0800120static void shared_irq_isr(const struct device *dev)
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700121{
Tomasz Bursztyka98d9b012020-05-28 21:23:02 +0200122 struct shared_irq_runtime *clients = dev->data;
Tomasz Bursztykaaf6140c2020-05-28 20:44:16 +0200123 const struct shared_irq_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500124 uint32_t i;
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700125
Patrik Flykt8ff96b52018-11-29 11:12:22 -0800126 for (i = 0U; i < config->client_count; i++) {
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700127 if (clients->client[i].isr_dev) {
Navinkumar Balabakthana8490c32023-08-24 06:03:17 +0000128 clients->client[i].isr_func(clients->client[i].isr_dev, config->irq_num);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700129 }
130 }
131}
132
Pieter De Gendt74fc1b12024-11-28 19:33:39 +0100133static DEVICE_API(shared_irq, api_funcs) = {
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700134 .isr_register = isr_register,
135 .enable = enable,
136 .disable = disable,
137};
138
139
Yong Cong Sinf6d5c2e2024-09-19 16:54:40 +0800140static int shared_irq_initialize(const struct device *dev)
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700141{
Tomasz Bursztykaaf6140c2020-05-28 20:44:16 +0200142 const struct shared_irq_config *config = dev->config;
Yong Cong Sinf6d5c2e2024-09-19 16:54:40 +0800143
Andrew Boied9cfbd52016-01-08 00:46:14 -0800144 config->config();
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700145 return 0;
146}
147
Thomas Strangera0bea082021-03-28 17:27:36 +0200148/*
149 * INST_SUPPORTS_DEP_ORDS_CNT: Counts the number of "elements" in
150 * DT_SUPPORTS_DEP_ORDS(n). There is a comma after each ordinal(inc. the last)
151 * Hence FOR_EACH adds "+1" once too often which has to be subtracted in the end.
152 */
153#define F1(x) 1
154#define INST_SUPPORTS_DEP_ORDS_CNT(n) \
155 (FOR_EACH(F1, (+), DT_INST_SUPPORTS_DEP_ORDS(n)) - 1)
156
Thomas Stranger23982032021-03-28 17:04:43 +0200157#define SHARED_IRQ_CONFIG_FUNC(n) \
158void shared_irq_config_func_##n(void) \
159{ \
160 IRQ_CONNECT(DT_INST_IRQN(n), \
161 DT_INST_IRQ(n, priority), \
162 shared_irq_isr, \
163 DEVICE_DT_INST_GET(n), \
Thomas Stranger8f559a32021-03-28 18:13:37 +0200164 COND_CODE_1(DT_INST_IRQ_HAS_CELL(n, sense), \
165 (DT_INST_IRQ(n, sense)), \
166 (0))); \
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700167}
168
Thomas Stranger23982032021-03-28 17:04:43 +0200169#define SHARED_IRQ_INIT(n) \
170 SHARED_IRQ_CONFIG_FUNC(n) \
Thomas Strangerdedd4442021-03-28 18:07:56 +0200171 struct shared_irq_client clients_##n[INST_SUPPORTS_DEP_ORDS_CNT(n)]; \
172 struct shared_irq_runtime shared_irq_data_##n = { \
173 .client = clients_##n \
174 }; \
Thomas Stranger23982032021-03-28 17:04:43 +0200175 \
176 const struct shared_irq_config shared_irq_config_##n = { \
177 .irq_num = DT_INST_IRQN(n), \
Thomas Strangera0bea082021-03-28 17:27:36 +0200178 .client_count = INST_SUPPORTS_DEP_ORDS_CNT(n), \
Thomas Stranger23982032021-03-28 17:04:43 +0200179 .config = shared_irq_config_func_##n \
180 }; \
181 DEVICE_DT_INST_DEFINE(n, shared_irq_initialize, \
182 NULL, \
183 &shared_irq_data_##n, \
184 &shared_irq_config_##n, POST_KERNEL, \
185 CONFIG_SHARED_IRQ_INIT_PRIORITY, \
186 &api_funcs);
Dirk Brandewie002c53b2015-09-29 08:42:22 -0700187
Thomas Stranger23982032021-03-28 17:04:43 +0200188DT_INST_FOREACH_STATUS_OKAY(SHARED_IRQ_INIT)