Skip to content

Commit 12a9512

Browse files
Lucas Tanurelag-linaro
authored andcommitted
soundwire: bus: Allow SoundWire peripherals to register IRQ handlers
Currently the in-band alerts for SoundWire peripherals can only be communicated to the driver through the interrupt_callback function. This however is slightly inconvenient for devices that wish to share IRQ handling code between SoundWire and I2C/SPI, the later would normally register an IRQ handler with the IRQ subsystem. However there is no reason the SoundWire in-band IRQs can not also be communicated as an actual IRQ to the driver. Add support for SoundWire peripherals to register a normal IRQ handler to receive SoundWire in-band alerts, allowing code to be shared across control buses. Note that we allow users to use both the interrupt_callback and the IRQ handler, this is useful for devices which must clear additional chip specific SoundWire registers that are not a part of the normal IRQ flow, or the SoundWire specification. Signed-off-by: Lucas Tanure <tanureal@opensource.cirrus.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Acked-by: Bard Liao <yung-chuan.liao@linux.intel.com> Acked-by: Vinod Koul <vkoul@kernel.org> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com> Link: https://lore.kernel.org/r/20230804104602.395892-2-ckeepax@opensource.cirrus.com Signed-off-by: Lee Jones <lee@kernel.org>
1 parent 06c2afb commit 12a9512

3 files changed

Lines changed: 53 additions & 0 deletions

File tree

drivers/soundwire/bus.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <linux/acpi.h>
55
#include <linux/delay.h>
6+
#include <linux/irq.h>
67
#include <linux/mod_devicetable.h>
78
#include <linux/pm_runtime.h>
89
#include <linux/soundwire/sdw_registers.h>
@@ -25,6 +26,23 @@ static int sdw_get_id(struct sdw_bus *bus)
2526
return 0;
2627
}
2728

29+
static int sdw_irq_map(struct irq_domain *h, unsigned int virq,
30+
irq_hw_number_t hw)
31+
{
32+
struct sdw_bus *bus = h->host_data;
33+
34+
irq_set_chip_data(virq, bus);
35+
irq_set_chip(virq, &bus->irq_chip);
36+
irq_set_nested_thread(virq, 1);
37+
irq_set_noprobe(virq);
38+
39+
return 0;
40+
}
41+
42+
static const struct irq_domain_ops sdw_domain_ops = {
43+
.map = sdw_irq_map,
44+
};
45+
2846
/**
2947
* sdw_bus_master_add() - add a bus Master instance
3048
* @bus: bus instance
@@ -151,6 +169,14 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
151169
bus->params.curr_bank = SDW_BANK0;
152170
bus->params.next_bank = SDW_BANK1;
153171

172+
bus->irq_chip.name = dev_name(bus->dev);
173+
bus->domain = irq_domain_create_linear(fwnode, SDW_MAX_DEVICES,
174+
&sdw_domain_ops, bus);
175+
if (!bus->domain) {
176+
dev_err(bus->dev, "Failed to add IRQ domain\n");
177+
return -EINVAL;
178+
}
179+
154180
return 0;
155181
}
156182
EXPORT_SYMBOL(sdw_bus_master_add);
@@ -187,6 +213,9 @@ static int sdw_delete_slave(struct device *dev, void *data)
187213
void sdw_bus_master_delete(struct sdw_bus *bus)
188214
{
189215
device_for_each_child(bus->dev, NULL, sdw_delete_slave);
216+
217+
irq_domain_remove(bus->domain);
218+
190219
sdw_master_device_del(bus);
191220

192221
sdw_bus_debugfs_exit(bus);
@@ -1725,6 +1754,9 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
17251754
struct device *dev = &slave->dev;
17261755
struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
17271756

1757+
if (slave->prop.use_domain_irq && slave->irq)
1758+
handle_nested_irq(slave->irq);
1759+
17281760
if (drv->ops && drv->ops->interrupt_callback) {
17291761
slave_intr.sdca_cascade = sdca_cascade;
17301762
slave_intr.control_port = clear;

drivers/soundwire/bus_type.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ static int sdw_drv_probe(struct device *dev)
122122
if (drv->ops && drv->ops->read_prop)
123123
drv->ops->read_prop(slave);
124124

125+
if (slave->prop.use_domain_irq) {
126+
slave->irq = irq_create_mapping(slave->bus->domain, slave->dev_num);
127+
if (!slave->irq)
128+
dev_warn(dev, "Failed to map IRQ\n");
129+
}
130+
125131
/* init the sysfs as we have properties now */
126132
ret = sdw_slave_sysfs_init(slave);
127133
if (ret < 0)
@@ -166,7 +172,13 @@ static int sdw_drv_remove(struct device *dev)
166172
int ret = 0;
167173

168174
mutex_lock(&slave->sdw_dev_lock);
175+
169176
slave->probed = false;
177+
178+
if (slave->prop.use_domain_irq)
179+
irq_dispose_mapping(irq_find_mapping(slave->bus->domain,
180+
slave->dev_num));
181+
170182
mutex_unlock(&slave->sdw_dev_lock);
171183

172184
if (drv->remove)

include/linux/soundwire/sdw.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#include <linux/bug.h>
88
#include <linux/lockdep_types.h>
9+
#include <linux/irq.h>
10+
#include <linux/irqdomain.h>
911
#include <linux/mod_devicetable.h>
1012
#include <linux/bitfield.h>
1113

@@ -370,6 +372,7 @@ struct sdw_dpn_prop {
370372
* @clock_reg_supported: the Peripheral implements the clock base and scale
371373
* registers introduced with the SoundWire 1.2 specification. SDCA devices
372374
* do not need to set this boolean property as the registers are required.
375+
* @use_domain_irq: call actual IRQ handler on slave, as well as callback
373376
*/
374377
struct sdw_slave_prop {
375378
u32 mipi_revision;
@@ -394,6 +397,7 @@ struct sdw_slave_prop {
394397
u8 scp_int1_mask;
395398
u32 quirks;
396399
bool clock_reg_supported;
400+
bool use_domain_irq;
397401
};
398402

399403
#define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0)
@@ -641,6 +645,7 @@ struct sdw_slave_ops {
641645
* struct sdw_slave - SoundWire Slave
642646
* @id: MIPI device ID
643647
* @dev: Linux device
648+
* @irq: IRQ number
644649
* @status: Status reported by the Slave
645650
* @bus: Bus handle
646651
* @prop: Slave properties
@@ -670,6 +675,7 @@ struct sdw_slave_ops {
670675
struct sdw_slave {
671676
struct sdw_slave_id id;
672677
struct device dev;
678+
int irq;
673679
enum sdw_slave_status status;
674680
struct sdw_bus *bus;
675681
struct sdw_slave_prop prop;
@@ -885,6 +891,7 @@ struct sdw_master_ops {
885891
* is used to compute and program bus bandwidth, clock, frame shape,
886892
* transport and port parameters
887893
* @debugfs: Bus debugfs
894+
* @domain: IRQ domain
888895
* @defer_msg: Defer message
889896
* @clk_stop_timeout: Clock stop timeout computed
890897
* @bank_switch_timeout: Bank switch timeout computed
@@ -920,6 +927,8 @@ struct sdw_bus {
920927
#ifdef CONFIG_DEBUG_FS
921928
struct dentry *debugfs;
922929
#endif
930+
struct irq_chip irq_chip;
931+
struct irq_domain *domain;
923932
struct sdw_defer defer_msg;
924933
unsigned int clk_stop_timeout;
925934
u32 bank_switch_timeout;

0 commit comments

Comments
 (0)