in cadence_master.c [1510:1582]
int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake)
{
bool slave_present = false;
struct sdw_slave *slave;
int ret;
sdw_cdns_check_self_clearing_bits(cdns, __func__, false, 0);
/* Check suspend status */
if (sdw_cdns_is_clock_stop(cdns)) {
dev_dbg(cdns->dev, "Clock is already stopped\n");
return 0;
}
/*
* Before entering clock stop we mask the Slave
* interrupts. This helps avoid having to deal with e.g. a
* Slave becoming UNATTACHED while the clock is being stopped
*/
cdns_enable_slave_interrupts(cdns, false);
/*
* For specific platforms, it is required to be able to put
* master into a state in which it ignores wake-up trials
* in clock stop state
*/
if (block_wake)
cdns_updatel(cdns, CDNS_MCP_CONTROL,
CDNS_MCP_CONTROL_BLOCK_WAKEUP,
CDNS_MCP_CONTROL_BLOCK_WAKEUP);
list_for_each_entry(slave, &cdns->bus.slaves, node) {
if (slave->status == SDW_SLAVE_ATTACHED ||
slave->status == SDW_SLAVE_ALERT) {
slave_present = true;
break;
}
}
/* commit changes */
ret = cdns_config_update(cdns);
if (ret < 0) {
dev_err(cdns->dev, "%s: config_update failed\n", __func__);
return ret;
}
/* Prepare slaves for clock stop */
if (slave_present) {
ret = sdw_bus_prep_clk_stop(&cdns->bus);
if (ret < 0 && ret != -ENODATA) {
dev_err(cdns->dev, "prepare clock stop failed %d\n", ret);
return ret;
}
}
/*
* Enter clock stop mode and only report errors if there are
* Slave devices present (ALERT or ATTACHED)
*/
ret = sdw_bus_clk_stop(&cdns->bus);
if (ret < 0 && slave_present && ret != -ENODATA) {
dev_err(cdns->dev, "bus clock stop failed %d\n", ret);
return ret;
}
ret = cdns_set_wait(cdns, CDNS_MCP_STAT,
CDNS_MCP_STAT_CLK_STOP,
CDNS_MCP_STAT_CLK_STOP);
if (ret < 0)
dev_err(cdns->dev, "Clock stop failed %d\n", ret);
return ret;
}