]>
Commit | Line | Data |
---|---|---|
d8f4f161 LP |
1 | /* |
2 | * ACPI GSI IRQ layer | |
3 | * | |
4 | * Copyright (C) 2015 ARM Ltd. | |
5 | * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | */ | |
11 | #include <linux/acpi.h> | |
12 | #include <linux/irq.h> | |
13 | #include <linux/irqdomain.h> | |
d7f8504d | 14 | #include <linux/of.h> |
d8f4f161 LP |
15 | |
16 | enum acpi_irq_model_id acpi_irq_model; | |
17 | ||
d7f8504d MZ |
18 | static struct fwnode_handle *acpi_gsi_domain_id; |
19 | ||
d8f4f161 LP |
20 | /** |
21 | * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI | |
22 | * @gsi: GSI IRQ number to map | |
23 | * @irq: pointer where linux IRQ number is stored | |
24 | * | |
25 | * irq location updated with irq value [>0 on success, 0 on failure] | |
26 | * | |
27 | * Returns: linux IRQ number on success (>0) | |
28 | * -EINVAL on failure | |
29 | */ | |
30 | int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) | |
31 | { | |
d7f8504d MZ |
32 | struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, |
33 | DOMAIN_BUS_ANY); | |
34 | ||
35 | *irq = irq_find_mapping(d, gsi); | |
d8f4f161 LP |
36 | /* |
37 | * *irq == 0 means no mapping, that should | |
38 | * be reported as a failure | |
39 | */ | |
40 | return (*irq > 0) ? *irq : -EINVAL; | |
41 | } | |
42 | EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); | |
43 | ||
44 | /** | |
45 | * acpi_register_gsi() - Map a GSI to a linux IRQ number | |
46 | * @dev: device for which IRQ has to be mapped | |
47 | * @gsi: GSI IRQ number | |
48 | * @trigger: trigger type of the GSI number to be mapped | |
49 | * @polarity: polarity of the GSI to be mapped | |
50 | * | |
51 | * Returns: a valid linux IRQ number on success | |
52 | * -EINVAL on failure | |
53 | */ | |
54 | int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, | |
55 | int polarity) | |
56 | { | |
462e4fc7 | 57 | struct irq_fwspec fwspec; |
d8f4f161 | 58 | |
462e4fc7 MZ |
59 | if (WARN_ON(!acpi_gsi_domain_id)) { |
60 | pr_warn("GSI: No registered irqchip, giving up\n"); | |
61 | return -EINVAL; | |
2bc6eba4 | 62 | } |
d8f4f161 | 63 | |
462e4fc7 MZ |
64 | fwspec.fwnode = acpi_gsi_domain_id; |
65 | fwspec.param[0] = gsi; | |
55a93417 | 66 | fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity); |
462e4fc7 MZ |
67 | fwspec.param_count = 2; |
68 | ||
69 | return irq_create_fwspec_mapping(&fwspec); | |
d8f4f161 LP |
70 | } |
71 | EXPORT_SYMBOL_GPL(acpi_register_gsi); | |
72 | ||
73 | /** | |
74 | * acpi_unregister_gsi() - Free a GSI<->linux IRQ number mapping | |
75 | * @gsi: GSI IRQ number | |
76 | */ | |
77 | void acpi_unregister_gsi(u32 gsi) | |
78 | { | |
d7f8504d MZ |
79 | struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, |
80 | DOMAIN_BUS_ANY); | |
81 | int irq = irq_find_mapping(d, gsi); | |
d8f4f161 LP |
82 | |
83 | irq_dispose_mapping(irq); | |
84 | } | |
85 | EXPORT_SYMBOL_GPL(acpi_unregister_gsi); | |
2bc6eba4 MZ |
86 | |
87 | /** | |
88 | * acpi_set_irq_model - Setup the GSI irqdomain information | |
89 | * @model: the value assigned to acpi_irq_model | |
90 | * @fwnode: the irq_domain identifier for mapping and looking up | |
91 | * GSI interrupts | |
92 | */ | |
93 | void __init acpi_set_irq_model(enum acpi_irq_model_id model, | |
94 | struct fwnode_handle *fwnode) | |
95 | { | |
96 | acpi_irq_model = model; | |
97 | acpi_gsi_domain_id = fwnode; | |
98 | } |