| /* |
| ** ============================================================================= |
| ** Copyright (c) 2016 Texas Instruments Inc. |
| ** |
| ** 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; version 2. |
| ** |
| ** This program is distributed in the hope that it will be useful, but WITHOUT |
| ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| ** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| ** |
| ** File: |
| ** tas2557-codec.c |
| ** |
| ** Description: |
| ** ALSA SoC driver for Texas Instruments TAS2557 High Performance 4W Smart Amplifier |
| ** |
| ** ============================================================================= |
| */ |
| |
| #ifdef CONFIG_TAS2557_CODEC |
| |
| #define DEBUG |
| #include <linux/module.h> |
| #include <linux/moduleparam.h> |
| #include <linux/init.h> |
| #include <linux/delay.h> |
| #include <linux/pm.h> |
| #include <linux/i2c.h> |
| #include <linux/gpio.h> |
| #include <linux/regulator/consumer.h> |
| #include <linux/firmware.h> |
| #include <linux/regmap.h> |
| #include <linux/of.h> |
| #include <linux/of_gpio.h> |
| #include <linux/slab.h> |
| #include <linux/syscalls.h> |
| #include <linux/fcntl.h> |
| #include <linux/uaccess.h> |
| #include <sound/core.h> |
| #include <sound/pcm.h> |
| #include <sound/pcm_params.h> |
| #include <sound/soc.h> |
| #include <sound/initval.h> |
| #include <sound/tlv.h> |
| |
| #include "tas2557-core.h" |
| #include "tas2557-codec.h" |
| |
| #define KCONTROL_CODEC |
| |
| static unsigned int tas2557_codec_read(struct snd_soc_codec *pCodec, |
| unsigned int nRegister) |
| { |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); |
| int ret = 0; |
| unsigned int Value = 0; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| ret = pTAS2557->read(pTAS2557, nRegister, &Value); |
| if (ret < 0) |
| dev_err(pTAS2557->dev, "%s, %d, ERROR happen=%d\n", __func__, |
| __LINE__, ret); |
| else |
| ret = Value; |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return ret; |
| } |
| |
| static int tas2557_codec_write(struct snd_soc_codec *pCodec, unsigned int nRegister, |
| unsigned int nValue) |
| { |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); |
| int ret = 0; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| ret = pTAS2557->write(pTAS2557, nRegister, nValue); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return ret; |
| } |
| |
| static int tas2557_codec_suspend(struct snd_soc_codec *pCodec) |
| { |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); |
| int ret = 0; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| dev_dbg(pTAS2557->dev, "%s\n", __func__); |
| pTAS2557->runtime_suspend(pTAS2557); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return ret; |
| } |
| |
| static int tas2557_codec_resume(struct snd_soc_codec *pCodec) |
| { |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); |
| int ret = 0; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| dev_dbg(pTAS2557->dev, "%s\n", __func__); |
| pTAS2557->runtime_resume(pTAS2557); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return ret; |
| } |
| |
| static const struct snd_soc_dapm_widget tas2557_dapm_widgets[] = { |
| SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), |
| SND_SOC_DAPM_AIF_IN("ASI2", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0), |
| SND_SOC_DAPM_AIF_IN("ASIM", "ASIM Playback", 0, SND_SOC_NOPM, 0, 0), |
| SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), |
| |
| SND_SOC_DAPM_OUT_DRV("ClassD", SND_SOC_NOPM, 0, 0, NULL, 0), |
| |
| SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_SUPPLY("NDivider", SND_SOC_NOPM, 0, 0, NULL, 0), |
| |
| SND_SOC_DAPM_OUTPUT("OUT") |
| }; |
| |
| static const struct snd_soc_dapm_route tas2557_audio_map[] = { |
| {"DAC", NULL, "ASI1"}, |
| {"DAC", NULL, "ASI2"}, |
| {"DAC", NULL, "ASIM"}, |
| {"ClassD", NULL, "DAC"}, |
| {"OUT", NULL, "ClassD"}, |
| {"DAC", NULL, "PLL"}, |
| {"DAC", NULL, "NDivider"}, |
| }; |
| |
| static int tas2557_startup(struct snd_pcm_substream *substream, |
| struct snd_soc_dai *dai) |
| { |
| struct snd_soc_codec *codec = dai->codec; |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| |
| dev_dbg(pTAS2557->dev, "%s\n", __func__); |
| return 0; |
| } |
| |
| static void tas2557_shutdown(struct snd_pcm_substream *substream, |
| struct snd_soc_dai *dai) |
| { |
| struct snd_soc_codec *codec = dai->codec; |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| |
| dev_dbg(pTAS2557->dev, "%s\n", __func__); |
| } |
| |
| static int tas2557_mute(struct snd_soc_dai *dai, int mute) |
| { |
| struct snd_soc_codec *codec = dai->codec; |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| dev_dbg(pTAS2557->dev, "%s\n", __func__); |
| tas2557_enable(pTAS2557, !mute); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| |
| static int tas2557_set_dai_sysclk(struct snd_soc_dai *pDAI, |
| int nClkID, unsigned int nFreqency, int nDir) |
| { |
| struct snd_soc_codec *pCodec = pDAI->codec; |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); |
| |
| dev_dbg(pTAS2557->dev, "tas2557_set_dai_sysclk: freq = %u\n", nFreqency); |
| |
| return 0; |
| } |
| |
| static int tas2557_hw_params(struct snd_pcm_substream *pSubstream, |
| struct snd_pcm_hw_params *pParams, struct snd_soc_dai *pDAI) |
| { |
| struct snd_soc_codec *pCodec = pDAI->codec; |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| dev_dbg(pTAS2557->dev, "%s\n", __func__); |
| /* do bit rate setting during platform data */ |
| /* tas2557_set_bit_rate(pTAS2557, channel_both, snd_pcm_format_width(params_format(pParams))); */ |
| tas2557_set_sampling_rate(pTAS2557, params_rate(pParams)); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| |
| static int tas2557_set_dai_fmt(struct snd_soc_dai *pDAI, unsigned int nFormat) |
| { |
| struct snd_soc_codec *codec = pDAI->codec; |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| |
| dev_dbg(pTAS2557->dev, "%s\n", __func__); |
| return 0; |
| } |
| |
| static int tas2557_prepare(struct snd_pcm_substream *pSubstream, |
| struct snd_soc_dai *pDAI) |
| { |
| struct snd_soc_codec *codec = pDAI->codec; |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| |
| dev_dbg(pTAS2557->dev, "%s\n", __func__); |
| return 0; |
| } |
| |
| static int tas2557_set_bias_level(struct snd_soc_codec *pCodec, |
| enum snd_soc_bias_level eLevel) |
| { |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); |
| |
| dev_dbg(pTAS2557->dev, "%s: %d\n", __func__, eLevel); |
| return 0; |
| } |
| |
| static int tas2557_codec_probe(struct snd_soc_codec *pCodec) |
| { |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); |
| |
| dev_dbg(pTAS2557->dev, "%s\n", __func__); |
| return 0; |
| } |
| |
| static int tas2557_codec_remove(struct snd_soc_codec *pCodec) |
| { |
| return 0; |
| } |
| |
| static int tas2557_power_ctrl_get(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| pValue->value.integer.value[0] = pTAS2557->mbPowerUp; |
| dev_dbg(pTAS2557->dev, "tas2557_power_ctrl_get = %d\n", |
| pTAS2557->mbPowerUp); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| |
| static int tas2557_power_ctrl_put(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| |
| int nPowerOn = pValue->value.integer.value[0]; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| dev_dbg(pTAS2557->dev, "tas2557_power_ctrl_put = %d\n", nPowerOn); |
| tas2557_enable(pTAS2557, (nPowerOn != 0)); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| |
| static int tas2557_fs_get(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| int nFS = 48000; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| if (pTAS2557->mpFirmware->mnConfigurations) |
| nFS = pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration].mnSamplingRate; |
| pValue->value.integer.value[0] = nFS; |
| dev_dbg(pTAS2557->dev, "tas2557_fs_get = %d\n", nFS); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| |
| static int tas2557_fs_put(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| int ret = 0; |
| int nFS = pValue->value.integer.value[0]; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| dev_info(pTAS2557->dev, "tas2557_fs_put = %d\n", nFS); |
| ret = tas2557_set_sampling_rate(pTAS2557, nFS); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return ret; |
| } |
| |
| static int tas2557_Cali_get(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| bool ret = 0; |
| int prm_r0 = 0; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| ret = tas2557_get_Cali_prm_r0(pTAS2557, &prm_r0); |
| if (ret) |
| pValue->value.integer.value[0] = prm_r0; |
| |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| |
| static int tas2557_program_get(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| pValue->value.integer.value[0] = pTAS2557->mnCurrentProgram; |
| dev_dbg(pTAS2557->dev, "tas2557_program_get = %d\n", |
| pTAS2557->mnCurrentProgram); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| |
| static int tas2557_program_put(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| unsigned int nProgram = pValue->value.integer.value[0]; |
| int ret = 0, nConfiguration = -1; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| if (nProgram == pTAS2557->mnCurrentProgram) |
| nConfiguration = pTAS2557->mnCurrentConfiguration; |
| ret = tas2557_set_program(pTAS2557, nProgram, nConfiguration); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return ret; |
| } |
| |
| static int tas2557_configuration_get(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| pValue->value.integer.value[0] = pTAS2557->mnCurrentConfiguration; |
| dev_dbg(pTAS2557->dev, "tas2557_configuration_get = %d\n", |
| pTAS2557->mnCurrentConfiguration); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| |
| static int tas2557_configuration_put(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| unsigned int nConfiguration = pValue->value.integer.value[0]; |
| int ret = 0; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| dev_info(pTAS2557->dev, "%s = %d\n", __func__, nConfiguration); |
| ret = tas2557_set_config(pTAS2557, nConfiguration); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return ret; |
| } |
| |
| static int tas2557_calibration_get(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| pValue->value.integer.value[0] = pTAS2557->mnCurrentCalibration; |
| dev_info(pTAS2557->dev, |
| "tas2557_calibration_get = %d\n", |
| pTAS2557->mnCurrentCalibration); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| |
| static int tas2557_calibration_put(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| unsigned int nCalibration = pValue->value.integer.value[0]; |
| int ret = 0; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| ret = tas2557_set_calibration(pTAS2557, nCalibration); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return ret; |
| } |
| |
| static const char * const classd_edge_text[] = { |
| "0 (50ns)", |
| "1 (40ns)", |
| "2 (29ns)", |
| "3 (25ns)", |
| "4 (14ns)", |
| "5 (13ns)", |
| "6 (12ns)", |
| "7 (11ns)", |
| }; |
| |
| static const struct soc_enum classd_edge_enum[] = { |
| SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(classd_edge_text), classd_edge_text), |
| }; |
| |
| static int tas2557_edge_get(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| pValue->value.integer.value[0] = pTAS2557->mnEdge; |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| static int tas2557_edge_put(struct snd_kcontrol *pKcontrol, |
| struct snd_ctl_elem_value *pValue) |
| { |
| #ifdef KCONTROL_CODEC |
| struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); |
| #else |
| struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); |
| #endif |
| struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); |
| unsigned int edge = pValue->value.integer.value[0]; |
| |
| mutex_lock(&pTAS2557->codec_lock); |
| |
| dev_dbg(pTAS2557->dev, "%s, edge %d\n", __func__, edge); |
| pTAS2557->mnEdge = pValue->value.integer.value[0]; |
| tas2557_update_edge(pTAS2557); |
| |
| mutex_unlock(&pTAS2557->codec_lock); |
| return 0; |
| } |
| |
| static const struct snd_kcontrol_new tas2557_snd_controls[] = { |
| SOC_SINGLE_EXT("PowerCtrl", SND_SOC_NOPM, 0, 0x0001, 0, |
| tas2557_power_ctrl_get, tas2557_power_ctrl_put), |
| SOC_SINGLE_EXT("Program", SND_SOC_NOPM, 0, 0x00FF, 0, tas2557_program_get, |
| tas2557_program_put), |
| SOC_SINGLE_EXT("Configuration", SND_SOC_NOPM, 0, 0x00FF, 0, |
| tas2557_configuration_get, tas2557_configuration_put), |
| SOC_SINGLE_EXT("FS", SND_SOC_NOPM, 8000, 48000, 0, |
| tas2557_fs_get, tas2557_fs_put), |
| SOC_SINGLE_EXT("Get Cali_Re", SND_SOC_NOPM, 0, 0x7f000000, 0, |
| tas2557_Cali_get, NULL), |
| SOC_SINGLE_EXT("Calibration", SND_SOC_NOPM, 0, 0x00FF, 0, |
| tas2557_calibration_get, tas2557_calibration_put), |
| SOC_ENUM_EXT("TAS2557 ClassD Edge", classd_edge_enum[0], |
| tas2557_edge_get, tas2557_edge_put), |
| }; |
| |
| static struct snd_soc_codec_driver soc_codec_driver_tas2557 = { |
| .probe = tas2557_codec_probe, |
| .remove = tas2557_codec_remove, |
| .read = tas2557_codec_read, |
| .write = tas2557_codec_write, |
| .suspend = tas2557_codec_suspend, |
| .resume = tas2557_codec_resume, |
| .set_bias_level = tas2557_set_bias_level, |
| .idle_bias_off = true, |
| .component_driver = { |
| .controls = tas2557_snd_controls, |
| .num_controls = ARRAY_SIZE(tas2557_snd_controls), |
| .dapm_widgets = tas2557_dapm_widgets, |
| .num_dapm_widgets = ARRAY_SIZE(tas2557_dapm_widgets), |
| .dapm_routes = tas2557_audio_map, |
| .num_dapm_routes = ARRAY_SIZE(tas2557_audio_map), |
| }, |
| }; |
| |
| static struct snd_soc_dai_ops tas2557_dai_ops = { |
| .startup = tas2557_startup, |
| .shutdown = tas2557_shutdown, |
| .digital_mute = tas2557_mute, |
| .hw_params = tas2557_hw_params, |
| .prepare = tas2557_prepare, |
| .set_sysclk = tas2557_set_dai_sysclk, |
| .set_fmt = tas2557_set_dai_fmt, |
| }; |
| |
| #define TAS2557_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
| SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
| static struct snd_soc_dai_driver tas2557_dai_driver[] = { |
| { |
| .name = "tas2557 ASI1", |
| .id = 0, |
| .playback = { |
| .stream_name = "ASI1 Playback", |
| .channels_min = 2, |
| .channels_max = 2, |
| .rates = SNDRV_PCM_RATE_8000_192000, |
| .formats = TAS2557_FORMATS, |
| }, |
| .ops = &tas2557_dai_ops, |
| .symmetric_rates = 1, |
| }, |
| { |
| .name = "tas2557 ASI2", |
| .id = 1, |
| .playback = { |
| .stream_name = "ASI2 Playback", |
| .channels_min = 2, |
| .channels_max = 2, |
| .rates = SNDRV_PCM_RATE_8000_192000, |
| .formats = TAS2557_FORMATS, |
| }, |
| .ops = &tas2557_dai_ops, |
| .symmetric_rates = 1, |
| }, |
| { |
| .name = "tas2557 ASIM", |
| .id = 2, |
| .playback = { |
| .stream_name = "ASIM Playback", |
| .channels_min = 2, |
| .channels_max = 2, |
| .rates = SNDRV_PCM_RATE_8000_192000, |
| .formats = TAS2557_FORMATS, |
| }, |
| .ops = &tas2557_dai_ops, |
| .symmetric_rates = 1, |
| }, |
| }; |
| |
| int tas2557_register_codec(struct tas2557_priv *pTAS2557) |
| { |
| int nResult = 0; |
| |
| dev_info(pTAS2557->dev, "%s, enter\n", __func__); |
| nResult = snd_soc_register_codec(pTAS2557->dev, |
| &soc_codec_driver_tas2557, |
| tas2557_dai_driver, ARRAY_SIZE(tas2557_dai_driver)); |
| return nResult; |
| } |
| |
| int tas2557_deregister_codec(struct tas2557_priv *pTAS2557) |
| { |
| snd_soc_unregister_codec(pTAS2557->dev); |
| return 0; |
| } |
| |
| MODULE_AUTHOR("Texas Instruments Inc."); |
| MODULE_DESCRIPTION("TAS2557 ALSA SOC Smart Amplifier driver"); |
| MODULE_LICENSE("GPL v2"); |
| #endif |