Commit 2306137b authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'soundwire-5.20-rc1' of...

Merge tag 'soundwire-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire into char-misc-next

Vinod writes:
 "soundwire updates for 5.20-rc1

   - Core: solve the driver bind/unbind problem and remove ops pointer
   - intel: runtime pm updates
   - qcom: audio clock gating updates and device status checks"

* tag 'soundwire-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  soundwire: qcom: Enable software clock gating requirement flag
  soundwire: qcom: Check device status before reading devid
  soundwire: qcom: Add flag for software clock gating check
  soundwire: qcom: Add support for controlling audio CGCR from HLOS
  soundwire: intel: use pm_runtime_resume() on component probe
  soundwire: peripheral: remove useless ops pointer
  soundwire: revisit driver bind/unbind and callbacks
  soundwire: bus_type: fix remove and shutdown support
parents c524193f 3f4a7026
Loading
Loading
Loading
Loading
+42 −33
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/pm_runtime.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include "bus.h"
#include "sysfs_local.h"

@@ -842,15 +843,21 @@ static int sdw_slave_clk_stop_callback(struct sdw_slave *slave,
				       enum sdw_clk_stop_mode mode,
				       enum sdw_clk_stop_type type)
{
	int ret;
	int ret = 0;

	if (slave->ops && slave->ops->clk_stop) {
		ret = slave->ops->clk_stop(slave, mode, type);
		if (ret < 0)
			return ret;
	mutex_lock(&slave->sdw_dev_lock);

	if (slave->probed)  {
		struct device *dev = &slave->dev;
		struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);

		if (drv->ops && drv->ops->clk_stop)
			ret = drv->ops->clk_stop(slave, mode, type);
	}

	return 0;
	mutex_unlock(&slave->sdw_dev_lock);

	return ret;
}

static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave,
@@ -1611,14 +1618,24 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
		}

		/* Update the Slave driver */
		if (slave_notify && slave->ops &&
		    slave->ops->interrupt_callback) {
		if (slave_notify) {
			mutex_lock(&slave->sdw_dev_lock);

			if (slave->probed) {
				struct device *dev = &slave->dev;
				struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);

				if (drv->ops && drv->ops->interrupt_callback) {
					slave_intr.sdca_cascade = sdca_cascade;
					slave_intr.control_port = clear;
					memcpy(slave_intr.port, &port_status,
					       sizeof(slave_intr.port));

			slave->ops->interrupt_callback(slave, &slave_intr);
					drv->ops->interrupt_callback(slave, &slave_intr);
				}
			}

			mutex_unlock(&slave->sdw_dev_lock);
		}

		/* Ack interrupt */
@@ -1692,29 +1709,21 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
static int sdw_update_slave_status(struct sdw_slave *slave,
				   enum sdw_slave_status status)
{
	unsigned long time;
	int ret = 0;

	if (!slave->probed) {
		/*
		 * the slave status update is typically handled in an
		 * interrupt thread, which can race with the driver
		 * probe, e.g. when a module needs to be loaded.
		 *
		 * make sure the probe is complete before updating
		 * status.
		 */
		time = wait_for_completion_timeout(&slave->probe_complete,
				msecs_to_jiffies(DEFAULT_PROBE_TIMEOUT));
		if (!time) {
			dev_err(&slave->dev, "Probe not complete, timed out\n");
			return -ETIMEDOUT;
		}
	mutex_lock(&slave->sdw_dev_lock);

	if (slave->probed) {
		struct device *dev = &slave->dev;
		struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);

		if (drv->ops && drv->ops->update_status)
			ret = drv->ops->update_status(slave, status);
	}

	if (!slave->ops || !slave->ops->update_status)
		return 0;
	mutex_unlock(&slave->sdw_dev_lock);

	return slave->ops->update_status(slave, status);
	return ret;
}

/**
+27 −11
Original line number Diff line number Diff line
@@ -98,8 +98,6 @@ static int sdw_drv_probe(struct device *dev)
	if (!id)
		return -ENODEV;

	slave->ops = drv->ops;

	/*
	 * attach to power domain but don't turn on (last arg)
	 */
@@ -107,19 +105,23 @@ static int sdw_drv_probe(struct device *dev)
	if (ret)
		return ret;

	mutex_lock(&slave->sdw_dev_lock);

	ret = drv->probe(slave, id);
	if (ret) {
		name = drv->name;
		if (!name)
			name = drv->driver.name;
		mutex_unlock(&slave->sdw_dev_lock);

		dev_err(dev, "Probe of %s failed: %d\n", name, ret);
		dev_pm_domain_detach(dev, false);
		return ret;
	}

	/* device is probed so let's read the properties now */
	if (slave->ops && slave->ops->read_prop)
		slave->ops->read_prop(slave);
	if (drv->ops && drv->ops->read_prop)
		drv->ops->read_prop(slave);

	/* init the sysfs as we have properties now */
	ret = sdw_slave_sysfs_init(slave);
@@ -139,7 +141,19 @@ static int sdw_drv_probe(struct device *dev)
					     slave->prop.clk_stop_timeout);

	slave->probed = true;
	complete(&slave->probe_complete);

	/*
	 * if the probe happened after the bus was started, notify the codec driver
	 * of the current hardware status to e.g. start the initialization.
	 * Errors are only logged as warnings to avoid failing the probe.
	 */
	if (drv->ops && drv->ops->update_status) {
		ret = drv->ops->update_status(slave, slave->status);
		if (ret < 0)
			dev_warn(dev, "%s: update_status failed with status %d\n", __func__, ret);
	}

	mutex_unlock(&slave->sdw_dev_lock);

	dev_dbg(dev, "probe complete\n");

@@ -152,9 +166,15 @@ static int sdw_drv_remove(struct device *dev)
	struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
	int ret = 0;

	mutex_lock(&slave->sdw_dev_lock);

	slave->probed = false;

	if (drv->remove)
		ret = drv->remove(slave);

	mutex_unlock(&slave->sdw_dev_lock);

	dev_pm_domain_detach(dev, false);

	return ret;
@@ -193,11 +213,7 @@ int __sdw_register_driver(struct sdw_driver *drv, struct module *owner)

	drv->driver.owner = owner;
	drv->driver.probe = sdw_drv_probe;

	if (drv->remove)
	drv->driver.remove = sdw_drv_remove;

	if (drv->shutdown)
	drv->driver.shutdown = sdw_drv_shutdown;

	return driver_register(&drv->driver);
+18 −0
Original line number Diff line number Diff line
@@ -1043,6 +1043,23 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sn
	return ret;
}

static int intel_component_probe(struct snd_soc_component *component)
{
	int ret;

	/*
	 * make sure the device is pm_runtime_active before initiating
	 * bus transactions during the card registration.
	 * We use pm_runtime_resume() here, without taking a reference
	 * and releasing it immediately.
	 */
	ret = pm_runtime_resume(component->dev);
	if (ret < 0 && ret != -EACCES)
		return ret;

	return 0;
}

static int intel_component_dais_suspend(struct snd_soc_component *component)
{
	struct snd_soc_dai *dai;
@@ -1098,6 +1115,7 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = {

static const struct snd_soc_component_driver dai_component = {
	.name           = "soundwire",
	.probe		= intel_component_probe,
	.suspend	= intel_component_dais_suspend
};

+31 −1
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/pm_wakeirq.h>
#include <linux/slimbus.h>
@@ -142,6 +143,7 @@ struct qcom_swrm_ctrl {
	struct device *dev;
	struct regmap *regmap;
	void __iomem *mmio;
	struct reset_control *audio_cgcr;
#ifdef CONFIG_DEBUG_FS
	struct dentry *debugfs;
#endif
@@ -179,6 +181,7 @@ struct qcom_swrm_ctrl {
struct qcom_swrm_data {
	u32 default_cols;
	u32 default_rows;
	bool sw_clk_gate_required;
};

static const struct qcom_swrm_data swrm_v1_3_data = {
@@ -191,6 +194,12 @@ static const struct qcom_swrm_data swrm_v1_5_data = {
	.default_cols = 16,
};

static const struct qcom_swrm_data swrm_v1_6_data = {
	.default_rows = 50,
	.default_cols = 16,
	.sw_clk_gate_required = true,
};

#define to_qcom_sdw(b)	container_of(b, struct qcom_swrm_ctrl, bus)

static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
@@ -471,6 +480,10 @@ static int qcom_swrm_enumerate(struct sdw_bus *bus)
	char *buf1 = (char *)&val1, *buf2 = (char *)&val2;

	for (i = 1; i <= SDW_MAX_DEVICES; i++) {
		/* do not continue if the status is Not Present  */
		if (!ctrl->status[i])
			continue;

		/*SCP_Devid5 - Devid 4*/
		ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_1(i), &val1);

@@ -656,6 +669,8 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
	val = FIELD_PREP(SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK, ctrl->rows_index);
	val |= FIELD_PREP(SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK, ctrl->cols_index);

	reset_control_reset(ctrl->audio_cgcr);

	ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val);

	/* Enable Auto enumeration */
@@ -1307,6 +1322,15 @@ static int qcom_swrm_probe(struct platform_device *pdev)
			return PTR_ERR(ctrl->mmio);
	}

	if (data->sw_clk_gate_required) {
		ctrl->audio_cgcr = devm_reset_control_get_exclusive(dev, "swr_audio_cgcr");
		if (IS_ERR_OR_NULL(ctrl->audio_cgcr)) {
			dev_err(dev, "Failed to get cgcr reset ctrl required for SW gating\n");
			ret = PTR_ERR(ctrl->audio_cgcr);
			goto err_init;
		}
	}

	ctrl->irq = of_irq_get(dev->of_node, 0);
	if (ctrl->irq < 0) {
		ret = ctrl->irq;
@@ -1332,6 +1356,10 @@ static int qcom_swrm_probe(struct platform_device *pdev)
	ctrl->bus.compute_params = &qcom_swrm_compute_params;
	ctrl->bus.clk_stop_timeout = 300;

	ctrl->audio_cgcr = devm_reset_control_get_exclusive(dev, "swr_audio_cgcr");
	if (IS_ERR(ctrl->audio_cgcr))
		dev_err(dev, "Failed to get audio_cgcr reset required for soundwire-v1.6.0\n");

	ret = qcom_swrm_get_port_config(ctrl);
	if (ret)
		goto err_clk;
@@ -1485,6 +1513,8 @@ static int __maybe_unused swrm_runtime_resume(struct device *dev)
		qcom_swrm_get_device_status(ctrl);
		sdw_handle_slave_status(&ctrl->bus, ctrl->status);
	} else {
		reset_control_reset(ctrl->audio_cgcr);

		ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START);
		ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR,
			SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET);
@@ -1548,7 +1578,7 @@ static const struct dev_pm_ops swrm_dev_pm_ops = {
static const struct of_device_id qcom_swrm_of_match[] = {
	{ .compatible = "qcom,soundwire-v1.3.0", .data = &swrm_v1_3_data },
	{ .compatible = "qcom,soundwire-v1.5.1", .data = &swrm_v1_5_data },
	{ .compatible = "qcom,soundwire-v1.6.0", .data = &swrm_v1_5_data },
	{ .compatible = "qcom,soundwire-v1.6.0", .data = &swrm_v1_6_data },
	{/* sentinel */},
};

+2 −1
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ static void sdw_slave_release(struct device *dev)
{
	struct sdw_slave *slave = dev_to_sdw_dev(dev);

	mutex_destroy(&slave->sdw_dev_lock);
	kfree(slave);
}

@@ -58,9 +59,9 @@ int sdw_slave_add(struct sdw_bus *bus,
	init_completion(&slave->enumeration_complete);
	init_completion(&slave->initialization_complete);
	slave->dev_num = 0;
	init_completion(&slave->probe_complete);
	slave->probed = false;
	slave->first_interrupt_done = false;
	mutex_init(&slave->sdw_dev_lock);

	for (i = 0; i < SDW_MAX_PORTS; i++)
		init_completion(&slave->port_ready[i]);
Loading