diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 6df9c48f42bf2..7a5d31483cfc0 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -679,6 +679,11 @@ struct wsa881x_priv { struct sdw_stream_runtime *sruntime; struct sdw_port_config port_config[WSA881X_MAX_SWR_PORTS]; struct gpio_desc *sd_n; + /* + * Logical state for SD_N GPIO: high for shutdown, low for enable. + * For backwards compatibility. + */ + unsigned int sd_n_val; int version; int active_ports; bool port_prepared[WSA881X_MAX_SWR_PORTS]; @@ -1123,6 +1128,26 @@ static int wsa881x_probe(struct sdw_slave *pdev, return dev_err_probe(dev, PTR_ERR(wsa881x->sd_n), "Shutdown Control GPIO not found\n"); + /* + * Backwards compatibility work-around. + * + * The SD_N GPIO is active low, however upstream DTS used always active + * high. Changing the flag in driver and DTS will break backwards + * compatibility, so add a simple value inversion to work with both old + * and new DTS. + * + * This won't work properly with DTS using the flags properly in cases: + * 1. Old DTS with proper ACTIVE_LOW, however such case was broken + * before as the driver required the active high. + * 2. New DTS with proper ACTIVE_HIGH (intended), which is rare case + * (not existing upstream) but possible. This is the price of + * backwards compatibility, therefore this hack should be removed at + * some point. + */ + wsa881x->sd_n_val = gpiod_is_active_low(wsa881x->sd_n); + if (!wsa881x->sd_n_val) + dev_warn(dev, "Using ACTIVE_HIGH for shutdown GPIO. Your DTB might be outdated or you use unsupported configuration for the GPIO."); + dev_set_drvdata(dev, wsa881x); wsa881x->slave = pdev; wsa881x->dev = dev; @@ -1134,7 +1159,7 @@ static int wsa881x_probe(struct sdw_slave *pdev, pdev->prop.sink_ports = GENMASK(WSA881X_MAX_SWR_PORTS, 0); pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop; pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; - gpiod_direction_output(wsa881x->sd_n, 1); + gpiod_direction_output(wsa881x->sd_n, !wsa881x->sd_n_val); wsa881x->regmap = devm_regmap_init_sdw(pdev, &wsa881x_regmap_config); if (IS_ERR(wsa881x->regmap)) @@ -1157,7 +1182,7 @@ static int __maybe_unused wsa881x_runtime_suspend(struct device *dev) struct regmap *regmap = dev_get_regmap(dev, NULL); struct wsa881x_priv *wsa881x = dev_get_drvdata(dev); - gpiod_direction_output(wsa881x->sd_n, 0); + gpiod_direction_output(wsa881x->sd_n, wsa881x->sd_n_val); regcache_cache_only(regmap, true); regcache_mark_dirty(regmap); @@ -1172,13 +1197,13 @@ static int __maybe_unused wsa881x_runtime_resume(struct device *dev) struct wsa881x_priv *wsa881x = dev_get_drvdata(dev); unsigned long time; - gpiod_direction_output(wsa881x->sd_n, 1); + gpiod_direction_output(wsa881x->sd_n, !wsa881x->sd_n_val); time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(WSA881X_PROBE_TIMEOUT)); if (!time) { dev_err(dev, "Initialization not complete, timed out\n"); - gpiod_direction_output(wsa881x->sd_n, 0); + gpiod_direction_output(wsa881x->sd_n, wsa881x->sd_n_val); return -ETIMEDOUT; }