Skip to content

Commit

Permalink
ASoC: codecs: wsa881x: Use proper shutdown GPIO polarity
Browse files Browse the repository at this point in the history
The shutdown GPIO is active low (SD_N), but this depends on actual board
layout.  Linux drivers should only care about logical state, where high
(1) means shutdown and low (0) means do not shutdown.

Invert the GPIO to match logical value while preserving backwards DTB
compatibility.  It is not possible to detect whether ACTIVE_HIGH flag in
DTB is because it is an old DTB (using incorrect flag) or it is a new
DTB with a correct hardware pin polarity description.  Therefore the
solution prioritizes backwards compatibility while relying on relevant
DTS being upstreamed.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20230102114152.297305-4-krzysztof.kozlowski@linaro.org
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Krzysztof Kozlowski authored and Mark Brown committed Jan 16, 2023
1 parent 31a9036 commit 7384558
Showing 1 changed file with 29 additions and 4 deletions.
33 changes: 29 additions & 4 deletions sound/soc/codecs/wsa881x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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;
Expand All @@ -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))
Expand All @@ -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);
Expand All @@ -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;
}

Expand Down

0 comments on commit 7384558

Please sign in to comment.