diff options
Diffstat (limited to 'drivers/soundwire')
-rw-r--r-- | drivers/soundwire/amd_manager.c | 4 | ||||
-rw-r--r-- | drivers/soundwire/bus.c | 58 | ||||
-rw-r--r-- | drivers/soundwire/bus_type.c | 12 | ||||
-rw-r--r-- | drivers/soundwire/intel_ace2x.c | 283 | ||||
-rw-r--r-- | drivers/soundwire/intel_auxdevice.c | 112 | ||||
-rw-r--r-- | drivers/soundwire/qcom.c | 3 |
6 files changed, 438 insertions, 34 deletions
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c index 08aeb7ed00e1..3a99f6dcdfaf 100644 --- a/drivers/soundwire/amd_manager.c +++ b/drivers/soundwire/amd_manager.c @@ -910,9 +910,9 @@ static int amd_sdw_manager_probe(struct platform_device *pdev) return -ENOMEM; amd_manager->acp_mmio = devm_ioremap(dev, res->start, resource_size(res)); - if (IS_ERR(amd_manager->mmio)) { + if (!amd_manager->acp_mmio) { dev_err(dev, "mmio not found\n"); - return PTR_ERR(amd_manager->mmio); + return -ENOMEM; } amd_manager->instance = pdata->instance; amd_manager->mmio = amd_manager->acp_mmio + diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index dba920ec88f6..1720031f35a3 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -3,6 +3,7 @@ #include <linux/acpi.h> #include <linux/delay.h> +#include <linux/irq.h> #include <linux/mod_devicetable.h> #include <linux/pm_runtime.h> #include <linux/soundwire/sdw_registers.h> @@ -12,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) { @@ -25,6 +25,23 @@ static int sdw_get_id(struct sdw_bus *bus) return 0; } +static int sdw_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct sdw_bus *bus = h->host_data; + + irq_set_chip_data(virq, bus); + irq_set_chip(virq, &bus->irq_chip); + irq_set_nested_thread(virq, 1); + irq_set_noprobe(virq); + + return 0; +} + +static const struct irq_domain_ops sdw_domain_ops = { + .map = sdw_irq_map, +}; + /** * sdw_bus_master_add() - add a bus Master instance * @bus: bus instance @@ -151,6 +168,14 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, bus->params.curr_bank = SDW_BANK0; bus->params.next_bank = SDW_BANK1; + bus->irq_chip.name = dev_name(bus->dev); + bus->domain = irq_domain_create_linear(fwnode, SDW_MAX_DEVICES, + &sdw_domain_ops, bus); + if (!bus->domain) { + dev_err(bus->dev, "Failed to add IRQ domain\n"); + return -EINVAL; + } + return 0; } EXPORT_SYMBOL(sdw_bus_master_add); @@ -168,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); @@ -187,6 +212,9 @@ static int sdw_delete_slave(struct device *dev, void *data) void sdw_bus_master_delete(struct sdw_bus *bus) { device_for_each_child(bus->dev, NULL, sdw_delete_slave); + + irq_domain_remove(bus->domain); + sdw_master_device_del(bus); sdw_bus_debugfs_exit(bus); @@ -710,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; @@ -730,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; @@ -781,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; } @@ -922,8 +949,8 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, "initializing enumeration and init completion for Slave %d\n", slave->dev_num); - init_completion(&slave->enumeration_complete); - init_completion(&slave->initialization_complete); + reinit_completion(&slave->enumeration_complete); + reinit_completion(&slave->initialization_complete); } else if ((status == SDW_SLAVE_ATTACHED) && (slave->status == SDW_SLAVE_UNATTACHED)) { @@ -931,7 +958,7 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, "signaling enumeration completion for Slave %d\n", slave->dev_num); - complete(&slave->enumeration_complete); + complete_all(&slave->enumeration_complete); } slave->status = status; mutex_unlock(&bus->bus_lock); @@ -1725,6 +1752,9 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) struct device *dev = &slave->dev; struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); + if (slave->prop.use_domain_irq && slave->irq) + handle_nested_irq(slave->irq); + if (drv->ops && drv->ops->interrupt_callback) { slave_intr.sdca_cascade = sdca_cascade; slave_intr.control_port = clear; @@ -1951,7 +1981,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, "signaling initialization completion for Slave %d\n", slave->dev_num); - complete(&slave->initialization_complete); + complete_all(&slave->initialization_complete); /* * If the manager became pm_runtime active, the peripherals will be diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 1f43ee848eac..fafbc284e82d 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -122,6 +122,12 @@ static int sdw_drv_probe(struct device *dev) if (drv->ops && drv->ops->read_prop) drv->ops->read_prop(slave); + if (slave->prop.use_domain_irq) { + slave->irq = irq_create_mapping(slave->bus->domain, slave->dev_num); + if (!slave->irq) + dev_warn(dev, "Failed to map IRQ\n"); + } + /* init the sysfs as we have properties now */ ret = sdw_slave_sysfs_init(slave); if (ret < 0) @@ -166,7 +172,13 @@ static int sdw_drv_remove(struct device *dev) int ret = 0; mutex_lock(&slave->sdw_dev_lock); + slave->probed = false; + + if (slave->prop.use_domain_irq) + irq_dispose_mapping(irq_find_mapping(slave->bus->domain, + slave->dev_num)); + mutex_unlock(&slave->sdw_dev_lock); if (drv->remove) diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 1be0bea5f40f..a9d25ae0b73f 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -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 = { diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 0daa6ca9a224..7f15e3549e53 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -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; diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 7970fdb27ba0..55be9f4b8d59 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -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> @@ -540,7 +539,7 @@ static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl) status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ)); if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) { - ctrl->status[dev_num] = status; + ctrl->status[dev_num] = status & SWRM_MCP_SLV_STATUS_MASK; return dev_num; } } |