| // SPDX-License-Identifier: GPL-2.0 | |
| // Copyright (C) 2023 Cirrus Logic, Inc. and | |
| // Cirrus Logic International Semiconductor Ltd. | |
| #include <linux/device.h> | |
| #include <linux/fwnode.h> | |
| #include <linux/irq.h> | |
| #include <linux/irqdomain.h> | |
| #include <linux/soundwire/sdw.h> | |
| #include "irq.h" | |
| static int sdw_irq_map(struct irq_domain *h, unsigned int virq, | |
| irq_hw_number_t hw) | |
| { | |
| struct sdw_bus *bus = h->host_data; | |
| irq_set_chip_data(virq, bus); | |
| irq_set_chip(virq, &bus->irq_chip); | |
| irq_set_nested_thread(virq, 1); | |
| irq_set_noprobe(virq); | |
| return 0; | |
| } | |
| static const struct irq_domain_ops sdw_domain_ops = { | |
| .map = sdw_irq_map, | |
| }; | |
| int sdw_irq_create(struct sdw_bus *bus, | |
| struct fwnode_handle *fwnode) | |
| { | |
| bus->irq_chip.name = dev_name(bus->dev); | |
| bus->domain = irq_domain_create_linear(fwnode, SDW_FW_MAX_DEVICES, | |
| &sdw_domain_ops, bus); | |
| if (!bus->domain) { | |
| dev_err(bus->dev, "Failed to add IRQ domain\n"); | |
| return -EINVAL; | |
| } | |
| return 0; | |
| } | |
| void sdw_irq_delete(struct sdw_bus *bus) | |
| { | |
| irq_domain_remove(bus->domain); | |
| } | |
| static void sdw_irq_dispose_mapping(void *data) | |
| { | |
| struct sdw_slave *slave = data; | |
| irq_dispose_mapping(slave->irq); | |
| } | |
| void sdw_irq_create_mapping(struct sdw_slave *slave) | |
| { | |
| slave->irq = irq_create_mapping(slave->bus->domain, slave->index); | |
| if (!slave->irq) | |
| dev_warn(&slave->dev, "Failed to map IRQ\n"); | |
| devm_add_action_or_reset(&slave->dev, sdw_irq_dispose_mapping, slave); | |
| } |