summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/rt5514.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-05-02 08:25:25 +0200
committerTakashi Iwai <tiwai@suse.de>2017-05-02 08:25:25 +0200
commita5c3b32a1146e44f6b38fdfdfffc27842953420c (patch)
treeeca93f51c8deabe77ed079a3e9190717b6380009 /sound/soc/codecs/rt5514.c
parentd7dc450d5a7162de96edbed6b1792240c2f3a55f (diff)
parent20d5c84bef067b7e804a163e2abca16c47125bad (diff)
Merge tag 'asoc-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v4.12 A quiet release for the core, but lots of new drivers this time around: - A new, generalized, API for hooking up jacks which makes it easier to write generic machine drivers for simple cases. - Continuing fixes for issues with the x86 CPU drivers. - New drivers for Cirrus CS35L35, DIO DIO2125, Everest ES7132, HiSilicon hi6210, Maxim MAX98927, MT2701 systems with WM8960, Nuvoton NAU8824, Odroid systems, ST STM32 SAI controllers and x86 systems with DA7213
Diffstat (limited to 'sound/soc/codecs/rt5514.c')
-rw-r--r--sound/soc/codecs/rt5514.c36
1 files changed, 32 insertions, 4 deletions
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index b281a46d769d..f91221b1ddf0 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -1084,13 +1084,28 @@ static int rt5514_parse_dt(struct rt5514_priv *rt5514, struct device *dev)
return 0;
}
+static __maybe_unused int rt5514_i2c_resume(struct device *dev)
+{
+ struct rt5514_priv *rt5514 = dev_get_drvdata(dev);
+ unsigned int val;
+
+ /*
+ * Add a bogus read to avoid rt5514's confusion after s2r in case it
+ * saw glitches on the i2c lines and thought the other side sent a
+ * start bit.
+ */
+ regmap_read(rt5514->regmap, RT5514_VENDOR_ID2, &val);
+
+ return 0;
+}
+
static int rt5514_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct rt5514_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5514_priv *rt5514;
int ret;
- unsigned int val;
+ unsigned int val = ~0;
rt5514 = devm_kzalloc(&i2c->dev, sizeof(struct rt5514_priv),
GFP_KERNEL);
@@ -1120,8 +1135,16 @@ static int rt5514_i2c_probe(struct i2c_client *i2c,
return ret;
}
- regmap_read(rt5514->regmap, RT5514_VENDOR_ID2, &val);
- if (val != RT5514_DEVICE_ID) {
+ /*
+ * The rt5514 can get confused if the i2c lines glitch together, as
+ * can happen at bootup as regulators are turned off and on. If it's
+ * in this glitched state the first i2c read will fail, so we'll give
+ * it one change to retry.
+ */
+ ret = regmap_read(rt5514->regmap, RT5514_VENDOR_ID2, &val);
+ if (ret || val != RT5514_DEVICE_ID)
+ ret = regmap_read(rt5514->regmap, RT5514_VENDOR_ID2, &val);
+ if (ret || val != RT5514_DEVICE_ID) {
dev_err(&i2c->dev,
"Device with ID register %x is not rt5514\n", val);
return -ENODEV;
@@ -1149,10 +1172,15 @@ static int rt5514_i2c_remove(struct i2c_client *i2c)
return 0;
}
-struct i2c_driver rt5514_i2c_driver = {
+static const struct dev_pm_ops rt5514_i2_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(NULL, rt5514_i2c_resume)
+};
+
+static struct i2c_driver rt5514_i2c_driver = {
.driver = {
.name = "rt5514",
.of_match_table = of_match_ptr(rt5514_of_match),
+ .pm = &rt5514_i2_pm_ops,
},
.probe = rt5514_i2c_probe,
.remove = rt5514_i2c_remove,