xref: /openbmc/linux/sound/soc/codecs/rt1015p.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1c07152d4STzung-Bi Shih // SPDX-License-Identifier: GPL-2.0-only
2c07152d4STzung-Bi Shih //
3c07152d4STzung-Bi Shih // rt1015p.c  --  RT1015P ALSA SoC audio amplifier driver
4c07152d4STzung-Bi Shih //
5c07152d4STzung-Bi Shih // Copyright 2020 The Linux Foundation. All rights reserved.
6c07152d4STzung-Bi Shih 
7464b489aSJack Yu #include <linux/acpi.h>
8f102d0d1STzung-Bi Shih #include <linux/delay.h>
9c07152d4STzung-Bi Shih #include <linux/device.h>
10c07152d4STzung-Bi Shih #include <linux/err.h>
11c07152d4STzung-Bi Shih #include <linux/gpio/consumer.h>
12c07152d4STzung-Bi Shih #include <linux/kernel.h>
13c07152d4STzung-Bi Shih #include <linux/module.h>
14c07152d4STzung-Bi Shih #include <linux/of.h>
15c07152d4STzung-Bi Shih #include <linux/platform_device.h>
16c07152d4STzung-Bi Shih #include <sound/pcm.h>
17c07152d4STzung-Bi Shih #include <sound/soc.h>
18c07152d4STzung-Bi Shih #include <sound/soc-dai.h>
19c07152d4STzung-Bi Shih #include <sound/soc-dapm.h>
20c07152d4STzung-Bi Shih 
21c07152d4STzung-Bi Shih struct rt1015p_priv {
22c07152d4STzung-Bi Shih 	struct gpio_desc *sdb;
23f102d0d1STzung-Bi Shih 	bool calib_done;
24c07152d4STzung-Bi Shih };
25c07152d4STzung-Bi Shih 
rt1015p_sdb_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)26c07152d4STzung-Bi Shih static int rt1015p_sdb_event(struct snd_soc_dapm_widget *w,
27c07152d4STzung-Bi Shih 		struct snd_kcontrol *kcontrol, int event)
28c07152d4STzung-Bi Shih {
29c07152d4STzung-Bi Shih 	struct snd_soc_component *component =
30c07152d4STzung-Bi Shih 		snd_soc_dapm_to_component(w->dapm);
31c07152d4STzung-Bi Shih 	struct rt1015p_priv *rt1015p =
32c07152d4STzung-Bi Shih 		snd_soc_component_get_drvdata(component);
33c07152d4STzung-Bi Shih 
344ab93017STzung-Bi Shih 	if (!rt1015p->sdb)
354ab93017STzung-Bi Shih 		return 0;
364ab93017STzung-Bi Shih 
374ab93017STzung-Bi Shih 	switch (event) {
384ab93017STzung-Bi Shih 	case SND_SOC_DAPM_PRE_PMU:
394ab93017STzung-Bi Shih 		gpiod_set_value_cansleep(rt1015p->sdb, 1);
404ab93017STzung-Bi Shih 		dev_dbg(component->dev, "set sdb to 1");
41f102d0d1STzung-Bi Shih 
42f102d0d1STzung-Bi Shih 		if (!rt1015p->calib_done) {
43f102d0d1STzung-Bi Shih 			msleep(300);
44f102d0d1STzung-Bi Shih 			rt1015p->calib_done = true;
45f102d0d1STzung-Bi Shih 		}
464ab93017STzung-Bi Shih 		break;
474ab93017STzung-Bi Shih 	case SND_SOC_DAPM_POST_PMD:
484ab93017STzung-Bi Shih 		gpiod_set_value_cansleep(rt1015p->sdb, 0);
494ab93017STzung-Bi Shih 		dev_dbg(component->dev, "set sdb to 0");
504ab93017STzung-Bi Shih 		break;
514ab93017STzung-Bi Shih 	default:
524ab93017STzung-Bi Shih 		break;
534ab93017STzung-Bi Shih 	}
54c07152d4STzung-Bi Shih 
55c07152d4STzung-Bi Shih 	return 0;
56c07152d4STzung-Bi Shih }
57c07152d4STzung-Bi Shih 
58c07152d4STzung-Bi Shih static const struct snd_soc_dapm_widget rt1015p_dapm_widgets[] = {
59c07152d4STzung-Bi Shih 	SND_SOC_DAPM_OUTPUT("Speaker"),
60c07152d4STzung-Bi Shih 	SND_SOC_DAPM_OUT_DRV_E("SDB", SND_SOC_NOPM, 0, 0, NULL, 0,
61c07152d4STzung-Bi Shih 			rt1015p_sdb_event,
624ab93017STzung-Bi Shih 			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
63c07152d4STzung-Bi Shih };
64c07152d4STzung-Bi Shih 
65c07152d4STzung-Bi Shih static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = {
66c07152d4STzung-Bi Shih 	{"SDB", NULL, "HiFi Playback"},
67c07152d4STzung-Bi Shih 	{"Speaker", NULL, "SDB"},
68c07152d4STzung-Bi Shih };
69c07152d4STzung-Bi Shih 
70f102d0d1STzung-Bi Shih #ifdef CONFIG_PM
rt1015p_suspend(struct snd_soc_component * component)71f102d0d1STzung-Bi Shih static int rt1015p_suspend(struct snd_soc_component *component)
72f102d0d1STzung-Bi Shih {
73f102d0d1STzung-Bi Shih 	struct rt1015p_priv *rt1015p = snd_soc_component_get_drvdata(component);
74f102d0d1STzung-Bi Shih 
75f102d0d1STzung-Bi Shih 	rt1015p->calib_done = false;
76f102d0d1STzung-Bi Shih 	return 0;
77f102d0d1STzung-Bi Shih }
78f102d0d1STzung-Bi Shih #else
79f102d0d1STzung-Bi Shih #define rt1015p_suspend NULL
80f102d0d1STzung-Bi Shih #endif
81f102d0d1STzung-Bi Shih 
82c07152d4STzung-Bi Shih static const struct snd_soc_component_driver rt1015p_component_driver = {
83f102d0d1STzung-Bi Shih 	.suspend		= rt1015p_suspend,
84c07152d4STzung-Bi Shih 	.dapm_widgets		= rt1015p_dapm_widgets,
85c07152d4STzung-Bi Shih 	.num_dapm_widgets	= ARRAY_SIZE(rt1015p_dapm_widgets),
86c07152d4STzung-Bi Shih 	.dapm_routes		= rt1015p_dapm_routes,
87c07152d4STzung-Bi Shih 	.num_dapm_routes	= ARRAY_SIZE(rt1015p_dapm_routes),
88c07152d4STzung-Bi Shih 	.idle_bias_on		= 1,
89c07152d4STzung-Bi Shih 	.use_pmdown_time	= 1,
90c07152d4STzung-Bi Shih 	.endianness		= 1,
91c07152d4STzung-Bi Shih };
92c07152d4STzung-Bi Shih 
93c07152d4STzung-Bi Shih static struct snd_soc_dai_driver rt1015p_dai_driver = {
94c07152d4STzung-Bi Shih 	.name = "HiFi",
95c07152d4STzung-Bi Shih 	.playback = {
96c07152d4STzung-Bi Shih 		.stream_name	= "HiFi Playback",
977f51384fSJack Yu 		.formats	= SNDRV_PCM_FMTBIT_S24 |
987f51384fSJack Yu 					SNDRV_PCM_FMTBIT_S32,
99c07152d4STzung-Bi Shih 		.rates		= SNDRV_PCM_RATE_48000,
100c07152d4STzung-Bi Shih 		.channels_min	= 1,
101c07152d4STzung-Bi Shih 		.channels_max	= 2,
102c07152d4STzung-Bi Shih 	},
103c07152d4STzung-Bi Shih };
104c07152d4STzung-Bi Shih 
rt1015p_platform_probe(struct platform_device * pdev)105c07152d4STzung-Bi Shih static int rt1015p_platform_probe(struct platform_device *pdev)
106c07152d4STzung-Bi Shih {
107c07152d4STzung-Bi Shih 	struct rt1015p_priv *rt1015p;
108c07152d4STzung-Bi Shih 
109c07152d4STzung-Bi Shih 	rt1015p = devm_kzalloc(&pdev->dev, sizeof(*rt1015p), GFP_KERNEL);
110c07152d4STzung-Bi Shih 	if (!rt1015p)
111c07152d4STzung-Bi Shih 		return -ENOMEM;
112c07152d4STzung-Bi Shih 
113c07152d4STzung-Bi Shih 	rt1015p->sdb = devm_gpiod_get_optional(&pdev->dev,
114c07152d4STzung-Bi Shih 				"sdb", GPIOD_OUT_LOW);
115c07152d4STzung-Bi Shih 	if (IS_ERR(rt1015p->sdb))
116c07152d4STzung-Bi Shih 		return PTR_ERR(rt1015p->sdb);
117c07152d4STzung-Bi Shih 
118c07152d4STzung-Bi Shih 	dev_set_drvdata(&pdev->dev, rt1015p);
119c07152d4STzung-Bi Shih 
120c07152d4STzung-Bi Shih 	return devm_snd_soc_register_component(&pdev->dev,
121c07152d4STzung-Bi Shih 			&rt1015p_component_driver,
122c07152d4STzung-Bi Shih 			&rt1015p_dai_driver, 1);
123c07152d4STzung-Bi Shih }
124c07152d4STzung-Bi Shih 
125c07152d4STzung-Bi Shih #ifdef CONFIG_OF
126c07152d4STzung-Bi Shih static const struct of_device_id rt1015p_device_id[] = {
127c07152d4STzung-Bi Shih 	{ .compatible = "realtek,rt1015p" },
128*6d0a764dSJack Yu 	{ .compatible = "realtek,rt1019p" },
129c07152d4STzung-Bi Shih 	{}
130c07152d4STzung-Bi Shih };
131c07152d4STzung-Bi Shih MODULE_DEVICE_TABLE(of, rt1015p_device_id);
132c07152d4STzung-Bi Shih #endif
133c07152d4STzung-Bi Shih 
134464b489aSJack Yu #ifdef CONFIG_ACPI
135464b489aSJack Yu static const struct acpi_device_id rt1015p_acpi_match[] = {
136464b489aSJack Yu 	{ "RTL1015", 0},
137*6d0a764dSJack Yu 	{ "RTL1019", 0},
138464b489aSJack Yu 	{ },
139464b489aSJack Yu };
140464b489aSJack Yu MODULE_DEVICE_TABLE(acpi, rt1015p_acpi_match);
141464b489aSJack Yu #endif
142464b489aSJack Yu 
143c07152d4STzung-Bi Shih static struct platform_driver rt1015p_platform_driver = {
144c07152d4STzung-Bi Shih 	.driver = {
145c07152d4STzung-Bi Shih 		.name = "rt1015p",
146c07152d4STzung-Bi Shih 		.of_match_table = of_match_ptr(rt1015p_device_id),
147464b489aSJack Yu 		.acpi_match_table = ACPI_PTR(rt1015p_acpi_match),
148c07152d4STzung-Bi Shih 	},
149c07152d4STzung-Bi Shih 	.probe = rt1015p_platform_probe,
150c07152d4STzung-Bi Shih };
151c07152d4STzung-Bi Shih module_platform_driver(rt1015p_platform_driver);
152c07152d4STzung-Bi Shih 
153c07152d4STzung-Bi Shih MODULE_DESCRIPTION("ASoC RT1015P driver");
154c07152d4STzung-Bi Shih MODULE_LICENSE("GPL v2");
155