Commit b7cab9be authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Vinod Koul

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: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarRander Wang <rander.wang@linux.intel.com>
Reviewed-by: default avatarGuennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Signed-off-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20201104152358.9518-1-yung-chuan.liao@linux.intel.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent e6db818a
...@@ -1424,6 +1424,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ...@@ -1424,6 +1424,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
int port_num, stat, ret, count = 0; int port_num, stat, ret, count = 0;
unsigned long port; unsigned long port;
bool slave_notify = false; bool slave_notify = false;
u8 sdca_cascade = 0;
u8 buf, buf2[2], _buf, _buf2[2]; u8 buf, buf2[2], _buf, _buf2[2];
bool parity_check; bool parity_check;
bool parity_quirk; bool parity_quirk;
...@@ -1453,6 +1454,16 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ...@@ -1453,6 +1454,16 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
goto io_err; 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 { do {
/* /*
* Check parity, bus clash and Slave (impl defined) * Check parity, bus clash and Slave (impl defined)
...@@ -1489,6 +1500,10 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ...@@ -1489,6 +1500,10 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
clear |= SDW_SCP_INT1_IMPL_DEF; 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 */ /* Check port 0 - 3 interrupts */
port = buf & SDW_SCP_INT1_PORT0_3; port = buf & SDW_SCP_INT1_PORT0_3;
...@@ -1526,6 +1541,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ...@@ -1526,6 +1541,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
/* Update the Slave driver */ /* Update the Slave driver */
if (slave_notify && slave->ops && if (slave_notify && slave->ops &&
slave->ops->interrupt_callback) { slave->ops->interrupt_callback) {
slave_intr.sdca_cascade = sdca_cascade;
slave_intr.control_port = clear; slave_intr.control_port = clear;
memcpy(slave_intr.port, &port_status, memcpy(slave_intr.port, &port_status,
sizeof(slave_intr.port)); sizeof(slave_intr.port));
...@@ -1563,11 +1579,21 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ...@@ -1563,11 +1579,21 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
goto io_err; 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 */ /* Make sure no interrupts are pending */
buf &= _buf; buf &= _buf;
buf2[0] &= _buf2[0]; buf2[0] &= _buf2[0];
buf2[1] &= _buf2[1]; 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 * Exit loop if Slave is continuously in ALERT state even
......
...@@ -359,6 +359,7 @@ struct sdw_dpn_prop { ...@@ -359,6 +359,7 @@ struct sdw_dpn_prop {
* @sink_dpn_prop: Sink Data Port N properties * @sink_dpn_prop: Sink Data Port N properties
* @scp_int1_mask: SCP_INT1_MASK desired settings * @scp_int1_mask: SCP_INT1_MASK desired settings
* @quirks: bitmask identifying deltas from the MIPI specification * @quirks: bitmask identifying deltas from the MIPI specification
* @is_sdca: the Slave supports the SDCA specification
*/ */
struct sdw_slave_prop { struct sdw_slave_prop {
u32 mipi_revision; u32 mipi_revision;
...@@ -382,6 +383,7 @@ struct sdw_slave_prop { ...@@ -382,6 +383,7 @@ struct sdw_slave_prop {
struct sdw_dpn_prop *sink_dpn_prop; struct sdw_dpn_prop *sink_dpn_prop;
u8 scp_int1_mask; u8 scp_int1_mask;
u32 quirks; u32 quirks;
bool is_sdca;
}; };
#define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0) #define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0)
...@@ -479,10 +481,12 @@ struct sdw_slave_id { ...@@ -479,10 +481,12 @@ struct sdw_slave_id {
/** /**
* struct sdw_slave_intr_status - Slave interrupt status * struct sdw_slave_intr_status - Slave interrupt status
* @sdca_cascade: set if the Slave device reports an SDCA interrupt
* @control_port: control port status * @control_port: control port status
* @port: data port status * @port: data port status
*/ */
struct sdw_slave_intr_status { struct sdw_slave_intr_status {
bool sdca_cascade;
u8 control_port; u8 control_port;
u8 port[15]; u8 port[15];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment