Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.18 175 lines 4.5 kB view raw
1/* 2 * tegra20_wm9712.c - Tegra machine ASoC driver for boards using WM9712 codec. 3 * 4 * Copyright 2012 Lucas Stach <dev@lynxeye.de> 5 * 6 * Partly based on code copyright/by: 7 * Copyright 2011,2012 Toradex Inc. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * version 2 as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 */ 19 20#include <linux/module.h> 21#include <linux/platform_device.h> 22#include <linux/slab.h> 23#include <linux/gpio.h> 24#include <linux/of_gpio.h> 25 26#include <sound/core.h> 27#include <sound/jack.h> 28#include <sound/pcm.h> 29#include <sound/pcm_params.h> 30#include <sound/soc.h> 31 32#include "tegra_asoc_utils.h" 33 34#define DRV_NAME "tegra-snd-wm9712" 35 36struct tegra_wm9712 { 37 struct platform_device *codec; 38 struct tegra_asoc_utils_data util_data; 39}; 40 41static const struct snd_soc_dapm_widget tegra_wm9712_dapm_widgets[] = { 42 SND_SOC_DAPM_HP("Headphone", NULL), 43 SND_SOC_DAPM_LINE("LineIn", NULL), 44 SND_SOC_DAPM_MIC("Mic", NULL), 45}; 46 47static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd) 48{ 49 return snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias"); 50} 51 52static struct snd_soc_dai_link tegra_wm9712_dai = { 53 .name = "AC97 HiFi", 54 .stream_name = "AC97 HiFi", 55 .codec_dai_name = "wm9712-hifi", 56 .codec_name = "wm9712-codec", 57 .init = tegra_wm9712_init, 58}; 59 60static struct snd_soc_card snd_soc_tegra_wm9712 = { 61 .name = "tegra-wm9712", 62 .owner = THIS_MODULE, 63 .dai_link = &tegra_wm9712_dai, 64 .num_links = 1, 65 66 .dapm_widgets = tegra_wm9712_dapm_widgets, 67 .num_dapm_widgets = ARRAY_SIZE(tegra_wm9712_dapm_widgets), 68 .fully_routed = true, 69}; 70 71static int tegra_wm9712_driver_probe(struct platform_device *pdev) 72{ 73 struct device_node *np = pdev->dev.of_node; 74 struct snd_soc_card *card = &snd_soc_tegra_wm9712; 75 struct tegra_wm9712 *machine; 76 int ret; 77 78 machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm9712), 79 GFP_KERNEL); 80 if (!machine) 81 return -ENOMEM; 82 83 card->dev = &pdev->dev; 84 snd_soc_card_set_drvdata(card, machine); 85 86 machine->codec = platform_device_alloc("wm9712-codec", -1); 87 if (!machine->codec) { 88 dev_err(&pdev->dev, "Can't allocate wm9712 platform device\n"); 89 return -ENOMEM; 90 } 91 92 ret = platform_device_add(machine->codec); 93 if (ret) 94 goto codec_put; 95 96 ret = snd_soc_of_parse_card_name(card, "nvidia,model"); 97 if (ret) 98 goto codec_unregister; 99 100 ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); 101 if (ret) 102 goto codec_unregister; 103 104 tegra_wm9712_dai.cpu_of_node = of_parse_phandle(np, 105 "nvidia,ac97-controller", 0); 106 if (!tegra_wm9712_dai.cpu_of_node) { 107 dev_err(&pdev->dev, 108 "Property 'nvidia,ac97-controller' missing or invalid\n"); 109 ret = -EINVAL; 110 goto codec_unregister; 111 } 112 113 tegra_wm9712_dai.platform_of_node = tegra_wm9712_dai.cpu_of_node; 114 115 ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); 116 if (ret) 117 goto codec_unregister; 118 119 ret = tegra_asoc_utils_set_ac97_rate(&machine->util_data); 120 if (ret) 121 goto asoc_utils_fini; 122 123 ret = snd_soc_register_card(card); 124 if (ret) { 125 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", 126 ret); 127 goto asoc_utils_fini; 128 } 129 130 return 0; 131 132asoc_utils_fini: 133 tegra_asoc_utils_fini(&machine->util_data); 134codec_unregister: 135 platform_device_del(machine->codec); 136codec_put: 137 platform_device_put(machine->codec); 138 return ret; 139} 140 141static int tegra_wm9712_driver_remove(struct platform_device *pdev) 142{ 143 struct snd_soc_card *card = platform_get_drvdata(pdev); 144 struct tegra_wm9712 *machine = snd_soc_card_get_drvdata(card); 145 146 snd_soc_unregister_card(card); 147 148 tegra_asoc_utils_fini(&machine->util_data); 149 150 platform_device_unregister(machine->codec); 151 152 return 0; 153} 154 155static const struct of_device_id tegra_wm9712_of_match[] = { 156 { .compatible = "nvidia,tegra-audio-wm9712", }, 157 {}, 158}; 159 160static struct platform_driver tegra_wm9712_driver = { 161 .driver = { 162 .name = DRV_NAME, 163 .pm = &snd_soc_pm_ops, 164 .of_match_table = tegra_wm9712_of_match, 165 }, 166 .probe = tegra_wm9712_driver_probe, 167 .remove = tegra_wm9712_driver_remove, 168}; 169module_platform_driver(tegra_wm9712_driver); 170 171MODULE_AUTHOR("Lucas Stach"); 172MODULE_DESCRIPTION("Tegra+WM9712 machine ASoC driver"); 173MODULE_LICENSE("GPL v2"); 174MODULE_ALIAS("platform:" DRV_NAME); 175MODULE_DEVICE_TABLE(of, tegra_wm9712_of_match);