18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PRU-ICSS INTC IRQChip driver for various TI SoCs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016-2020 Texas Instruments Incorporated - http://www.ti.com/ 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author(s): 88c2ecf20Sopenharmony_ci * Andrew F. Davis <afd@ti.com> 98c2ecf20Sopenharmony_ci * Suman Anna <s-anna@ti.com> 108c2ecf20Sopenharmony_ci * Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org> for Texas Instruments 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright (C) 2019 David Lechner <david@lechnology.com> 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/irq.h> 178c2ecf20Sopenharmony_ci#include <linux/irqchip/chained_irq.h> 188c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/of_device.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * Number of host interrupts reaching the main MPU sub-system. Note that this 258c2ecf20Sopenharmony_ci * is not the same as the total number of host interrupts supported by the PRUSS 268c2ecf20Sopenharmony_ci * INTC instance 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci#define MAX_NUM_HOST_IRQS 8 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* minimum starting host interrupt number for MPU */ 318c2ecf20Sopenharmony_ci#define FIRST_PRU_HOST_INT 2 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* PRU_ICSS_INTC registers */ 348c2ecf20Sopenharmony_ci#define PRU_INTC_REVID 0x0000 358c2ecf20Sopenharmony_ci#define PRU_INTC_CR 0x0004 368c2ecf20Sopenharmony_ci#define PRU_INTC_GER 0x0010 378c2ecf20Sopenharmony_ci#define PRU_INTC_GNLR 0x001c 388c2ecf20Sopenharmony_ci#define PRU_INTC_SISR 0x0020 398c2ecf20Sopenharmony_ci#define PRU_INTC_SICR 0x0024 408c2ecf20Sopenharmony_ci#define PRU_INTC_EISR 0x0028 418c2ecf20Sopenharmony_ci#define PRU_INTC_EICR 0x002c 428c2ecf20Sopenharmony_ci#define PRU_INTC_HIEISR 0x0034 438c2ecf20Sopenharmony_ci#define PRU_INTC_HIDISR 0x0038 448c2ecf20Sopenharmony_ci#define PRU_INTC_GPIR 0x0080 458c2ecf20Sopenharmony_ci#define PRU_INTC_SRSR(x) (0x0200 + (x) * 4) 468c2ecf20Sopenharmony_ci#define PRU_INTC_SECR(x) (0x0280 + (x) * 4) 478c2ecf20Sopenharmony_ci#define PRU_INTC_ESR(x) (0x0300 + (x) * 4) 488c2ecf20Sopenharmony_ci#define PRU_INTC_ECR(x) (0x0380 + (x) * 4) 498c2ecf20Sopenharmony_ci#define PRU_INTC_CMR(x) (0x0400 + (x) * 4) 508c2ecf20Sopenharmony_ci#define PRU_INTC_HMR(x) (0x0800 + (x) * 4) 518c2ecf20Sopenharmony_ci#define PRU_INTC_HIPIR(x) (0x0900 + (x) * 4) 528c2ecf20Sopenharmony_ci#define PRU_INTC_SIPR(x) (0x0d00 + (x) * 4) 538c2ecf20Sopenharmony_ci#define PRU_INTC_SITR(x) (0x0d80 + (x) * 4) 548c2ecf20Sopenharmony_ci#define PRU_INTC_HINLR(x) (0x1100 + (x) * 4) 558c2ecf20Sopenharmony_ci#define PRU_INTC_HIER 0x1500 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* CMR register bit-field macros */ 588c2ecf20Sopenharmony_ci#define CMR_EVT_MAP_MASK 0xf 598c2ecf20Sopenharmony_ci#define CMR_EVT_MAP_BITS 8 608c2ecf20Sopenharmony_ci#define CMR_EVT_PER_REG 4 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* HMR register bit-field macros */ 638c2ecf20Sopenharmony_ci#define HMR_CH_MAP_MASK 0xf 648c2ecf20Sopenharmony_ci#define HMR_CH_MAP_BITS 8 658c2ecf20Sopenharmony_ci#define HMR_CH_PER_REG 4 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* HIPIR register bit-fields */ 688c2ecf20Sopenharmony_ci#define INTC_HIPIR_NONE_HINT 0x80000000 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define MAX_PRU_SYS_EVENTS 160 718c2ecf20Sopenharmony_ci#define MAX_PRU_CHANNELS 20 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/** 748c2ecf20Sopenharmony_ci * struct pruss_intc_map_record - keeps track of actual mapping state 758c2ecf20Sopenharmony_ci * @value: The currently mapped value (channel or host) 768c2ecf20Sopenharmony_ci * @ref_count: Keeps track of number of current users of this resource 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistruct pruss_intc_map_record { 798c2ecf20Sopenharmony_ci u8 value; 808c2ecf20Sopenharmony_ci u8 ref_count; 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/** 848c2ecf20Sopenharmony_ci * struct pruss_intc_match_data - match data to handle SoC variations 858c2ecf20Sopenharmony_ci * @num_system_events: number of input system events handled by the PRUSS INTC 868c2ecf20Sopenharmony_ci * @num_host_events: number of host events (which is equal to number of 878c2ecf20Sopenharmony_ci * channels) supported by the PRUSS INTC 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_cistruct pruss_intc_match_data { 908c2ecf20Sopenharmony_ci u8 num_system_events; 918c2ecf20Sopenharmony_ci u8 num_host_events; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/** 958c2ecf20Sopenharmony_ci * struct pruss_intc - PRUSS interrupt controller structure 968c2ecf20Sopenharmony_ci * @event_channel: current state of system event to channel mappings 978c2ecf20Sopenharmony_ci * @channel_host: current state of channel to host mappings 988c2ecf20Sopenharmony_ci * @irqs: kernel irq numbers corresponding to PRUSS host interrupts 998c2ecf20Sopenharmony_ci * @base: base virtual address of INTC register space 1008c2ecf20Sopenharmony_ci * @domain: irq domain for this interrupt controller 1018c2ecf20Sopenharmony_ci * @soc_config: cached PRUSS INTC IP configuration data 1028c2ecf20Sopenharmony_ci * @dev: PRUSS INTC device pointer 1038c2ecf20Sopenharmony_ci * @lock: mutex to serialize interrupts mapping 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistruct pruss_intc { 1068c2ecf20Sopenharmony_ci struct pruss_intc_map_record event_channel[MAX_PRU_SYS_EVENTS]; 1078c2ecf20Sopenharmony_ci struct pruss_intc_map_record channel_host[MAX_PRU_CHANNELS]; 1088c2ecf20Sopenharmony_ci unsigned int irqs[MAX_NUM_HOST_IRQS]; 1098c2ecf20Sopenharmony_ci void __iomem *base; 1108c2ecf20Sopenharmony_ci struct irq_domain *domain; 1118c2ecf20Sopenharmony_ci const struct pruss_intc_match_data *soc_config; 1128c2ecf20Sopenharmony_ci struct device *dev; 1138c2ecf20Sopenharmony_ci struct mutex lock; /* PRUSS INTC lock */ 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/** 1178c2ecf20Sopenharmony_ci * struct pruss_host_irq_data - PRUSS host irq data structure 1188c2ecf20Sopenharmony_ci * @intc: PRUSS interrupt controller pointer 1198c2ecf20Sopenharmony_ci * @host_irq: host irq number 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_cistruct pruss_host_irq_data { 1228c2ecf20Sopenharmony_ci struct pruss_intc *intc; 1238c2ecf20Sopenharmony_ci u8 host_irq; 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic inline u32 pruss_intc_read_reg(struct pruss_intc *intc, unsigned int reg) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci return readl_relaxed(intc->base + reg); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic inline void pruss_intc_write_reg(struct pruss_intc *intc, 1328c2ecf20Sopenharmony_ci unsigned int reg, u32 val) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci writel_relaxed(val, intc->base + reg); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void pruss_intc_update_cmr(struct pruss_intc *intc, unsigned int evt, 1388c2ecf20Sopenharmony_ci u8 ch) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci u32 idx, offset, val; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci idx = evt / CMR_EVT_PER_REG; 1438c2ecf20Sopenharmony_ci offset = (evt % CMR_EVT_PER_REG) * CMR_EVT_MAP_BITS; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci val = pruss_intc_read_reg(intc, PRU_INTC_CMR(idx)); 1468c2ecf20Sopenharmony_ci val &= ~(CMR_EVT_MAP_MASK << offset); 1478c2ecf20Sopenharmony_ci val |= ch << offset; 1488c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_CMR(idx), val); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci dev_dbg(intc->dev, "SYSEV%u -> CH%d (CMR%d 0x%08x)\n", evt, ch, 1518c2ecf20Sopenharmony_ci idx, pruss_intc_read_reg(intc, PRU_INTC_CMR(idx))); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic void pruss_intc_update_hmr(struct pruss_intc *intc, u8 ch, u8 host) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci u32 idx, offset, val; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci idx = ch / HMR_CH_PER_REG; 1598c2ecf20Sopenharmony_ci offset = (ch % HMR_CH_PER_REG) * HMR_CH_MAP_BITS; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci val = pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)); 1628c2ecf20Sopenharmony_ci val &= ~(HMR_CH_MAP_MASK << offset); 1638c2ecf20Sopenharmony_ci val |= host << offset; 1648c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_HMR(idx), val); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci dev_dbg(intc->dev, "CH%d -> HOST%d (HMR%d 0x%08x)\n", ch, host, idx, 1678c2ecf20Sopenharmony_ci pruss_intc_read_reg(intc, PRU_INTC_HMR(idx))); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/** 1718c2ecf20Sopenharmony_ci * pruss_intc_map() - configure the PRUSS INTC 1728c2ecf20Sopenharmony_ci * @intc: PRUSS interrupt controller pointer 1738c2ecf20Sopenharmony_ci * @hwirq: the system event number 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * Configures the PRUSS INTC with the provided configuration from the one parsed 1768c2ecf20Sopenharmony_ci * in the xlate function. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_cistatic void pruss_intc_map(struct pruss_intc *intc, unsigned long hwirq) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct device *dev = intc->dev; 1818c2ecf20Sopenharmony_ci u8 ch, host, reg_idx; 1828c2ecf20Sopenharmony_ci u32 val; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci mutex_lock(&intc->lock); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci intc->event_channel[hwirq].ref_count++; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci ch = intc->event_channel[hwirq].value; 1898c2ecf20Sopenharmony_ci host = intc->channel_host[ch].value; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci pruss_intc_update_cmr(intc, hwirq, ch); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci reg_idx = hwirq / 32; 1948c2ecf20Sopenharmony_ci val = BIT(hwirq % 32); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* clear and enable system event */ 1978c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_ESR(reg_idx), val); 1988c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_SECR(reg_idx), val); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (++intc->channel_host[ch].ref_count == 1) { 2018c2ecf20Sopenharmony_ci pruss_intc_update_hmr(intc, ch, host); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* enable host interrupts */ 2048c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_HIEISR, host); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci dev_dbg(dev, "mapped system_event = %lu channel = %d host = %d", 2088c2ecf20Sopenharmony_ci hwirq, ch, host); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci mutex_unlock(&intc->lock); 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/** 2148c2ecf20Sopenharmony_ci * pruss_intc_unmap() - unconfigure the PRUSS INTC 2158c2ecf20Sopenharmony_ci * @intc: PRUSS interrupt controller pointer 2168c2ecf20Sopenharmony_ci * @hwirq: the system event number 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * Undo whatever was done in pruss_intc_map() for a PRU core. 2198c2ecf20Sopenharmony_ci * Mappings are reference counted, so resources are only disabled when there 2208c2ecf20Sopenharmony_ci * are no longer any users. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_cistatic void pruss_intc_unmap(struct pruss_intc *intc, unsigned long hwirq) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci u8 ch, host, reg_idx; 2258c2ecf20Sopenharmony_ci u32 val; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci mutex_lock(&intc->lock); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci ch = intc->event_channel[hwirq].value; 2308c2ecf20Sopenharmony_ci host = intc->channel_host[ch].value; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (--intc->channel_host[ch].ref_count == 0) { 2338c2ecf20Sopenharmony_ci /* disable host interrupts */ 2348c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_HIDISR, host); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* clear the map using reset value 0 */ 2378c2ecf20Sopenharmony_ci pruss_intc_update_hmr(intc, ch, 0); 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci intc->event_channel[hwirq].ref_count--; 2418c2ecf20Sopenharmony_ci reg_idx = hwirq / 32; 2428c2ecf20Sopenharmony_ci val = BIT(hwirq % 32); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* disable system events */ 2458c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_ECR(reg_idx), val); 2468c2ecf20Sopenharmony_ci /* clear any pending status */ 2478c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_SECR(reg_idx), val); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* clear the map using reset value 0 */ 2508c2ecf20Sopenharmony_ci pruss_intc_update_cmr(intc, hwirq, 0); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci dev_dbg(intc->dev, "unmapped system_event = %lu channel = %d host = %d\n", 2538c2ecf20Sopenharmony_ci hwirq, ch, host); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci mutex_unlock(&intc->lock); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void pruss_intc_init(struct pruss_intc *intc) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci const struct pruss_intc_match_data *soc_config = intc->soc_config; 2618c2ecf20Sopenharmony_ci int num_chnl_map_regs, num_host_intr_regs, num_event_type_regs, i; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci num_chnl_map_regs = DIV_ROUND_UP(soc_config->num_system_events, 2648c2ecf20Sopenharmony_ci CMR_EVT_PER_REG); 2658c2ecf20Sopenharmony_ci num_host_intr_regs = DIV_ROUND_UP(soc_config->num_host_events, 2668c2ecf20Sopenharmony_ci HMR_CH_PER_REG); 2678c2ecf20Sopenharmony_ci num_event_type_regs = DIV_ROUND_UP(soc_config->num_system_events, 32); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* 2708c2ecf20Sopenharmony_ci * configure polarity (SIPR register) to active high and 2718c2ecf20Sopenharmony_ci * type (SITR register) to level interrupt for all system events 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci for (i = 0; i < num_event_type_regs; i++) { 2748c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_SIPR(i), 0xffffffff); 2758c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_SITR(i), 0); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* clear all interrupt channel map registers, 4 events per register */ 2798c2ecf20Sopenharmony_ci for (i = 0; i < num_chnl_map_regs; i++) 2808c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_CMR(i), 0); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* clear all host interrupt map registers, 4 channels per register */ 2838c2ecf20Sopenharmony_ci for (i = 0; i < num_host_intr_regs; i++) 2848c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_HMR(i), 0); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* global interrupt enable */ 2878c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_GER, 1); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void pruss_intc_irq_ack(struct irq_data *data) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct pruss_intc *intc = irq_data_get_irq_chip_data(data); 2938c2ecf20Sopenharmony_ci unsigned int hwirq = data->hwirq; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic void pruss_intc_irq_mask(struct irq_data *data) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct pruss_intc *intc = irq_data_get_irq_chip_data(data); 3018c2ecf20Sopenharmony_ci unsigned int hwirq = data->hwirq; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_EICR, hwirq); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void pruss_intc_irq_unmask(struct irq_data *data) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct pruss_intc *intc = irq_data_get_irq_chip_data(data); 3098c2ecf20Sopenharmony_ci unsigned int hwirq = data->hwirq; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_EISR, hwirq); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int pruss_intc_irq_reqres(struct irq_data *data) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 3178c2ecf20Sopenharmony_ci return -ENODEV; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic void pruss_intc_irq_relres(struct irq_data *data) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int pruss_intc_irq_get_irqchip_state(struct irq_data *data, 3288c2ecf20Sopenharmony_ci enum irqchip_irq_state which, 3298c2ecf20Sopenharmony_ci bool *state) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct pruss_intc *intc = irq_data_get_irq_chip_data(data); 3328c2ecf20Sopenharmony_ci u32 reg, mask, srsr; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (which != IRQCHIP_STATE_PENDING) 3358c2ecf20Sopenharmony_ci return -EINVAL; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci reg = PRU_INTC_SRSR(data->hwirq / 32); 3388c2ecf20Sopenharmony_ci mask = BIT(data->hwirq % 32); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci srsr = pruss_intc_read_reg(intc, reg); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci *state = !!(srsr & mask); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int pruss_intc_irq_set_irqchip_state(struct irq_data *data, 3488c2ecf20Sopenharmony_ci enum irqchip_irq_state which, 3498c2ecf20Sopenharmony_ci bool state) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct pruss_intc *intc = irq_data_get_irq_chip_data(data); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (which != IRQCHIP_STATE_PENDING) 3548c2ecf20Sopenharmony_ci return -EINVAL; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (state) 3578c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_SISR, data->hwirq); 3588c2ecf20Sopenharmony_ci else 3598c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_SICR, data->hwirq); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return 0; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic struct irq_chip pruss_irqchip = { 3658c2ecf20Sopenharmony_ci .name = "pruss-intc", 3668c2ecf20Sopenharmony_ci .irq_ack = pruss_intc_irq_ack, 3678c2ecf20Sopenharmony_ci .irq_mask = pruss_intc_irq_mask, 3688c2ecf20Sopenharmony_ci .irq_unmask = pruss_intc_irq_unmask, 3698c2ecf20Sopenharmony_ci .irq_request_resources = pruss_intc_irq_reqres, 3708c2ecf20Sopenharmony_ci .irq_release_resources = pruss_intc_irq_relres, 3718c2ecf20Sopenharmony_ci .irq_get_irqchip_state = pruss_intc_irq_get_irqchip_state, 3728c2ecf20Sopenharmony_ci .irq_set_irqchip_state = pruss_intc_irq_set_irqchip_state, 3738c2ecf20Sopenharmony_ci}; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int pruss_intc_validate_mapping(struct pruss_intc *intc, int event, 3768c2ecf20Sopenharmony_ci int channel, int host) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct device *dev = intc->dev; 3798c2ecf20Sopenharmony_ci int ret = 0; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci mutex_lock(&intc->lock); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* check if sysevent already assigned */ 3848c2ecf20Sopenharmony_ci if (intc->event_channel[event].ref_count > 0 && 3858c2ecf20Sopenharmony_ci intc->event_channel[event].value != channel) { 3868c2ecf20Sopenharmony_ci dev_err(dev, "event %d (req. ch %d) already assigned to channel %d\n", 3878c2ecf20Sopenharmony_ci event, channel, intc->event_channel[event].value); 3888c2ecf20Sopenharmony_ci ret = -EBUSY; 3898c2ecf20Sopenharmony_ci goto unlock; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* check if channel already assigned */ 3938c2ecf20Sopenharmony_ci if (intc->channel_host[channel].ref_count > 0 && 3948c2ecf20Sopenharmony_ci intc->channel_host[channel].value != host) { 3958c2ecf20Sopenharmony_ci dev_err(dev, "channel %d (req. host %d) already assigned to host %d\n", 3968c2ecf20Sopenharmony_ci channel, host, intc->channel_host[channel].value); 3978c2ecf20Sopenharmony_ci ret = -EBUSY; 3988c2ecf20Sopenharmony_ci goto unlock; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci intc->event_channel[event].value = channel; 4028c2ecf20Sopenharmony_ci intc->channel_host[channel].value = host; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ciunlock: 4058c2ecf20Sopenharmony_ci mutex_unlock(&intc->lock); 4068c2ecf20Sopenharmony_ci return ret; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic int 4108c2ecf20Sopenharmony_cipruss_intc_irq_domain_xlate(struct irq_domain *d, struct device_node *node, 4118c2ecf20Sopenharmony_ci const u32 *intspec, unsigned int intsize, 4128c2ecf20Sopenharmony_ci unsigned long *out_hwirq, unsigned int *out_type) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct pruss_intc *intc = d->host_data; 4158c2ecf20Sopenharmony_ci struct device *dev = intc->dev; 4168c2ecf20Sopenharmony_ci int ret, sys_event, channel, host; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (intsize < 3) 4198c2ecf20Sopenharmony_ci return -EINVAL; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci sys_event = intspec[0]; 4228c2ecf20Sopenharmony_ci if (sys_event < 0 || sys_event >= intc->soc_config->num_system_events) { 4238c2ecf20Sopenharmony_ci dev_err(dev, "%d is not valid event number\n", sys_event); 4248c2ecf20Sopenharmony_ci return -EINVAL; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci channel = intspec[1]; 4288c2ecf20Sopenharmony_ci if (channel < 0 || channel >= intc->soc_config->num_host_events) { 4298c2ecf20Sopenharmony_ci dev_err(dev, "%d is not valid channel number", channel); 4308c2ecf20Sopenharmony_ci return -EINVAL; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci host = intspec[2]; 4348c2ecf20Sopenharmony_ci if (host < 0 || host >= intc->soc_config->num_host_events) { 4358c2ecf20Sopenharmony_ci dev_err(dev, "%d is not valid host irq number\n", host); 4368c2ecf20Sopenharmony_ci return -EINVAL; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* check if requested sys_event was already mapped, if so validate it */ 4408c2ecf20Sopenharmony_ci ret = pruss_intc_validate_mapping(intc, sys_event, channel, host); 4418c2ecf20Sopenharmony_ci if (ret) 4428c2ecf20Sopenharmony_ci return ret; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci *out_hwirq = sys_event; 4458c2ecf20Sopenharmony_ci *out_type = IRQ_TYPE_LEVEL_HIGH; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int pruss_intc_irq_domain_map(struct irq_domain *d, unsigned int virq, 4518c2ecf20Sopenharmony_ci irq_hw_number_t hw) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct pruss_intc *intc = d->host_data; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci pruss_intc_map(intc, hw); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci irq_set_chip_data(virq, intc); 4588c2ecf20Sopenharmony_ci irq_set_chip_and_handler(virq, &pruss_irqchip, handle_level_irq); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic void pruss_intc_irq_domain_unmap(struct irq_domain *d, unsigned int virq) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct pruss_intc *intc = d->host_data; 4668c2ecf20Sopenharmony_ci unsigned long hwirq = irqd_to_hwirq(irq_get_irq_data(virq)); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci irq_set_chip_and_handler(virq, NULL, NULL); 4698c2ecf20Sopenharmony_ci irq_set_chip_data(virq, NULL); 4708c2ecf20Sopenharmony_ci pruss_intc_unmap(intc, hwirq); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic const struct irq_domain_ops pruss_intc_irq_domain_ops = { 4748c2ecf20Sopenharmony_ci .xlate = pruss_intc_irq_domain_xlate, 4758c2ecf20Sopenharmony_ci .map = pruss_intc_irq_domain_map, 4768c2ecf20Sopenharmony_ci .unmap = pruss_intc_irq_domain_unmap, 4778c2ecf20Sopenharmony_ci}; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void pruss_intc_irq_handler(struct irq_desc *desc) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci unsigned int irq = irq_desc_get_irq(desc); 4828c2ecf20Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 4838c2ecf20Sopenharmony_ci struct pruss_host_irq_data *host_irq_data = irq_get_handler_data(irq); 4848c2ecf20Sopenharmony_ci struct pruss_intc *intc = host_irq_data->intc; 4858c2ecf20Sopenharmony_ci u8 host_irq = host_irq_data->host_irq + FIRST_PRU_HOST_INT; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci chained_irq_enter(chip, desc); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci while (true) { 4908c2ecf20Sopenharmony_ci u32 hipir; 4918c2ecf20Sopenharmony_ci unsigned int virq; 4928c2ecf20Sopenharmony_ci int hwirq; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* get highest priority pending PRUSS system event */ 4958c2ecf20Sopenharmony_ci hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(host_irq)); 4968c2ecf20Sopenharmony_ci if (hipir & INTC_HIPIR_NONE_HINT) 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci hwirq = hipir & GENMASK(9, 0); 5008c2ecf20Sopenharmony_ci virq = irq_find_mapping(intc->domain, hwirq); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* 5038c2ecf20Sopenharmony_ci * NOTE: manually ACK any system events that do not have a 5048c2ecf20Sopenharmony_ci * handler mapped yet 5058c2ecf20Sopenharmony_ci */ 5068c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!virq)) 5078c2ecf20Sopenharmony_ci pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq); 5088c2ecf20Sopenharmony_ci else 5098c2ecf20Sopenharmony_ci generic_handle_irq(virq); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci chained_irq_exit(chip, desc); 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic const char * const irq_names[MAX_NUM_HOST_IRQS] = { 5168c2ecf20Sopenharmony_ci "host_intr0", "host_intr1", "host_intr2", "host_intr3", 5178c2ecf20Sopenharmony_ci "host_intr4", "host_intr5", "host_intr6", "host_intr7", 5188c2ecf20Sopenharmony_ci}; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int pruss_intc_probe(struct platform_device *pdev) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci const struct pruss_intc_match_data *data; 5238c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5248c2ecf20Sopenharmony_ci struct pruss_intc *intc; 5258c2ecf20Sopenharmony_ci struct pruss_host_irq_data *host_data; 5268c2ecf20Sopenharmony_ci int i, irq, ret; 5278c2ecf20Sopenharmony_ci u8 max_system_events, irqs_reserved = 0; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci data = of_device_get_match_data(dev); 5308c2ecf20Sopenharmony_ci if (!data) 5318c2ecf20Sopenharmony_ci return -ENODEV; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci max_system_events = data->num_system_events; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL); 5368c2ecf20Sopenharmony_ci if (!intc) 5378c2ecf20Sopenharmony_ci return -ENOMEM; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci intc->soc_config = data; 5408c2ecf20Sopenharmony_ci intc->dev = dev; 5418c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, intc); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci intc->base = devm_platform_ioremap_resource(pdev, 0); 5448c2ecf20Sopenharmony_ci if (IS_ERR(intc->base)) 5458c2ecf20Sopenharmony_ci return PTR_ERR(intc->base); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ret = of_property_read_u8(dev->of_node, "ti,irqs-reserved", 5488c2ecf20Sopenharmony_ci &irqs_reserved); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* 5518c2ecf20Sopenharmony_ci * The irqs-reserved is used only for some SoC's therefore not having 5528c2ecf20Sopenharmony_ci * this property is still valid 5538c2ecf20Sopenharmony_ci */ 5548c2ecf20Sopenharmony_ci if (ret < 0 && ret != -EINVAL) 5558c2ecf20Sopenharmony_ci return ret; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci pruss_intc_init(intc); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci mutex_init(&intc->lock); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci intc->domain = irq_domain_add_linear(dev->of_node, max_system_events, 5628c2ecf20Sopenharmony_ci &pruss_intc_irq_domain_ops, intc); 5638c2ecf20Sopenharmony_ci if (!intc->domain) 5648c2ecf20Sopenharmony_ci return -ENOMEM; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NUM_HOST_IRQS; i++) { 5678c2ecf20Sopenharmony_ci if (irqs_reserved & BIT(i)) 5688c2ecf20Sopenharmony_ci continue; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, irq_names[i]); 5718c2ecf20Sopenharmony_ci if (irq <= 0) { 5728c2ecf20Sopenharmony_ci ret = (irq == 0) ? -EINVAL : irq; 5738c2ecf20Sopenharmony_ci goto fail_irq; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci intc->irqs[i] = irq; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL); 5798c2ecf20Sopenharmony_ci if (!host_data) { 5808c2ecf20Sopenharmony_ci ret = -ENOMEM; 5818c2ecf20Sopenharmony_ci goto fail_irq; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci host_data->intc = intc; 5858c2ecf20Sopenharmony_ci host_data->host_irq = i; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci irq_set_handler_data(irq, host_data); 5888c2ecf20Sopenharmony_ci irq_set_chained_handler(irq, pruss_intc_irq_handler); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci return 0; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cifail_irq: 5948c2ecf20Sopenharmony_ci while (--i >= 0) { 5958c2ecf20Sopenharmony_ci if (intc->irqs[i]) 5968c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(intc->irqs[i], NULL, 5978c2ecf20Sopenharmony_ci NULL); 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci irq_domain_remove(intc->domain); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return ret; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int pruss_intc_remove(struct platform_device *pdev) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct pruss_intc *intc = platform_get_drvdata(pdev); 6088c2ecf20Sopenharmony_ci u8 max_system_events = intc->soc_config->num_system_events; 6098c2ecf20Sopenharmony_ci unsigned int hwirq; 6108c2ecf20Sopenharmony_ci int i; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NUM_HOST_IRQS; i++) { 6138c2ecf20Sopenharmony_ci if (intc->irqs[i]) 6148c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(intc->irqs[i], NULL, 6158c2ecf20Sopenharmony_ci NULL); 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci for (hwirq = 0; hwirq < max_system_events; hwirq++) 6198c2ecf20Sopenharmony_ci irq_dispose_mapping(irq_find_mapping(intc->domain, hwirq)); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci irq_domain_remove(intc->domain); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return 0; 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic const struct pruss_intc_match_data pruss_intc_data = { 6278c2ecf20Sopenharmony_ci .num_system_events = 64, 6288c2ecf20Sopenharmony_ci .num_host_events = 10, 6298c2ecf20Sopenharmony_ci}; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic const struct pruss_intc_match_data icssg_intc_data = { 6328c2ecf20Sopenharmony_ci .num_system_events = 160, 6338c2ecf20Sopenharmony_ci .num_host_events = 20, 6348c2ecf20Sopenharmony_ci}; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic const struct of_device_id pruss_intc_of_match[] = { 6378c2ecf20Sopenharmony_ci { 6388c2ecf20Sopenharmony_ci .compatible = "ti,pruss-intc", 6398c2ecf20Sopenharmony_ci .data = &pruss_intc_data, 6408c2ecf20Sopenharmony_ci }, 6418c2ecf20Sopenharmony_ci { 6428c2ecf20Sopenharmony_ci .compatible = "ti,icssg-intc", 6438c2ecf20Sopenharmony_ci .data = &icssg_intc_data, 6448c2ecf20Sopenharmony_ci }, 6458c2ecf20Sopenharmony_ci { /* sentinel */ }, 6468c2ecf20Sopenharmony_ci}; 6478c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pruss_intc_of_match); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic struct platform_driver pruss_intc_driver = { 6508c2ecf20Sopenharmony_ci .driver = { 6518c2ecf20Sopenharmony_ci .name = "pruss-intc", 6528c2ecf20Sopenharmony_ci .of_match_table = pruss_intc_of_match, 6538c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 6548c2ecf20Sopenharmony_ci }, 6558c2ecf20Sopenharmony_ci .probe = pruss_intc_probe, 6568c2ecf20Sopenharmony_ci .remove = pruss_intc_remove, 6578c2ecf20Sopenharmony_ci}; 6588c2ecf20Sopenharmony_cimodule_platform_driver(pruss_intc_driver); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); 6618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Suman Anna <s-anna@ti.com>"); 6628c2ecf20Sopenharmony_ciMODULE_AUTHOR("Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>"); 6638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI PRU-ICSS INTC Driver"); 6648c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 665