diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 8eaf31e76677..ffe4600fd95b 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1424,6 +1424,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) int port_num, stat, ret, count = 0; unsigned long port; bool slave_notify = false; + u8 sdca_cascade = 0; u8 buf, buf2[2], _buf, _buf2[2]; bool parity_check; bool parity_quirk; @@ -1453,6 +1454,16 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) goto io_err; } + if (slave->prop.is_sdca) { + ret = sdw_read(slave, SDW_DP0_INT); + if (ret < 0) { + dev_err(slave->bus->dev, + "SDW_DP0_INT read failed:%d\n", ret); + goto io_err; + } + sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; + } + do { /* * Check parity, bus clash and Slave (impl defined) @@ -1489,6 +1500,10 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) clear |= SDW_SCP_INT1_IMPL_DEF; } + /* the SDCA interrupts are cleared in the codec driver .interrupt_callback() */ + if (sdca_cascade) + slave_notify = true; + /* Check port 0 - 3 interrupts */ port = buf & SDW_SCP_INT1_PORT0_3; @@ -1526,6 +1541,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) /* Update the Slave driver */ if (slave_notify && slave->ops && slave->ops->interrupt_callback) { + slave_intr.sdca_cascade = sdca_cascade; slave_intr.control_port = clear; memcpy(slave_intr.port, &port_status, sizeof(slave_intr.port)); @@ -1563,11 +1579,21 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) goto io_err; } + if (slave->prop.is_sdca) { + ret = sdw_read(slave, SDW_DP0_INT); + if (ret < 0) { + dev_err(slave->bus->dev, + "SDW_DP0_INT read failed:%d\n", ret); + goto io_err; + } + sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; + } + /* Make sure no interrupts are pending */ buf &= _buf; buf2[0] &= _buf2[0]; buf2[1] &= _buf2[1]; - stat = buf || buf2[0] || buf2[1]; + stat = buf || buf2[0] || buf2[1] || sdca_cascade; /* * Exit loop if Slave is continuously in ALERT state even diff --git a/drivers/soundwire/sysfs_slave_dpn.c b/drivers/soundwire/sysfs_slave_dpn.c index 05a721ea9830..c4b6543c09fd 100644 --- a/drivers/soundwire/sysfs_slave_dpn.c +++ b/drivers/soundwire/sysfs_slave_dpn.c @@ -37,6 +37,7 @@ static int field##_attribute_alloc(struct device *dev, \ return -ENOMEM; \ dpn_attr->N = N; \ dpn_attr->dir = dir; \ + sysfs_attr_init(&dpn_attr->dev_attr.attr); \ dpn_attr->format_string = format_string; \ dpn_attr->dev_attr.attr.name = __stringify(field); \ dpn_attr->dev_attr.attr.mode = 0444; \ diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 41cc1192f9aa..f0b01b728640 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -359,6 +359,7 @@ struct sdw_dpn_prop { * @sink_dpn_prop: Sink Data Port N properties * @scp_int1_mask: SCP_INT1_MASK desired settings * @quirks: bitmask identifying deltas from the MIPI specification + * @is_sdca: the Slave supports the SDCA specification */ struct sdw_slave_prop { u32 mipi_revision; @@ -382,6 +383,7 @@ struct sdw_slave_prop { struct sdw_dpn_prop *sink_dpn_prop; u8 scp_int1_mask; u32 quirks; + bool is_sdca; }; #define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0) @@ -479,10 +481,12 @@ struct sdw_slave_id { /** * struct sdw_slave_intr_status - Slave interrupt status + * @sdca_cascade: set if the Slave device reports an SDCA interrupt * @control_port: control port status * @port: data port status */ struct sdw_slave_intr_status { + bool sdca_cascade; u8 control_port; u8 port[15]; };