1/* 2 * SiRF audio card driver 3 * 4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. 5 * 6 * Licensed under GPLv2 or later. 7 */ 8 9#include <linux/platform_device.h> 10#include <linux/module.h> 11#include <linux/of.h> 12#include <linux/gpio.h> 13#include <linux/of_gpio.h> 14#include <sound/core.h> 15#include <sound/pcm.h> 16#include <sound/soc.h> 17 18struct sirf_audio_card { 19 unsigned int gpio_hp_pa; 20 unsigned int gpio_spk_pa; 21}; 22 23static int sirf_audio_hp_event(struct snd_soc_dapm_widget *w, 24 struct snd_kcontrol *ctrl, int event) 25{ 26 struct snd_soc_dapm_context *dapm = w->dapm; 27 struct snd_soc_card *card = dapm->card; 28 struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card); 29 int on = !SND_SOC_DAPM_EVENT_OFF(event); 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 */ 63static struct snd_soc_dai_link sirf_audio_dai_link[] = { 64 { 65 .name = "SiRF audio card", 66 .stream_name = "SiRF audio HiFi", 67 .codec_dai_name = "sirf-audio-codec", 68 }, 69}; 70 71/* Audio machine driver */ 72static struct snd_soc_card snd_soc_sirf_audio_card = { 73 .name = "SiRF audio card", 74 .owner = THIS_MODULE, 75 .dai_link = sirf_audio_dai_link, 76 .num_links = ARRAY_SIZE(sirf_audio_dai_link), 77 .dapm_widgets = sirf_audio_dapm_widgets, 78 .num_dapm_widgets = ARRAY_SIZE(sirf_audio_dapm_widgets), 79 .dapm_routes = intercon, 80 .num_dapm_routes = ARRAY_SIZE(intercon), 81}; 82 83static int sirf_audio_probe(struct platform_device *pdev) 84{ 85 struct snd_soc_card *card = &snd_soc_sirf_audio_card; 86 struct sirf_audio_card *sirf_audio_card; 87 int ret; 88 89 sirf_audio_card = devm_kzalloc(&pdev->dev, sizeof(struct sirf_audio_card), 90 GFP_KERNEL); 91 if (sirf_audio_card == NULL) 92 return -ENOMEM; 93 94 sirf_audio_dai_link[0].cpu_of_node = 95 of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0); 96 sirf_audio_dai_link[0].platform_of_node = 97 of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0); 98 sirf_audio_dai_link[0].codec_of_node = 99 of_parse_phandle(pdev->dev.of_node, "sirf,audio-codec", 0); 100 sirf_audio_card->gpio_spk_pa = of_get_named_gpio(pdev->dev.of_node, 101 "spk-pa-gpios", 0); 102 sirf_audio_card->gpio_hp_pa = of_get_named_gpio(pdev->dev.of_node, 103 "hp-pa-gpios", 0); 104 if (gpio_is_valid(sirf_audio_card->gpio_spk_pa)) { 105 ret = devm_gpio_request_one(&pdev->dev, 106 sirf_audio_card->gpio_spk_pa, 107 GPIOF_OUT_INIT_LOW, "SPA_PA_SD"); 108 if (ret) { 109 dev_err(&pdev->dev, 110 "Failed to request GPIO_%d for reset: %d\n", 111 sirf_audio_card->gpio_spk_pa, ret); 112 return ret; 113 } 114 } 115 if (gpio_is_valid(sirf_audio_card->gpio_hp_pa)) { 116 ret = devm_gpio_request_one(&pdev->dev, 117 sirf_audio_card->gpio_hp_pa, 118 GPIOF_OUT_INIT_LOW, "HP_PA_SD"); 119 if (ret) { 120 dev_err(&pdev->dev, 121 "Failed to request GPIO_%d for reset: %d\n", 122 sirf_audio_card->gpio_hp_pa, ret); 123 return ret; 124 } 125 } 126 127 card->dev = &pdev->dev; 128 snd_soc_card_set_drvdata(card, sirf_audio_card); 129 130 ret = devm_snd_soc_register_card(&pdev->dev, card); 131 if (ret) 132 dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); 133 134 return ret; 135} 136 137static const struct of_device_id sirf_audio_of_match[] = { 138 {.compatible = "sirf,sirf-audio-card", }, 139 { }, 140}; 141MODULE_DEVICE_TABLE(of, sirf_audio_of_match); 142 143static struct platform_driver sirf_audio_driver = { 144 .driver = { 145 .name = "sirf-audio-card", 146 .pm = &snd_soc_pm_ops, 147 .of_match_table = sirf_audio_of_match, 148 }, 149 .probe = sirf_audio_probe, 150}; 151module_platform_driver(sirf_audio_driver); 152 153MODULE_AUTHOR("RongJun Ying <RongJun.Ying@csr.com>"); 154MODULE_DESCRIPTION("ALSA SoC SIRF audio card driver"); 155MODULE_LICENSE("GPL v2"); 156