From 395713d8ca434967808670000e6baa3505e8e947 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 21 Aug 2019 13:58:21 -0500 Subject: [PATCH] soundwire: intel: handle disabled links On most hardware platforms, SoundWire interfaces are pin-muxed with other interfaces (typically DMIC or I2S) and the status of each link needs to be checked at boot time. For Intel platforms, the BIOS provides a menu to enable/disable the links separately, and the information is provided to the OS with an Intel-specific _DSD property. The same capability will be added to revisions of the MIPI DisCo specification. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190821185821.12690-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 25 ++++++++++++++++++++++--- include/linux/soundwire/sdw.h | 2 ++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 85014181a40d..f1e38a293967 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -91,6 +91,8 @@ #define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0) #define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16) +#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1) + enum intel_pdi_type { INTEL_PDI_IN = 0, INTEL_PDI_OUT = 1, @@ -944,6 +946,7 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) struct sdw_master_prop *prop = &bus->prop; struct fwnode_handle *link; char name[32]; + u32 quirk_mask; /* Find master handle */ snprintf(name, sizeof(name), @@ -958,6 +961,14 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) fwnode_property_read_u32(link, "intel-sdw-ip-clock", &prop->mclk_freq); + + fwnode_property_read_u32(link, + "intel-quirk-mask", + &quirk_mask); + + if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) + prop->hw_disabled = true; + return 0; } @@ -1018,6 +1029,12 @@ static int intel_probe(struct platform_device *pdev) goto err_master_reg; } + if (sdw->cdns.bus.prop.hw_disabled) { + dev_info(&pdev->dev, "SoundWire master %d is disabled, ignoring\n", + sdw->cdns.bus.link_id); + return 0; + } + /* Initialize shim and controller */ intel_link_power_up(sdw); intel_shim_init(sdw); @@ -1071,9 +1088,11 @@ static int intel_remove(struct platform_device *pdev) sdw = platform_get_drvdata(pdev); - intel_debugfs_exit(sdw); - free_irq(sdw->res->irq, sdw); - snd_soc_unregister_component(sdw->cdns.dev); + if (!sdw->cdns.bus.prop.hw_disabled) { + intel_debugfs_exit(sdw); + free_irq(sdw->res->irq, sdw); + snd_soc_unregister_component(sdw->cdns.dev); + } sdw_delete_bus_master(&sdw->cdns.bus); return 0; diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 2028318a4c62..be9fe08d4e9c 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -380,6 +380,7 @@ struct sdw_slave_prop { * @err_threshold: Number of times that software may retry sending a single * command * @mclk_freq: clock reference passed to SoundWire Master, in Hz. + * @hw_disabled: if true, the Master is not functional, typically due to pin-mux */ struct sdw_master_prop { u32 revision; @@ -395,6 +396,7 @@ struct sdw_master_prop { bool dynamic_frame; u32 err_threshold; u32 mclk_freq; + bool hw_disabled; }; int sdw_master_read_prop(struct sdw_bus *bus);