summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>2020-11-04 23:23:58 +0800
committerVinod Koul <vkoul@kernel.org>2020-11-24 14:09:31 +0530
commitb7cab9be7c16128a0de21ed7ae67211838813437 (patch)
tree9e541f2a6385dca379061b0016824744cc5ac30d /drivers
parente6db818a3f51781ba12ac4d52b8773f74d57b06b (diff)
soundwire: SDCA: detect sdca_cascade interrupt
The SoundWire 1.2 specification defines an "SDCA cascade" bit which handles a logical OR of all SDCA interrupt sources (up to 30 defined). Due to limitations of the addressing space, this bit is located in the SDW_DP0_INT register when DP0 is used, or alternatively in the DP0_SDCA_Support_INTSTAT register when DP0 is not used. To allow for both cases to be handled, this bit will be checked in the main device-level interrupt handling code. This will result in the register being read twice if DP0 is enabled, but it's not clear how to optimize this case. It's also more logical to deal with this interrupt at the device than the port level, this bit is really not DP0 specific and its location in the DP0_INTSTAT bit is only due to the lack of free space in SCP_INTSTAT_1. The SDCA_Cascade bit cannot be masked or cleared, so the interrupt handling only forwards the detection to the Slave driver, which will deal with reading the relevant SDCA status bits and clearing them. The bus driver only signals the detection. The communication with the Slave driver is based on the same interrupt callback, with only an extension to provide the status of the sdca_cascade bit. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Rander Wang <rander.wang@linux.intel.com> Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Link: https://lore.kernel.org/r/20201104152358.9518-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/soundwire/bus.c28
1 files changed, 27 insertions, 1 deletions
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