^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) // Copyright 2017 NXP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) /* INTMUX Block Diagram
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * ________________
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * interrupt source # 0 +---->| |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * interrupt source # 1 +++-->| |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * ... | | | channel # 0 |--------->interrupt out # 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * ... | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * ... | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * interrupt source # X-1 +++-->|________________|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * | | | ________________
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * +---->| |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * | | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * | +-->| |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * | | | | channel # 1 |--------->interrupt out # 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * | | +>| |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * | | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * | | | |________________|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * | | | ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * | | | ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * | | | ________________
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * +---->| |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * +-->| |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * | | channel # N |--------->interrupt out # N
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * +>| |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * |________________|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * N: Interrupt Channel Instance Number (N=7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * X: Interrupt Source Number for each channel (X=32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * The INTMUX interrupt multiplexer has 8 channels, each channel receives 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * interrupt sources and generates 1 interrupt output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #include <linux/irqchip/chained_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #include <linux/irqdomain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define CHANIER(n) (0x10 + (0x40 * n))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define CHANIPR(n) (0x20 + (0x40 * n))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define CHAN_MAX_NUM 0x8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct intmux_irqchip_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct irq_chip chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u32 saved_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) int chanidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct irq_domain *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct intmux_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) raw_spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct clk *ipg_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) int channum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct intmux_irqchip_data irqchip_data[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static void imx_intmux_irq_mask(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct intmux_irqchip_data *irqchip_data = d->chip_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int idx = irqchip_data->chanidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct intmux_data *data = container_of(irqchip_data, struct intmux_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) irqchip_data[idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) raw_spin_lock_irqsave(&data->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) reg = data->regs + CHANIER(idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) val = readl_relaxed(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* disable the interrupt source of this channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) val &= ~BIT(d->hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) writel_relaxed(val, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) raw_spin_unlock_irqrestore(&data->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static void imx_intmux_irq_unmask(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct intmux_irqchip_data *irqchip_data = d->chip_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) int idx = irqchip_data->chanidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct intmux_data *data = container_of(irqchip_data, struct intmux_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) irqchip_data[idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) raw_spin_lock_irqsave(&data->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) reg = data->regs + CHANIER(idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) val = readl_relaxed(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* enable the interrupt source of this channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) val |= BIT(d->hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) writel_relaxed(val, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) raw_spin_unlock_irqrestore(&data->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static struct irq_chip imx_intmux_irq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .name = "intmux",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .irq_mask = imx_intmux_irq_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .irq_unmask = imx_intmux_irq_unmask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static int imx_intmux_irq_map(struct irq_domain *h, unsigned int irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) irq_hw_number_t hwirq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct intmux_irqchip_data *data = h->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) irq_set_chip_data(irq, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) irq_set_chip_and_handler(irq, &data->chip, handle_level_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static int imx_intmux_irq_xlate(struct irq_domain *d, struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) const u32 *intspec, unsigned int intsize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) unsigned long *out_hwirq, unsigned int *out_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) struct intmux_irqchip_data *irqchip_data = d->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) int idx = irqchip_data->chanidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct intmux_data *data = container_of(irqchip_data, struct intmux_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) irqchip_data[idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * two cells needed in interrupt specifier:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * the 1st cell: hw interrupt number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * the 2nd cell: channel index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (WARN_ON(intsize != 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (WARN_ON(intspec[1] >= data->channum))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) *out_hwirq = intspec[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) *out_type = IRQ_TYPE_LEVEL_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static int imx_intmux_irq_select(struct irq_domain *d, struct irq_fwspec *fwspec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) enum irq_domain_bus_token bus_token)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct intmux_irqchip_data *irqchip_data = d->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* Not for us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (fwspec->fwnode != d->fwnode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return irqchip_data->chanidx == fwspec->param[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static const struct irq_domain_ops imx_intmux_domain_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .map = imx_intmux_irq_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .xlate = imx_intmux_irq_xlate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .select = imx_intmux_irq_select,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static void imx_intmux_irq_handler(struct irq_desc *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct intmux_irqchip_data *irqchip_data = irq_desc_get_handler_data(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) int idx = irqchip_data->chanidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct intmux_data *data = container_of(irqchip_data, struct intmux_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) irqchip_data[idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) unsigned long irqstat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) int pos, virq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) chained_irq_enter(irq_desc_get_chip(desc), desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /* read the interrupt source pending status of this channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) irqstat = readl_relaxed(data->regs + CHANIPR(idx));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) for_each_set_bit(pos, &irqstat, 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) virq = irq_find_mapping(irqchip_data->domain, pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (virq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) generic_handle_irq(virq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) chained_irq_exit(irq_desc_get_chip(desc), desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static int imx_intmux_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct device_node *np = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct irq_domain *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) struct intmux_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int channum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) channum = platform_irq_count(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (channum == -EPROBE_DEFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) } else if (channum > CHAN_MAX_NUM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) dev_err(&pdev->dev, "supports up to %d multiplex channels\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) CHAN_MAX_NUM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) data = devm_kzalloc(&pdev->dev, struct_size(data, irqchip_data, channum), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) data->regs = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (IS_ERR(data->regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) dev_err(&pdev->dev, "failed to initialize reg\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return PTR_ERR(data->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) data->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (IS_ERR(data->ipg_clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return dev_err_probe(&pdev->dev, PTR_ERR(data->ipg_clk),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) "failed to get ipg clk\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) data->channum = channum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) raw_spin_lock_init(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) pm_runtime_get_noresume(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) pm_runtime_set_active(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) pm_runtime_enable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) ret = clk_prepare_enable(data->ipg_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) dev_err(&pdev->dev, "failed to enable ipg clk: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) for (i = 0; i < channum; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) data->irqchip_data[i].chip = imx_intmux_irq_chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) data->irqchip_data[i].chip.parent_device = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) data->irqchip_data[i].chanidx = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) data->irqchip_data[i].irq = irq_of_parse_and_map(np, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (data->irqchip_data[i].irq <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) dev_err(&pdev->dev, "failed to get irq\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) domain = irq_domain_add_linear(np, 32, &imx_intmux_domain_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) &data->irqchip_data[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (!domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) dev_err(&pdev->dev, "failed to create IRQ domain\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) data->irqchip_data[i].domain = domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /* disable all interrupt sources of this channel firstly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) writel_relaxed(0, data->regs + CHANIER(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) irq_set_chained_handler_and_data(data->irqchip_data[i].irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) imx_intmux_irq_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) &data->irqchip_data[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) platform_set_drvdata(pdev, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * Let pm_runtime_put() disable clock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * If CONFIG_PM is not enabled, the clock will stay powered.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) pm_runtime_put(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) clk_disable_unprepare(data->ipg_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static int imx_intmux_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) struct intmux_data *data = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) for (i = 0; i < data->channum; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) /* disable all interrupt sources of this channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) writel_relaxed(0, data->regs + CHANIER(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) irq_set_chained_handler_and_data(data->irqchip_data[i].irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) irq_domain_remove(data->irqchip_data[i].domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) static int imx_intmux_runtime_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) struct intmux_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) struct intmux_irqchip_data *irqchip_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) for (i = 0; i < data->channum; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) irqchip_data = &data->irqchip_data[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) irqchip_data->saved_reg = readl_relaxed(data->regs + CHANIER(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) clk_disable_unprepare(data->ipg_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static int imx_intmux_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) struct intmux_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) struct intmux_irqchip_data *irqchip_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) ret = clk_prepare_enable(data->ipg_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) dev_err(dev, "failed to enable ipg clk: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) for (i = 0; i < data->channum; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) irqchip_data = &data->irqchip_data[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) writel_relaxed(irqchip_data->saved_reg, data->regs + CHANIER(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static const struct dev_pm_ops imx_intmux_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) pm_runtime_force_resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) SET_RUNTIME_PM_OPS(imx_intmux_runtime_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) imx_intmux_runtime_resume, NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) static const struct of_device_id imx_intmux_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) { .compatible = "fsl,imx-intmux", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) { /* sentinel */ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) static struct platform_driver imx_intmux_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) .name = "imx-intmux",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) .of_match_table = imx_intmux_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) .pm = &imx_intmux_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) .probe = imx_intmux_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) .remove = imx_intmux_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) builtin_platform_driver(imx_intmux_driver);