soundwire updates for 6.6
- Core support for soundwire device number allocation - intel driver updates for adding hw_params for DAI ops, hybrid number allocation and power managemnt callback updates - DT header include changes for subsystem -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmT0vxoACgkQfBQHDyUj g0f/Lg/8CHWdjQzNJVOoJIqY+mFjIKT+QtyRZSpdaQIFYcQF4xcd6v6/rEJzLjgg bMlJ+Icwe19sIq2Yhq69kcecCD5/Arx3tqo2WAwcUF5NykFVQnO/FO+qZYdNM8A9 ohI8+1ZM1qyrC0YocpiUUINOek0MVeLf4wBFFiJMZRVNNMpCH7LrOcs+vH8bLKYn i03dXc/sbM0QyBnfsjnu02wbaq84pFOlbkLJYn21cFoiqryMAXjNXRIpuJ35T5BX iXgHHhVX4vWgOszLM83BhKQnSCemNb4y24ablm9gtVBMpNg2yAyHL0qpAk9nFhGn vVZIup8OVpfziW6O48BBA7HWMBA0fRL8Iz80oH8ZoAAfRl32QGKal37jUaOL7ycO +kMNbJq85v0NDRnUiHeUAY/X5gnnRZpbCLzWxpp3ohx8W0mQctQRFoArhITV7O0Q 38RNfe89Fq6f9poz56tj+d8d/zLx0VzLqPjiuP89HeeOboIjkGtNRfU1z/V9Wh2G 8Fr77rwSAo+wghlFpHE8S9gkyLvMiVeEdNEHskQod7ZvAD2YrfHPLENOW7L0rpGw Eurl+bby1hqgsvA6gQqUQt2xeumeLYelttZYcmMGhPLo7RTYbTckwh6CO2iomNL/ noCtG/mNbR78pOKIab4VWoLcOzFfJ3qCpdOLzYBQYphxJo2oj50= =4w8N -----END PGP SIGNATURE----- Merge tag 'soundwire-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire Pull soundwire updates from Vinod Koul: "Device numbering and intel driver changes are main features: - Core support for soundwire device number allocation - intel driver updates for adding hw_params for DAI ops, hybrid number allocation and power managemnt callback updates - DT header include changes for subsystem" * tag 'soundwire-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: soundwire: intel_ace2x: add DAI hw_params/prepare/hw_free callbacks soundwire: intel_auxdevice: add hybrid IDA-based device_number allocation soundwire: bus: add callbacks for device_number allocation soundwire: extend parameters of new_peripheral_assigned() callback soundWire: intel_auxdevice: resume 'sdw-master' on startup and system resume soundwire: intel_auxdevice: enable pm_runtime earlier on startup soundwire: Explicitly include correct DT includes
This commit is contained in:
commit
6e32dfcccf
@ -13,7 +13,6 @@
|
||||
#include "sysfs_local.h"
|
||||
|
||||
static DEFINE_IDA(sdw_bus_ida);
|
||||
static DEFINE_IDA(sdw_peripheral_ida);
|
||||
|
||||
static int sdw_get_id(struct sdw_bus *bus)
|
||||
{
|
||||
@ -194,8 +193,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
|
||||
|
||||
if (slave->dev_num) { /* clear dev_num if assigned */
|
||||
clear_bit(slave->dev_num, bus->assigned);
|
||||
if (bus->dev_num_ida_min)
|
||||
ida_free(&sdw_peripheral_ida, slave->dev_num);
|
||||
if (bus->ops && bus->ops->put_device_num)
|
||||
bus->ops->put_device_num(bus, slave);
|
||||
}
|
||||
list_del_init(&slave->node);
|
||||
mutex_unlock(&bus->bus_lock);
|
||||
@ -739,16 +738,15 @@ EXPORT_SYMBOL(sdw_compare_devid);
|
||||
/* called with bus_lock held */
|
||||
static int sdw_get_device_num(struct sdw_slave *slave)
|
||||
{
|
||||
struct sdw_bus *bus = slave->bus;
|
||||
int bit;
|
||||
|
||||
if (slave->bus->dev_num_ida_min) {
|
||||
bit = ida_alloc_range(&sdw_peripheral_ida,
|
||||
slave->bus->dev_num_ida_min, SDW_MAX_DEVICES,
|
||||
GFP_KERNEL);
|
||||
if (bus->ops && bus->ops->get_device_num) {
|
||||
bit = bus->ops->get_device_num(bus, slave);
|
||||
if (bit < 0)
|
||||
goto err;
|
||||
} else {
|
||||
bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES);
|
||||
bit = find_first_zero_bit(bus->assigned, SDW_MAX_DEVICES);
|
||||
if (bit == SDW_MAX_DEVICES) {
|
||||
bit = -ENODEV;
|
||||
goto err;
|
||||
@ -759,7 +757,7 @@ static int sdw_get_device_num(struct sdw_slave *slave)
|
||||
* Do not update dev_num in Slave data structure here,
|
||||
* Update once program dev_num is successful
|
||||
*/
|
||||
set_bit(bit, slave->bus->assigned);
|
||||
set_bit(bit, bus->assigned);
|
||||
|
||||
err:
|
||||
return bit;
|
||||
@ -810,7 +808,7 @@ static int sdw_assign_device_num(struct sdw_slave *slave)
|
||||
slave->dev_num = slave->dev_num_sticky;
|
||||
|
||||
if (bus->ops && bus->ops->new_peripheral_assigned)
|
||||
bus->ops->new_peripheral_assigned(bus, dev_num);
|
||||
bus->ops->new_peripheral_assigned(bus, slave, dev_num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/soundwire/sdw_registers.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_intel.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/hda-mlink.h>
|
||||
#include "cadence_master.h"
|
||||
#include "bus.h"
|
||||
@ -191,10 +192,292 @@ static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw)
|
||||
return hdac_bus_eml_sdw_check_cmdsync_unlocked(sdw->link_res->hbus);
|
||||
}
|
||||
|
||||
/* DAI callbacks */
|
||||
static int intel_params_stream(struct sdw_intel *sdw,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai,
|
||||
struct snd_pcm_hw_params *hw_params,
|
||||
int link_id, int alh_stream_id)
|
||||
{
|
||||
struct sdw_intel_link_res *res = sdw->link_res;
|
||||
struct sdw_intel_stream_params_data params_data;
|
||||
|
||||
params_data.substream = substream;
|
||||
params_data.dai = dai;
|
||||
params_data.hw_params = hw_params;
|
||||
params_data.link_id = link_id;
|
||||
params_data.alh_stream_id = alh_stream_id;
|
||||
|
||||
if (res->ops && res->ops->params_stream && res->dev)
|
||||
return res->ops->params_stream(res->dev,
|
||||
¶ms_data);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int intel_free_stream(struct sdw_intel *sdw,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai,
|
||||
int link_id)
|
||||
|
||||
{
|
||||
struct sdw_intel_link_res *res = sdw->link_res;
|
||||
struct sdw_intel_stream_free_data free_data;
|
||||
|
||||
free_data.substream = substream;
|
||||
free_data.dai = dai;
|
||||
free_data.link_id = link_id;
|
||||
|
||||
if (res->ops && res->ops->free_stream && res->dev)
|
||||
return res->ops->free_stream(res->dev,
|
||||
&free_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DAI operations
|
||||
*/
|
||||
static int intel_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
|
||||
struct sdw_intel *sdw = cdns_to_intel(cdns);
|
||||
struct sdw_cdns_dai_runtime *dai_runtime;
|
||||
struct sdw_cdns_pdi *pdi;
|
||||
struct sdw_stream_config sconfig;
|
||||
struct sdw_port_config *pconfig;
|
||||
int ch, dir;
|
||||
int ret;
|
||||
|
||||
dai_runtime = cdns->dai_runtime_array[dai->id];
|
||||
if (!dai_runtime)
|
||||
return -EIO;
|
||||
|
||||
ch = params_channels(params);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
dir = SDW_DATA_DIR_RX;
|
||||
else
|
||||
dir = SDW_DATA_DIR_TX;
|
||||
|
||||
pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
|
||||
|
||||
if (!pdi) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* the SHIM will be configured in the callback functions */
|
||||
|
||||
sdw_cdns_config_stream(cdns, ch, dir, pdi);
|
||||
|
||||
/* store pdi and state, may be needed in prepare step */
|
||||
dai_runtime->paused = false;
|
||||
dai_runtime->suspended = false;
|
||||
dai_runtime->pdi = pdi;
|
||||
|
||||
/* Inform DSP about PDI stream number */
|
||||
ret = intel_params_stream(sdw, substream, dai, params,
|
||||
sdw->instance,
|
||||
pdi->intel_alh_id);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
sconfig.direction = dir;
|
||||
sconfig.ch_count = ch;
|
||||
sconfig.frame_rate = params_rate(params);
|
||||
sconfig.type = dai_runtime->stream_type;
|
||||
|
||||
sconfig.bps = snd_pcm_format_width(params_format(params));
|
||||
|
||||
/* Port configuration */
|
||||
pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL);
|
||||
if (!pconfig) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pconfig->num = pdi->num;
|
||||
pconfig->ch_mask = (1 << ch) - 1;
|
||||
|
||||
ret = sdw_stream_add_master(&cdns->bus, &sconfig,
|
||||
pconfig, 1, dai_runtime->stream);
|
||||
if (ret)
|
||||
dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
|
||||
|
||||
kfree(pconfig);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
|
||||
struct sdw_intel *sdw = cdns_to_intel(cdns);
|
||||
struct sdw_cdns_dai_runtime *dai_runtime;
|
||||
int ch, dir;
|
||||
int ret = 0;
|
||||
|
||||
dai_runtime = cdns->dai_runtime_array[dai->id];
|
||||
if (!dai_runtime) {
|
||||
dev_err(dai->dev, "failed to get dai runtime in %s\n",
|
||||
__func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (dai_runtime->suspended) {
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_pcm_hw_params *hw_params;
|
||||
|
||||
hw_params = &rtd->dpcm[substream->stream].hw_params;
|
||||
|
||||
dai_runtime->suspended = false;
|
||||
|
||||
/*
|
||||
* .prepare() is called after system resume, where we
|
||||
* need to reinitialize the SHIM/ALH/Cadence IP.
|
||||
* .prepare() is also called to deal with underflows,
|
||||
* but in those cases we cannot touch ALH/SHIM
|
||||
* registers
|
||||
*/
|
||||
|
||||
/* configure stream */
|
||||
ch = params_channels(hw_params);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
dir = SDW_DATA_DIR_RX;
|
||||
else
|
||||
dir = SDW_DATA_DIR_TX;
|
||||
|
||||
/* the SHIM will be configured in the callback functions */
|
||||
|
||||
sdw_cdns_config_stream(cdns, ch, dir, dai_runtime->pdi);
|
||||
|
||||
/* Inform DSP about PDI stream number */
|
||||
ret = intel_params_stream(sdw, substream, dai,
|
||||
hw_params,
|
||||
sdw->instance,
|
||||
dai_runtime->pdi->intel_alh_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
|
||||
struct sdw_intel *sdw = cdns_to_intel(cdns);
|
||||
struct sdw_cdns_dai_runtime *dai_runtime;
|
||||
int ret;
|
||||
|
||||
dai_runtime = cdns->dai_runtime_array[dai->id];
|
||||
if (!dai_runtime)
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* The sdw stream state will transition to RELEASED when stream->
|
||||
* master_list is empty. So the stream state will transition to
|
||||
* DEPREPARED for the first cpu-dai and to RELEASED for the last
|
||||
* cpu-dai.
|
||||
*/
|
||||
ret = sdw_stream_remove_master(&cdns->bus, dai_runtime->stream);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "remove master from stream %s failed: %d\n",
|
||||
dai_runtime->stream->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = intel_free_stream(sdw, substream, dai, sdw->instance);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "intel_free_stream: failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dai_runtime->pdi = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
|
||||
void *stream, int direction)
|
||||
{
|
||||
return cdns_set_sdw_stream(dai, stream, direction);
|
||||
}
|
||||
|
||||
static void *intel_get_sdw_stream(struct snd_soc_dai *dai,
|
||||
int direction)
|
||||
{
|
||||
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
|
||||
struct sdw_cdns_dai_runtime *dai_runtime;
|
||||
|
||||
dai_runtime = cdns->dai_runtime_array[dai->id];
|
||||
if (!dai_runtime)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return dai_runtime->stream;
|
||||
}
|
||||
|
||||
static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
|
||||
struct sdw_intel *sdw = cdns_to_intel(cdns);
|
||||
struct sdw_intel_link_res *res = sdw->link_res;
|
||||
struct sdw_cdns_dai_runtime *dai_runtime;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* The .trigger callback is used to program HDaudio DMA and send required IPC to audio
|
||||
* firmware.
|
||||
*/
|
||||
if (res->ops && res->ops->trigger) {
|
||||
ret = res->ops->trigger(substream, cmd, dai);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dai_runtime = cdns->dai_runtime_array[dai->id];
|
||||
if (!dai_runtime) {
|
||||
dev_err(dai->dev, "failed to get dai runtime in %s\n",
|
||||
__func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
|
||||
/*
|
||||
* The .prepare callback is used to deal with xruns and resume operations.
|
||||
* In the case of xruns, the DMAs and SHIM registers cannot be touched,
|
||||
* but for resume operations the DMAs and SHIM registers need to be initialized.
|
||||
* the .trigger callback is used to track the suspend case only.
|
||||
*/
|
||||
|
||||
dai_runtime->suspended = true;
|
||||
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
dai_runtime->paused = true;
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
dai_runtime->paused = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
|
||||
.hw_params = intel_hw_params,
|
||||
.prepare = intel_prepare,
|
||||
.hw_free = intel_hw_free,
|
||||
.trigger = intel_trigger,
|
||||
.set_stream = intel_pcm_set_sdw_stream,
|
||||
.get_stream = intel_get_sdw_stream,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver dai_component = {
|
||||
|
@ -23,9 +23,6 @@
|
||||
#include "intel.h"
|
||||
#include "intel_auxdevice.h"
|
||||
|
||||
/* IDA min selected to avoid conflicts with HDaudio/iDISP SDI values */
|
||||
#define INTEL_DEV_NUM_IDA_MIN 4
|
||||
|
||||
#define INTEL_MASTER_SUSPEND_DELAY_MS 3000
|
||||
|
||||
/*
|
||||
@ -44,6 +41,39 @@ static int md_flags;
|
||||
module_param_named(sdw_md_flags, md_flags, int, 0444);
|
||||
MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off)");
|
||||
|
||||
struct wake_capable_part {
|
||||
const u16 mfg_id;
|
||||
const u16 part_id;
|
||||
};
|
||||
|
||||
static struct wake_capable_part wake_capable_list[] = {
|
||||
{0x025d, 0x5682},
|
||||
{0x025d, 0x700},
|
||||
{0x025d, 0x711},
|
||||
{0x025d, 0x1712},
|
||||
{0x025d, 0x1713},
|
||||
{0x025d, 0x1716},
|
||||
{0x025d, 0x1717},
|
||||
{0x025d, 0x712},
|
||||
{0x025d, 0x713},
|
||||
{0x025d, 0x714},
|
||||
{0x025d, 0x715},
|
||||
{0x025d, 0x716},
|
||||
{0x025d, 0x717},
|
||||
{0x025d, 0x722},
|
||||
};
|
||||
|
||||
static bool is_wake_capable(struct sdw_slave *slave)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wake_capable_list); i++)
|
||||
if (slave->id.part_id == wake_capable_list[i].part_id &&
|
||||
slave->id.mfg_id == wake_capable_list[i].mfg_id)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int generic_pre_bank_switch(struct sdw_bus *bus)
|
||||
{
|
||||
struct sdw_cdns *cdns = bus_to_cdns(bus);
|
||||
@ -60,18 +90,32 @@ static int generic_post_bank_switch(struct sdw_bus *bus)
|
||||
return sdw->link_res->hw_ops->post_bank_switch(sdw);
|
||||
}
|
||||
|
||||
static void generic_new_peripheral_assigned(struct sdw_bus *bus, int dev_num)
|
||||
static void generic_new_peripheral_assigned(struct sdw_bus *bus,
|
||||
struct sdw_slave *slave,
|
||||
int dev_num)
|
||||
{
|
||||
struct sdw_cdns *cdns = bus_to_cdns(bus);
|
||||
struct sdw_intel *sdw = cdns_to_intel(cdns);
|
||||
int dev_num_min;
|
||||
int dev_num_max;
|
||||
bool wake_capable = slave->prop.wake_capable || is_wake_capable(slave);
|
||||
|
||||
if (wake_capable) {
|
||||
dev_num_min = SDW_INTEL_DEV_NUM_IDA_MIN;
|
||||
dev_num_max = SDW_MAX_DEVICES;
|
||||
} else {
|
||||
dev_num_min = 1;
|
||||
dev_num_max = SDW_INTEL_DEV_NUM_IDA_MIN - 1;
|
||||
}
|
||||
|
||||
/* paranoia check, this should never happen */
|
||||
if (dev_num < INTEL_DEV_NUM_IDA_MIN || dev_num > SDW_MAX_DEVICES) {
|
||||
dev_err(bus->dev, "%s: invalid dev_num %d\n", __func__, dev_num);
|
||||
if (dev_num < dev_num_min || dev_num > dev_num_max) {
|
||||
dev_err(bus->dev, "%s: invalid dev_num %d, wake supported %d\n",
|
||||
__func__, dev_num, slave->prop.wake_capable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sdw->link_res->hw_ops->program_sdi)
|
||||
if (sdw->link_res->hw_ops->program_sdi && wake_capable)
|
||||
sdw->link_res->hw_ops->program_sdi(sdw, dev_num);
|
||||
}
|
||||
|
||||
@ -123,6 +167,30 @@ static int intel_prop_read(struct sdw_bus *bus)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_IDA(intel_peripheral_ida);
|
||||
|
||||
static int intel_get_device_num_ida(struct sdw_bus *bus, struct sdw_slave *slave)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (slave->prop.wake_capable || is_wake_capable(slave))
|
||||
return ida_alloc_range(&intel_peripheral_ida,
|
||||
SDW_INTEL_DEV_NUM_IDA_MIN, SDW_MAX_DEVICES,
|
||||
GFP_KERNEL);
|
||||
|
||||
bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES);
|
||||
if (bit == SDW_MAX_DEVICES)
|
||||
return -ENODEV;
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
static void intel_put_device_num_ida(struct sdw_bus *bus, struct sdw_slave *slave)
|
||||
{
|
||||
if (slave->prop.wake_capable || is_wake_capable(slave))
|
||||
ida_free(&intel_peripheral_ida, slave->dev_num);
|
||||
}
|
||||
|
||||
static struct sdw_master_ops sdw_intel_ops = {
|
||||
.read_prop = intel_prop_read,
|
||||
.override_adr = sdw_dmi_override_adr,
|
||||
@ -132,6 +200,8 @@ static struct sdw_master_ops sdw_intel_ops = {
|
||||
.pre_bank_switch = generic_pre_bank_switch,
|
||||
.post_bank_switch = generic_post_bank_switch,
|
||||
.read_ping_status = cdns_read_ping_status,
|
||||
.get_device_num = intel_get_device_num_ida,
|
||||
.put_device_num = intel_put_device_num_ida,
|
||||
.new_peripheral_assigned = generic_new_peripheral_assigned,
|
||||
};
|
||||
|
||||
@ -165,7 +235,6 @@ static int intel_link_probe(struct auxiliary_device *auxdev,
|
||||
cdns->msg_count = 0;
|
||||
|
||||
bus->link_id = auxdev->id;
|
||||
bus->dev_num_ida_min = INTEL_DEV_NUM_IDA_MIN;
|
||||
bus->clk_stop_timeout = 1;
|
||||
|
||||
sdw_cdns_probe(cdns);
|
||||
@ -248,13 +317,6 @@ int intel_link_startup(struct auxiliary_device *auxdev)
|
||||
|
||||
sdw_intel_debugfs_init(sdw);
|
||||
|
||||
/* start bus */
|
||||
ret = sdw_intel_start_bus(sdw);
|
||||
if (ret) {
|
||||
dev_err(dev, "bus start failed: %d\n", ret);
|
||||
goto err_power_up;
|
||||
}
|
||||
|
||||
/* Enable runtime PM */
|
||||
if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) {
|
||||
pm_runtime_set_autosuspend_delay(dev,
|
||||
@ -264,6 +326,15 @@ int intel_link_startup(struct auxiliary_device *auxdev)
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
pm_runtime_resume(bus->dev);
|
||||
}
|
||||
|
||||
/* start bus */
|
||||
ret = sdw_intel_start_bus(sdw);
|
||||
if (ret) {
|
||||
dev_err(dev, "bus start failed: %d\n", ret);
|
||||
goto err_pm_runtime;
|
||||
}
|
||||
|
||||
clock_stop_quirks = sdw->link_res->clock_stop_quirks;
|
||||
@ -293,12 +364,18 @@ int intel_link_startup(struct auxiliary_device *auxdev)
|
||||
* with a delay. A more complete solution would require the
|
||||
* definition of Master properties.
|
||||
*/
|
||||
if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE))
|
||||
if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) {
|
||||
pm_runtime_mark_last_busy(bus->dev);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_idle(dev);
|
||||
}
|
||||
|
||||
sdw->startup_done = true;
|
||||
return 0;
|
||||
|
||||
err_pm_runtime:
|
||||
if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME))
|
||||
pm_runtime_disable(dev);
|
||||
err_power_up:
|
||||
sdw_intel_link_power_down(sdw);
|
||||
err_init:
|
||||
@ -552,6 +629,8 @@ static int __maybe_unused intel_resume(struct device *dev)
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
pm_runtime_resume(bus->dev);
|
||||
|
||||
link_flags = md_flags >> (bus->link_id * 8);
|
||||
|
||||
if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE))
|
||||
@ -587,6 +666,7 @@ static int __maybe_unused intel_resume(struct device *dev)
|
||||
* counters and delay the pm_runtime suspend by several
|
||||
* seconds, by when all enumeration should be complete.
|
||||
*/
|
||||
pm_runtime_mark_last_busy(bus->dev);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
|
||||
return 0;
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
|
@ -858,6 +858,8 @@ struct sdw_defer {
|
||||
* @post_bank_switch: Callback for post bank switch
|
||||
* @read_ping_status: Read status from PING frames, reported with two bits per Device.
|
||||
* Bits 31:24 are reserved.
|
||||
* @get_device_num: Callback for vendor-specific device_number allocation
|
||||
* @put_device_num: Callback for vendor-specific device_number release
|
||||
* @new_peripheral_assigned: Callback to handle enumeration of new peripheral.
|
||||
*/
|
||||
struct sdw_master_ops {
|
||||
@ -873,7 +875,11 @@ struct sdw_master_ops {
|
||||
int (*pre_bank_switch)(struct sdw_bus *bus);
|
||||
int (*post_bank_switch)(struct sdw_bus *bus);
|
||||
u32 (*read_ping_status)(struct sdw_bus *bus);
|
||||
void (*new_peripheral_assigned)(struct sdw_bus *bus, int dev_num);
|
||||
int (*get_device_num)(struct sdw_bus *bus, struct sdw_slave *slave);
|
||||
void (*put_device_num)(struct sdw_bus *bus, struct sdw_slave *slave);
|
||||
void (*new_peripheral_assigned)(struct sdw_bus *bus,
|
||||
struct sdw_slave *slave,
|
||||
int dev_num);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -908,9 +914,6 @@ struct sdw_master_ops {
|
||||
* meaningful if multi_link is set. If set to 1, hardware-based
|
||||
* synchronization will be used even if a stream only uses a single
|
||||
* SoundWire segment.
|
||||
* @dev_num_ida_min: if set, defines the minimum values for the IDA
|
||||
* used to allocate system-unique device numbers. This value needs to be
|
||||
* identical across all SoundWire bus in the system.
|
||||
*/
|
||||
struct sdw_bus {
|
||||
struct device *dev;
|
||||
@ -939,7 +942,6 @@ struct sdw_bus {
|
||||
u32 bank_switch_timeout;
|
||||
bool multi_link;
|
||||
int hw_sync_min_links;
|
||||
int dev_num_ida_min;
|
||||
};
|
||||
|
||||
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
|
||||
|
@ -428,4 +428,11 @@ struct sdw_intel_hw_ops {
|
||||
extern const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops;
|
||||
extern const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops;
|
||||
|
||||
/*
|
||||
* IDA min selected to allow for 5 unconstrained devices per link,
|
||||
* and 6 system-unique Device Numbers for wake-capable devices.
|
||||
*/
|
||||
|
||||
#define SDW_INTEL_DEV_NUM_IDA_MIN 6
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user