📄 neo1973_wm8753.c
字号:
/* * neo1973_wm8753.c -- SoC audio for Neo1973 * * Copyright 2007 Wolfson Microelectronics PLC. * Author: Graeme Gregory * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * Revision history * 20th Jan 2007 Initial version. * 05th Feb 2007 Rename all to Neo1973 * */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/i2c.h>#include <sound/driver.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/soc.h>#include <sound/soc-dapm.h>#include <asm/mach-types.h>#include <asm/hardware/scoop.h>#include <asm/arch/regs-iis.h>#include <asm/arch/regs-clock.h>#include <asm/arch/regs-gpio.h>#include <asm/hardware.h>#include <asm/arch/audio.h>#include <asm/io.h>#include <asm/arch/spi-gpio.h>#include "../codecs/wm8753.h"#include "lm4857.h"#include "s3c24xx-pcm.h"#include "s3c24xx-i2s.h"/* define the scenarios */#define NEO_AUDIO_OFF 0#define NEO_GSM_CALL_AUDIO_HANDSET 1#define NEO_GSM_CALL_AUDIO_HEADSET 2#define NEO_GSM_CALL_AUDIO_BLUETOOTH 3#define NEO_STEREO_TO_SPEAKERS 4#define NEO_STEREO_TO_HEADPHONES 5#define NEO_CAPTURE_HANDSET 6#define NEO_CAPTURE_HEADSET 7#define NEO_CAPTURE_BLUETOOTH 8static struct snd_soc_machine neo1973;static struct i2c_client *i2c;static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params){ struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; unsigned int pll_out = 0, bclk = 0; int ret = 0; unsigned long iis_clkrate; iis_clkrate = s3c24xx_i2s_get_clockrate(); switch (params_rate(params)) { case 8000: case 16000: pll_out = 12288000; break; case 48000: bclk = WM8753_BCLK_DIV_4; pll_out = 12288000; break; case 96000: bclk = WM8753_BCLK_DIV_2; pll_out = 12288000; break; case 11025: bclk = WM8753_BCLK_DIV_16; pll_out = 11289600; break; case 22050: bclk = WM8753_BCLK_DIV_8; pll_out = 11289600; break; case 44100: bclk = WM8753_BCLK_DIV_4; pll_out = 11289600; break; case 88200: bclk = WM8753_BCLK_DIV_2; pll_out = 11289600; break; } /* set codec DAI configuration */ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set cpu DAI configuration */ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set the codec system clock for DAC and ADC */ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out, SND_SOC_CLOCK_IN); if (ret < 0) return ret; /* set MCLK division for sample rate */ ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, S3C2410_IISMOD_32FS ); if (ret < 0) return ret; /* set codec BCLK division for sample rate */ ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); if (ret < 0) return ret; /* set prescaler division for sample rate */ ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, S3C24XX_PRESCALE(4,4)); if (ret < 0) return ret; /* codec PLL input is PCLK/4 */ ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, iis_clkrate / 4, pll_out); if (ret < 0) return ret; return 0;}static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream){ struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; /* disable the PLL */ return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0);}/* * Neo1973 WM8753 HiFi DAI opserations. */static struct snd_soc_ops neo1973_hifi_ops = { .hw_params = neo1973_hifi_hw_params, .hw_free = neo1973_hifi_hw_free,};static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params){ struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; unsigned int pcmdiv = 0; int ret = 0; unsigned long iis_clkrate; iis_clkrate = s3c24xx_i2s_get_clockrate(); if (params_rate(params) != 8000) return -EINVAL; if (params_channels(params) != 1) return -EINVAL; pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */ /* todo: gg check mode (DSP_B) against CSR datasheet */ /* set codec DAI configuration */ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* set the codec system clock for DAC and ADC */ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, SND_SOC_CLOCK_IN); if (ret < 0) return ret; /* set codec PCM division for sample rate */ ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); if (ret < 0) return ret; /* configue and enable PLL for 12.288MHz output */ ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, iis_clkrate / 4, 12288000); if (ret < 0) return ret; return 0;}static int neo1973_voice_hw_free(struct snd_pcm_substream *substream){ struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; /* disable the PLL */ return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0);}static struct snd_soc_ops neo1973_voice_ops = { .hw_params = neo1973_voice_hw_params, .hw_free = neo1973_voice_hw_free,};static int neo1973_scenario = 0;static int neo1973_get_scenario(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ ucontrol->value.integer.value[0] = neo1973_scenario; return 0;}static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario){ switch(neo1973_scenario) { case NEO_AUDIO_OFF: snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_GSM_CALL_AUDIO_HANDSET: snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); snd_soc_dapm_set_endpoint(codec, "Call Mic", 1); break; case NEO_GSM_CALL_AUDIO_HEADSET: snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1); snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_GSM_CALL_AUDIO_BLUETOOTH: snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_STEREO_TO_SPEAKERS: snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_STEREO_TO_HEADPHONES: snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_CAPTURE_HANDSET: snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); snd_soc_dapm_set_endpoint(codec, "Call Mic", 1); break; case NEO_CAPTURE_HEADSET: snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1); snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_CAPTURE_BLUETOOTH: snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; default: snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); } snd_soc_dapm_sync_endpoints(codec); return 0;}static int neo1973_set_scenario(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); if (neo1973_scenario == ucontrol->value.integer.value[0]) return 0; neo1973_scenario = ucontrol->value.integer.value[0]; set_scenario_endpoints(codec, neo1973_scenario); return 1;}static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};static void lm4857_write_regs(void){ if (i2c_master_send(i2c, lm4857_regs, 4) != 4) printk(KERN_ERR "lm4857: i2c write failed\n");}static int lm4857_get_reg(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ int reg=kcontrol->private_value & 0xFF;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -