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.1 234 lines 6.7 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 59 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 60 25000000, SND_SOC_CLOCK_OUT); 61 if (ret) { 62 pr_err("%s: failed setting codec sysclk\n", __func__); 63 return ret; 64 } 65 66 ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, 67 SND_SOC_CLOCK_IN); 68 if (ret) { 69 pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n"); 70 return ret; 71 } 72 73 return 0; 74} 75 76static struct snd_soc_ops mx27vis_aic32x4_snd_ops = { 77 .hw_params = mx27vis_aic32x4_hw_params, 78}; 79 80static int mx27vis_amp_set(struct snd_kcontrol *kcontrol, 81 struct snd_ctl_elem_value *ucontrol) 82{ 83 struct soc_mixer_control *mc = 84 (struct soc_mixer_control *)kcontrol->private_value; 85 int value = ucontrol->value.integer.value[0]; 86 unsigned int reg = mc->reg; 87 int max = mc->max; 88 89 if (value > max) 90 return -EINVAL; 91 92 switch (reg) { 93 case MX27VIS_AMP_GAIN: 94 gpio_set_value(mx27vis_amp_gain0_gpio, value & 1); 95 gpio_set_value(mx27vis_amp_gain1_gpio, value >> 1); 96 mx27vis_amp_gain = value; 97 break; 98 case MX27VIS_AMP_MUTE: 99 gpio_set_value(mx27vis_amp_mutel_gpio, value & 1); 100 gpio_set_value(mx27vis_amp_muter_gpio, value >> 1); 101 mx27vis_amp_mute = value; 102 break; 103 } 104 return 0; 105} 106 107static int mx27vis_amp_get(struct snd_kcontrol *kcontrol, 108 struct snd_ctl_elem_value *ucontrol) 109{ 110 struct soc_mixer_control *mc = 111 (struct soc_mixer_control *)kcontrol->private_value; 112 unsigned int reg = mc->reg; 113 114 switch (reg) { 115 case MX27VIS_AMP_GAIN: 116 ucontrol->value.integer.value[0] = mx27vis_amp_gain; 117 break; 118 case MX27VIS_AMP_MUTE: 119 ucontrol->value.integer.value[0] = mx27vis_amp_mute; 120 break; 121 } 122 return 0; 123} 124 125/* From 6dB to 24dB in steps of 6dB */ 126static const DECLARE_TLV_DB_SCALE(mx27vis_amp_tlv, 600, 600, 0); 127 128static const struct snd_kcontrol_new mx27vis_aic32x4_controls[] = { 129 SOC_DAPM_PIN_SWITCH("External Mic"), 130 SOC_SINGLE_EXT_TLV("LO Ext Boost", MX27VIS_AMP_GAIN, 0, 3, 0, 131 mx27vis_amp_get, mx27vis_amp_set, mx27vis_amp_tlv), 132 SOC_DOUBLE_EXT("LO Ext Mute Switch", MX27VIS_AMP_MUTE, 0, 1, 1, 0, 133 mx27vis_amp_get, mx27vis_amp_set), 134}; 135 136static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { 137 SND_SOC_DAPM_MIC("External Mic", NULL), 138}; 139 140static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { 141 {"Mic Bias", NULL, "External Mic"}, 142 {"IN1_R", NULL, "Mic Bias"}, 143 {"IN2_R", NULL, "Mic Bias"}, 144 {"IN3_R", NULL, "Mic Bias"}, 145 {"IN1_L", NULL, "Mic Bias"}, 146 {"IN2_L", NULL, "Mic Bias"}, 147 {"IN3_L", NULL, "Mic Bias"}, 148}; 149 150static struct snd_soc_dai_link mx27vis_aic32x4_dai = { 151 .name = "tlv320aic32x4", 152 .stream_name = "TLV320AIC32X4", 153 .codec_dai_name = "tlv320aic32x4-hifi", 154 .platform_name = "imx-ssi.0", 155 .codec_name = "tlv320aic32x4.0-0018", 156 .cpu_dai_name = "imx-ssi.0", 157 .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | 158 SND_SOC_DAIFMT_CBM_CFM, 159 .ops = &mx27vis_aic32x4_snd_ops, 160}; 161 162static struct snd_soc_card mx27vis_aic32x4 = { 163 .name = "visstrim_m10-audio", 164 .owner = THIS_MODULE, 165 .dai_link = &mx27vis_aic32x4_dai, 166 .num_links = 1, 167 .controls = mx27vis_aic32x4_controls, 168 .num_controls = ARRAY_SIZE(mx27vis_aic32x4_controls), 169 .dapm_widgets = aic32x4_dapm_widgets, 170 .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets), 171 .dapm_routes = aic32x4_dapm_routes, 172 .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), 173}; 174 175static int mx27vis_aic32x4_probe(struct platform_device *pdev) 176{ 177 struct snd_mx27vis_platform_data *pdata = pdev->dev.platform_data; 178 int ret; 179 180 if (!pdata) { 181 dev_err(&pdev->dev, "No platform data supplied\n"); 182 return -EINVAL; 183 } 184 185 mx27vis_amp_gain0_gpio = pdata->amp_gain0_gpio; 186 mx27vis_amp_gain1_gpio = pdata->amp_gain1_gpio; 187 mx27vis_amp_mutel_gpio = pdata->amp_mutel_gpio; 188 mx27vis_amp_muter_gpio = pdata->amp_muter_gpio; 189 190 mx27vis_aic32x4.dev = &pdev->dev; 191 ret = snd_soc_register_card(&mx27vis_aic32x4); 192 if (ret) { 193 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", 194 ret); 195 return ret; 196 } 197 198 /* Connect SSI0 as clock slave to SSI1 external pins */ 199 imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, 200 IMX_AUDMUX_V1_PCR_SYN | 201 IMX_AUDMUX_V1_PCR_TFSDIR | 202 IMX_AUDMUX_V1_PCR_TCLKDIR | 203 IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) | 204 IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) 205 ); 206 imx_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1, 207 IMX_AUDMUX_V1_PCR_SYN | 208 IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) 209 ); 210 211 return ret; 212} 213 214static int mx27vis_aic32x4_remove(struct platform_device *pdev) 215{ 216 snd_soc_unregister_card(&mx27vis_aic32x4); 217 218 return 0; 219} 220 221static struct platform_driver mx27vis_aic32x4_audio_driver = { 222 .driver = { 223 .name = "mx27vis", 224 }, 225 .probe = mx27vis_aic32x4_probe, 226 .remove = mx27vis_aic32x4_remove, 227}; 228 229module_platform_driver(mx27vis_aic32x4_audio_driver); 230 231MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); 232MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim"); 233MODULE_LICENSE("GPL"); 234MODULE_ALIAS("platform:mx27vis");