summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/wsa881x.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wsa881x.c')
-rw-r--r--sound/soc/codecs/wsa881x.c63
1 files changed, 41 insertions, 22 deletions
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 6c8b1db649b8..f709231b1277 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -5,10 +5,7 @@
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
-#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@@ -424,7 +421,7 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = {
}
};
-static struct sdw_port_config wsa881x_pconfig[WSA881X_MAX_SWR_PORTS] = {
+static const struct sdw_port_config wsa881x_pconfig[WSA881X_MAX_SWR_PORTS] = {
{
.num = 1,
.ch_mask = 0x1,
@@ -679,6 +676,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];
@@ -1101,7 +1103,7 @@ static int wsa881x_bus_config(struct sdw_slave *slave,
return 0;
}
-static struct sdw_slave_ops wsa881x_slave_ops = {
+static const struct sdw_slave_ops wsa881x_slave_ops = {
.update_status = wsa881x_update_status,
.bus_config = wsa881x_bus_config,
.port_prep = wsa881x_port_prep,
@@ -1113,20 +1115,39 @@ static int wsa881x_probe(struct sdw_slave *pdev,
struct wsa881x_priv *wsa881x;
struct device *dev = &pdev->dev;
- wsa881x = devm_kzalloc(&pdev->dev, sizeof(*wsa881x), GFP_KERNEL);
+ wsa881x = devm_kzalloc(dev, sizeof(*wsa881x), GFP_KERNEL);
if (!wsa881x)
return -ENOMEM;
- wsa881x->sd_n = devm_gpiod_get_optional(&pdev->dev, "powerdown",
+ wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown",
GPIOD_FLAGS_BIT_NONEXCLUSIVE);
- if (IS_ERR(wsa881x->sd_n)) {
- dev_err(&pdev->dev, "Shutdown Control GPIO not found\n");
- return PTR_ERR(wsa881x->sd_n);
- }
+ if (IS_ERR(wsa881x->sd_n))
+ return dev_err_probe(dev, PTR_ERR(wsa881x->sd_n),
+ "Shutdown Control GPIO not found\n");
- dev_set_drvdata(&pdev->dev, wsa881x);
+ /*
+ * 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 = &pdev->dev;
+ wsa881x->dev = dev;
wsa881x->sconfig.ch_count = 1;
wsa881x->sconfig.bps = 1;
wsa881x->sconfig.frame_rate = 48000;
@@ -1135,13 +1156,11 @@ 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)) {
- dev_err(&pdev->dev, "regmap_init failed\n");
- return PTR_ERR(wsa881x->regmap);
- }
+ if (IS_ERR(wsa881x->regmap))
+ return dev_err_probe(dev, PTR_ERR(wsa881x->regmap), "regmap_init failed\n");
pm_runtime_set_autosuspend_delay(dev, 3000);
pm_runtime_use_autosuspend(dev);
@@ -1149,7 +1168,7 @@ static int wsa881x_probe(struct sdw_slave *pdev,
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- return devm_snd_soc_register_component(&pdev->dev,
+ return devm_snd_soc_register_component(dev,
&wsa881x_component_drv,
wsa881x_dais,
ARRAY_SIZE(wsa881x_dais));
@@ -1160,7 +1179,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);
@@ -1175,13 +1194,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;
}