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> 14 15enum acpi_irq_model_id acpi_irq_model; 16 17static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) 18{ 19 switch (polarity) { 20 case ACPI_ACTIVE_LOW: 21 return trigger == ACPI_EDGE_SENSITIVE ? 22 IRQ_TYPE_EDGE_FALLING : 23 IRQ_TYPE_LEVEL_LOW; 24 case ACPI_ACTIVE_HIGH: 25 return trigger == ACPI_EDGE_SENSITIVE ? 26 IRQ_TYPE_EDGE_RISING : 27 IRQ_TYPE_LEVEL_HIGH; 28 case ACPI_ACTIVE_BOTH: 29 if (trigger == ACPI_EDGE_SENSITIVE) 30 return IRQ_TYPE_EDGE_BOTH; 31 default: 32 return IRQ_TYPE_NONE; 33 } 34} 35 36/** 37 * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI 38 * @gsi: GSI IRQ number to map 39 * @irq: pointer where linux IRQ number is stored 40 * 41 * irq location updated with irq value [>0 on success, 0 on failure] 42 * 43 * Returns: linux IRQ number on success (>0) 44 * -EINVAL on failure 45 */ 46int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) 47{ 48 /* 49 * Only default domain is supported at present, always find 50 * the mapping corresponding to default domain by passing NULL 51 * as irq_domain parameter 52 */ 53 *irq = irq_find_mapping(NULL, gsi); 54 /* 55 * *irq == 0 means no mapping, that should 56 * be reported as a failure 57 */ 58 return (*irq > 0) ? *irq : -EINVAL; 59} 60EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); 61 62/** 63 * acpi_register_gsi() - Map a GSI to a linux IRQ number 64 * @dev: device for which IRQ has to be mapped 65 * @gsi: GSI IRQ number 66 * @trigger: trigger type of the GSI number to be mapped 67 * @polarity: polarity of the GSI to be mapped 68 * 69 * Returns: a valid linux IRQ number on success 70 * -EINVAL on failure 71 */ 72int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, 73 int polarity) 74{ 75 unsigned int irq; 76 unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity); 77 78 /* 79 * There is no way at present to look-up the IRQ domain on ACPI, 80 * hence always create mapping referring to the default domain 81 * by passing NULL as irq_domain parameter 82 */ 83 irq = irq_create_mapping(NULL, gsi); 84 if (!irq) 85 return -EINVAL; 86 87 /* Set irq type if specified and different than the current one */ 88 if (irq_type != IRQ_TYPE_NONE && 89 irq_type != irq_get_trigger_type(irq)) 90 irq_set_irq_type(irq, irq_type); 91 return irq; 92} 93EXPORT_SYMBOL_GPL(acpi_register_gsi); 94 95/** 96 * acpi_unregister_gsi() - Free a GSI<->linux IRQ number mapping 97 * @gsi: GSI IRQ number 98 */ 99void acpi_unregister_gsi(u32 gsi) 100{ 101 int irq = irq_find_mapping(NULL, gsi); 102 103 irq_dispose_mapping(irq); 104} 105EXPORT_SYMBOL_GPL(acpi_unregister_gsi); 106