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 v3.11 210 lines 5.6 kB view raw
1/* 2 * trimslice.c - TrimSlice machine ASoC driver 3 * 4 * Copyright (C) 2011 - CompuLab, Ltd. 5 * Author: Mike Rapoport <mike@compulab.co.il> 6 * 7 * Based on code copyright/by: 8 * Author: Stephen Warren <swarren@nvidia.com> 9 * Copyright (C) 2010-2011 - NVIDIA, Inc. 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * version 2 as published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 23 * 02110-1301 USA 24 * 25 */ 26 27#include <asm/mach-types.h> 28 29#include <linux/module.h> 30#include <linux/of.h> 31#include <linux/platform_device.h> 32#include <linux/slab.h> 33 34#include <sound/core.h> 35#include <sound/jack.h> 36#include <sound/pcm.h> 37#include <sound/pcm_params.h> 38#include <sound/soc.h> 39 40#include "../codecs/tlv320aic23.h" 41 42#include "tegra_asoc_utils.h" 43 44#define DRV_NAME "tegra-snd-trimslice" 45 46struct tegra_trimslice { 47 struct tegra_asoc_utils_data util_data; 48}; 49 50static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, 51 struct snd_pcm_hw_params *params) 52{ 53 struct snd_soc_pcm_runtime *rtd = substream->private_data; 54 struct snd_soc_dai *codec_dai = rtd->codec_dai; 55 struct snd_soc_codec *codec = codec_dai->codec; 56 struct snd_soc_card *card = codec->card; 57 struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); 58 int srate, mclk; 59 int err; 60 61 srate = params_rate(params); 62 mclk = 128 * srate; 63 64 err = tegra_asoc_utils_set_rate(&trimslice->util_data, srate, mclk); 65 if (err < 0) { 66 dev_err(card->dev, "Can't configure clocks\n"); 67 return err; 68 } 69 70 err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, 71 SND_SOC_CLOCK_IN); 72 if (err < 0) { 73 dev_err(card->dev, "codec_dai clock not set\n"); 74 return err; 75 } 76 77 return 0; 78} 79 80static struct snd_soc_ops trimslice_asoc_ops = { 81 .hw_params = trimslice_asoc_hw_params, 82}; 83 84static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = { 85 SND_SOC_DAPM_HP("Line Out", NULL), 86 SND_SOC_DAPM_LINE("Line In", NULL), 87}; 88 89static const struct snd_soc_dapm_route trimslice_audio_map[] = { 90 {"Line Out", NULL, "LOUT"}, 91 {"Line Out", NULL, "ROUT"}, 92 93 {"LLINEIN", NULL, "Line In"}, 94 {"RLINEIN", NULL, "Line In"}, 95}; 96 97static struct snd_soc_dai_link trimslice_tlv320aic23_dai = { 98 .name = "TLV320AIC23", 99 .stream_name = "AIC23", 100 .codec_dai_name = "tlv320aic23-hifi", 101 .ops = &trimslice_asoc_ops, 102 .dai_fmt = SND_SOC_DAIFMT_I2S | 103 SND_SOC_DAIFMT_NB_NF | 104 SND_SOC_DAIFMT_CBS_CFS, 105}; 106 107static struct snd_soc_card snd_soc_trimslice = { 108 .name = "tegra-trimslice", 109 .owner = THIS_MODULE, 110 .dai_link = &trimslice_tlv320aic23_dai, 111 .num_links = 1, 112 113 .dapm_widgets = trimslice_dapm_widgets, 114 .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets), 115 .dapm_routes = trimslice_audio_map, 116 .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map), 117 .fully_routed = true, 118}; 119 120static int tegra_snd_trimslice_probe(struct platform_device *pdev) 121{ 122 struct device_node *np = pdev->dev.of_node; 123 struct snd_soc_card *card = &snd_soc_trimslice; 124 struct tegra_trimslice *trimslice; 125 int ret; 126 127 trimslice = devm_kzalloc(&pdev->dev, sizeof(struct tegra_trimslice), 128 GFP_KERNEL); 129 if (!trimslice) { 130 dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n"); 131 return -ENOMEM; 132 } 133 134 card->dev = &pdev->dev; 135 platform_set_drvdata(pdev, card); 136 snd_soc_card_set_drvdata(card, trimslice); 137 138 trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(np, 139 "nvidia,audio-codec", 0); 140 if (!trimslice_tlv320aic23_dai.codec_of_node) { 141 dev_err(&pdev->dev, 142 "Property 'nvidia,audio-codec' missing or invalid\n"); 143 ret = -EINVAL; 144 goto err; 145 } 146 147 trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle(np, 148 "nvidia,i2s-controller", 0); 149 if (!trimslice_tlv320aic23_dai.cpu_of_node) { 150 dev_err(&pdev->dev, 151 "Property 'nvidia,i2s-controller' missing or invalid\n"); 152 ret = -EINVAL; 153 goto err; 154 } 155 156 trimslice_tlv320aic23_dai.platform_of_node = 157 trimslice_tlv320aic23_dai.cpu_of_node; 158 159 ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); 160 if (ret) 161 goto err; 162 163 ret = snd_soc_register_card(card); 164 if (ret) { 165 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", 166 ret); 167 goto err_fini_utils; 168 } 169 170 return 0; 171 172err_fini_utils: 173 tegra_asoc_utils_fini(&trimslice->util_data); 174err: 175 return ret; 176} 177 178static int tegra_snd_trimslice_remove(struct platform_device *pdev) 179{ 180 struct snd_soc_card *card = platform_get_drvdata(pdev); 181 struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); 182 183 snd_soc_unregister_card(card); 184 185 tegra_asoc_utils_fini(&trimslice->util_data); 186 187 return 0; 188} 189 190static const struct of_device_id trimslice_of_match[] = { 191 { .compatible = "nvidia,tegra-audio-trimslice", }, 192 {}, 193}; 194MODULE_DEVICE_TABLE(of, trimslice_of_match); 195 196static struct platform_driver tegra_snd_trimslice_driver = { 197 .driver = { 198 .name = DRV_NAME, 199 .owner = THIS_MODULE, 200 .of_match_table = trimslice_of_match, 201 }, 202 .probe = tegra_snd_trimslice_probe, 203 .remove = tegra_snd_trimslice_remove, 204}; 205module_platform_driver(tegra_snd_trimslice_driver); 206 207MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); 208MODULE_DESCRIPTION("Trimslice machine ASoC driver"); 209MODULE_LICENSE("GPL"); 210MODULE_ALIAS("platform:" DRV_NAME);