1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * SiRF audio card driver 4 * 5 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. 6 */ 7 8#include <linux/platform_device.h> 9#include <linux/module.h> 10#include <linux/of.h> 11#include <linux/gpio.h> 12#include <linux/of_gpio.h> 13#include <sound/core.h> 14#include <sound/pcm.h> 15#include <sound/soc.h> 16 17struct sirf_audio_card { 18 unsigned int gpio_hp_pa; 19 unsigned int gpio_spk_pa; 20}; 21 22static int sirf_audio_hp_event(struct snd_soc_dapm_widget *w, 23 struct snd_kcontrol *ctrl, int event) 24{ 25 struct snd_soc_dapm_context *dapm = w->dapm; 26 struct snd_soc_card *card = dapm->card; 27 struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card); 28 int on = !SND_SOC_DAPM_EVENT_OFF(event); 29 30 if (gpio_is_valid(sirf_audio_card->gpio_hp_pa)) 31 gpio_set_value(sirf_audio_card->gpio_hp_pa, on); 32 return 0; 33} 34 35static int sirf_audio_spk_event(struct snd_soc_dapm_widget *w, 36 struct snd_kcontrol *ctrl, int event) 37{ 38 struct snd_soc_dapm_context *dapm = w->dapm; 39 struct snd_soc_card *card = dapm->card; 40 struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card); 41 int on = !SND_SOC_DAPM_EVENT_OFF(event); 42 43 if (gpio_is_valid(sirf_audio_card->gpio_spk_pa)) 44 gpio_set_value(sirf_audio_card->gpio_spk_pa, on); 45 46 return 0; 47} 48static const struct snd_soc_dapm_widget sirf_audio_dapm_widgets[] = { 49 SND_SOC_DAPM_HP("Hp", sirf_audio_hp_event), 50 SND_SOC_DAPM_SPK("Ext Spk", sirf_audio_spk_event), 51 SND_SOC_DAPM_MIC("Ext Mic", NULL), 52}; 53 54static const struct snd_soc_dapm_route intercon[] = { 55 {"Hp", NULL, "HPOUTL"}, 56 {"Hp", NULL, "HPOUTR"}, 57 {"Ext Spk", NULL, "SPKOUT"}, 58 {"MICIN1", NULL, "Mic Bias"}, 59 {"Mic Bias", NULL, "Ext Mic"}, 60}; 61 62/* Digital audio interface glue - connects codec <--> CPU */ 63SND_SOC_DAILINK_DEFS(sirf, 64 DAILINK_COMP_ARRAY(COMP_EMPTY()), 65 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "sirf-audio-codec")), 66 DAILINK_COMP_ARRAY(COMP_EMPTY())); 67 68static struct snd_soc_dai_link sirf_audio_dai_link[] = { 69 { 70 .name = "SiRF audio card", 71 .stream_name = "SiRF audio HiFi", 72 SND_SOC_DAILINK_REG(sirf), 73 }, 74}; 75 76/* Audio machine driver */ 77static struct snd_soc_card snd_soc_sirf_audio_card = { 78 .name = "SiRF audio card", 79 .owner = THIS_MODULE, 80 .dai_link = sirf_audio_dai_link, 81 .num_links = ARRAY_SIZE(sirf_audio_dai_link), 82 .dapm_widgets = sirf_audio_dapm_widgets, 83 .num_dapm_widgets = ARRAY_SIZE(sirf_audio_dapm_widgets), 84 .dapm_routes = intercon, 85 .num_dapm_routes = ARRAY_SIZE(intercon), 86}; 87 88static int sirf_audio_probe(struct platform_device *pdev) 89{ 90 struct snd_soc_card *card = &snd_soc_sirf_audio_card; 91 struct sirf_audio_card *sirf_audio_card; 92 int ret; 93 94 sirf_audio_card = devm_kzalloc(&pdev->dev, sizeof(struct sirf_audio_card), 95 GFP_KERNEL); 96 if (sirf_audio_card == NULL) 97 return -ENOMEM; 98 99 sirf_audio_dai_link[0].cpus->of_node = 100 of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0); 101 sirf_audio_dai_link[0].platforms->of_node = 102 of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0); 103 sirf_audio_dai_link[0].codecs->of_node = 104 of_parse_phandle(pdev->dev.of_node, "sirf,audio-codec", 0); 105 sirf_audio_card->gpio_spk_pa = of_get_named_gpio(pdev->dev.of_node, 106 "spk-pa-gpios", 0); 107 sirf_audio_card->gpio_hp_pa = of_get_named_gpio(pdev->dev.of_node, 108 "hp-pa-gpios", 0); 109 if (gpio_is_valid(sirf_audio_card->gpio_spk_pa)) { 110 ret = devm_gpio_request_one(&pdev->dev, 111 sirf_audio_card->gpio_spk_pa, 112 GPIOF_OUT_INIT_LOW, "SPA_PA_SD"); 113 if (ret) { 114 dev_err(&pdev->dev, 115 "Failed to request GPIO_%d for reset: %d\n", 116 sirf_audio_card->gpio_spk_pa, ret); 117 return ret; 118 } 119 } 120 if (gpio_is_valid(sirf_audio_card->gpio_hp_pa)) { 121 ret = devm_gpio_request_one(&pdev->dev, 122 sirf_audio_card->gpio_hp_pa, 123 GPIOF_OUT_INIT_LOW, "HP_PA_SD"); 124 if (ret) { 125 dev_err(&pdev->dev, 126 "Failed to request GPIO_%d for reset: %d\n", 127 sirf_audio_card->gpio_hp_pa, ret); 128 return ret; 129 } 130 } 131 132 card->dev = &pdev->dev; 133 snd_soc_card_set_drvdata(card, sirf_audio_card); 134 135 ret = devm_snd_soc_register_card(&pdev->dev, card); 136 if (ret) 137 dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); 138 139 return ret; 140} 141 142static const struct of_device_id sirf_audio_of_match[] = { 143 {.compatible = "sirf,sirf-audio-card", }, 144 { }, 145}; 146MODULE_DEVICE_TABLE(of, sirf_audio_of_match); 147 148static struct platform_driver sirf_audio_driver = { 149 .driver = { 150 .name = "sirf-audio-card", 151 .pm = &snd_soc_pm_ops, 152 .of_match_table = sirf_audio_of_match, 153 }, 154 .probe = sirf_audio_probe, 155}; 156module_platform_driver(sirf_audio_driver); 157 158MODULE_AUTHOR("RongJun Ying <RongJun.Ying@csr.com>"); 159MODULE_DESCRIPTION("ALSA SoC SIRF audio card driver"); 160MODULE_LICENSE("GPL v2"); 161