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 20 struct rt1015p_priv { 21 struct gpio_desc *sdb; 22 int sdb_switch; 23 }; 24 25 static 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 55 static 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 71 static 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 78 static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = { 79 {"SDB", NULL, "HiFi Playback"}, 80 {"Speaker", NULL, "SDB"}, 81 }; 82 83 static 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 94 static const struct snd_soc_dai_ops rt1015p_dai_ops = { 95 .trigger = rt1015p_daiops_trigger, 96 }; 97 98 static 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 110 static 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 131 static const struct of_device_id rt1015p_device_id[] = { 132 { .compatible = "realtek,rt1015p" }, 133 {} 134 }; 135 MODULE_DEVICE_TABLE(of, rt1015p_device_id); 136 #endif 137 138 static 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 }; 145 module_platform_driver(rt1015p_platform_driver); 146 147 MODULE_DESCRIPTION("ASoC RT1015P driver"); 148 MODULE_LICENSE("GPL v2"); 149