1*37571febSLiu Ying // SPDX-License-Identifier: GPL-2.0+ 2*37571febSLiu Ying /* 3*37571febSLiu Ying * Copyright 2024 NXP 4*37571febSLiu Ying */ 5*37571febSLiu Ying 6*37571febSLiu Ying #include <linux/clk.h> 7*37571febSLiu Ying #include <linux/interrupt.h> 8*37571febSLiu Ying #include <linux/irq.h> 9*37571febSLiu Ying #include <linux/irqchip/chained_irq.h> 10*37571febSLiu Ying #include <linux/irqdomain.h> 11*37571febSLiu Ying #include <linux/of.h> 12*37571febSLiu Ying #include <linux/of_irq.h> 13*37571febSLiu Ying #include <linux/platform_device.h> 14*37571febSLiu Ying #include <linux/pm_runtime.h> 15*37571febSLiu Ying #include <linux/regmap.h> 16*37571febSLiu Ying 17*37571febSLiu Ying #define USERINTERRUPTMASK(n) (0x8 + 4 * (n)) 18*37571febSLiu Ying #define INTERRUPTENABLE(n) (0x10 + 4 * (n)) 19*37571febSLiu Ying #define INTERRUPTPRESET(n) (0x18 + 4 * (n)) 20*37571febSLiu Ying #define INTERRUPTCLEAR(n) (0x20 + 4 * (n)) 21*37571febSLiu Ying #define INTERRUPTSTATUS(n) (0x28 + 4 * (n)) 22*37571febSLiu Ying #define USERINTERRUPTENABLE(n) (0x40 + 4 * (n)) 23*37571febSLiu Ying #define USERINTERRUPTPRESET(n) (0x48 + 4 * (n)) 24*37571febSLiu Ying #define USERINTERRUPTCLEAR(n) (0x50 + 4 * (n)) 25*37571febSLiu Ying #define USERINTERRUPTSTATUS(n) (0x58 + 4 * (n)) 26*37571febSLiu Ying 27*37571febSLiu Ying #define IRQ_COUNT 49 28*37571febSLiu Ying #define IRQ_RESERVED 35 29*37571febSLiu Ying #define REG_NUM 2 30*37571febSLiu Ying 31*37571febSLiu Ying struct dc_ic_data { 32*37571febSLiu Ying struct regmap *regs; 33*37571febSLiu Ying struct clk *clk_axi; 34*37571febSLiu Ying int irq[IRQ_COUNT]; 35*37571febSLiu Ying struct irq_domain *domain; 36*37571febSLiu Ying }; 37*37571febSLiu Ying 38*37571febSLiu Ying struct dc_ic_entry { 39*37571febSLiu Ying struct dc_ic_data *data; 40*37571febSLiu Ying int irq; 41*37571febSLiu Ying }; 42*37571febSLiu Ying 43*37571febSLiu Ying static const struct regmap_range dc_ic_regmap_write_ranges[] = { 44*37571febSLiu Ying regmap_reg_range(USERINTERRUPTMASK(0), INTERRUPTCLEAR(1)), 45*37571febSLiu Ying regmap_reg_range(USERINTERRUPTENABLE(0), USERINTERRUPTCLEAR(1)), 46*37571febSLiu Ying }; 47*37571febSLiu Ying 48*37571febSLiu Ying static const struct regmap_access_table dc_ic_regmap_write_table = { 49*37571febSLiu Ying .yes_ranges = dc_ic_regmap_write_ranges, 50*37571febSLiu Ying .n_yes_ranges = ARRAY_SIZE(dc_ic_regmap_write_ranges), 51*37571febSLiu Ying }; 52*37571febSLiu Ying 53*37571febSLiu Ying static const struct regmap_range dc_ic_regmap_read_ranges[] = { 54*37571febSLiu Ying regmap_reg_range(USERINTERRUPTMASK(0), INTERRUPTENABLE(1)), 55*37571febSLiu Ying regmap_reg_range(INTERRUPTSTATUS(0), INTERRUPTSTATUS(1)), 56*37571febSLiu Ying regmap_reg_range(USERINTERRUPTENABLE(0), USERINTERRUPTENABLE(1)), 57*37571febSLiu Ying regmap_reg_range(USERINTERRUPTSTATUS(0), USERINTERRUPTSTATUS(1)), 58*37571febSLiu Ying }; 59*37571febSLiu Ying 60*37571febSLiu Ying static const struct regmap_access_table dc_ic_regmap_read_table = { 61*37571febSLiu Ying .yes_ranges = dc_ic_regmap_read_ranges, 62*37571febSLiu Ying .n_yes_ranges = ARRAY_SIZE(dc_ic_regmap_read_ranges), 63*37571febSLiu Ying }; 64*37571febSLiu Ying 65*37571febSLiu Ying static const struct regmap_range dc_ic_regmap_volatile_ranges[] = { 66*37571febSLiu Ying regmap_reg_range(INTERRUPTPRESET(0), INTERRUPTCLEAR(1)), 67*37571febSLiu Ying regmap_reg_range(USERINTERRUPTPRESET(0), USERINTERRUPTCLEAR(1)), 68*37571febSLiu Ying }; 69*37571febSLiu Ying 70*37571febSLiu Ying static const struct regmap_access_table dc_ic_regmap_volatile_table = { 71*37571febSLiu Ying .yes_ranges = dc_ic_regmap_volatile_ranges, 72*37571febSLiu Ying .n_yes_ranges = ARRAY_SIZE(dc_ic_regmap_volatile_ranges), 73*37571febSLiu Ying }; 74*37571febSLiu Ying 75*37571febSLiu Ying static const struct regmap_config dc_ic_regmap_config = { 76*37571febSLiu Ying .reg_bits = 32, 77*37571febSLiu Ying .reg_stride = 4, 78*37571febSLiu Ying .val_bits = 32, 79*37571febSLiu Ying .fast_io = true, 80*37571febSLiu Ying .wr_table = &dc_ic_regmap_write_table, 81*37571febSLiu Ying .rd_table = &dc_ic_regmap_read_table, 82*37571febSLiu Ying .volatile_table = &dc_ic_regmap_volatile_table, 83*37571febSLiu Ying .max_register = USERINTERRUPTSTATUS(1), 84*37571febSLiu Ying }; 85*37571febSLiu Ying 86*37571febSLiu Ying static void dc_ic_irq_handler(struct irq_desc *desc) 87*37571febSLiu Ying { 88*37571febSLiu Ying struct dc_ic_entry *entry = irq_desc_get_handler_data(desc); 89*37571febSLiu Ying struct dc_ic_data *data = entry->data; 90*37571febSLiu Ying unsigned int status, enable; 91*37571febSLiu Ying unsigned int virq; 92*37571febSLiu Ying 93*37571febSLiu Ying chained_irq_enter(irq_desc_get_chip(desc), desc); 94*37571febSLiu Ying 95*37571febSLiu Ying regmap_read(data->regs, USERINTERRUPTSTATUS(entry->irq / 32), &status); 96*37571febSLiu Ying regmap_read(data->regs, USERINTERRUPTENABLE(entry->irq / 32), &enable); 97*37571febSLiu Ying 98*37571febSLiu Ying status &= enable; 99*37571febSLiu Ying 100*37571febSLiu Ying if (status & BIT(entry->irq % 32)) { 101*37571febSLiu Ying virq = irq_find_mapping(data->domain, entry->irq); 102*37571febSLiu Ying if (virq) 103*37571febSLiu Ying generic_handle_irq(virq); 104*37571febSLiu Ying } 105*37571febSLiu Ying 106*37571febSLiu Ying chained_irq_exit(irq_desc_get_chip(desc), desc); 107*37571febSLiu Ying } 108*37571febSLiu Ying 109*37571febSLiu Ying static const unsigned long unused_irq[REG_NUM] = {0x00000000, 0xfffe0008}; 110*37571febSLiu Ying 111*37571febSLiu Ying static int dc_ic_probe(struct platform_device *pdev) 112*37571febSLiu Ying { 113*37571febSLiu Ying struct device *dev = &pdev->dev; 114*37571febSLiu Ying struct irq_chip_generic *gc; 115*37571febSLiu Ying struct dc_ic_entry *entry; 116*37571febSLiu Ying struct irq_chip_type *ct; 117*37571febSLiu Ying struct dc_ic_data *data; 118*37571febSLiu Ying void __iomem *base; 119*37571febSLiu Ying int i, ret; 120*37571febSLiu Ying 121*37571febSLiu Ying data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 122*37571febSLiu Ying if (!data) 123*37571febSLiu Ying return -ENOMEM; 124*37571febSLiu Ying 125*37571febSLiu Ying entry = devm_kcalloc(dev, IRQ_COUNT, sizeof(*entry), GFP_KERNEL); 126*37571febSLiu Ying if (!entry) 127*37571febSLiu Ying return -ENOMEM; 128*37571febSLiu Ying 129*37571febSLiu Ying base = devm_platform_ioremap_resource(pdev, 0); 130*37571febSLiu Ying if (IS_ERR(base)) { 131*37571febSLiu Ying dev_err(dev, "failed to initialize reg\n"); 132*37571febSLiu Ying return PTR_ERR(base); 133*37571febSLiu Ying } 134*37571febSLiu Ying 135*37571febSLiu Ying data->regs = devm_regmap_init_mmio(dev, base, &dc_ic_regmap_config); 136*37571febSLiu Ying if (IS_ERR(data->regs)) 137*37571febSLiu Ying return PTR_ERR(data->regs); 138*37571febSLiu Ying 139*37571febSLiu Ying data->clk_axi = devm_clk_get(dev, NULL); 140*37571febSLiu Ying if (IS_ERR(data->clk_axi)) 141*37571febSLiu Ying return dev_err_probe(dev, PTR_ERR(data->clk_axi), 142*37571febSLiu Ying "failed to get AXI clock\n"); 143*37571febSLiu Ying 144*37571febSLiu Ying for (i = 0; i < IRQ_COUNT; i++) { 145*37571febSLiu Ying /* skip the reserved IRQ */ 146*37571febSLiu Ying if (i == IRQ_RESERVED) 147*37571febSLiu Ying continue; 148*37571febSLiu Ying 149*37571febSLiu Ying ret = platform_get_irq(pdev, i); 150*37571febSLiu Ying if (ret < 0) 151*37571febSLiu Ying return ret; 152*37571febSLiu Ying } 153*37571febSLiu Ying 154*37571febSLiu Ying dev_set_drvdata(dev, data); 155*37571febSLiu Ying 156*37571febSLiu Ying ret = devm_pm_runtime_enable(dev); 157*37571febSLiu Ying if (ret) 158*37571febSLiu Ying return ret; 159*37571febSLiu Ying 160*37571febSLiu Ying ret = pm_runtime_resume_and_get(dev); 161*37571febSLiu Ying if (ret < 0) { 162*37571febSLiu Ying dev_err(dev, "failed to get runtime PM sync: %d\n", ret); 163*37571febSLiu Ying return ret; 164*37571febSLiu Ying } 165*37571febSLiu Ying 166*37571febSLiu Ying for (i = 0; i < REG_NUM; i++) { 167*37571febSLiu Ying /* mask and clear all interrupts */ 168*37571febSLiu Ying regmap_write(data->regs, USERINTERRUPTENABLE(i), 0x0); 169*37571febSLiu Ying regmap_write(data->regs, INTERRUPTENABLE(i), 0x0); 170*37571febSLiu Ying regmap_write(data->regs, USERINTERRUPTCLEAR(i), 0xffffffff); 171*37571febSLiu Ying regmap_write(data->regs, INTERRUPTCLEAR(i), 0xffffffff); 172*37571febSLiu Ying 173*37571febSLiu Ying /* set all interrupts to user mode */ 174*37571febSLiu Ying regmap_write(data->regs, USERINTERRUPTMASK(i), 0xffffffff); 175*37571febSLiu Ying } 176*37571febSLiu Ying 177*37571febSLiu Ying data->domain = irq_domain_add_linear(dev->of_node, IRQ_COUNT, 178*37571febSLiu Ying &irq_generic_chip_ops, data); 179*37571febSLiu Ying if (!data->domain) { 180*37571febSLiu Ying dev_err(dev, "failed to create IRQ domain\n"); 181*37571febSLiu Ying pm_runtime_put(dev); 182*37571febSLiu Ying return -ENOMEM; 183*37571febSLiu Ying } 184*37571febSLiu Ying irq_domain_set_pm_device(data->domain, dev); 185*37571febSLiu Ying 186*37571febSLiu Ying ret = irq_alloc_domain_generic_chips(data->domain, 32, 1, "DC", 187*37571febSLiu Ying handle_level_irq, 0, 0, 0); 188*37571febSLiu Ying if (ret) { 189*37571febSLiu Ying dev_err(dev, "failed to alloc generic IRQ chips: %d\n", ret); 190*37571febSLiu Ying irq_domain_remove(data->domain); 191*37571febSLiu Ying pm_runtime_put(dev); 192*37571febSLiu Ying return ret; 193*37571febSLiu Ying } 194*37571febSLiu Ying 195*37571febSLiu Ying for (i = 0; i < IRQ_COUNT; i += 32) { 196*37571febSLiu Ying gc = irq_get_domain_generic_chip(data->domain, i); 197*37571febSLiu Ying gc->reg_base = base; 198*37571febSLiu Ying gc->unused = unused_irq[i / 32]; 199*37571febSLiu Ying ct = gc->chip_types; 200*37571febSLiu Ying ct->chip.irq_ack = irq_gc_ack_set_bit; 201*37571febSLiu Ying ct->chip.irq_mask = irq_gc_mask_clr_bit; 202*37571febSLiu Ying ct->chip.irq_unmask = irq_gc_mask_set_bit; 203*37571febSLiu Ying ct->regs.ack = USERINTERRUPTCLEAR(i / 32); 204*37571febSLiu Ying ct->regs.mask = USERINTERRUPTENABLE(i / 32); 205*37571febSLiu Ying } 206*37571febSLiu Ying 207*37571febSLiu Ying for (i = 0; i < IRQ_COUNT; i++) { 208*37571febSLiu Ying /* skip the reserved IRQ */ 209*37571febSLiu Ying if (i == IRQ_RESERVED) 210*37571febSLiu Ying continue; 211*37571febSLiu Ying 212*37571febSLiu Ying data->irq[i] = irq_of_parse_and_map(dev->of_node, i); 213*37571febSLiu Ying 214*37571febSLiu Ying entry[i].data = data; 215*37571febSLiu Ying entry[i].irq = i; 216*37571febSLiu Ying 217*37571febSLiu Ying irq_set_chained_handler_and_data(data->irq[i], 218*37571febSLiu Ying dc_ic_irq_handler, &entry[i]); 219*37571febSLiu Ying } 220*37571febSLiu Ying 221*37571febSLiu Ying return 0; 222*37571febSLiu Ying } 223*37571febSLiu Ying 224*37571febSLiu Ying static void dc_ic_remove(struct platform_device *pdev) 225*37571febSLiu Ying { 226*37571febSLiu Ying struct dc_ic_data *data = dev_get_drvdata(&pdev->dev); 227*37571febSLiu Ying int i; 228*37571febSLiu Ying 229*37571febSLiu Ying for (i = 0; i < IRQ_COUNT; i++) { 230*37571febSLiu Ying if (i == IRQ_RESERVED) 231*37571febSLiu Ying continue; 232*37571febSLiu Ying 233*37571febSLiu Ying irq_set_chained_handler_and_data(data->irq[i], NULL, NULL); 234*37571febSLiu Ying } 235*37571febSLiu Ying 236*37571febSLiu Ying irq_domain_remove(data->domain); 237*37571febSLiu Ying 238*37571febSLiu Ying pm_runtime_put_sync(&pdev->dev); 239*37571febSLiu Ying } 240*37571febSLiu Ying 241*37571febSLiu Ying static int dc_ic_runtime_suspend(struct device *dev) 242*37571febSLiu Ying { 243*37571febSLiu Ying struct dc_ic_data *data = dev_get_drvdata(dev); 244*37571febSLiu Ying 245*37571febSLiu Ying clk_disable_unprepare(data->clk_axi); 246*37571febSLiu Ying 247*37571febSLiu Ying return 0; 248*37571febSLiu Ying } 249*37571febSLiu Ying 250*37571febSLiu Ying static int dc_ic_runtime_resume(struct device *dev) 251*37571febSLiu Ying { 252*37571febSLiu Ying struct dc_ic_data *data = dev_get_drvdata(dev); 253*37571febSLiu Ying int ret; 254*37571febSLiu Ying 255*37571febSLiu Ying ret = clk_prepare_enable(data->clk_axi); 256*37571febSLiu Ying if (ret) 257*37571febSLiu Ying dev_err(dev, "failed to enable AXI clock: %d\n", ret); 258*37571febSLiu Ying 259*37571febSLiu Ying return ret; 260*37571febSLiu Ying } 261*37571febSLiu Ying 262*37571febSLiu Ying static const struct dev_pm_ops dc_ic_pm_ops = { 263*37571febSLiu Ying SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 264*37571febSLiu Ying pm_runtime_force_resume) 265*37571febSLiu Ying RUNTIME_PM_OPS(dc_ic_runtime_suspend, dc_ic_runtime_resume, NULL) 266*37571febSLiu Ying }; 267*37571febSLiu Ying 268*37571febSLiu Ying static const struct of_device_id dc_ic_dt_ids[] = { 269*37571febSLiu Ying { .compatible = "fsl,imx8qxp-dc-intc", }, 270*37571febSLiu Ying { /* sentinel */ } 271*37571febSLiu Ying }; 272*37571febSLiu Ying 273*37571febSLiu Ying struct platform_driver dc_ic_driver = { 274*37571febSLiu Ying .probe = dc_ic_probe, 275*37571febSLiu Ying .remove = dc_ic_remove, 276*37571febSLiu Ying .driver = { 277*37571febSLiu Ying .name = "imx8-dc-intc", 278*37571febSLiu Ying .suppress_bind_attrs = true, 279*37571febSLiu Ying .of_match_table = dc_ic_dt_ids, 280*37571febSLiu Ying .pm = pm_sleep_ptr(&dc_ic_pm_ops), 281*37571febSLiu Ying }, 282*37571febSLiu Ying }; 283