| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Renesas IRQC Driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2013 Magnus Damm |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | | - * |
|---|
| 15 | | - * You should have received a copy of the GNU General Public License |
|---|
| 16 | | - * along with this program; if not, write to the Free Software |
|---|
| 17 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 18 | 6 | */ |
|---|
| 19 | 7 | |
|---|
| 20 | 8 | #include <linux/init.h> |
|---|
| 21 | 9 | #include <linux/platform_device.h> |
|---|
| 22 | | -#include <linux/spinlock.h> |
|---|
| 23 | 10 | #include <linux/interrupt.h> |
|---|
| 24 | 11 | #include <linux/ioport.h> |
|---|
| 25 | 12 | #include <linux/io.h> |
|---|
| .. | .. |
|---|
| 60 | 47 | void __iomem *cpu_int_base; |
|---|
| 61 | 48 | struct irqc_irq irq[IRQC_IRQ_MAX]; |
|---|
| 62 | 49 | unsigned int number_of_irqs; |
|---|
| 63 | | - struct platform_device *pdev; |
|---|
| 50 | + struct device *dev; |
|---|
| 64 | 51 | struct irq_chip_generic *gc; |
|---|
| 65 | 52 | struct irq_domain *irq_domain; |
|---|
| 66 | 53 | atomic_t wakeup_path; |
|---|
| .. | .. |
|---|
| 73 | 60 | |
|---|
| 74 | 61 | static void irqc_dbg(struct irqc_irq *i, char *str) |
|---|
| 75 | 62 | { |
|---|
| 76 | | - dev_dbg(&i->p->pdev->dev, "%s (%d:%d)\n", |
|---|
| 77 | | - str, i->requested_irq, i->hw_irq); |
|---|
| 63 | + dev_dbg(i->p->dev, "%s (%d:%d)\n", str, i->requested_irq, i->hw_irq); |
|---|
| 78 | 64 | } |
|---|
| 79 | 65 | |
|---|
| 80 | 66 | static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = { |
|---|
| .. | .. |
|---|
| 137 | 123 | |
|---|
| 138 | 124 | static int irqc_probe(struct platform_device *pdev) |
|---|
| 139 | 125 | { |
|---|
| 126 | + struct device *dev = &pdev->dev; |
|---|
| 127 | + const char *name = dev_name(dev); |
|---|
| 140 | 128 | struct irqc_priv *p; |
|---|
| 141 | | - struct resource *io; |
|---|
| 142 | 129 | struct resource *irq; |
|---|
| 143 | | - const char *name = dev_name(&pdev->dev); |
|---|
| 144 | 130 | int ret; |
|---|
| 145 | 131 | int k; |
|---|
| 146 | 132 | |
|---|
| 147 | | - p = kzalloc(sizeof(*p), GFP_KERNEL); |
|---|
| 148 | | - if (!p) { |
|---|
| 149 | | - dev_err(&pdev->dev, "failed to allocate driver data\n"); |
|---|
| 150 | | - ret = -ENOMEM; |
|---|
| 151 | | - goto err0; |
|---|
| 152 | | - } |
|---|
| 133 | + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); |
|---|
| 134 | + if (!p) |
|---|
| 135 | + return -ENOMEM; |
|---|
| 153 | 136 | |
|---|
| 154 | | - p->pdev = pdev; |
|---|
| 137 | + p->dev = dev; |
|---|
| 155 | 138 | platform_set_drvdata(pdev, p); |
|---|
| 156 | 139 | |
|---|
| 157 | | - pm_runtime_enable(&pdev->dev); |
|---|
| 158 | | - pm_runtime_get_sync(&pdev->dev); |
|---|
| 159 | | - |
|---|
| 160 | | - /* get hold of manadatory IOMEM */ |
|---|
| 161 | | - io = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 162 | | - if (!io) { |
|---|
| 163 | | - dev_err(&pdev->dev, "not enough IOMEM resources\n"); |
|---|
| 164 | | - ret = -EINVAL; |
|---|
| 165 | | - goto err1; |
|---|
| 166 | | - } |
|---|
| 140 | + pm_runtime_enable(dev); |
|---|
| 141 | + pm_runtime_get_sync(dev); |
|---|
| 167 | 142 | |
|---|
| 168 | 143 | /* allow any number of IRQs between 1 and IRQC_IRQ_MAX */ |
|---|
| 169 | 144 | for (k = 0; k < IRQC_IRQ_MAX; k++) { |
|---|
| .. | .. |
|---|
| 178 | 153 | |
|---|
| 179 | 154 | p->number_of_irqs = k; |
|---|
| 180 | 155 | if (p->number_of_irqs < 1) { |
|---|
| 181 | | - dev_err(&pdev->dev, "not enough IRQ resources\n"); |
|---|
| 156 | + dev_err(dev, "not enough IRQ resources\n"); |
|---|
| 182 | 157 | ret = -EINVAL; |
|---|
| 183 | | - goto err1; |
|---|
| 158 | + goto err_runtime_pm_disable; |
|---|
| 184 | 159 | } |
|---|
| 185 | 160 | |
|---|
| 186 | 161 | /* ioremap IOMEM and setup read/write callbacks */ |
|---|
| 187 | | - p->iomem = ioremap_nocache(io->start, resource_size(io)); |
|---|
| 188 | | - if (!p->iomem) { |
|---|
| 189 | | - dev_err(&pdev->dev, "failed to remap IOMEM\n"); |
|---|
| 190 | | - ret = -ENXIO; |
|---|
| 191 | | - goto err2; |
|---|
| 162 | + p->iomem = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 163 | + if (IS_ERR(p->iomem)) { |
|---|
| 164 | + ret = PTR_ERR(p->iomem); |
|---|
| 165 | + goto err_runtime_pm_disable; |
|---|
| 192 | 166 | } |
|---|
| 193 | 167 | |
|---|
| 194 | 168 | p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */ |
|---|
| 195 | 169 | |
|---|
| 196 | | - p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, |
|---|
| 197 | | - p->number_of_irqs, |
|---|
| 170 | + p->irq_domain = irq_domain_add_linear(dev->of_node, p->number_of_irqs, |
|---|
| 198 | 171 | &irq_generic_chip_ops, p); |
|---|
| 199 | 172 | if (!p->irq_domain) { |
|---|
| 200 | 173 | ret = -ENXIO; |
|---|
| 201 | | - dev_err(&pdev->dev, "cannot initialize irq domain\n"); |
|---|
| 202 | | - goto err2; |
|---|
| 174 | + dev_err(dev, "cannot initialize irq domain\n"); |
|---|
| 175 | + goto err_runtime_pm_disable; |
|---|
| 203 | 176 | } |
|---|
| 204 | 177 | |
|---|
| 205 | 178 | ret = irq_alloc_domain_generic_chips(p->irq_domain, p->number_of_irqs, |
|---|
| 206 | | - 1, name, handle_level_irq, |
|---|
| 179 | + 1, "irqc", handle_level_irq, |
|---|
| 207 | 180 | 0, 0, IRQ_GC_INIT_NESTED_LOCK); |
|---|
| 208 | 181 | if (ret) { |
|---|
| 209 | | - dev_err(&pdev->dev, "cannot allocate generic chip\n"); |
|---|
| 210 | | - goto err3; |
|---|
| 182 | + dev_err(dev, "cannot allocate generic chip\n"); |
|---|
| 183 | + goto err_remove_domain; |
|---|
| 211 | 184 | } |
|---|
| 212 | 185 | |
|---|
| 213 | 186 | p->gc = irq_get_domain_generic_chip(p->irq_domain, 0); |
|---|
| 214 | 187 | p->gc->reg_base = p->cpu_int_base; |
|---|
| 215 | 188 | p->gc->chip_types[0].regs.enable = IRQC_EN_SET; |
|---|
| 216 | 189 | p->gc->chip_types[0].regs.disable = IRQC_EN_STS; |
|---|
| 190 | + p->gc->chip_types[0].chip.parent_device = dev; |
|---|
| 217 | 191 | p->gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; |
|---|
| 218 | 192 | p->gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; |
|---|
| 219 | 193 | p->gc->chip_types[0].chip.irq_set_type = irqc_irq_set_type; |
|---|
| .. | .. |
|---|
| 222 | 196 | |
|---|
| 223 | 197 | /* request interrupts one by one */ |
|---|
| 224 | 198 | for (k = 0; k < p->number_of_irqs; k++) { |
|---|
| 225 | | - if (request_irq(p->irq[k].requested_irq, irqc_irq_handler, |
|---|
| 226 | | - 0, name, &p->irq[k])) { |
|---|
| 227 | | - dev_err(&pdev->dev, "failed to request IRQ\n"); |
|---|
| 199 | + if (devm_request_irq(dev, p->irq[k].requested_irq, |
|---|
| 200 | + irqc_irq_handler, 0, name, &p->irq[k])) { |
|---|
| 201 | + dev_err(dev, "failed to request IRQ\n"); |
|---|
| 228 | 202 | ret = -ENOENT; |
|---|
| 229 | | - goto err4; |
|---|
| 203 | + goto err_remove_domain; |
|---|
| 230 | 204 | } |
|---|
| 231 | 205 | } |
|---|
| 232 | 206 | |
|---|
| 233 | | - dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs); |
|---|
| 207 | + dev_info(dev, "driving %d irqs\n", p->number_of_irqs); |
|---|
| 234 | 208 | |
|---|
| 235 | 209 | return 0; |
|---|
| 236 | | -err4: |
|---|
| 237 | | - while (--k >= 0) |
|---|
| 238 | | - free_irq(p->irq[k].requested_irq, &p->irq[k]); |
|---|
| 239 | 210 | |
|---|
| 240 | | -err3: |
|---|
| 211 | +err_remove_domain: |
|---|
| 241 | 212 | irq_domain_remove(p->irq_domain); |
|---|
| 242 | | -err2: |
|---|
| 243 | | - iounmap(p->iomem); |
|---|
| 244 | | -err1: |
|---|
| 245 | | - pm_runtime_put(&pdev->dev); |
|---|
| 246 | | - pm_runtime_disable(&pdev->dev); |
|---|
| 247 | | - kfree(p); |
|---|
| 248 | | -err0: |
|---|
| 213 | +err_runtime_pm_disable: |
|---|
| 214 | + pm_runtime_put(dev); |
|---|
| 215 | + pm_runtime_disable(dev); |
|---|
| 249 | 216 | return ret; |
|---|
| 250 | 217 | } |
|---|
| 251 | 218 | |
|---|
| 252 | 219 | static int irqc_remove(struct platform_device *pdev) |
|---|
| 253 | 220 | { |
|---|
| 254 | 221 | struct irqc_priv *p = platform_get_drvdata(pdev); |
|---|
| 255 | | - int k; |
|---|
| 256 | | - |
|---|
| 257 | | - for (k = 0; k < p->number_of_irqs; k++) |
|---|
| 258 | | - free_irq(p->irq[k].requested_irq, &p->irq[k]); |
|---|
| 259 | 222 | |
|---|
| 260 | 223 | irq_domain_remove(p->irq_domain); |
|---|
| 261 | | - iounmap(p->iomem); |
|---|
| 262 | 224 | pm_runtime_put(&pdev->dev); |
|---|
| 263 | 225 | pm_runtime_disable(&pdev->dev); |
|---|
| 264 | | - kfree(p); |
|---|
| 265 | 226 | return 0; |
|---|
| 266 | 227 | } |
|---|
| 267 | 228 | |
|---|