1// SPDX-License-Identifier: GPL-2.0-only 2// 3// rt1015p.c -- RT1015P ALSA SoC audio amplifier driver 4// 5// Copyright 2020 The Linux Foundation. All rights reserved. 6 7#include <linux/device.h> 8#include <linux/err.h> 9#include <linux/gpio.h> 10#include <linux/gpio/consumer.h> 11#include <linux/kernel.h> 12#include <linux/module.h> 13#include <linux/of.h> 14#include <linux/platform_device.h> 15#include <sound/pcm.h> 16#include <sound/soc.h> 17#include <sound/soc-dai.h> 18#include <sound/soc-dapm.h> 19 20struct rt1015p_priv { 21 struct gpio_desc *sdb; 22 int sdb_switch; 23}; 24 25static int rt1015p_daiops_trigger(struct snd_pcm_substream *substream, 26 int cmd, struct snd_soc_dai *dai) 27{ 28 struct snd_soc_component *component = dai->component; 29 struct rt1015p_priv *rt1015p = 30 snd_soc_component_get_drvdata(component); 31 32 if (!rt1015p->sdb) 33 return 0; 34 35 switch (cmd) { 36 case SNDRV_PCM_TRIGGER_START: 37 case SNDRV_PCM_TRIGGER_RESUME: 38 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 39 if (rt1015p->sdb_switch) { 40 gpiod_set_value(rt1015p->sdb, 1); 41 dev_dbg(component->dev, "set sdb to 1"); 42 } 43 break; 44 case SNDRV_PCM_TRIGGER_STOP: 45 case SNDRV_PCM_TRIGGER_SUSPEND: 46 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 47 gpiod_set_value(rt1015p->sdb, 0); 48 dev_dbg(component->dev, "set sdb to 0"); 49 break; 50 } 51 52 return 0; 53} 54 55static int rt1015p_sdb_event(struct snd_soc_dapm_widget *w, 56 struct snd_kcontrol *kcontrol, int event) 57{ 58 struct snd_soc_component *component = 59 snd_soc_dapm_to_component(w->dapm); 60 struct rt1015p_priv *rt1015p = 61 snd_soc_component_get_drvdata(component); 62 63 if (event & SND_SOC_DAPM_POST_PMU) 64 rt1015p->sdb_switch = 1; 65 else if (event & SND_SOC_DAPM_POST_PMD) 66 rt1015p->sdb_switch = 0; 67 68 return 0; 69} 70 71static const struct snd_soc_dapm_widget rt1015p_dapm_widgets[] = { 72 SND_SOC_DAPM_OUTPUT("Speaker"), 73 SND_SOC_DAPM_OUT_DRV_E("SDB", SND_SOC_NOPM, 0, 0, NULL, 0, 74 rt1015p_sdb_event, 75 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 76}; 77 78static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = { 79 {"SDB", NULL, "HiFi Playback"}, 80 {"Speaker", NULL, "SDB"}, 81}; 82 83static const struct snd_soc_component_driver rt1015p_component_driver = { 84 .dapm_widgets = rt1015p_dapm_widgets, 85 .num_dapm_widgets = ARRAY_SIZE(rt1015p_dapm_widgets), 86 .dapm_routes = rt1015p_dapm_routes, 87 .num_dapm_routes = ARRAY_SIZE(rt1015p_dapm_routes), 88 .idle_bias_on = 1, 89 .use_pmdown_time = 1, 90 .endianness = 1, 91 .non_legacy_dai_naming = 1, 92}; 93 94static const struct snd_soc_dai_ops rt1015p_dai_ops = { 95 .trigger = rt1015p_daiops_trigger, 96}; 97 98static struct snd_soc_dai_driver rt1015p_dai_driver = { 99 .name = "HiFi", 100 .playback = { 101 .stream_name = "HiFi Playback", 102 .formats = SNDRV_PCM_FMTBIT_S24, 103 .rates = SNDRV_PCM_RATE_48000, 104 .channels_min = 1, 105 .channels_max = 2, 106 }, 107 .ops = &rt1015p_dai_ops, 108}; 109 110static int rt1015p_platform_probe(struct platform_device *pdev) 111{ 112 struct rt1015p_priv *rt1015p; 113 114 rt1015p = devm_kzalloc(&pdev->dev, sizeof(*rt1015p), GFP_KERNEL); 115 if (!rt1015p) 116 return -ENOMEM; 117 118 rt1015p->sdb = devm_gpiod_get_optional(&pdev->dev, 119 "sdb", GPIOD_OUT_LOW); 120 if (IS_ERR(rt1015p->sdb)) 121 return PTR_ERR(rt1015p->sdb); 122 123 dev_set_drvdata(&pdev->dev, rt1015p); 124 125 return devm_snd_soc_register_component(&pdev->dev, 126 &rt1015p_component_driver, 127 &rt1015p_dai_driver, 1); 128} 129 130#ifdef CONFIG_OF 131static const struct of_device_id rt1015p_device_id[] = { 132 { .compatible = "realtek,rt1015p" }, 133 {} 134}; 135MODULE_DEVICE_TABLE(of, rt1015p_device_id); 136#endif 137 138static struct platform_driver rt1015p_platform_driver = { 139 .driver = { 140 .name = "rt1015p", 141 .of_match_table = of_match_ptr(rt1015p_device_id), 142 }, 143 .probe = rt1015p_platform_probe, 144}; 145module_platform_driver(rt1015p_platform_driver); 146 147MODULE_DESCRIPTION("ASoC RT1015P driver"); 148MODULE_LICENSE("GPL v2"); 149