int sdw_cdns_clock_stop()

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;
}