diff options
author | Shengjiu Wang <b02247@freescale.com> | 2014-05-12 13:38:52 +0800 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-08-27 18:28:49 -0500 |
commit | 5588f3590453f0b0dba42a91e0465b9e84eac825 (patch) | |
tree | cc17f0c05782d4af67119695225ae52d30665ca8 /sound | |
parent | 24157860b770cb54c1f6c0f3c2e1f7be6cb10936 (diff) |
ENGR00313280-2 ASoC: fsl: Merge upsteamed cs42xx8 driver.
The upsteamed commit is 0c516b4ff85c0be4cee5b30ae59c9565c7f91a00
ASoC: cs42xx8: Add codec driver support for CS42448/CS42888
This patch adds support for the Cirrus Logic CS42448/CS42888 Audio CODEC that
has six/four 24-bit AD and eight 24-bit DA converters.
[ CS42448/CS42888 supports both I2C and SPI control ports. As initial patch,
this patch only adds the support for I2C. ]
Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
Acked-by: Brian Austin <brian.austin@cirrus.com>
Acked-by: Paul Handrigan <Paul.Handrigan@cirrus.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Signed-off-by: Shengjiu Wang <b02247@freescale.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/Kconfig | 10 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 6 | ||||
-rw-r--r-- | sound/soc/codecs/cs42888.c | 913 | ||||
-rw-r--r-- | sound/soc/codecs/cs42888.h | 123 | ||||
-rw-r--r-- | sound/soc/codecs/cs42xx8-i2c.c | 64 | ||||
-rw-r--r-- | sound/soc/codecs/cs42xx8.c | 602 | ||||
-rw-r--r-- | sound/soc/codecs/cs42xx8.h | 238 | ||||
-rw-r--r-- | sound/soc/fsl/imx-cs42888.c | 8 |
8 files changed, 920 insertions, 1044 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7b7801e06b86..60e4fe8b6fe4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -35,7 +35,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS42L73 if I2C select SND_SOC_CS4270 if I2C select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI - select SND_SOC_CS42888 if I2C + select SND_SOC_CS42XX8_I2C if I2C select SND_SOC_CX20442 if TTY select SND_SOC_DA7210 if I2C select SND_SOC_DA7213 if I2C @@ -241,9 +241,15 @@ config SND_SOC_CS4270_VD33_ERRATA config SND_SOC_CS4271 tristate -config SND_SOC_CS42888 +config SND_SOC_CS42XX8 tristate +config SND_SOC_CS42XX8_I2C + tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)" + depends on I2C + select SND_SOC_CS42XX8 + select REGMAP_I2C + config SND_SOC_CX20442 tristate depends on TTY diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index ea9bd25f9a4a..57a05ca96798 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -22,7 +22,8 @@ snd-soc-cs42l52-objs := cs42l52.o snd-soc-cs42l73-objs := cs42l73.o snd-soc-cs4270-objs := cs4270.o snd-soc-cs4271-objs := cs4271.o -snd-soc-cs42888-objs := cs42888.o +snd-soc-cs42xx8-objs := cs42xx8.o +snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o snd-soc-da7213-objs := da7213.o @@ -150,7 +151,8 @@ obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o -obj-$(CONFIG_SND_SOC_CS42888) += snd-soc-cs42888.o +obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o +obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o diff --git a/sound/soc/codecs/cs42888.c b/sound/soc/codecs/cs42888.c deleted file mode 100644 index 24b68a4de234..000000000000 --- a/sound/soc/codecs/cs42888.c +++ /dev/null @@ -1,913 +0,0 @@ -/* - * cs42888.c -- CS42888 ALSA SoC Audio Driver - * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. All Rights Reserved. - */ -/* - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/i2c.h> -#include <linux/spi/spi.h> -#include <linux/platform_device.h> -#include <linux/regulator/consumer.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/tlv.h> -#include <sound/initval.h> -#include <asm/div64.h> -#include "cs42888.h" - -#define CS42888_NUM_SUPPLIES 4 -static const char *cs42888_supply_names[CS42888_NUM_SUPPLIES] = { - "VA", - "VD", - "VLS", - "VLC", -}; - -#define CS42888_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -/* Private data for the CS42888 */ -struct cs42888_private { - struct clk *clk; - struct snd_soc_codec *codec; - u8 reg_cache[CS42888_NUMREGS + 1]; - unsigned int mclk; /* Input frequency of the MCLK pin */ - unsigned int slave_mode; - struct regulator_bulk_data supplies[CS42888_NUM_SUPPLIES]; -}; - -/** - * cs42888_fill_cache - pre-fill the CS42888 register cache. - * @codec: the codec for this CS42888 - * - * This function fills in the CS42888 register cache by reading the register - * values from the hardware. - * - * This CS42888 registers are cached to avoid excessive I2C I/O operations. - * After the initial read to pre-fill the cache, the CS42888 never updates - * the register values, so we won't have a cache coherency problem. - * - * We use the auto-increment feature of the CS42888 to read all registers in - * one shot. - */ -static int cs42888_fill_cache(struct snd_soc_codec *codec) -{ - u8 *cache = codec->reg_cache; - struct i2c_client *i2c_client = to_i2c_client(codec->dev); - s32 length; - - length = i2c_smbus_read_i2c_block_data(i2c_client, - CS42888_FIRSTREG | CS42888_I2C_INCR, CS42888_NUMREGS, \ - cache + 1); - - if (length != CS42888_NUMREGS) { - dev_err(codec->dev, "i2c read failure, addr=0x%x\n", - i2c_client->addr); - return -EIO; - } - return 0; -} - -#ifdef DEBUG -static void dump_reg(struct snd_soc_codec *codec) -{ - int i, reg; - int ret; - u8 *cache = codec->reg_cache + 1; - - dev_dbg(codec->dev, "dump begin\n"); - dev_dbg(codec->dev, "reg value in cache\n"); - for (i = 0; i < CS42888_NUMREGS; i++) - dev_dbg(codec->dev, "reg[%d] = 0x%x\n", i, cache[i]); - - dev_dbg(codec->dev, "real reg value\n"); - ret = cs42888_fill_cache(codec); - if (ret < 0) { - dev_err(codec->dev, "failed to fill register cache\n"); - return ret; - } - for (i = 0; i < CS42888_NUMREGS; i++) - dev_dbg(codec->dev, "reg[%d] = 0x%x\n", i, cache[i]); - - dev_dbg(codec->dev, "dump end\n"); -} -#else -static void dump_reg(struct snd_soc_codec *codec) -{ -} -#endif - -/* -127.5dB to 0dB with step of 0.5dB */ -static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); -/* -64dB to 24dB with step of 0.5dB */ -static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 1); - -static int cs42888_out_vu(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return snd_soc_put_volsw_2r(kcontrol, ucontrol); -} - -static int cs42888_info_volsw_s8(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = mc->max - mc->min; - return 0; -} - -static int cs42888_get_volsw_s8(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - s8 val = snd_soc_read(codec, mc->reg); - ucontrol->value.integer.value[0] = val - mc->min; - - val = snd_soc_read(codec, mc->rreg); - ucontrol->value.integer.value[1] = val - mc->min; - return 0; -} - -int cs42888_put_volsw_s8(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned short val; - int ret; - - val = ucontrol->value.integer.value[0] + mc->min; - ret = snd_soc_write(codec, mc->reg, val); - if (ret < 0) { - dev_err(codec->dev, "i2c write failed\n"); - return ret; - } - - val = ucontrol->value.integer.value[1] + mc->min; - ret = snd_soc_write(codec, mc->rreg, val); - if (ret < 0) { - dev_err(codec->dev, "i2c write failed\n"); - return ret; - } - return 0; -} - -#define SOC_CS42888_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, \ - xinvert, tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = (xname), \ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw, \ - .get = snd_soc_get_volsw, \ - .put = cs42888_out_vu, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = reg_left, \ - .rreg = reg_right, \ - .shift = xshift, \ - .max = xmax, \ - .invert = xinvert} \ -} - -#define SOC_CS42888_DOUBLE_R_S8_TLV(xname, reg_left, reg_right, xmin, xmax, \ - tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .tlv.p = (tlv_array), \ - .info = cs42888_info_volsw_s8, \ - .get = cs42888_get_volsw_s8, \ - .put = cs42888_put_volsw_s8, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = reg_left, \ - .rreg = reg_right, \ - .min = xmin, \ - .max = xmax} \ -} - -static const char *cs42888_adcfilter[] = { "None", "High Pass" }; -static const char *cs42888_dacinvert[] = { "Disabled", "Enabled" }; -static const char *cs42888_adcinvert[] = { "Disabled", "Enabled" }; -static const char *cs42888_dacamute[] = { "Disabled", "AutoMute" }; -static const char *cs42888_dac_sngvol[] = { "Disabled", "Enabled" }; -static const char *cs42888_dac_szc[] = { "Immediate Change", "Zero Cross", - "Soft Ramp", "Soft Ramp on Zero Cross" }; -static const char *cs42888_mute_adc[] = { "UnMute", "Mute" }; -static const char *cs42888_adc_sngvol[] = { "Disabled", "Enabled" }; -static const char *cs42888_adc_szc[] = { "Immediate Change", "Zero Cross", - "Soft Ramp", "Soft Ramp on Zero Cross" }; -static const char *cs42888_dac_dem[] = { "No-De-Emphasis", "De-Emphasis" }; -static const char *cs42888_adc_single[] = { "Differential", "Single-Ended" }; - -static const struct soc_enum cs42888_enum[] = { - SOC_ENUM_SINGLE(CS42888_ADCCTL, 7, 2, cs42888_adcfilter), - SOC_ENUM_DOUBLE(CS42888_DACINV, 0, 1, 2, cs42888_dacinvert), - SOC_ENUM_DOUBLE(CS42888_DACINV, 2, 3, 2, cs42888_dacinvert), - SOC_ENUM_DOUBLE(CS42888_DACINV, 4, 5, 2, cs42888_dacinvert), - SOC_ENUM_DOUBLE(CS42888_DACINV, 6, 7, 2, cs42888_dacinvert), - SOC_ENUM_DOUBLE(CS42888_ADCINV, 0, 1, 2, cs42888_adcinvert), - SOC_ENUM_DOUBLE(CS42888_ADCINV, 2, 3, 2, cs42888_adcinvert), - SOC_ENUM_SINGLE(CS42888_TRANS, 4, 2, cs42888_dacamute), - SOC_ENUM_SINGLE(CS42888_TRANS, 7, 2, cs42888_dac_sngvol), - SOC_ENUM_SINGLE(CS42888_TRANS, 5, 4, cs42888_dac_szc), - SOC_ENUM_SINGLE(CS42888_TRANS, 3, 2, cs42888_mute_adc), - SOC_ENUM_SINGLE(CS42888_TRANS, 2, 2, cs42888_adc_sngvol), - SOC_ENUM_SINGLE(CS42888_TRANS, 0, 4, cs42888_adc_szc), - SOC_ENUM_SINGLE(CS42888_ADCCTL, 5, 2, cs42888_dac_dem), - SOC_ENUM_SINGLE(CS42888_ADCCTL, 4, 2, cs42888_adc_single), - SOC_ENUM_SINGLE(CS42888_ADCCTL, 3, 2, cs42888_adc_single), -}; - -static const struct snd_kcontrol_new cs42888_snd_controls[] = { - SOC_CS42888_DOUBLE_R_TLV("DAC1 Playback Volume", CS42888_VOLAOUT1, - CS42888_VOLAOUT2, 0, 0xff, 1, dac_tlv), - SOC_CS42888_DOUBLE_R_TLV("DAC2 Playback Volume", CS42888_VOLAOUT3, - CS42888_VOLAOUT4, 0, 0xff, 1, dac_tlv), - SOC_CS42888_DOUBLE_R_TLV("DAC3 Playback Volume", CS42888_VOLAOUT5, - CS42888_VOLAOUT6, 0, 0xff, 1, dac_tlv), - SOC_CS42888_DOUBLE_R_TLV("DAC4 Playback Volume", CS42888_VOLAOUT7, - CS42888_VOLAOUT8, 0, 0xff, 1, dac_tlv), - SOC_CS42888_DOUBLE_R_S8_TLV("ADC1 Capture Volume", CS42888_VOLAIN1, - CS42888_VOLAIN2, -128, 48, adc_tlv), - SOC_CS42888_DOUBLE_R_S8_TLV("ADC2 Capture Volume", CS42888_VOLAIN3, - CS42888_VOLAIN4, -128, 48, adc_tlv), - SOC_ENUM("ADC High-Pass Filter Switch", cs42888_enum[0]), - SOC_ENUM("DAC1 Invert Switch", cs42888_enum[1]), - SOC_ENUM("DAC2 Invert Switch", cs42888_enum[2]), - SOC_ENUM("DAC3 Invert Switch", cs42888_enum[3]), - SOC_ENUM("DAC4 Invert Switch", cs42888_enum[4]), - SOC_ENUM("ADC1 Invert Switch", cs42888_enum[5]), - SOC_ENUM("ADC2 Invert Switch", cs42888_enum[6]), - SOC_ENUM("DAC Auto Mute Switch", cs42888_enum[7]), - SOC_ENUM("DAC Single Volume Control Switch", cs42888_enum[8]), - SOC_ENUM("DAC Soft Ramp and Zero Cross Control Switch", cs42888_enum[9]), - SOC_ENUM("Mute ADC Serial Port Switch", cs42888_enum[10]), - SOC_ENUM("ADC Single Volume Control Switch", cs42888_enum[11]), - SOC_ENUM("ADC Soft Ramp and Zero Cross Control Switch", cs42888_enum[12]), - SOC_ENUM("DAC Deemphasis Switch", cs42888_enum[13]), - SOC_ENUM("ADC1 Single Ended Mode Switch", cs42888_enum[14]), - SOC_ENUM("ADC2 Single Ended Mode Switch", cs42888_enum[15]), -}; - - -static const struct snd_soc_dapm_widget cs42888_dapm_widgets[] = { - SND_SOC_DAPM_DAC("DAC1", "codec-Playback", CS42888_PWRCTL, 1, 1), - SND_SOC_DAPM_DAC("DAC2", "codec-Playback", CS42888_PWRCTL, 2, 1), - SND_SOC_DAPM_DAC("DAC3", "codec-Playback", CS42888_PWRCTL, 3, 1), - SND_SOC_DAPM_DAC("DAC4", "codec-Playback", CS42888_PWRCTL, 4, 1), - - SND_SOC_DAPM_OUTPUT("AOUT1L"), - SND_SOC_DAPM_OUTPUT("AOUT1R"), - SND_SOC_DAPM_OUTPUT("AOUT2L"), - SND_SOC_DAPM_OUTPUT("AOUT2R"), - SND_SOC_DAPM_OUTPUT("AOUT3L"), - SND_SOC_DAPM_OUTPUT("AOUT3R"), - SND_SOC_DAPM_OUTPUT("AOUT4L"), - SND_SOC_DAPM_OUTPUT("AOUT4R"), - - SND_SOC_DAPM_ADC("ADC1", "codec-Capture", CS42888_PWRCTL, 5, 1), - SND_SOC_DAPM_ADC("ADC2", "codec-Capture", CS42888_PWRCTL, 6, 1), - - SND_SOC_DAPM_INPUT("AIN1L"), - SND_SOC_DAPM_INPUT("AIN1R"), - SND_SOC_DAPM_INPUT("AIN2L"), - SND_SOC_DAPM_INPUT("AIN2R"), - - SND_SOC_DAPM_PGA_E("PWR", CS42888_PWRCTL, 0, 1, NULL, 0, - NULL, 0), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* Playback */ - { "PWR", NULL, "DAC1" }, - { "PWR", NULL, "DAC1" }, - - { "PWR", NULL, "DAC2" }, - { "PWR", NULL, "DAC2" }, - - { "PWR", NULL, "DAC3" }, - { "PWR", NULL, "DAC3" }, - - { "PWR", NULL, "DAC4" }, - { "PWR", NULL, "DAC4" }, - - { "AOUT1L", NULL, "PWR" }, - { "AOUT1R", NULL, "PWR" }, - - { "AOUT2L", NULL, "PWR" }, - { "AOUT2R", NULL, "PWR" }, - - { "AOUT3L", NULL, "PWR" }, - { "AOUT3R", NULL, "PWR" }, - - { "AOUT4L", NULL, "PWR" }, - { "AOUT4R", NULL, "PWR" }, - - /* Capture */ - { "PWR", NULL, "AIN1L" }, - { "PWR", NULL, "AIN1R" }, - - { "PWR", NULL, "AIN2L" }, - { "PWR", NULL, "AIN2R" }, - - { "ADC1", NULL, "PWR" }, - { "ADC1", NULL, "PWR" }, - - { "ADC2", NULL, "PWR" }, - { "ADC2", NULL, "PWR" }, -}; - - -static int cs42888_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(&codec->dapm, cs42888_dapm_widgets, - ARRAY_SIZE(cs42888_dapm_widgets)); - - snd_soc_dapm_add_routes(&codec->dapm, audio_map, ARRAY_SIZE(audio_map)); - - snd_soc_dapm_new_widgets(&codec->dapm); - return 0; -} - -/** - * struct cs42888_mode_ratios - clock ratio tables - * @ratio: the ratio of MCLK to the sample rate - * @speed_mode: the Speed Mode bits to set in the Mode Control register for - * this ratio - * @mclk: the Ratio Select bits to set in the Mode Control register for this - * ratio - * - * The data for this chart is taken from Table 10 of the CS42888 reference - * manual. - * - * This table is used to determine how to program the Functional Mode register. - * It is also used by cs42888_set_dai_sysclk() to tell ALSA which sampling - * rates the CS42888 currently supports. - * - * @speed_mode is the corresponding bit pattern to be written to the - * MODE bits of the Mode Control Register - * - * @mclk is the corresponding bit pattern to be wirten to the MCLK bits of - * the Mode Control Register. - * - */ -struct cs42888_mode_ratios { - unsigned int ratio; - u8 speed_mode; - u8 mclk; -}; - -static struct cs42888_mode_ratios cs42888_mode_ratios[] = { - {64, CS42888_MODE_4X, CS42888_MODE_DIV1}, - {96, CS42888_MODE_4X, CS42888_MODE_DIV2}, - {128, CS42888_MODE_2X, CS42888_MODE_DIV1}, - {192, CS42888_MODE_2X, CS42888_MODE_DIV2}, - {256, CS42888_MODE_1X, CS42888_MODE_DIV1}, - {384, CS42888_MODE_2X, CS42888_MODE_DIV4}, - {512, CS42888_MODE_1X, CS42888_MODE_DIV3}, - {768, CS42888_MODE_1X, CS42888_MODE_DIV4}, - {1024, CS42888_MODE_1X, CS42888_MODE_DIV5} -}; - -/* The number of MCLK/LRCK ratios supported by the CS42888 */ -#define NUM_MCLK_RATIOS ARRAY_SIZE(cs42888_mode_ratios) - -/** - * cs42888_set_dai_sysclk - determine the CS42888 samples rates. - * @codec_dai: the codec DAI - * @clk_id: the clock ID (ignored) - * @freq: the MCLK input frequency - * @dir: the clock direction (ignored) - * - * This function is used to tell the codec driver what the input MCLK - * frequency is. - * - */ -static int cs42888_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct cs42888_private *cs42888 = snd_soc_codec_get_drvdata(codec); - - cs42888->mclk = freq; - return 0; -} - -/** - * cs42888_set_dai_fmt - configure the codec for the selected audio format - * @codec_dai: the codec DAI - * @format: a SND_SOC_DAIFMT_x value indicating the data format - * - * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the - * codec accordingly. - * - * Currently, this function only supports SND_SOC_DAIFMT_I2S and - * SND_SOC_DAIFMT_LEFT_J. The CS42888 codec also supports right-justified - * data for playback only, but ASoC currently does not support different - * formats for playback vs. record. - */ -static int cs42888_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int format) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct cs42888_private *cs42888 = snd_soc_codec_get_drvdata(codec); - int ret = 0; - u8 val; - - val = snd_soc_read(codec, CS42888_FORMAT); - val &= ~CS42888_FORMAT_DAC_DIF_MASK; - val &= ~CS42888_FORMAT_ADC_DIF_MASK; - /* set DAI format */ - switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_LEFT_J: - val |= DIF_LEFT_J << CS42888_FORMAT_DAC_DIF_OFFSET; - val |= DIF_LEFT_J << CS42888_FORMAT_ADC_DIF_OFFSET; - break; - case SND_SOC_DAIFMT_I2S: - val |= DIF_I2S << CS42888_FORMAT_DAC_DIF_OFFSET; - val |= DIF_I2S << CS42888_FORMAT_ADC_DIF_OFFSET; - break; - case SND_SOC_DAIFMT_RIGHT_J: - val |= DIF_RIGHT_J << CS42888_FORMAT_DAC_DIF_OFFSET; - val |= DIF_RIGHT_J << CS42888_FORMAT_ADC_DIF_OFFSET; - break; - default: - dev_err(codec->dev, "invalid dai format\n"); - return -EINVAL; - } - - ret = snd_soc_write(codec, CS42888_FORMAT, val); - if (ret < 0) { - dev_err(codec->dev, "i2c write failed\n"); - return ret; - } - - val = snd_soc_read(codec, CS42888_MODE); - /* set master/slave audio interface */ - switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - cs42888->slave_mode = 1; - val &= ~CS42888_MODE_SPEED_MASK; - val |= CS42888_MODE_SLAVE; - break; - case SND_SOC_DAIFMT_CBM_CFM: - cs42888->slave_mode = 0; - break; - default: - /* all other modes are unsupported by the hardware */ - return -EINVAL; - } - - ret = snd_soc_write(codec, CS42888_MODE, val); - if (ret < 0) { - dev_err(codec->dev, "i2c write failed\n"); - return ret; - } - - dump_reg(codec); - return ret; -} - -/** - * cs42888_hw_params - program the CS42888 with the given hardware parameters. - * @substream: the audio stream - * @params: the hardware parameters to set - - * @dai: the SOC DAI (ignored) - * - * This function programs the hardware with the values provided. - * Specifically, the sample rate and the data format. - * - * The .ops functions are used to provide board-specific data, like input - * frequencies, to this driver. This function takes that information, - * combines it with the hardware parameters provided, and programs the - * hardware accordingly. - */ -static int cs42888_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; - struct cs42888_private *cs42888 = snd_soc_codec_get_drvdata(codec); - int ret; - u32 i, rate, ratio, val; - - rate = params_rate(params); /* Sampling rate, in Hz */ - ratio = cs42888->mclk / rate; /* MCLK/LRCK ratio */ - for (i = 0; i < NUM_MCLK_RATIOS; i++) { - if (cs42888_mode_ratios[i].ratio == ratio) - break; - } - - if (i == NUM_MCLK_RATIOS) { - /* We did not find a matching ratio */ - dev_err(codec->dev, "could not find matching ratio\n"); - return -EINVAL; - } - - if (!cs42888->slave_mode) { - val = snd_soc_read(codec, CS42888_MODE); - val &= ~CS42888_MODE_SPEED_MASK; - val |= cs42888_mode_ratios[i].speed_mode; - val &= ~CS42888_MODE_DIV_MASK; - val |= cs42888_mode_ratios[i].mclk; - } else { - val = snd_soc_read(codec, CS42888_MODE); - val &= ~CS42888_MODE_SPEED_MASK; - val |= CS42888_MODE_SLAVE; - val &= ~CS42888_MODE_DIV_MASK; - val |= cs42888_mode_ratios[i].mclk; - } - ret = snd_soc_write(codec, CS42888_MODE, val); - if (ret < 0) { - dev_err(codec->dev, "i2c write failed\n"); - return ret; - } - - /* Unmute all the channels */ - val = snd_soc_read(codec, CS42888_MUTE); - val &= ~CS42888_MUTE_ALL; - ret = snd_soc_write(codec, CS42888_MUTE, val); - if (ret < 0) { - dev_err(codec->dev, "i2c write failed\n"); - return ret; - } - - ret = cs42888_fill_cache(codec); - if (ret < 0) { - dev_err(codec->dev, "failed to fill register cache\n"); - return ret; - } - - dump_reg(codec); - return ret; -} - -/** - * cs42888_shutdown - cs42888 enters into low power mode again. - * @substream: the audio stream - * @dai: the SOC DAI (ignored) - * - * The .ops functions are used to provide board-specific data, like input - * frequencies, to this driver. This function takes that information, - * combines it with the hardware parameters provided, and programs the - * hardware accordingly. - */ -static void cs42888_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; - int ret; - u8 val; - - /* Mute all the channels */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - val = snd_soc_read(codec, CS42888_MUTE); - val |= CS42888_MUTE_ALL; - ret = snd_soc_write(codec, CS42888_MUTE, val); - if (ret < 0) - dev_err(codec->dev, "i2c write failed\n"); - } -} - -static int cs42888_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_card *card = rtd->card; - struct snd_soc_dai *tmp_codec_dai; - struct snd_soc_pcm_runtime *tmp_rtd; - u32 i; - - for (i = 0; i < card->num_rtd; i++) { - tmp_codec_dai = card->rtd[i].codec_dai; - tmp_rtd = (struct snd_soc_pcm_runtime *)(card->rtd + i); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - cancel_delayed_work(&tmp_rtd->delayed_work); - } - return 0; -} - -static struct snd_soc_dai_ops cs42888_dai_ops = { - .set_fmt = cs42888_set_dai_fmt, - .set_sysclk = cs42888_set_dai_sysclk, - .hw_params = cs42888_hw_params, - .shutdown = cs42888_shutdown, - .prepare = cs42888_prepare, -}; - - -static struct snd_soc_dai_driver cs42888_dai = { - .name = "CS42888", - .playback = { - .stream_name = "codec-Playback", - .channels_min = 2, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = CS42888_FORMATS, - }, - .capture = { - .stream_name = "codec-Capture", - .channels_min = 2, - .channels_max = 4, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = CS42888_FORMATS, - }, - .ops = &cs42888_dai_ops, -}; - -/** - * cs42888_probe - ASoC probe function - * @pdev: platform device - * - * This function is called when ASoC has all the pieces it needs to - * instantiate a sound driver. - */ -static int cs42888_probe(struct snd_soc_codec *codec) -{ - struct cs42888_private *cs42888 = snd_soc_codec_get_drvdata(codec); - int ret, i, val; - - cs42888->codec = codec; - /* setup i2c data ops */ - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(cs42888->supplies); i++) - cs42888->supplies[i].supply = cs42888_supply_names[i]; - - ret = devm_regulator_bulk_get(codec->dev, - ARRAY_SIZE(cs42888->supplies), cs42888->supplies); - if (ret) { - dev_err(codec->dev, "Failed to request supplies: %d\n", - ret); - return ret; - } - - ret = regulator_bulk_enable(ARRAY_SIZE(cs42888->supplies), - cs42888->supplies); - if (ret) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", - ret); - goto err; - } - msleep(1); - - /* The I2C interface is set up, so pre-fill our register cache */ - ret = cs42888_fill_cache(codec); - if (ret < 0) { - dev_err(codec->dev, "failed to fill register cache\n"); - goto err; - } - - /* Enter low power state */ - val = snd_soc_read(codec, CS42888_PWRCTL); - val |= CS42888_PWRCTL_PDN_MASK; - ret = snd_soc_write(codec, CS42888_PWRCTL, val); - if (ret < 0) { - dev_err(codec->dev, "i2c write failed\n"); - goto err; - } - - /* Disable auto-mute */ - val = snd_soc_read(codec, CS42888_TRANS); - val &= ~CS42888_TRANS_AMUTE_MASK; - val &= ~CS42888_TRANS_DAC_SZC_MASK; - val |= CS42888_TRANS_DAC_SZC_SR; - ret = snd_soc_write(codec, CS42888_TRANS, val); - if (ret < 0) { - dev_err(codec->dev, "i2c write failed\n"); - goto err; - } - /* Add the non-DAPM controls */ - snd_soc_add_codec_controls(codec, cs42888_snd_controls, - ARRAY_SIZE(cs42888_snd_controls)); - - /* Add DAPM controls */ - cs42888_add_widgets(codec); - return 0; -err: - regulator_bulk_disable(ARRAY_SIZE(cs42888->supplies), - cs42888->supplies); - return ret; -} - -/** - * cs42888_remove - ASoC remove function - * @pdev: platform device - * - * This function is the counterpart to cs42888_probe(). - */ -static int cs42888_remove(struct snd_soc_codec *codec) -{ - struct cs42888_private *cs42888 = snd_soc_codec_get_drvdata(codec); - - regulator_bulk_disable(ARRAY_SIZE(cs42888->supplies), - cs42888->supplies); - - return 0; -}; - -/* - * ASoC codec device structure - * - * Assign this variable to the codec_dev field of the machine driver's - * snd_soc_device structure. - */ -static struct snd_soc_codec_driver cs42888_driver = { - .probe = cs42888_probe, - .remove = cs42888_remove, - .reg_cache_size = CS42888_NUMREGS + 1, - .reg_word_size = sizeof(u8), - .reg_cache_step = 1, -}; - -/** - * cs42888_i2c_probe - initialize the I2C interface of the CS42888 - * @i2c_client: the I2C client object - * @id: the I2C device ID (ignored) - * - * This function is called whenever the I2C subsystem finds a device that - * matches the device ID given via a prior call to i2c_add_driver(). - */ -static int cs42888_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) -{ - struct cs42888_private *cs42888; - int ret, val; - - /* Verify that we have a CS42888 */ - val = i2c_smbus_read_byte_data(i2c_client, CS42888_CHIPID); - if (val < 0) { - dev_err(&i2c_client->dev, "Device with ID register %x is not a CS42888", val); - return -ENODEV; - } - /* The top four bits of the chip ID should be 0000. */ - if ((val & CS42888_CHIPID_ID_MASK) != 0x00) { - dev_err(&i2c_client->dev, "device is not a CS42888\n"); - return -ENODEV; - } - - dev_info(&i2c_client->dev, "found device at i2c address %X\n", - i2c_client->addr); - dev_info(&i2c_client->dev, "hardware revision %X\n", val & 0xF); - - /* Allocate enough space for the snd_soc_codec structure - and our private data together. */ - cs42888 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42888_private), GFP_KERNEL); - if (!cs42888) { - dev_err(&i2c_client->dev, "could not allocate codec\n"); - return -ENOMEM; - } - - i2c_set_clientdata(i2c_client, cs42888); - - cs42888->clk = devm_clk_get(&i2c_client->dev, NULL); - if (IS_ERR(cs42888->clk)) { - ret = PTR_ERR(cs42888->clk); - dev_err(&i2c_client->dev, "Cannot get the clock: %d\n", ret); - return ret; - } - - cs42888->mclk = clk_get_rate(cs42888->clk); - - ret = snd_soc_register_codec(&i2c_client->dev, - &cs42888_driver, &cs42888_dai, 1); - if (ret) { - dev_err(&i2c_client->dev, "Failed to register codec:%d\n", ret); - return ret; - } - return 0; -} - -/** - * cs42888_i2c_remove - remove an I2C device - * @i2c_client: the I2C client object - * - * This function is the counterpart to cs42888_i2c_probe(). - */ -static int cs42888_i2c_remove(struct i2c_client *i2c_client) -{ - snd_soc_unregister_codec(&i2c_client->dev); - return 0; -} - -/* - * cs42888_i2c_id - I2C device IDs supported by this driver - */ -static struct i2c_device_id cs42888_i2c_id[] = { - {"cs42888", 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, cs42888_i2c_id); - -#ifdef CONFIG_PM -/* This suspend/resume implementation can handle both - a simple standby - * where the codec remains powered, and a full suspend, where the voltage - * domain the codec is connected to is teared down and/or any other hardware - * reset condition is asserted. - * - * The codec's own power saving features are enabled in the suspend callback, - * and all registers are written back to the hardware when resuming. - */ - -static int cs42888_i2c_suspend(struct i2c_client *client, pm_message_t mesg) -{ - struct cs42888_private *cs42888 = i2c_get_clientdata(client); - struct snd_soc_codec *codec = cs42888->codec; - int reg = snd_soc_read(codec, CS42888_PWRCTL) | CS42888_PWRCTL_PDN_MASK; - return snd_soc_write(codec, CS42888_PWRCTL, reg); -} - -static int cs42888_i2c_resume(struct i2c_client *client) -{ - struct cs42888_private *cs42888 = i2c_get_clientdata(client); - struct snd_soc_codec *codec = cs42888->codec; - int reg; - - /* In case the device was put to hard reset during sleep, we need to - * wait 500ns here before any I2C communication. */ - ndelay(500); - - /* first restore the entire register cache ... */ - for (reg = CS42888_FIRSTREG; reg <= CS42888_LASTREG; reg++) { - u8 val = snd_soc_read(codec, reg); - - if (i2c_smbus_write_byte_data(client, reg, val)) { - dev_err(codec->dev, "i2c write failed\n"); - return -EIO; - } - } - - /* ... then disable the power-down bits */ - reg = snd_soc_read(codec, CS42888_PWRCTL); - reg &= ~CS42888_PWRCTL_PDN_MASK; - return snd_soc_write(codec, CS42888_PWRCTL, reg); -} -#else -#define cs42888_i2c_suspend NULL -#define cs42888_i2c_resume NULL -#endif /* CONFIG_PM */ - -/* - * cs42888_i2c_driver - I2C device identification - * - * This structure tells the I2C subsystem how to identify and support a - * given I2C device type. - */ - -static const struct of_device_id cs42888_dt_ids[] = { - { .compatible = "cirrus,cs42888", }, - { /* sentinel */ } -}; - -static struct i2c_driver cs42888_i2c_driver = { - .driver = { - .name = "cs42888", - .owner = THIS_MODULE, - .of_match_table = cs42888_dt_ids, - }, - .probe = cs42888_i2c_probe, - .remove = cs42888_i2c_remove, - .suspend = cs42888_i2c_suspend, - .resume = cs42888_i2c_resume, - .id_table = cs42888_i2c_id, -}; - -module_i2c_driver(cs42888_i2c_driver); - -MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("Cirrus Logic CS42888 ALSA SoC Codec Driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42888.h b/sound/soc/codecs/cs42888.h deleted file mode 100644 index d06d78196b9a..000000000000 --- a/sound/soc/codecs/cs42888.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved. - */ - -/* - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#ifndef _CS42888_H -#define _CS42888_H - -/* CS42888 registers addresses */ -#define CS42888_CHIPID 0x01 /* Chip ID */ -#define CS42888_PWRCTL 0x02 /* Power Control */ -#define CS42888_MODE 0x03 /* Functional Mode */ -#define CS42888_FORMAT 0x04 /* Interface Formats */ -#define CS42888_ADCCTL 0x05 /* ADC Control */ -#define CS42888_TRANS 0x06 /* Transition Control */ -#define CS42888_MUTE 0x07 /* Mute Control */ -#define CS42888_VOLAOUT1 0x08 /* Volume Control AOUT1*/ -#define CS42888_VOLAOUT2 0x09 /* Volume Control AOUT2*/ -#define CS42888_VOLAOUT3 0x0A /* Volume Control AOUT3*/ -#define CS42888_VOLAOUT4 0x0B /* Volume Control AOUT4*/ -#define CS42888_VOLAOUT5 0x0C /* Volume Control AOUT5*/ -#define CS42888_VOLAOUT6 0x0D /* Volume Control AOUT6*/ -#define CS42888_VOLAOUT7 0x0E /* Volume Control AOUT7*/ -#define CS42888_VOLAOUT8 0x0F /* Volume Control AOUT8*/ -#define CS42888_DACINV 0x10 /* DAC Channel Invert */ -#define CS42888_VOLAIN1 0x11 /* Volume Control AIN1 */ -#define CS42888_VOLAIN2 0x12 /* Volume Control AIN2 */ -#define CS42888_VOLAIN3 0x13 /* Volume Control AIN3 */ -#define CS42888_VOLAIN4 0x14 /* Volume Control AIN4 */ -#define CS42888_ADCINV 0x17 /* ADC Channel Invert */ -#define CS42888_STATUSCTL 0x18 /* Status Control */ -#define CS42888_STATUS 0x19 /* Status */ -#define CS42888_STATUSMASK 0x1A /* Status Mask */ - -#define CS42888_FIRSTREG 0x01 -#define CS42888_LASTREG 0x1A -#define CS42888_NUMREGS (CS42888_LASTREG - CS42888_FIRSTREG + 1) -#define CS42888_I2C_INCR 0x80 - -/* Bit masks for the CS42888 registers */ -#define CS42888_CHIPID_ID_MASK 0xF0 -#define CS42888_CHIPID_REV 0x0F -#define CS42888_PWRCTL_PDN_ADC2_OFFSET 6 -#define CS42888_PWRCTL_PDN_ADC1_OFFSET 5 -#define CS42888_PWRCTL_PDN_DAC4_OFFSET 4 -#define CS42888_PWRCTL_PDN_DAC3_OFFSET 3 -#define CS42888_PWRCTL_PDN_DAC2_OFFSET 2 -#define CS42888_PWRCTL_PDN_DAC1_OFFSET 1 -#define CS42888_PWRCTL_PDN_OFFSET 0 -#define CS42888_PWRCTL_PDN_ADC2_MASK (1 << CS42888_PWRCTL_PDN_ADC2_OFFSET) -#define CS42888_PWRCTL_PDN_ADC1_MASK (1 << CS42888_PWRCTL_PDN_ADC1_OFFSET) -#define CS42888_PWRCTL_PDN_DAC4_MASK (1 << CS42888_PWRCTL_PDN_DAC4_OFFSET) -#define CS42888_PWRCTL_PDN_DAC3_MASK (1 << CS42888_PWRCTL_PDN_DAC3_OFFSET) -#define CS42888_PWRCTL_PDN_DAC2_MASK (1 << CS42888_PWRCTL_PDN_DAC2_OFFSET) -#define CS42888_PWRCTL_PDN_DAC1_MASK (1 << CS42888_PWRCTL_PDN_DAC1_OFFSET) -#define CS42888_PWRCTL_PDN_MASK (1 << CS42888_PWRCTL_PDN_OFFSET) - -#define CS42888_MODE_SPEED_MASK 0xF0 -#define CS42888_MODE_1X 0x00 -#define CS42888_MODE_2X 0x50 -#define CS42888_MODE_4X 0xA0 -#define CS42888_MODE_SLAVE 0xF0 -#define CS42888_MODE_DIV_MASK 0x0E -#define CS42888_MODE_DIV1 0x00 -#define CS42888_MODE_DIV2 0x02 -#define CS42888_MODE_DIV3 0x04 -#define CS42888_MODE_DIV4 0x06 -#define CS42888_MODE_DIV5 0x08 - -#define CS42888_FORMAT_FREEZE_OFFSET 7 -#define CS42888_FORMAT_AUX_DIF_OFFSET 6 -#define CS42888_FORMAT_DAC_DIF_OFFSET 3 -#define CS42888_FORMAT_ADC_DIF_OFFSET 0 -#define CS42888_FORMAT_FREEZE_MASK (1 << CS42888_FORMAT_FREEZE_OFFSET) -#define CS42888_FORMAT_AUX_DIF_MASK (1 << CS42888_FORMAT_AUX_DIF_OFFSET) -#define CS42888_FORMAT_DAC_DIF_MASK (7 << CS42888_FORMAT_DAC_DIF_OFFSET) -#define CS42888_FORMAT_ADC_DIF_MASK (7 << CS42888_FORMAT_ADC_DIF_OFFSET) - -#define CS42888_TRANS_DAC_SNGVOL_OFFSET 7 -#define CS42888_TRANS_DAC_SZC_OFFSET 5 -#define CS42888_TRANS_AMUTE_OFFSET 4 -#define CS42888_TRANS_MUTE_ADC_SP_OFFSET 3 -#define CS42888_TRANS_ADC_SNGVOL_OFFSET 2 -#define CS42888_TRANS_ADC_SZC_OFFSET 0 -#define CS42888_TRANS_DAC_SNGVOL_MASK (1 << CS42888_TRANS_DAC_SNGVOL_OFFSET) -#define CS42888_TRANS_DAC_SZC_MASK (3 << CS42888_TRANS_DAC_SZC_OFFSET) -#define CS42888_TRANS_AMUTE_MASK (1 << CS42888_TRANS_AMUTE_OFFSET) -#define CS42888_TRANS_MUTE_ADC_SP_MASK (1 << CS42888_TRANS_MUTE_ADC_SP_OFFSET) -#define CS42888_TRANS_ADC_SNGVOL_MASK (1 << CS42888_TRANS_ADC_SNGVOL_OFFSET) -#define CS42888_TRANS_ADC_SZC_MASK (3 << CS42888_TRANS_ADC_SZC_OFFSET) -#define CS42888_TRANS_DAC_SZC_IC (0 << CS42888_TRANS_DAC_SZC_OFFSET) -#define CS42888_TRANS_DAC_SZC_ZC (1 << CS42888_TRANS_DAC_SZC_OFFSET) -#define CS42888_TRANS_DAC_SZC_SR (2 << CS42888_TRANS_DAC_SZC_OFFSET) -#define CS42888_TRANS_DAC_SZC_SRZC (3 << CS42888_TRANS_DAC_SZC_OFFSET) - -#define CS42888_MUTE_AOUT8 (0x1 << 7) -#define CS42888_MUTE_AOUT7 (0x1 << 6) -#define CS42888_MUTE_AOUT6 (0x1 << 5) -#define CS42888_MUTE_AOUT5 (0x1 << 4) -#define CS42888_MUTE_AOUT4 (0x1 << 3) -#define CS42888_MUTE_AOUT3 (0x1 << 2) -#define CS42888_MUTE_AOUT2 (0x1 << 1) -#define CS42888_MUTE_AOUT1 (0x1 << 0) -#define CS42888_MUTE_ALL (CS42888_MUTE_AOUT1 | CS42888_MUTE_AOUT2 | \ - CS42888_MUTE_AOUT3 | CS42888_MUTE_AOUT4 | \ - CS42888_MUTE_AOUT5 | CS42888_MUTE_AOUT6 | \ - CS42888_MUTE_AOUT7 | CS42888_MUTE_AOUT8) - -#define DIF_LEFT_J 0 -#define DIF_I2S 1 -#define DIF_RIGHT_J 2 -#define DIF_TDM 6 - - -#endif diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c new file mode 100644 index 000000000000..657dce27eade --- /dev/null +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -0,0 +1,64 @@ +/* + * Cirrus Logic CS42448/CS42888 Audio CODEC DAI I2C driver + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen <Guangyu.Chen@freescale.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <sound/soc.h> + +#include "cs42xx8.h" + +static int cs42xx8_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + u32 ret = cs42xx8_probe(&i2c->dev, + devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config)); + if (ret) + return ret; + + pm_runtime_enable(&i2c->dev); + pm_request_idle(&i2c->dev); + + return 0; +} + +static int cs42xx8_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + pm_runtime_disable(&i2c->dev); + + return 0; +} + +static struct i2c_device_id cs42xx8_i2c_id[] = { + {"cs42448", (kernel_ulong_t)&cs42448_data}, + {"cs42888", (kernel_ulong_t)&cs42888_data}, + {} +}; +MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id); + +static struct i2c_driver cs42xx8_i2c_driver = { + .driver = { + .name = "cs42xx8", + .owner = THIS_MODULE, + .pm = &cs42xx8_pm, + }, + .probe = cs42xx8_i2c_probe, + .remove = cs42xx8_i2c_remove, + .id_table = cs42xx8_i2c_id, +}; + +module_i2c_driver(cs42xx8_i2c_driver); + +MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec I2C Driver"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c new file mode 100644 index 000000000000..082299a4e2fa --- /dev/null +++ b/sound/soc/codecs/cs42xx8.c @@ -0,0 +1,602 @@ +/* + * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen <Guangyu.Chen@freescale.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "cs42xx8.h" + +#define CS42XX8_NUM_SUPPLIES 4 +static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = { + "VA", + "VD", + "VLS", + "VLC", +}; + +#define CS42XX8_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +/* codec private data */ +struct cs42xx8_priv { + struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES]; + const struct cs42xx8_driver_data *drvdata; + struct regmap *regmap; + struct clk *clk; + + bool slave_mode; + unsigned long sysclk; +}; + +/* -127.5dB to 0dB with step of 0.5dB */ +static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); +/* -64dB to 24dB with step of 0.5dB */ +static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0); + +static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" }; +static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross", + "Soft Ramp", "Soft Ramp on Zero Cross" }; + +static const struct soc_enum adc1_single_enum = + SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single); +static const struct soc_enum adc2_single_enum = + SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single); +static const struct soc_enum adc3_single_enum = + SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single); +static const struct soc_enum dac_szc_enum = + SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc); +static const struct soc_enum adc_szc_enum = + SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc); + +static const struct snd_kcontrol_new cs42xx8_snd_controls[] = { + SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1, + CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv), + SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3, + CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv), + SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5, + CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv), + SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7, + CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv), + SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1, + CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv), + SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3, + CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv), + SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0), + SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0), + SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0), + SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0), + SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0), + SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0), + SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1), + SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0), + SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum), + SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum), + SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0), + SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum), + SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0), + SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0), + SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0), + SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum), +}; + +static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = { + SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5, + CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv), + SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0), + SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum), +}; + +static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1), + SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1), + SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1), + SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1), + + SND_SOC_DAPM_OUTPUT("AOUT1L"), + SND_SOC_DAPM_OUTPUT("AOUT1R"), + SND_SOC_DAPM_OUTPUT("AOUT2L"), + SND_SOC_DAPM_OUTPUT("AOUT2R"), + SND_SOC_DAPM_OUTPUT("AOUT3L"), + SND_SOC_DAPM_OUTPUT("AOUT3R"), + SND_SOC_DAPM_OUTPUT("AOUT4L"), + SND_SOC_DAPM_OUTPUT("AOUT4R"), + + SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1), + SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1), + + SND_SOC_DAPM_INPUT("AIN1L"), + SND_SOC_DAPM_INPUT("AIN1R"), + SND_SOC_DAPM_INPUT("AIN2L"), + SND_SOC_DAPM_INPUT("AIN2R"), + + SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0), +}; + +static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = { + SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1), + + SND_SOC_DAPM_INPUT("AIN3L"), + SND_SOC_DAPM_INPUT("AIN3R"), +}; + +static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = { + /* Playback */ + { "AOUT1L", NULL, "DAC1" }, + { "AOUT1R", NULL, "DAC1" }, + { "DAC1", NULL, "PWR" }, + + { "AOUT2L", NULL, "DAC2" }, + { "AOUT2R", NULL, "DAC2" }, + { "DAC2", NULL, "PWR" }, + + { "AOUT3L", NULL, "DAC3" }, + { "AOUT3R", NULL, "DAC3" }, + { "DAC3", NULL, "PWR" }, + + { "AOUT4L", NULL, "DAC4" }, + { "AOUT4R", NULL, "DAC4" }, + { "DAC4", NULL, "PWR" }, + + /* Capture */ + { "ADC1", NULL, "AIN1L" }, + { "ADC1", NULL, "AIN1R" }, + { "ADC1", NULL, "PWR" }, + + { "ADC2", NULL, "AIN2L" }, + { "ADC2", NULL, "AIN2R" }, + { "ADC2", NULL, "PWR" }, +}; + +static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = { + /* Capture */ + { "ADC3", NULL, "AIN3L" }, + { "ADC3", NULL, "AIN3R" }, + { "ADC3", NULL, "PWR" }, +}; + +struct cs42xx8_ratios { + unsigned int ratio; + unsigned char speed; + unsigned char mclk; +}; + +static const struct cs42xx8_ratios cs42xx8_ratios[] = { + { 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) }, + { 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) }, + { 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) }, + { 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) }, + { 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) }, + { 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) }, + { 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) }, + { 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) }, + { 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) } +}; + +static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); + + cs42xx8->sysclk = freq; + + return 0; +} + +static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); + u32 val; + + /* Set DAI format */ + switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_LEFT_J: + val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ; + break; + case SND_SOC_DAIFMT_I2S: + val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ; + break; + default: + dev_err(codec->dev, "unsupported dai format\n"); + return -EINVAL; + } + + regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF, + CS42XX8_INTF_DAC_DIF_MASK | + CS42XX8_INTF_ADC_DIF_MASK, val); + + /* Set master/slave audio interface */ + switch (format & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + cs42xx8->slave_mode = true; + break; + case SND_SOC_DAIFMT_CBM_CFM: + cs42xx8->slave_mode = false; + break; + default: + dev_err(codec->dev, "unsupported master/slave mode\n"); + return -EINVAL; + } + + return 0; +} + +static int cs42xx8_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + u32 ratio = cs42xx8->sysclk / params_rate(params); + u32 i, fm, val, mask; + + for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) { + if (cs42xx8_ratios[i].ratio == ratio) + break; + } + + if (i == ARRAY_SIZE(cs42xx8_ratios)) { + dev_err(codec->dev, "unsupported sysclk ratio\n"); + return -EINVAL; + } + + mask = CS42XX8_FUNCMOD_MFREQ_MASK; + val = cs42xx8_ratios[i].mclk; + + fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed; + + regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD, + CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask, + CS42XX8_FUNCMOD_xC_FM(tx, fm) | val); + + return 0; +} + +static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); + + regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE, + CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0); + + return 0; +} + +static const struct snd_soc_dai_ops cs42xx8_dai_ops = { + .set_fmt = cs42xx8_set_dai_fmt, + .set_sysclk = cs42xx8_set_dai_sysclk, + .hw_params = cs42xx8_hw_params, + .digital_mute = cs42xx8_digital_mute, +}; + +static struct snd_soc_dai_driver cs42xx8_dai = { + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = CS42XX8_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = CS42XX8_FORMATS, + }, + .ops = &cs42xx8_dai_ops, +}; + +static const struct reg_default cs42xx8_reg[] = { + { 0x01, 0x01 }, /* Chip I.D. and Revision Register */ + { 0x02, 0x00 }, /* Power Control */ + { 0x03, 0xF0 }, /* Functional Mode */ + { 0x04, 0x46 }, /* Interface Formats */ + { 0x05, 0x00 }, /* ADC Control & DAC De-Emphasis */ + { 0x06, 0x10 }, /* Transition Control */ + { 0x07, 0x00 }, /* DAC Channel Mute */ + { 0x08, 0x00 }, /* Volume Control AOUT1 */ + { 0x09, 0x00 }, /* Volume Control AOUT2 */ + { 0x0a, 0x00 }, /* Volume Control AOUT3 */ + { 0x0b, 0x00 }, /* Volume Control AOUT4 */ + { 0x0c, 0x00 }, /* Volume Control AOUT5 */ + { 0x0d, 0x00 }, /* Volume Control AOUT6 */ + { 0x0e, 0x00 }, /* Volume Control AOUT7 */ + { 0x0f, 0x00 }, /* Volume Control AOUT8 */ + { 0x10, 0x00 }, /* DAC Channel Invert */ + { 0x11, 0x00 }, /* Volume Control AIN1 */ + { 0x12, 0x00 }, /* Volume Control AIN2 */ + { 0x13, 0x00 }, /* Volume Control AIN3 */ + { 0x14, 0x00 }, /* Volume Control AIN4 */ + { 0x15, 0x00 }, /* Volume Control AIN5 */ + { 0x16, 0x00 }, /* Volume Control AIN6 */ + { 0x17, 0x00 }, /* ADC Channel Invert */ + { 0x18, 0x00 }, /* Status Control */ + { 0x1a, 0x00 }, /* Status Mask */ + { 0x1b, 0x00 }, /* MUTEC Pin Control */ +}; + +static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42XX8_STATUS: + return true; + default: + return false; + } +} + +static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42XX8_CHIPID: + case CS42XX8_STATUS: + return false; + default: + return true; + } +} + +const struct regmap_config cs42xx8_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS42XX8_LASTREG, + .reg_defaults = cs42xx8_reg, + .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg), + .volatile_reg = cs42xx8_volatile_register, + .writeable_reg = cs42xx8_writeable_register, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs42xx8_regmap_config); + +static int cs42xx8_codec_probe(struct snd_soc_codec *codec) +{ + struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; + + switch (cs42xx8->drvdata->num_adcs) { + case 3: + snd_soc_add_codec_controls(codec, cs42xx8_adc3_snd_controls, + ARRAY_SIZE(cs42xx8_adc3_snd_controls)); + snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets, + ARRAY_SIZE(cs42xx8_adc3_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes, + ARRAY_SIZE(cs42xx8_adc3_dapm_routes)); + break; + default: + break; + } + + /* Mute all DAC channels */ + regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL); + + return 0; +} + +static const struct snd_soc_codec_driver cs42xx8_driver = { + .probe = cs42xx8_codec_probe, + .idle_bias_off = true, + + .controls = cs42xx8_snd_controls, + .num_controls = ARRAY_SIZE(cs42xx8_snd_controls), + .dapm_widgets = cs42xx8_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets), + .dapm_routes = cs42xx8_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes), +}; + +const struct cs42xx8_driver_data cs42448_data = { + .name = "cs42448", + .num_adcs = 3, +}; +EXPORT_SYMBOL_GPL(cs42448_data); + +const struct cs42xx8_driver_data cs42888_data = { + .name = "cs42888", + .num_adcs = 2, +}; +EXPORT_SYMBOL_GPL(cs42888_data); + +const struct of_device_id cs42xx8_of_match[] = { + { .compatible = "cirrus,cs42448", .data = &cs42448_data, }, + { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, cs42xx8_of_match); +EXPORT_SYMBOL_GPL(cs42xx8_of_match); + +int cs42xx8_probe(struct device *dev, struct regmap *regmap) +{ + const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev); + struct cs42xx8_priv *cs42xx8; + int ret, val, i; + + cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL); + if (cs42xx8 == NULL) + return -ENOMEM; + + dev_set_drvdata(dev, cs42xx8); + + if (of_id) + cs42xx8->drvdata = of_id->data; + + if (!cs42xx8->drvdata) { + dev_err(dev, "failed to find driver data\n"); + return -EINVAL; + } + + cs42xx8->clk = devm_clk_get(dev, "mclk"); + if (IS_ERR(cs42xx8->clk)) { + dev_err(dev, "failed to get the clock: %ld\n", + PTR_ERR(cs42xx8->clk)); + return -EINVAL; + } + + cs42xx8->sysclk = clk_get_rate(cs42xx8->clk); + + for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++) + cs42xx8->supplies[i].supply = cs42xx8_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, + ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies); + if (ret) { + dev_err(dev, "failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies), + cs42xx8->supplies); + if (ret) { + dev_err(dev, "failed to enable supplies: %d\n", ret); + return ret; + } + + /* Make sure hardware reset done */ + msleep(5); + + cs42xx8->regmap = regmap; + if (IS_ERR(cs42xx8->regmap)) { + ret = PTR_ERR(cs42xx8->regmap); + dev_err(dev, "failed to allocate regmap: %d\n", ret); + goto err_enable; + } + + /* + * We haven't marked the chip revision as volatile due to + * sharing a register with the right input volume; explicitly + * bypass the cache to read it. + */ + regcache_cache_bypass(cs42xx8->regmap, true); + + /* Validate the chip ID */ + regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val); + if (val < 0) { + dev_err(dev, "failed to get device ID: %x", val); + ret = -EINVAL; + goto err_enable; + } + + /* The top four bits of the chip ID should be 0000 */ + if ((val & CS42XX8_CHIPID_CHIP_ID_MASK) != 0x00) { + dev_err(dev, "unmatched chip ID: %d\n", + val & CS42XX8_CHIPID_CHIP_ID_MASK); + ret = -EINVAL; + goto err_enable; + } + + dev_info(dev, "found device, revision %X\n", + val & CS42XX8_CHIPID_REV_ID_MASK); + + regcache_cache_bypass(cs42xx8->regmap, false); + + cs42xx8_dai.name = cs42xx8->drvdata->name; + + /* Each adc supports stereo input */ + cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2; + + ret = snd_soc_register_codec(dev, &cs42xx8_driver, &cs42xx8_dai, 1); + if (ret) { + dev_err(dev, "failed to register codec:%d\n", ret); + goto err_enable; + } + + regcache_cache_only(cs42xx8->regmap, true); + +err_enable: + regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies), + cs42xx8->supplies); + + return ret; +} +EXPORT_SYMBOL_GPL(cs42xx8_probe); + +#ifdef CONFIG_PM_RUNTIME +static int cs42xx8_runtime_resume(struct device *dev) +{ + struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(cs42xx8->clk); + if (ret) { + dev_err(dev, "failed to enable mclk: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies), + cs42xx8->supplies); + if (ret) { + dev_err(dev, "failed to enable supplies: %d\n", ret); + goto err_clk; + } + + /* Make sure hardware reset done */ + msleep(5); + + regcache_cache_only(cs42xx8->regmap, false); + + ret = regcache_sync(cs42xx8->regmap); + if (ret) { + dev_err(dev, "failed to sync regmap: %d\n", ret); + goto err_bulk; + } + + return 0; + +err_bulk: + regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies), + cs42xx8->supplies); +err_clk: + clk_disable_unprepare(cs42xx8->clk); + + return ret; +} + +static int cs42xx8_runtime_suspend(struct device *dev) +{ + struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev); + + regcache_cache_only(cs42xx8->regmap, true); + + regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies), + cs42xx8->supplies); + + clk_disable_unprepare(cs42xx8->clk); + + return 0; +} +#endif + +const struct dev_pm_ops cs42xx8_pm = { + SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL) +}; +EXPORT_SYMBOL_GPL(cs42xx8_pm); + +MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h new file mode 100644 index 000000000000..da0b94aee419 --- /dev/null +++ b/sound/soc/codecs/cs42xx8.h @@ -0,0 +1,238 @@ +/* + * cs42xx8.h - Cirrus Logic CS42448/CS42888 Audio CODEC driver header file + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen <Guangyu.Chen@freescale.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef _CS42XX8_H +#define _CS42XX8_H + +struct cs42xx8_driver_data { + char name[32]; + int num_adcs; +}; + +extern const struct dev_pm_ops cs42xx8_pm; +extern const struct cs42xx8_driver_data cs42448_data; +extern const struct cs42xx8_driver_data cs42888_data; +extern const struct regmap_config cs42xx8_regmap_config; +int cs42xx8_probe(struct device *dev, struct regmap *regmap); + +/* CS42888 register map */ +#define CS42XX8_CHIPID 0x01 /* Chip ID */ +#define CS42XX8_PWRCTL 0x02 /* Power Control */ +#define CS42XX8_FUNCMOD 0x03 /* Functional Mode */ +#define CS42XX8_INTF 0x04 /* Interface Formats */ +#define CS42XX8_ADCCTL 0x05 /* ADC Control */ +#define CS42XX8_TXCTL 0x06 /* Transition Control */ +#define CS42XX8_DACMUTE 0x07 /* DAC Mute Control */ +#define CS42XX8_VOLAOUT1 0x08 /* Volume Control AOUT1 */ +#define CS42XX8_VOLAOUT2 0x09 /* Volume Control AOUT2 */ +#define CS42XX8_VOLAOUT3 0x0A /* Volume Control AOUT3 */ +#define CS42XX8_VOLAOUT4 0x0B /* Volume Control AOUT4 */ +#define CS42XX8_VOLAOUT5 0x0C /* Volume Control AOUT5 */ +#define CS42XX8_VOLAOUT6 0x0D /* Volume Control AOUT6 */ +#define CS42XX8_VOLAOUT7 0x0E /* Volume Control AOUT7 */ +#define CS42XX8_VOLAOUT8 0x0F /* Volume Control AOUT8 */ +#define CS42XX8_DACINV 0x10 /* DAC Channel Invert */ +#define CS42XX8_VOLAIN1 0x11 /* Volume Control AIN1 */ +#define CS42XX8_VOLAIN2 0x12 /* Volume Control AIN2 */ +#define CS42XX8_VOLAIN3 0x13 /* Volume Control AIN3 */ +#define CS42XX8_VOLAIN4 0x14 /* Volume Control AIN4 */ +#define CS42XX8_VOLAIN5 0x15 /* Volume Control AIN5 */ +#define CS42XX8_VOLAIN6 0x16 /* Volume Control AIN6 */ +#define CS42XX8_ADCINV 0x17 /* ADC Channel Invert */ +#define CS42XX8_STATUSCTL 0x18 /* Status Control */ +#define CS42XX8_STATUS 0x19 /* Status */ +#define CS42XX8_STATUSM 0x1A /* Status Mask */ +#define CS42XX8_MUTEC 0x1B /* MUTEC Pin Control */ + +#define CS42XX8_FIRSTREG CS42XX8_CHIPID +#define CS42XX8_LASTREG CS42XX8_MUTEC +#define CS42XX8_NUMREGS (CS42XX8_LASTREG - CS42XX8_FIRSTREG + 1) +#define CS42XX8_I2C_INCR 0x80 + +/* Chip I.D. and Revision Register (Address 01h) */ +#define CS42XX8_CHIPID_CHIP_ID_MASK 0xF0 +#define CS42XX8_CHIPID_REV_ID_MASK 0x0F + +/* Power Control (Address 02h) */ +#define CS42XX8_PWRCTL_PDN_ADC3_SHIFT 7 +#define CS42XX8_PWRCTL_PDN_ADC3_MASK (1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT) +#define CS42XX8_PWRCTL_PDN_ADC3 (1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT) +#define CS42XX8_PWRCTL_PDN_ADC2_SHIFT 6 +#define CS42XX8_PWRCTL_PDN_ADC2_MASK (1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT) +#define CS42XX8_PWRCTL_PDN_ADC2 (1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT) +#define CS42XX8_PWRCTL_PDN_ADC1_SHIFT 5 +#define CS42XX8_PWRCTL_PDN_ADC1_MASK (1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT) +#define CS42XX8_PWRCTL_PDN_ADC1 (1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC4_SHIFT 4 +#define CS42XX8_PWRCTL_PDN_DAC4_MASK (1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC4 (1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC3_SHIFT 3 +#define CS42XX8_PWRCTL_PDN_DAC3_MASK (1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC3 (1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC2_SHIFT 2 +#define CS42XX8_PWRCTL_PDN_DAC2_MASK (1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC2 (1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC1_SHIFT 1 +#define CS42XX8_PWRCTL_PDN_DAC1_MASK (1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT) +#define CS42XX8_PWRCTL_PDN_DAC1 (1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT) +#define CS42XX8_PWRCTL_PDN_SHIFT 0 +#define CS42XX8_PWRCTL_PDN_MASK (1 << CS42XX8_PWRCTL_PDN_SHIFT) +#define CS42XX8_PWRCTL_PDN (1 << CS42XX8_PWRCTL_PDN_SHIFT) + +/* Functional Mode (Address 03h) */ +#define CS42XX8_FUNCMOD_DAC_FM_SHIFT 6 +#define CS42XX8_FUNCMOD_DAC_FM_WIDTH 2 +#define CS42XX8_FUNCMOD_DAC_FM_MASK (((1 << CS42XX8_FUNCMOD_DAC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_DAC_FM_SHIFT) +#define CS42XX8_FUNCMOD_DAC_FM(v) ((v) << CS42XX8_FUNCMOD_DAC_FM_SHIFT) +#define CS42XX8_FUNCMOD_ADC_FM_SHIFT 4 +#define CS42XX8_FUNCMOD_ADC_FM_WIDTH 2 +#define CS42XX8_FUNCMOD_ADC_FM_MASK (((1 << CS42XX8_FUNCMOD_ADC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_ADC_FM_SHIFT) +#define CS42XX8_FUNCMOD_ADC_FM(v) ((v) << CS42XX8_FUNCMOD_ADC_FM_SHIFT) +#define CS42XX8_FUNCMOD_xC_FM_MASK(x) ((x) ? CS42XX8_FUNCMOD_DAC_FM_MASK : CS42XX8_FUNCMOD_ADC_FM_MASK) +#define CS42XX8_FUNCMOD_xC_FM(x, v) ((x) ? CS42XX8_FUNCMOD_DAC_FM(v) : CS42XX8_FUNCMOD_ADC_FM(v)) +#define CS42XX8_FUNCMOD_MFREQ_SHIFT 1 +#define CS42XX8_FUNCMOD_MFREQ_WIDTH 3 +#define CS42XX8_FUNCMOD_MFREQ_MASK (((1 << CS42XX8_FUNCMOD_MFREQ_WIDTH) - 1) << CS42XX8_FUNCMOD_MFREQ_SHIFT) +#define CS42XX8_FUNCMOD_MFREQ_256(s) ((0 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1)) +#define CS42XX8_FUNCMOD_MFREQ_384(s) ((1 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1)) +#define CS42XX8_FUNCMOD_MFREQ_512(s) ((2 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1)) +#define CS42XX8_FUNCMOD_MFREQ_768(s) ((3 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1)) +#define CS42XX8_FUNCMOD_MFREQ_1024(s) ((4 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1)) + +#define CS42XX8_FM_SINGLE 0 +#define CS42XX8_FM_DOUBLE 1 +#define CS42XX8_FM_QUAD 2 +#define CS42XX8_FM_AUTO 3 + +/* Interface Formats (Address 04h) */ +#define CS42XX8_INTF_FREEZE_SHIFT 7 +#define CS42XX8_INTF_FREEZE_MASK (1 << CS42XX8_INTF_FREEZE_SHIFT) +#define CS42XX8_INTF_FREEZE (1 << CS42XX8_INTF_FREEZE_SHIFT) +#define CS42XX8_INTF_AUX_DIF_SHIFT 6 +#define CS42XX8_INTF_AUX_DIF_MASK (1 << CS42XX8_INTF_AUX_DIF_SHIFT) +#define CS42XX8_INTF_AUX_DIF (1 << CS42XX8_INTF_AUX_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_SHIFT 3 +#define CS42XX8_INTF_DAC_DIF_WIDTH 3 +#define CS42XX8_INTF_DAC_DIF_MASK (((1 << CS42XX8_INTF_DAC_DIF_WIDTH) - 1) << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_LEFTJ (0 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_I2S (1 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_RIGHTJ (2 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_ONELINE_20 (4 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_ONELINE_24 (6 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_TDM (7 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_SHIFT 0 +#define CS42XX8_INTF_ADC_DIF_WIDTH 3 +#define CS42XX8_INTF_ADC_DIF_MASK (((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_LEFTJ (0 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_I2S (1 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_RIGHTJ (2 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_ONELINE_20 (4 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_ONELINE_24 (6 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_TDM (7 << CS42XX8_INTF_ADC_DIF_SHIFT) + +/* ADC Control & DAC De-Emphasis (Address 05h) */ +#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT 7 +#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_MASK (1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT) +#define CS42XX8_ADCCTL_ADC_HPF_FREEZE (1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT) +#define CS42XX8_ADCCTL_DAC_DEM_SHIFT 5 +#define CS42XX8_ADCCTL_DAC_DEM_MASK (1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT) +#define CS42XX8_ADCCTL_DAC_DEM (1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT) +#define CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT 4 +#define CS42XX8_ADCCTL_ADC1_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_ADC1_SINGLE (1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT 3 +#define CS42XX8_ADCCTL_ADC2_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_ADC2_SINGLE (1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT 2 +#define CS42XX8_ADCCTL_ADC3_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_ADC3_SINGLE (1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT) +#define CS42XX8_ADCCTL_AIN5_MUX_SHIFT 1 +#define CS42XX8_ADCCTL_AIN5_MUX_MASK (1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT) +#define CS42XX8_ADCCTL_AIN5_MUX (1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT) +#define CS42XX8_ADCCTL_AIN6_MUX_SHIFT 0 +#define CS42XX8_ADCCTL_AIN6_MUX_MASK (1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT) +#define CS42XX8_ADCCTL_AIN6_MUX (1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT) + +/* Transition Control (Address 06h) */ +#define CS42XX8_TXCTL_DAC_SNGVOL_SHIFT 7 +#define CS42XX8_TXCTL_DAC_SNGVOL_MASK (1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT) +#define CS42XX8_TXCTL_DAC_SNGVOL (1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT) +#define CS42XX8_TXCTL_DAC_SZC_SHIFT 5 +#define CS42XX8_TXCTL_DAC_SZC_WIDTH 2 +#define CS42XX8_TXCTL_DAC_SZC_MASK (((1 << CS42XX8_TXCTL_DAC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_DAC_SZC_SHIFT) +#define CS42XX8_TXCTL_DAC_SZC_IC (0 << CS42XX8_TXCTL_DAC_SZC_SHIFT) +#define CS42XX8_TXCTL_DAC_SZC_ZC (1 << CS42XX8_TXCTL_DAC_SZC_SHIFT) +#define CS42XX8_TXCTL_DAC_SZC_SR (2 << CS42XX8_TXCTL_DAC_SZC_SHIFT) +#define CS42XX8_TXCTL_DAC_SZC_SRZC (3 << CS42XX8_TXCTL_DAC_SZC_SHIFT) +#define CS42XX8_TXCTL_AMUTE_SHIFT 4 +#define CS42XX8_TXCTL_AMUTE_MASK (1 << CS42XX8_TXCTL_AMUTE_SHIFT) +#define CS42XX8_TXCTL_AMUTE (1 << CS42XX8_TXCTL_AMUTE_SHIFT) +#define CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT 3 +#define CS42XX8_TXCTL_MUTE_ADC_SP_MASK (1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT) +#define CS42XX8_TXCTL_MUTE_ADC_SP (1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT) +#define CS42XX8_TXCTL_ADC_SNGVOL_SHIFT 2 +#define CS42XX8_TXCTL_ADC_SNGVOL_MASK (1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT) +#define CS42XX8_TXCTL_ADC_SNGVOL (1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT) +#define CS42XX8_TXCTL_ADC_SZC_SHIFT 0 +#define CS42XX8_TXCTL_ADC_SZC_MASK (((1 << CS42XX8_TXCTL_ADC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_ADC_SZC_SHIFT) +#define CS42XX8_TXCTL_ADC_SZC_IC (0 << CS42XX8_TXCTL_ADC_SZC_SHIFT) +#define CS42XX8_TXCTL_ADC_SZC_ZC (1 << CS42XX8_TXCTL_ADC_SZC_SHIFT) +#define CS42XX8_TXCTL_ADC_SZC_SR (2 << CS42XX8_TXCTL_ADC_SZC_SHIFT) +#define CS42XX8_TXCTL_ADC_SZC_SRZC (3 << CS42XX8_TXCTL_ADC_SZC_SHIFT) + +/* DAC Channel Mute (Address 07h) */ +#define CS42XX8_DACMUTE_AOUT(n) (0x1 << n) +#define CS42XX8_DACMUTE_ALL 0xff + +/* Status Control (Address 18h)*/ +#define CS42XX8_STATUSCTL_INI_SHIFT 2 +#define CS42XX8_STATUSCTL_INI_WIDTH 2 +#define CS42XX8_STATUSCTL_INI_MASK (((1 << CS42XX8_STATUSCTL_INI_WIDTH) - 1) << CS42XX8_STATUSCTL_INI_SHIFT) +#define CS42XX8_STATUSCTL_INT_ACTIVE_HIGH (0 << CS42XX8_STATUSCTL_INI_SHIFT) +#define CS42XX8_STATUSCTL_INT_ACTIVE_LOW (1 << CS42XX8_STATUSCTL_INI_SHIFT) +#define CS42XX8_STATUSCTL_INT_OPEN_DRAIN (2 << CS42XX8_STATUSCTL_INI_SHIFT) + +/* Status (Address 19h)*/ +#define CS42XX8_STATUS_DAC_CLK_ERR_SHIFT 4 +#define CS42XX8_STATUS_DAC_CLK_ERR_MASK (1 << CS42XX8_STATUS_DAC_CLK_ERR_SHIFT) +#define CS42XX8_STATUS_ADC_CLK_ERR_SHIFT 3 +#define CS42XX8_STATUS_ADC_CLK_ERR_MASK (1 << CS42XX8_STATUS_ADC_CLK_ERR_SHIFT) +#define CS42XX8_STATUS_ADC3_OVFL_SHIFT 2 +#define CS42XX8_STATUS_ADC3_OVFL_MASK (1 << CS42XX8_STATUS_ADC3_OVFL_SHIFT) +#define CS42XX8_STATUS_ADC2_OVFL_SHIFT 1 +#define CS42XX8_STATUS_ADC2_OVFL_MASK (1 << CS42XX8_STATUS_ADC2_OVFL_SHIFT) +#define CS42XX8_STATUS_ADC1_OVFL_SHIFT 0 +#define CS42XX8_STATUS_ADC1_OVFL_MASK (1 << CS42XX8_STATUS_ADC1_OVFL_SHIFT) + +/* Status Mask (Address 1Ah) */ +#define CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT 4 +#define CS42XX8_STATUS_DAC_CLK_ERR_M_MASK (1 << CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT) +#define CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT 3 +#define CS42XX8_STATUS_ADC_CLK_ERR_M_MASK (1 << CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT) +#define CS42XX8_STATUS_ADC3_OVFL_M_SHIFT 2 +#define CS42XX8_STATUS_ADC3_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC3_OVFL_M_SHIFT) +#define CS42XX8_STATUS_ADC2_OVFL_M_SHIFT 1 +#define CS42XX8_STATUS_ADC2_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC2_OVFL_M_SHIFT) +#define CS42XX8_STATUS_ADC1_OVFL_M_SHIFT 0 +#define CS42XX8_STATUS_ADC1_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC1_OVFL_M_SHIFT) + +/* MUTEC Pin Control (Address 1Bh) */ +#define CS42XX8_MUTEC_MCPOLARITY_SHIFT 1 +#define CS42XX8_MUTEC_MCPOLARITY_MASK (1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT) +#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_LOW (0 << CS42XX8_MUTEC_MCPOLARITY_SHIFT) +#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_HIGH (1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT) +#define CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT 0 +#define CS42XX8_MUTEC_MUTEC_ACTIVE_MASK (1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT) +#define CS42XX8_MUTEC_MUTEC_ACTIVE (1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT) +#endif /* _CS42XX8_H */ diff --git a/sound/soc/fsl/imx-cs42888.c b/sound/soc/fsl/imx-cs42888.c index 3750cd917465..357933ecf989 100644 --- a/sound/soc/fsl/imx-cs42888.c +++ b/sound/soc/fsl/imx-cs42888.c @@ -132,9 +132,9 @@ static const struct snd_soc_dapm_route audio_map[] = { {"AIN2L", NULL, "Line In Jack"}, {"AIN2R", NULL, "Line In Jack"}, {"esai-Playback", NULL, "asrc-Playback"}, - {"codec-Playback", NULL, "esai-Playback"},/* dai route for be and fe */ + {"Playback", NULL, "esai-Playback"},/* dai route for be and fe */ {"asrc-Capture", NULL, "esai-Capture"}, - {"esai-Capture", NULL, "codec-Capture"}, + {"esai-Capture", NULL, "Capture"}, }; static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, @@ -158,7 +158,7 @@ static struct snd_soc_dai_link imx_cs42888_dai[] = { { .name = "HiFi", .stream_name = "HiFi", - .codec_dai_name = "CS42888", + .codec_dai_name = "cs42888", .ops = &imx_cs42888_surround_ops, }, { @@ -171,7 +171,7 @@ static struct snd_soc_dai_link imx_cs42888_dai[] = { { .name = "HiFi-ASRC-BE", .stream_name = "HiFi-ASRC-BE", - .codec_dai_name = "CS42888", + .codec_dai_name = "cs42888", .platform_name = "snd-soc-dummy", .no_pcm = 1, .ops = &imx_cs42888_surround_ops_be, |