summaryrefslogtreecommitdiff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorShengjiu Wang <shengjiu.wang@nxp.com>2020-03-30 14:32:53 +0800
committerShengjiu Wang <shengjiu.wang@nxp.com>2020-03-31 15:04:07 +0800
commitccb83f789e7db74582b0726f75b5197fcdac7482 (patch)
tree098e568047f24f102a3749bc026802be299aa486 /sound/soc/codecs
parent0bc59849c4b20ba7ae7526935af48123827e1655 (diff)
MLK-23702-3: ASoC: rpmsg_wm8960: Add i2c interface
rpmsg wm8960 also can be registered as an i2c device. Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> Reviewed-by: Viorel Suman <viorel.suman@nxp.com>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/rpmsg_wm8960.c127
1 files changed, 126 insertions, 1 deletions
diff --git a/sound/soc/codecs/rpmsg_wm8960.c b/sound/soc/codecs/rpmsg_wm8960.c
index d70e5a9b0606..b1c6dd476776 100644
--- a/sound/soc/codecs/rpmsg_wm8960.c
+++ b/sound/soc/codecs/rpmsg_wm8960.c
@@ -15,6 +15,7 @@
* General Public License for more details.
*/
#include <linux/clk.h>
+#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/pm_runtime.h>
@@ -1348,6 +1349,12 @@ static int rpmsg_wm8960_probe(struct snd_soc_component *component)
ARRAY_SIZE(wm8960_snd_controls));
wm8960_add_widgets(component);
+ snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(component), "HP_L");
+ snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(component), "HP_R");
+ snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(component), "Playback");
+ snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(component), "Capture");
+ snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(component), "MICB");
+
return 0;
}
@@ -1400,7 +1407,7 @@ static const struct snd_soc_component_driver rpmsg_wm8960_component = {
.suspend_bias_off = 1,
};
-static const struct regmap_config rpmsg_wm8960_regmap = {
+static struct regmap_config rpmsg_wm8960_regmap = {
.reg_bits = 7,
.val_bits = 9,
.max_register = WM8960_PLL4,
@@ -1538,5 +1545,123 @@ static struct platform_driver rpmsg_wm8960_codec_driver = {
module_platform_driver(rpmsg_wm8960_codec_driver);
+static void rpmsg_wm8960_set_pdata_from_of(struct i2c_client *i2c,
+ struct wm8960_data *pdata)
+{
+ const struct device_node *np = i2c->dev.of_node;
+
+ if (of_property_read_bool(np, "wlf,capless"))
+ pdata->capless = true;
+
+ if (of_property_read_bool(np, "wlf,shared-lrclk"))
+ pdata->shared_lrclk = true;
+}
+
+static int rpmsg_wm8960_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
+ struct rpmsg_wm8960_priv *wm8960;
+ int ret;
+ int repeat_reset = 10;
+
+ wm8960 = devm_kzalloc(&i2c->dev, sizeof(struct rpmsg_wm8960_priv),
+ GFP_KERNEL);
+ if (wm8960 == NULL)
+ return -ENOMEM;
+
+ wm8960->mclk = devm_clk_get(&i2c->dev, "mclk");
+ if (IS_ERR(wm8960->mclk)) {
+ if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ }
+
+ rpmsg_wm8960_regmap.reg_read = NULL;
+ rpmsg_wm8960_regmap.reg_write = NULL;
+
+ wm8960->regmap = devm_regmap_init_i2c(i2c, &rpmsg_wm8960_regmap);
+ if (IS_ERR(wm8960->regmap))
+ return PTR_ERR(wm8960->regmap);
+
+ if (pdata)
+ memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data));
+ else if (i2c->dev.of_node)
+ rpmsg_wm8960_set_pdata_from_of(i2c, &wm8960->pdata);
+
+ i2c_set_clientdata(i2c, wm8960);
+
+ do {
+ ret = wm8960_reset(wm8960->regmap);
+ repeat_reset--;
+ } while (repeat_reset > 0 && ret != 0);
+
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to issue reset\n");
+ return ret;
+ }
+
+ if (wm8960->pdata.shared_lrclk) {
+ ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2,
+ 0x4, 0x4);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to enable LRCM: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ /* Latch the update bits */
+ regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_LADC, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_RADC, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_LDAC, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_RDAC, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_LOUT1, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100);
+
+ /*
+ * codec ADCLRC pin configured as GPIO, DACLRC pin is used as a frame
+ * clock for ADCs and DACs
+ */
+ regmap_update_bits(wm8960->regmap, WM8960_IFACE2, 1<<6, 1<<6);
+
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &rpmsg_wm8960_component, &rpmsg_wm8960_codec_dai, 1);
+
+ return ret;
+}
+
+static int rpmsg_wm8960_i2c_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static const struct i2c_device_id rpmsg_wm8960_i2c_id[] = {
+ { "wm8960", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
+
+static const struct of_device_id rpmsg_wm8960_of_match[] = {
+ { .compatible = "wlf,wm8960,lpa", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rpmsg_wm8960_of_match);
+
+static struct i2c_driver rpmsg_wm8960_i2c_driver = {
+ .driver = {
+ .name = RPMSG_CODEC_DRV_NAME_WM8960,
+ .of_match_table = rpmsg_wm8960_of_match,
+ },
+ .probe = rpmsg_wm8960_i2c_probe,
+ .remove = rpmsg_wm8960_i2c_remove,
+ .id_table = rpmsg_wm8960_i2c_id,
+};
+
+module_i2c_driver(rpmsg_wm8960_i2c_driver);
+
MODULE_DESCRIPTION("rpmsg wm8960 Codec Driver");
MODULE_LICENSE("GPL");