static int sdw_prep_deprep_slave_ports()

in stream.c [420:505]


static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
				       struct sdw_slave_runtime *s_rt,
				       struct sdw_port_runtime *p_rt,
				       bool prep)
{
	struct completion *port_ready;
	struct sdw_dpn_prop *dpn_prop;
	struct sdw_prepare_ch prep_ch;
	bool intr = false;
	int ret = 0, val;
	u32 addr;

	prep_ch.num = p_rt->num;
	prep_ch.ch_mask = p_rt->ch_mask;

	dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave,
					  s_rt->direction,
					  prep_ch.num);
	if (!dpn_prop) {
		dev_err(bus->dev,
			"Slave Port:%d properties not found\n", prep_ch.num);
		return -EINVAL;
	}

	prep_ch.prepare = prep;

	prep_ch.bank = bus->params.next_bank;

	if (dpn_prop->imp_def_interrupts || !dpn_prop->simple_ch_prep_sm ||
	    bus->params.s_data_mode != SDW_PORT_DATA_MODE_NORMAL)
		intr = true;

	/*
	 * Enable interrupt before Port prepare.
	 * For Port de-prepare, it is assumed that port
	 * was prepared earlier
	 */
	if (prep && intr) {
		ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
					     dpn_prop->imp_def_interrupts);
		if (ret < 0)
			return ret;
	}

	/* Inform slave about the impending port prepare */
	sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_PRE_PREP);

	/* Prepare Slave port implementing CP_SM */
	if (!dpn_prop->simple_ch_prep_sm) {
		addr = SDW_DPN_PREPARECTRL(p_rt->num);

		if (prep)
			ret = sdw_write(s_rt->slave, addr, p_rt->ch_mask);
		else
			ret = sdw_write(s_rt->slave, addr, 0x0);

		if (ret < 0) {
			dev_err(&s_rt->slave->dev,
				"Slave prep_ctrl reg write failed\n");
			return ret;
		}

		/* Wait for completion on port ready */
		port_ready = &s_rt->slave->port_ready[prep_ch.num];
		wait_for_completion_timeout(port_ready,
			msecs_to_jiffies(dpn_prop->ch_prep_timeout));

		val = sdw_read(s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num));
		if ((val < 0) || (val & p_rt->ch_mask)) {
			ret = (val < 0) ? val : -ETIMEDOUT;
			dev_err(&s_rt->slave->dev,
				"Chn prep failed for port %d: %d\n", prep_ch.num, ret);
			return ret;
		}
	}

	/* Inform slaves about ports prepared */
	sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_POST_PREP);

	/* Disable interrupt after Port de-prepare */
	if (!prep && intr)
		ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
					     dpn_prop->imp_def_interrupts);

	return ret;
}