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.12 243 lines 6.9 kB view raw
1/* 2 * mx27vis-aic32x4.c 3 * 4 * Copyright 2011 Vista Silicon S.L. 5 * 6 * Author: Javier Martin <javier.martin@vista-silicon.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 21 * MA 02110-1301, USA. 22 */ 23 24#include <linux/module.h> 25#include <linux/moduleparam.h> 26#include <linux/device.h> 27#include <linux/i2c.h> 28#include <linux/gpio.h> 29#include <linux/platform_data/asoc-mx27vis.h> 30#include <sound/core.h> 31#include <sound/pcm.h> 32#include <sound/soc.h> 33#include <sound/soc-dapm.h> 34#include <sound/tlv.h> 35#include <asm/mach-types.h> 36 37#include "../codecs/tlv320aic32x4.h" 38#include "imx-ssi.h" 39#include "imx-audmux.h" 40 41#define MX27VIS_AMP_GAIN 0 42#define MX27VIS_AMP_MUTE 1 43 44static int mx27vis_amp_gain; 45static int mx27vis_amp_mute; 46static int mx27vis_amp_gain0_gpio; 47static int mx27vis_amp_gain1_gpio; 48static int mx27vis_amp_mutel_gpio; 49static int mx27vis_amp_muter_gpio; 50 51static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream, 52 struct snd_pcm_hw_params *params) 53{ 54 struct snd_soc_pcm_runtime *rtd = substream->private_data; 55 struct snd_soc_dai *codec_dai = rtd->codec_dai; 56 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 57 int ret; 58 u32 dai_format; 59 60 dai_format = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | 61 SND_SOC_DAIFMT_CBM_CFM; 62 63 /* set codec DAI configuration */ 64 snd_soc_dai_set_fmt(codec_dai, dai_format); 65 66 /* set cpu DAI configuration */ 67 snd_soc_dai_set_fmt(cpu_dai, dai_format); 68 69 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 70 25000000, SND_SOC_CLOCK_OUT); 71 if (ret) { 72 pr_err("%s: failed setting codec sysclk\n", __func__); 73 return ret; 74 } 75 76 ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, 77 SND_SOC_CLOCK_IN); 78 if (ret) { 79 pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n"); 80 return ret; 81 } 82 83 return 0; 84} 85 86static struct snd_soc_ops mx27vis_aic32x4_snd_ops = { 87 .hw_params = mx27vis_aic32x4_hw_params, 88}; 89 90static int mx27vis_amp_set(struct snd_kcontrol *kcontrol, 91 struct snd_ctl_elem_value *ucontrol) 92{ 93 struct soc_mixer_control *mc = 94 (struct soc_mixer_control *)kcontrol->private_value; 95 int value = ucontrol->value.integer.value[0]; 96 unsigned int reg = mc->reg; 97 int max = mc->max; 98 99 if (value > max) 100 return -EINVAL; 101 102 switch (reg) { 103 case MX27VIS_AMP_GAIN: 104 gpio_set_value(mx27vis_amp_gain0_gpio, value & 1); 105 gpio_set_value(mx27vis_amp_gain1_gpio, value >> 1); 106 mx27vis_amp_gain = value; 107 break; 108 case MX27VIS_AMP_MUTE: 109 gpio_set_value(mx27vis_amp_mutel_gpio, value & 1); 110 gpio_set_value(mx27vis_amp_muter_gpio, value >> 1); 111 mx27vis_amp_mute = value; 112 break; 113 } 114 return 0; 115} 116 117static int mx27vis_amp_get(struct snd_kcontrol *kcontrol, 118 struct snd_ctl_elem_value *ucontrol) 119{ 120 struct soc_mixer_control *mc = 121 (struct soc_mixer_control *)kcontrol->private_value; 122 unsigned int reg = mc->reg; 123 124 switch (reg) { 125 case MX27VIS_AMP_GAIN: 126 ucontrol->value.integer.value[0] = mx27vis_amp_gain; 127 break; 128 case MX27VIS_AMP_MUTE: 129 ucontrol->value.integer.value[0] = mx27vis_amp_mute; 130 break; 131 } 132 return 0; 133} 134 135/* From 6dB to 24dB in steps of 6dB */ 136static const DECLARE_TLV_DB_SCALE(mx27vis_amp_tlv, 600, 600, 0); 137 138static const struct snd_kcontrol_new mx27vis_aic32x4_controls[] = { 139 SOC_DAPM_PIN_SWITCH("External Mic"), 140 SOC_SINGLE_EXT_TLV("LO Ext Boost", MX27VIS_AMP_GAIN, 0, 3, 0, 141 mx27vis_amp_get, mx27vis_amp_set, mx27vis_amp_tlv), 142 SOC_DOUBLE_EXT("LO Ext Mute Switch", MX27VIS_AMP_MUTE, 0, 1, 1, 0, 143 mx27vis_amp_get, mx27vis_amp_set), 144}; 145 146static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { 147 SND_SOC_DAPM_MIC("External Mic", NULL), 148}; 149 150static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { 151 {"Mic Bias", NULL, "External Mic"}, 152 {"IN1_R", NULL, "Mic Bias"}, 153 {"IN2_R", NULL, "Mic Bias"}, 154 {"IN3_R", NULL, "Mic Bias"}, 155 {"IN1_L", NULL, "Mic Bias"}, 156 {"IN2_L", NULL, "Mic Bias"}, 157 {"IN3_L", NULL, "Mic Bias"}, 158}; 159 160static struct snd_soc_dai_link mx27vis_aic32x4_dai = { 161 .name = "tlv320aic32x4", 162 .stream_name = "TLV320AIC32X4", 163 .codec_dai_name = "tlv320aic32x4-hifi", 164 .platform_name = "imx-ssi.0", 165 .codec_name = "tlv320aic32x4.0-0018", 166 .cpu_dai_name = "imx-ssi.0", 167 .ops = &mx27vis_aic32x4_snd_ops, 168}; 169 170static struct snd_soc_card mx27vis_aic32x4 = { 171 .name = "visstrim_m10-audio", 172 .owner = THIS_MODULE, 173 .dai_link = &mx27vis_aic32x4_dai, 174 .num_links = 1, 175 .controls = mx27vis_aic32x4_controls, 176 .num_controls = ARRAY_SIZE(mx27vis_aic32x4_controls), 177 .dapm_widgets = aic32x4_dapm_widgets, 178 .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets), 179 .dapm_routes = aic32x4_dapm_routes, 180 .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), 181}; 182 183static int mx27vis_aic32x4_probe(struct platform_device *pdev) 184{ 185 struct snd_mx27vis_platform_data *pdata = pdev->dev.platform_data; 186 int ret; 187 188 if (!pdata) { 189 dev_err(&pdev->dev, "No platform data supplied\n"); 190 return -EINVAL; 191 } 192 193 mx27vis_amp_gain0_gpio = pdata->amp_gain0_gpio; 194 mx27vis_amp_gain1_gpio = pdata->amp_gain1_gpio; 195 mx27vis_amp_mutel_gpio = pdata->amp_mutel_gpio; 196 mx27vis_amp_muter_gpio = pdata->amp_muter_gpio; 197 198 mx27vis_aic32x4.dev = &pdev->dev; 199 ret = snd_soc_register_card(&mx27vis_aic32x4); 200 if (ret) { 201 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", 202 ret); 203 return ret; 204 } 205 206 /* Connect SSI0 as clock slave to SSI1 external pins */ 207 imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, 208 IMX_AUDMUX_V1_PCR_SYN | 209 IMX_AUDMUX_V1_PCR_TFSDIR | 210 IMX_AUDMUX_V1_PCR_TCLKDIR | 211 IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) | 212 IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) 213 ); 214 imx_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1, 215 IMX_AUDMUX_V1_PCR_SYN | 216 IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) 217 ); 218 219 return ret; 220} 221 222static int mx27vis_aic32x4_remove(struct platform_device *pdev) 223{ 224 snd_soc_unregister_card(&mx27vis_aic32x4); 225 226 return 0; 227} 228 229static struct platform_driver mx27vis_aic32x4_audio_driver = { 230 .driver = { 231 .name = "mx27vis", 232 .owner = THIS_MODULE, 233 }, 234 .probe = mx27vis_aic32x4_probe, 235 .remove = mx27vis_aic32x4_remove, 236}; 237 238module_platform_driver(mx27vis_aic32x4_audio_driver); 239 240MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); 241MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim"); 242MODULE_LICENSE("GPL"); 243MODULE_ALIAS("platform:mx27vis");