Alsa-devel
Threads by month
- ----- 2025 -----
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
January 2022
- 134 participants
- 282 discussions

Re: [PATCH v5] ASoC: adds component driver for TAS575xM digital amplifiers
by Joerg Schambacher 20 Jan '22
by Joerg Schambacher 20 Jan '22
20 Jan '22
On Thu, Jan 20, 2022 at 02:18:26AM +0800, kernel test robot wrote:
> tree: https://github.com/0day-ci/linux/commits/UPDATE-20220119-210919/Joerg-Scham…
> head: 05b8bf5544bc621031f5a0a6bdf1ac6468a7367b
> commit: 05b8bf5544bc621031f5a0a6bdf1ac6468a7367b ASoC: adds component driver for TAS575xM digital amplifiers
> date: 5 hours ago
> config: riscv-randconfig-c006-20220118 (https://download.01.org/0day-ci/archive/20220120/202201200259.nNgbKOJd-lkp@…)
> compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project f7b7138a62648f4019c55e4671682af1f851f295)
> reproduce (this is a W=1 build):
> wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # install riscv cross compiling tool for clang build
> # apt-get install binutils-riscv64-linux-gnu
> # https://github.com/0day-ci/linux/commit/05b8bf5544bc621031f5a0a6bdf1ac6468a…
> git remote add linux-review https://github.com/0day-ci/linux
> git fetch --no-tags linux-review UPDATE-20220119-210919/Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
> git checkout 05b8bf5544bc621031f5a0a6bdf1ac6468a7367b
> # save the config file to linux build tree
> mkdir build_dir
> COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv SHELL=/bin/bash sound/soc/codecs/
>
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp(a)intel.com>
>
> All warnings (new ones prefixed by >>):
>
> >> sound/soc/codecs/tas5754m.c:246:7: warning: variable 'ret' is used uninitialized whenever switch case is taken [-Wsometimes-uninitialized]
> case SND_SOC_BIAS_ON:
> ^~~~~~~~~~~~~~~
> sound/soc/codecs/tas5754m.c:267:9: note: uninitialized use occurs here
> return ret;
> ^~~
> sound/soc/codecs/tas5754m.c:247:7: warning: variable 'ret' is used uninitialized whenever switch case is taken [-Wsometimes-uninitialized]
> case SND_SOC_BIAS_PREPARE:
> ^~~~~~~~~~~~~~~~~~~~
> sound/soc/codecs/tas5754m.c:267:9: note: uninitialized use occurs here
> return ret;
> ^~~
> sound/soc/codecs/tas5754m.c:242:9: note: initialize the variable 'ret' to silence this warning
> int ret;
> ^
> = 0
> 2 warnings generated.
>
>
> vim +/ret +246 sound/soc/codecs/tas5754m.c
>
> 236
> 237 static int tas5754m_set_bias_level(struct snd_soc_component *component,
> 238 enum snd_soc_bias_level level)
> 239 {
> 240 struct tas5754m_priv *tas5754m =
> 241 snd_soc_component_get_drvdata(component);
> 242 int ret;
> 243
> 244 switch (level) {
> 245 default:
> > 246 case SND_SOC_BIAS_ON:
> 247 case SND_SOC_BIAS_PREPARE:
> 248 break;
> 249
> 250 case SND_SOC_BIAS_STANDBY:
> 251 ret = regmap_update_bits(tas5754m->regmap,
> 252 TAS5754M_POWER, TAS5754M_RQST, 0);
> 253 if (ret)
> 254 dev_err(component->dev,
> 255 "Failed to remove standby: %d\n", ret);
> 256 break;
> 257
> 258 case SND_SOC_BIAS_OFF:
> 259 ret = regmap_update_bits(tas5754m->regmap,
> 260 TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
> 261 if (ret)
> 262 dev_err(component->dev,
> 263 "Failed to request standby: %d\n", ret);
> 264 break;
> 265 }
> 266
> 267 return ret;
> 268 }
> 269
>
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
all, fixed.
Joerg
>From 331a880edff308e8f0608f72f244c25e56162e24 Mon Sep 17 00:00:00 2001
From: Joerg Schambacher <joerg(a)hifiberry.com>
Date: Tue, 5 Oct 2021 14:38:21 +0200
Subject: [PATCH] ASoC: adds component driver for TAS575xM digital amplifiers
Adds a minimum component driver to run the amplifier in I2S master
mode only from standard audio clocks. Therefore, it only allows
44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
sample size. Digital volume control and the -6dB and +0.8dB switches
are supported.
Signed-off-by: Joerg Schambacher <joerg(a)hifiberry.com>
---
sound/soc/codecs/Kconfig | 8 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/tas5754m.c | 691 ++++++++++++++++++++++++++++++++++++
sound/soc/codecs/tas5754m.h | 260 ++++++++++++++
4 files changed, 961 insertions(+)
create mode 100644 sound/soc/codecs/tas5754m.c
create mode 100644 sound/soc/codecs/tas5754m.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..cf0584948fcf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -210,6 +210,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TAS5086
imply SND_SOC_TAS571X
imply SND_SOC_TAS5720
+ imply SND_SOC_TAS5754M
imply SND_SOC_TAS6424
imply SND_SOC_TDA7419
imply SND_SOC_TFA9879
@@ -1419,6 +1420,13 @@ config SND_SOC_TAS5720
Enable support for Texas Instruments TAS5720L/M high-efficiency mono
Class-D audio power amplifiers.
+config SND_SOC_TAS5754M
+ tristate "Texas Instruments TAS5754M Digital Input Audio amplifier"
+ depends on I2C
+ help
+ Enable support for Texas Instruments TAS5754M digital input
+ Class-D audio power amplifiers.
+
config SND_SOC_TAS6424
tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..39984900258a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -227,6 +227,7 @@ snd-soc-sti-sas-objs := sti-sas.o
snd-soc-tas5086-objs := tas5086.o
snd-soc-tas571x-objs := tas571x.o
snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas5754m-objs := tas5754m.o
snd-soc-tas6424-objs := tas6424.o
snd-soc-tda7419-objs := tda7419.o
snd-soc-tas2770-objs := tas2770.o
@@ -555,6 +556,7 @@ obj-$(CONFIG_SND_SOC_TAS2764) += snd-soc-tas2764.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS5754M) += snd-soc-tas5754m.o
obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o
obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o
obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
diff --git a/sound/soc/codecs/tas5754m.c b/sound/soc/codecs/tas5754m.c
new file mode 100644
index 000000000000..06c10002f32e
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.c
@@ -0,0 +1,691 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the TAS5754M Audio Amplifier
+ *
+ * Author: Joerg Schambacher <joerg(a)hifiberry.com>
+ * with fragments from Andy Liu <andy-liu(a)ti.com>
+ *
+ * The driver supports I2S master mode only with standard audio
+ * frequencies 44.1 to 192 ksps from a 24.576/22.2592MHz master
+ * clock input
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "tas5754m.h"
+
+#define TAS5754M_RATES (SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_192000 | \
+ SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_176400)
+#define TAS5754M_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct reg_default tas5754m_reg_defaults[] = {
+ { TAS5754M_RESET, 0x00 },
+ { TAS5754M_POWER, 0x00 },
+ { TAS5754M_MUTE, 0x00 },
+ { TAS5754M_DSP, 0x00 },
+ { TAS5754M_PLL_REF, 0x00 },
+ { TAS5754M_DAC_REF, 0x00 },
+ { TAS5754M_DAC_ROUTING, 0x11 },
+ { TAS5754M_DSP_PROGRAM, 0x01 },
+ { TAS5754M_CLKDET, 0x00 },
+ { TAS5754M_AUTO_MUTE, 0x00 },
+ { TAS5754M_ERROR_DETECT, 0x00 },
+ { TAS5754M_DIGITAL_VOLUME_1, 0x00 },
+ { TAS5754M_DIGITAL_VOLUME_2, 0x30 },
+ { TAS5754M_DIGITAL_VOLUME_3, 0x30 },
+ { TAS5754M_DIGITAL_MUTE_1, 0x22 },
+ { TAS5754M_DIGITAL_MUTE_2, 0x00 },
+ { TAS5754M_DIGITAL_MUTE_3, 0x07 },
+ { TAS5754M_OUTPUT_AMPLITUDE, 0x00 },
+ { TAS5754M_ANALOG_GAIN_CTRL, 0x00 },
+ { TAS5754M_UNDERVOLTAGE_PROT, 0x00 },
+ { TAS5754M_ANALOG_MUTE_CTRL, 0x00 },
+ { TAS5754M_ANALOG_GAIN_BOOST, 0x00 },
+ { TAS5754M_VCOM_CTRL_1, 0x00 },
+ { TAS5754M_VCOM_CTRL_2, 0x01 },
+ { TAS5754M_BCLK_LRCLK_CFG, 0x00 },
+ { TAS5754M_MASTER_MODE, 0x7c },
+ { TAS5754M_GPIO_PLLIN, 0x00 },
+ { TAS5754M_SYNCHRONIZE, 0x10 },
+ { TAS5754M_PLL_COEFF_P, 0x00 },
+ { TAS5754M_PLL_COEFF_J, 0x00 },
+ { TAS5754M_PLL_COEFF_DH, 0x00 },
+ { TAS5754M_PLL_COEFF_DL, 0x00 },
+ { TAS5754M_PLL_COEFF_R, 0x00 },
+ { TAS5754M_DSP_CLKDIV, 0x00 },
+ { TAS5754M_DAC_CLKDIV, 0x00 },
+ { TAS5754M_NCP_CLKDIV, 0x00 },
+ { TAS5754M_OSR_CLKDIV, 0x00 },
+ { TAS5754M_MASTER_SCLKDIV, 0x00 },
+ { TAS5754M_MASTER_LRCLKDIV, 0x00 },
+ { TAS5754M_FS_SPEED_MODE, 0x00 },
+ { TAS5754M_IDAC_1, 0x01 },
+ { TAS5754M_IDAC_2, 0x00 },
+};
+
+static bool tas5754m_readable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TAS5754M_RESET:
+ case TAS5754M_POWER:
+ case TAS5754M_MUTE:
+ case TAS5754M_PLL_EN:
+ case TAS5754M_DSP:
+ case TAS5754M_GPIO_EN:
+ case TAS5754M_BCLK_LRCLK_CFG:
+ case TAS5754M_DSP_GPIO_INPUT:
+ case TAS5754M_MASTER_MODE:
+ case TAS5754M_PLL_REF:
+ case TAS5754M_DAC_REF:
+ case TAS5754M_GPIO_PLLIN:
+ case TAS5754M_SYNCHRONIZE:
+ case TAS5754M_PLL_COEFF_P:
+ case TAS5754M_PLL_COEFF_J:
+ case TAS5754M_PLL_COEFF_DH:
+ case TAS5754M_PLL_COEFF_DL:
+ case TAS5754M_PLL_COEFF_R:
+ case TAS5754M_DSP_CLKDIV:
+ case TAS5754M_DAC_CLKDIV:
+ case TAS5754M_NCP_CLKDIV:
+ case TAS5754M_OSR_CLKDIV:
+ case TAS5754M_MASTER_SCLKDIV:
+ case TAS5754M_MASTER_LRCLKDIV:
+ case TAS5754M_FS_SPEED_MODE:
+ case TAS5754M_IDAC_1:
+ case TAS5754M_IDAC_2:
+ case TAS5754M_ERROR_DETECT:
+ case TAS5754M_I2S_1:
+ case TAS5754M_I2S_2:
+ case TAS5754M_DAC_ROUTING:
+ case TAS5754M_DSP_PROGRAM:
+ case TAS5754M_CLKDET:
+ case TAS5754M_AUTO_MUTE:
+ case TAS5754M_DIGITAL_VOLUME_1:
+ case TAS5754M_DIGITAL_VOLUME_2:
+ case TAS5754M_DIGITAL_VOLUME_3:
+ case TAS5754M_DIGITAL_MUTE_1:
+ case TAS5754M_DIGITAL_MUTE_2:
+ case TAS5754M_DIGITAL_MUTE_3:
+ case TAS5754M_GPIO_OUTPUT_0:
+ case TAS5754M_GPIO_OUTPUT_1:
+ case TAS5754M_GPIO_OUTPUT_2:
+ case TAS5754M_GPIO_CONTROL_1:
+ case TAS5754M_GPIO_CONTROL_2:
+ case TAS5754M_OVERFLOW:
+ case TAS5754M_RATE_DET_1:
+ case TAS5754M_RATE_DET_2:
+ case TAS5754M_RATE_DET_3:
+ case TAS5754M_RATE_DET_4:
+ case TAS5754M_CLOCK_STATUS:
+ case TAS5754M_ANALOG_MUTE_DET:
+ case TAS5754M_GPIN:
+ case TAS5754M_DIGITAL_MUTE_DET:
+ case TAS5754M_OUTPUT_AMPLITUDE:
+ case TAS5754M_ANALOG_GAIN_CTRL:
+ case TAS5754M_UNDERVOLTAGE_PROT:
+ case TAS5754M_ANALOG_MUTE_CTRL:
+ case TAS5754M_ANALOG_GAIN_BOOST:
+ case TAS5754M_VCOM_CTRL_1:
+ case TAS5754M_VCOM_CTRL_2:
+ case TAS5754M_CRAM_CTRL:
+ case TAS5754M_FLEX_A:
+ case TAS5754M_FLEX_B:
+ return true;
+ default:
+ return reg < 0x7f;
+ }
+}
+
+static bool tas5754m_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TAS5754M_PLL_EN:
+ case TAS5754M_OVERFLOW:
+ case TAS5754M_RATE_DET_1:
+ case TAS5754M_RATE_DET_2:
+ case TAS5754M_RATE_DET_3:
+ case TAS5754M_RATE_DET_4:
+ case TAS5754M_CLOCK_STATUS:
+ case TAS5754M_ANALOG_MUTE_DET:
+ case TAS5754M_GPIN:
+ case TAS5754M_DIGITAL_MUTE_DET:
+ case TAS5754M_CRAM_CTRL:
+ return true;
+ default:
+ return reg < 0x7f;
+ }
+}
+
+struct tas5754m_priv {
+ struct regmap *regmap;
+ struct clk *sclk;
+ int sample_len;
+ int fmt;
+ int mode;
+};
+
+static const struct regmap_range_cfg tas5754m_range = {
+ .name = "Pages",
+ .range_min = TAS5754M_VIRT_BASE,
+ .range_max = TAS5754M_MAX_REGISTER,
+ .selector_reg = TAS5754M_PAGE,
+ .selector_mask = 0x7f,
+ .window_start = 0,
+ .window_len = 128,
+};
+
+const struct regmap_config tas5754m_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .ranges = &tas5754m_range,
+ .num_ranges = 1,
+ .max_register = TAS5754M_MAX_REGISTER,
+
+ .reg_defaults = tas5754m_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tas5754m_reg_defaults),
+ .readable_reg = tas5754m_readable,
+ .volatile_reg = tas5754m_volatile,
+
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const struct snd_kcontrol_new tas5754m_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", TAS5754M_DIGITAL_VOLUME_2,
+ TAS5754M_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analog Playback Volume", TAS5754M_ANALOG_GAIN_CTRL,
+ TAS5754M_LAGN_SHIFT, TAS5754M_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Analogue Playback Boost Volume", TAS5754M_ANALOG_GAIN_BOOST,
+ TAS5754M_AGBL_SHIFT, TAS5754M_AGBR_SHIFT, 1, 0, boost_tlv),
+};
+
+static int tas5754m_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ switch (level) {
+ default:
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ ret = regmap_update_bits(tas5754m->regmap,
+ TAS5754M_POWER, TAS5754M_RQST, 0);
+ if (ret)
+ dev_err(component->dev,
+ "Failed to remove standby: %d\n", ret);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ ret = regmap_update_bits(tas5754m->regmap,
+ TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
+ if (ret)
+ dev_err(component->dev,
+ "Failed to request standby: %d\n", ret);
+ break;
+ }
+
+ return ret;
+}
+
+static int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+ static const struct reg_sequence pll_settings[] = {
+ { TAS5754M_PLL_COEFF_P, 0x01 }, // P=2
+ { TAS5754M_PLL_COEFF_J, 0x08 }, // J=8
+ { TAS5754M_PLL_COEFF_DL, 0x00 }, // D12-8 = 0
+ { TAS5754M_PLL_COEFF_DH, 0x00 }, // D7-0 = 0
+ { TAS5754M_PLL_COEFF_R, 0x00 }, // R=1
+ };
+ int ret;
+
+ /* disable PLL before any clock tree change */
+ ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+ TAS5754M_PLLE, 0);
+ if (ret) {
+ dev_err(component->dev, "Failed to disable PLL\n");
+ return ret;
+ }
+ /* set DAC clock source to MCLK */
+ ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
+ if (ret) {
+ dev_err(component->dev, "Failed to set DAC ref\n");
+ return ret;
+ }
+ /* run PLL at fixed ratio to MCLK */
+ ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
+ ARRAY_SIZE(pll_settings));
+ if (ret) {
+ dev_err(component->dev, "Failed to set PLL ratio\n");
+ return ret;
+ }
+ /* set DSP divider to 2 => reg 0x01 */
+ ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
+ if (ret) {
+ dev_err(component->dev, "Failed to set DSP divider\n");
+ return ret;
+ }
+ /* set DAC divider to 4 => reg 0x03*/
+ ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
+ if (ret) {
+ dev_err(component->dev, "Failed to set OSDACR divider\n");
+ return ret;
+ }
+ /* set OSR divider to 1 */
+ ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
+ if (ret) {
+ dev_err(component->dev, "Failed to set OSR divider\n");
+ return ret;
+ }
+ /* set CP divider to 4 => reg 0x03*/
+ ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
+ if (ret) {
+ dev_err(component->dev, "Failed to set CP divider\n");
+ return ret;
+ }
+ /* finally enable PLL */
+ ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+ TAS5754M_PLLE, 1);
+ if (ret) {
+ dev_err(component->dev, "Failed to enable PLL\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+ int fmt = tas5754m->fmt;
+
+ /* only I2S MASTER mode implemented */
+ if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
+ dev_err(component->dev,
+ "DAI format not supported (I2S master only)\n");
+ return -EINVAL;
+ }
+
+ /* TAS5754/6m do not support inverted clocks in MASTER mode */
+ if ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF) {
+ dev_err(component->dev, "Inverted clocks not supported\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ regmap_update_bits(tas5754m->regmap,
+ TAS5754M_BCLK_LRCLK_CFG,
+ TAS5754M_LRKO | TAS5754M_BCKO,
+ TAS5754M_LRKO | TAS5754M_BCKO);
+ /* reset CLK dividers */
+ regmap_update_bits(tas5754m->regmap,
+ TAS5754M_MASTER_MODE,
+ 0x00,
+ TAS5754M_RLRK | TAS5754M_RBCK);
+ /* ignore all clock error detection but MCLK */
+ regmap_update_bits(tas5754m->regmap,
+ TAS5754M_ERROR_DETECT,
+ TAS5754M_IPLK | TAS5754M_DCAS |
+ TAS5754M_IDCM | TAS5754M_IDSK |
+ TAS5754M_IDBK | TAS5754M_IDFS,
+ TAS5754M_IPLK | TAS5754M_DCAS |
+ TAS5754M_IDCM | TAS5754M_IDSK |
+ TAS5754M_IDBK | TAS5754M_IDFS);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+ unsigned long bclk;
+ unsigned long mclk;
+ int bclk_div;
+ int lrclk_div;
+ int osr;
+ int ret;
+
+ /* calculate divider settings based on mclk and sample_len */
+ mclk = clk_get_rate(tas5754m->sclk);
+ bclk = tas5754m->sample_len * 2 * params_rate(params);
+ bclk_div = mclk / bclk;
+ lrclk_div = tas5754m->sample_len * 2;
+ osr = mclk / 4 / params_rate(params) / 16;
+
+ /* stop LR / SCLK clocks */
+ ret = regmap_update_bits(tas5754m->regmap,
+ TAS5754M_MASTER_MODE, 0,
+ TAS5754M_RLRK | TAS5754M_RBCK);
+ if (ret) {
+ dev_err(component->dev, "Failed to stop PLL\n");
+ return ret;
+ }
+ /* set SCLK divider */
+ ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
+ bclk_div - 1);
+ if (ret) {
+ dev_err(component->dev, "Failed to set SCLK divider\n");
+ return ret;
+ }
+ /* set LRCLK divider */
+ ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
+ lrclk_div - 1);
+ if (ret) {
+ dev_err(component->dev, "Failed to set LRCLK divider\n");
+ return ret;
+ }
+ ret = regmap_write(tas5754m->regmap,
+ TAS5754M_OSR_CLKDIV, osr - 1);
+ if (ret) {
+ dev_err(component->dev, "Failed to set OSR divider\n");
+ return ret;
+ }
+ /* restart LR / SCLK clocks */
+ ret = regmap_update_bits(tas5754m->regmap,
+ TAS5754M_MASTER_MODE,
+ TAS5754M_RLRK | TAS5754M_RBCK,
+ TAS5754M_RLRK | TAS5754M_RBCK);
+ if (ret) {
+ dev_err(component->dev, "Failed to restart PLL\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tas5754m_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+ int alen;
+ int ret;
+
+ switch (params_width(params)) {
+ case 16:
+ tas5754m->sample_len = 16;
+ alen = TAS5754M_ALEN_16;
+ break;
+ case 20:
+ tas5754m->sample_len = 32;
+ alen = TAS5754M_ALEN_20;
+ break;
+ case 24:
+ tas5754m->sample_len = 32;
+ alen = TAS5754M_ALEN_24;
+ break;
+ case 32:
+ tas5754m->sample_len = 32;
+ alen = TAS5754M_ALEN_32;
+ break;
+ default:
+ dev_err(component->dev, "Unsupported sample size: %d\n",
+ params_width(params));
+ return -EINVAL;
+ }
+ ret = regmap_update_bits(tas5754m->regmap, TAS5754M_I2S_1, alen, alen);
+ if (ret) {
+ dev_err(component->dev,
+ "Cannot set sample size: %d\n", ret);
+ return ret;
+ }
+
+ ret = tas5754m_set_dai_mode(dai);
+ if (ret) {
+ dev_err(component->dev,
+ "DAI mode not supported: %d\n", ret);
+ return ret;
+ }
+
+ ret = tas5754m_set_clock_tree_master(dai, params);
+ if (ret)
+ return ret;
+
+ switch (params_rate(params)) {
+ case 44100:
+ case 48000:
+ ret = regmap_write(tas5754m->regmap,
+ TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_48KHZ);
+ break;
+ case 88200:
+ case 96000:
+ ret = regmap_write(tas5754m->regmap,
+ TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_96KHZ);
+ break;
+ case 176400:
+ case 192000:
+ ret = regmap_write(tas5754m->regmap,
+ TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_192KHZ);
+ break;
+ default:
+ dev_err(component->dev, "Sample rate not supported: %d\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+ if (ret) {
+ dev_err(component->dev, "Failed to config PLL\n");
+ return ret;
+ }
+
+ ret = tas5754m_set_dividers_master(dai, params);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int tas5754m_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+
+ tas5754m->fmt = fmt;
+
+ return 0;
+}
+
+
+static const struct snd_soc_component_driver tas5754m_soc_component = {
+ .set_bias_level = tas5754m_set_bias_level,
+ .idle_bias_on = true,
+ .controls = tas5754m_controls,
+ .num_controls = ARRAY_SIZE(tas5754m_controls),
+};
+
+static int tas5754m_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *component = dai->component;
+
+ if (mute) {
+ snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
+ } else {
+ /* wait for stable operation before unmute */
+ usleep_range(1000, 2000);
+ snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
+ }
+ return 0;
+}
+
+static const struct snd_soc_dai_ops tas5754m_dai_ops = {
+ .mute_stream = tas5754m_mute,
+ .hw_params = tas5754m_hw_params,
+ .set_fmt = tas5754m_set_fmt,
+};
+
+static struct snd_soc_dai_driver tas5754m_dai = {
+ .name = "tas5754m-amplifier",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = TAS5754M_RATES,
+ .formats = TAS5754M_FORMATS,
+ },
+ .ops = &tas5754m_dai_ops,
+};
+
+static int tas5754m_probe(struct device *dev, struct regmap *regmap)
+{
+ struct tas5754m_priv *tas5754m;
+ int ret;
+
+ tas5754m = devm_kzalloc(dev, sizeof(struct tas5754m_priv), GFP_KERNEL);
+ if (!tas5754m)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, tas5754m);
+ tas5754m->regmap = regmap;
+
+ ret = regmap_write(regmap, TAS5754M_RESET,
+ TAS5754M_RSTR | TAS5754M_RSTM);
+ if (ret) {
+ dev_err(dev, "Failed to initialize TAS5754M: %d\n", ret);
+ goto err;
+ }
+
+ tas5754m->sclk = devm_clk_get(dev, NULL);
+ if (PTR_ERR(tas5754m->sclk) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+ if (!IS_ERR(tas5754m->sclk)) {
+ ret = clk_prepare_enable(tas5754m->sclk);
+ if (ret) {
+ dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+ goto err;
+ }
+ }
+
+ ret = devm_snd_soc_register_component(dev,
+ &tas5754m_soc_component, &tas5754m_dai, 1);
+ if (ret) {
+ dev_err(dev, "Failed to register CODEC: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ return ret;
+
+}
+
+static int tas5754m_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ struct regmap_config config = tas5754m_regmap;
+
+ /* enable auto-increment mode */
+ config.read_flag_mask = 0x80;
+ config.write_flag_mask = 0x80;
+
+ regmap = devm_regmap_init_i2c(i2c, &config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return tas5754m_probe(&i2c->dev, regmap);
+}
+
+static int tas5754m_remove(struct device *dev)
+{
+ snd_soc_unregister_component(dev);
+
+ return 0;
+}
+
+static int tas5754m_i2c_remove(struct i2c_client *i2c)
+{
+ tas5754m_remove(&i2c->dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id tas5754m_i2c_id[] = {
+ { "tas5754m", },
+ { "tas5756m", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5754m_of_match[] = {
+ { .compatible = "ti,tas5754m", },
+ { .compatible = "ti,tas5756m", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tas5754m_of_match);
+#endif
+
+static struct i2c_driver tas5754m_i2c_driver = {
+ .probe = tas5754m_i2c_probe,
+ .remove = tas5754m_i2c_remove,
+ .id_table = tas5754m_i2c_id,
+ .driver = {
+ .name = "tas5754m",
+ .of_match_table = of_match_ptr(tas5754m_of_match),
+ },
+};
+
+module_i2c_driver(tas5754m_i2c_driver);
+
+MODULE_AUTHOR("Joerg Schambacher <joerg(a)hifiberry.com>");
+MODULE_DESCRIPTION("TAS5754M Audio Amplifier Driver - Master mode only");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5754m.h b/sound/soc/codecs/tas5754m.h
new file mode 100644
index 000000000000..c6e26dba169f
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.h
@@ -0,0 +1,260 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Driver for the TAS575xM DAC+amplifier combo devices
+ *
+ * Author: (copied from pcm512x.h)
+ * Mark Brown <broonie(a)kernel.org>
+ * Copyright 2014 Linaro Ltd
+ *
+ * Register names adapted and non available
+ * register definitions removed according
+ + to TAS5754M specification
+ * Joerg Schambacher <joerg(a)hifiberry.com>
+ */
+
+#ifndef _SND_SOC_TAS5754M
+#define _SND_SOC_TAS5754M
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define TAS5754M_VIRT_BASE 0x000
+#define TAS5754M_PAGE_LEN 0x80
+#define TAS5754M_PAGE_BASE(n) (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
+
+#define TAS5754M_PAGE 0
+
+#define TAS5754M_RESET (TAS5754M_PAGE_BASE(0) + 1)
+#define TAS5754M_POWER (TAS5754M_PAGE_BASE(0) + 2)
+#define TAS5754M_MUTE (TAS5754M_PAGE_BASE(0) + 3)
+#define TAS5754M_PLL_EN (TAS5754M_PAGE_BASE(0) + 4)
+#define TAS5754M_DSP (TAS5754M_PAGE_BASE(0) + 7)
+#define TAS5754M_GPIO_EN (TAS5754M_PAGE_BASE(0) + 8)
+#define TAS5754M_BCLK_LRCLK_CFG (TAS5754M_PAGE_BASE(0) + 9)
+#define TAS5754M_DSP_GPIO_INPUT (TAS5754M_PAGE_BASE(0) + 10)
+#define TAS5754M_MASTER_MODE (TAS5754M_PAGE_BASE(0) + 12)
+#define TAS5754M_PLL_REF (TAS5754M_PAGE_BASE(0) + 13)
+#define TAS5754M_DAC_REF (TAS5754M_PAGE_BASE(0) + 14)
+#define TAS5754M_GPIO_PLLIN (TAS5754M_PAGE_BASE(0) + 18)
+#define TAS5754M_SYNCHRONIZE (TAS5754M_PAGE_BASE(0) + 19)
+#define TAS5754M_PLL_COEFF_P (TAS5754M_PAGE_BASE(0) + 20)
+#define TAS5754M_PLL_COEFF_J (TAS5754M_PAGE_BASE(0) + 21)
+#define TAS5754M_PLL_COEFF_DH (TAS5754M_PAGE_BASE(0) + 22)
+#define TAS5754M_PLL_COEFF_DL (TAS5754M_PAGE_BASE(0) + 23)
+#define TAS5754M_PLL_COEFF_R (TAS5754M_PAGE_BASE(0) + 24)
+#define TAS5754M_DSP_CLKDIV (TAS5754M_PAGE_BASE(0) + 27)
+#define TAS5754M_DAC_CLKDIV (TAS5754M_PAGE_BASE(0) + 28)
+#define TAS5754M_NCP_CLKDIV (TAS5754M_PAGE_BASE(0) + 29)
+#define TAS5754M_OSR_CLKDIV (TAS5754M_PAGE_BASE(0) + 30)
+#define TAS5754M_MASTER_SCLKDIV (TAS5754M_PAGE_BASE(0) + 32)
+#define TAS5754M_MASTER_LRCLKDIV (TAS5754M_PAGE_BASE(0) + 33)
+#define TAS5754M_FS_SPEED_MODE (TAS5754M_PAGE_BASE(0) + 34)
+#define TAS5754M_IDAC_1 (TAS5754M_PAGE_BASE(0) + 35)
+#define TAS5754M_IDAC_2 (TAS5754M_PAGE_BASE(0) + 36)
+#define TAS5754M_ERROR_DETECT (TAS5754M_PAGE_BASE(0) + 37)
+#define TAS5754M_I2S_1 (TAS5754M_PAGE_BASE(0) + 40)
+#define TAS5754M_I2S_2 (TAS5754M_PAGE_BASE(0) + 41)
+#define TAS5754M_DAC_ROUTING (TAS5754M_PAGE_BASE(0) + 42)
+#define TAS5754M_DSP_PROGRAM (TAS5754M_PAGE_BASE(0) + 43)
+#define TAS5754M_CLKDET (TAS5754M_PAGE_BASE(0) + 44)
+#define TAS5754M_AUTO_MUTE (TAS5754M_PAGE_BASE(0) + 59)
+#define TAS5754M_DIGITAL_VOLUME_1 (TAS5754M_PAGE_BASE(0) + 60)
+#define TAS5754M_DIGITAL_VOLUME_2 (TAS5754M_PAGE_BASE(0) + 61)
+#define TAS5754M_DIGITAL_VOLUME_3 (TAS5754M_PAGE_BASE(0) + 62)
+#define TAS5754M_DIGITAL_MUTE_1 (TAS5754M_PAGE_BASE(0) + 63)
+#define TAS5754M_DIGITAL_MUTE_2 (TAS5754M_PAGE_BASE(0) + 64)
+#define TAS5754M_DIGITAL_MUTE_3 (TAS5754M_PAGE_BASE(0) + 65)
+#define TAS5754M_GPIO_OUTPUT_1 (TAS5754M_PAGE_BASE(0) + 82)
+#define TAS5754M_GPIO_OUTPUT_0 (TAS5754M_PAGE_BASE(0) + 83)
+#define TAS5754M_GPIO_OUTPUT_2 (TAS5754M_PAGE_BASE(0) + 85)
+#define TAS5754M_GPIO_CONTROL_1 (TAS5754M_PAGE_BASE(0) + 86)
+#define TAS5754M_GPIO_CONTROL_2 (TAS5754M_PAGE_BASE(0) + 87)
+#define TAS5754M_OVERFLOW (TAS5754M_PAGE_BASE(0) + 90)
+#define TAS5754M_RATE_DET_1 (TAS5754M_PAGE_BASE(0) + 91)
+#define TAS5754M_RATE_DET_2 (TAS5754M_PAGE_BASE(0) + 92)
+#define TAS5754M_RATE_DET_3 (TAS5754M_PAGE_BASE(0) + 93)
+#define TAS5754M_RATE_DET_4 (TAS5754M_PAGE_BASE(0) + 94)
+#define TAS5754M_CLOCK_STATUS (TAS5754M_PAGE_BASE(0) + 95)
+#define TAS5754M_ANALOG_MUTE_DET (TAS5754M_PAGE_BASE(0) + 108)
+#define TAS5754M_FS_MODE_MON (TAS5754M_PAGE_BASE(0) + 115)
+#define TAS5754M_GPIN (TAS5754M_PAGE_BASE(0) + 119)
+#define TAS5754M_DIGITAL_MUTE_DET (TAS5754M_PAGE_BASE(0) + 120)
+
+#define TAS5754M_OUTPUT_AMPLITUDE (TAS5754M_PAGE_BASE(1) + 1)
+#define TAS5754M_ANALOG_GAIN_CTRL (TAS5754M_PAGE_BASE(1) + 2)
+#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) + 5)
+#define TAS5754M_ANALOG_MUTE_CTRL (TAS5754M_PAGE_BASE(1) + 6)
+#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) + 7)
+#define TAS5754M_VCOM_CTRL_1 (TAS5754M_PAGE_BASE(1) + 8)
+#define TAS5754M_VCOM_CTRL_2 (TAS5754M_PAGE_BASE(1) + 9)
+
+#define TAS5754M_CRAM_CTRL (TAS5754M_PAGE_BASE(44) + 1)
+
+#define TAS5754M_FLEX_A (TAS5754M_PAGE_BASE(253) + 63)
+#define TAS5754M_FLEX_B (TAS5754M_PAGE_BASE(253) + 64)
+
+#define TAS5754M_MAX_REGISTER (TAS5754M_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define TAS5754M_RSTR (1 << 0)
+#define TAS5754M_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define TAS5754M_RQPD (1 << 0)
+#define TAS5754M_RQPD_SHIFT 0
+#define TAS5754M_RQST (1 << 4)
+#define TAS5754M_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define TAS5754M_RQMR (1 << 0)
+#define TAS5754M_RQMR_SHIFT 0
+#define TAS5754M_RQML (1 << 4)
+#define TAS5754M_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define TAS5754M_PLLE (1 << 0)
+#define TAS5754M_PLLE_SHIFT 0
+#define TAS5754M_PLCK (1 << 4)
+#define TAS5754M_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define TAS5754M_SDSL (1 << 0)
+#define TAS5754M_SDSL_SHIFT 0
+#define TAS5754M_DEMP (1 << 4)
+#define TAS5754M_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define TAS5754M_G1OE (1 << 0)
+#define TAS5754M_G2OE (1 << 1)
+#define TAS5754M_G3OE (1 << 2)
+#define TAS5754M_G4OE (1 << 3)
+#define TAS5754M_G5OE (1 << 4)
+#define TAS5754M_G6OE (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define TAS5754M_LRKO (1 << 0)
+#define TAS5754M_LRKO_SHIFT 0
+#define TAS5754M_BCKO (1 << 4)
+#define TAS5754M_BCKO_SHIFT 4
+#define TAS5754M_BCKP (1 << 5)
+#define TAS5754M_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define TAS5754M_RLRK (1 << 0)
+#define TAS5754M_RLRK_SHIFT 0
+#define TAS5754M_RBCK (1 << 1)
+#define TAS5754M_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define TAS5754M_SREF (7 << 4)
+#define TAS5754M_SREF_SHIFT 4
+#define TAS5754M_SREF_SCK (0 << 4)
+#define TAS5754M_SREF_BCK (1 << 4)
+#define TAS5754M_SREF_GPIO (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define TAS5754M_SDAC (7 << 4)
+#define TAS5754M_SDAC_SHIFT 4
+#define TAS5754M_SDAC_MCK (0 << 4)
+#define TAS5754M_SDAC_PLL (1 << 4)
+#define TAS5754M_SDAC_SCK (3 << 4)
+#define TAS5754M_SDAC_BCK (4 << 4)
+#define TAS5754M_SDAC_GPIO (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define TAS5754M_GREF (7 << 0)
+#define TAS5754M_GREF_SHIFT 0
+#define TAS5754M_GREF_GPIO1 (0 << 0)
+#define TAS5754M_GREF_GPIO2 (1 << 0)
+#define TAS5754M_GREF_GPIO3 (2 << 0)
+#define TAS5754M_GREF_GPIO4 (3 << 0)
+#define TAS5754M_GREF_GPIO5 (4 << 0)
+#define TAS5754M_GREF_GPIO6 (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define TAS5754M_RQSY (1 << 0)
+#define TAS5754M_RQSY_RESUME (0 << 0)
+#define TAS5754M_RQSY_HALT (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define TAS5754M_FSSP (3 << 0)
+#define TAS5754M_FSSP_SHIFT 0
+#define TAS5754M_FSSP_48KHZ (0 << 0)
+#define TAS5754M_FSSP_96KHZ (1 << 0)
+#define TAS5754M_FSSP_192KHZ (2 << 0)
+#define TAS5754M_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define TAS5754M_IPLK (1 << 0)
+#define TAS5754M_DCAS (1 << 1)
+#define TAS5754M_IDCM (1 << 2)
+#define TAS5754M_IDCH (1 << 3)
+#define TAS5754M_IDSK (1 << 4)
+#define TAS5754M_IDBK (1 << 5)
+#define TAS5754M_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define TAS5754M_ALEN (3 << 0)
+#define TAS5754M_ALEN_SHIFT 0
+#define TAS5754M_ALEN_16 (0 << 0)
+#define TAS5754M_ALEN_20 (1 << 0)
+#define TAS5754M_ALEN_24 (2 << 0)
+#define TAS5754M_ALEN_32 (3 << 0)
+#define TAS5754M_AFMT (3 << 4)
+#define TAS5754M_AFMT_SHIFT 4
+#define TAS5754M_AFMT_I2S (0 << 4)
+#define TAS5754M_AFMT_DSP (1 << 4)
+#define TAS5754M_AFMT_RTJ (2 << 4)
+#define TAS5754M_AFMT_LTJ (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define TAS5754M_AUPR_SHIFT 0
+#define TAS5754M_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define TAS5754M_ATMR_SHIFT 0
+#define TAS5754M_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define TAS5754M_VNDF_SHIFT 6
+#define TAS5754M_VNDS_SHIFT 4
+#define TAS5754M_VNUF_SHIFT 2
+#define TAS5754M_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define TAS5754M_VEDF_SHIFT 6
+#define TAS5754M_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define TAS5754M_ACTL_SHIFT 2
+#define TAS5754M_AMLE_SHIFT 1
+#define TAS5754M_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define TAS5754M_GxSL (31 << 0)
+#define TAS5754M_GxSL_SHIFT 0
+#define TAS5754M_GxSL_OFF (0 << 0)
+#define TAS5754M_GxSL_DSP (1 << 0)
+#define TAS5754M_GxSL_REG (2 << 0)
+#define TAS5754M_GxSL_AMUTB (3 << 0)
+#define TAS5754M_GxSL_AMUTL (4 << 0)
+#define TAS5754M_GxSL_AMUTR (5 << 0)
+#define TAS5754M_GxSL_CLKI (6 << 0)
+#define TAS5754M_GxSL_SDOUT (7 << 0)
+#define TAS5754M_GxSL_ANMUL (8 << 0)
+#define TAS5754M_GxSL_ANMUR (9 << 0)
+#define TAS5754M_GxSL_PLLLK (10 << 0)
+#define TAS5754M_GxSL_CPCLK (11 << 0)
+#define TAS5754M_GxSL_UV0_7 (14 << 0)
+#define TAS5754M_GxSL_UV0_3 (15 << 0)
+#define TAS5754M_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define TAS5754M_RAGN_SHIFT 0
+#define TAS5754M_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define TAS5754M_AGBR_SHIFT 0
+#define TAS5754M_AGBL_SHIFT 4
+
+#endif
--
2.25.1
1
0

20 Jan '22
From: Stefan Binding <sbinding(a)opensource.cirrus.com>
Signed-off-by: Stefan Binding <sbinding(a)opensource.cirrus.com>
Signed-off-by: Vitaly Rodionov <vitalyr(a)opensource.cirrus.com>
---
sound/pci/hda/patch_cs8409-tables.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/pci/hda/patch_cs8409-tables.c
index df0b4522babf..2d1fa706327b 100644
--- a/sound/pci/hda/patch_cs8409-tables.c
+++ b/sound/pci/hda/patch_cs8409-tables.c
@@ -490,6 +490,8 @@ const struct snd_pci_quirk cs8409_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0ADC, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AF4, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AF5, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0BB5, "Warlock N3 15 TGL-U Nuvoton EC", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0BB6, "Warlock V3 15 TGL-U Nuvoton EC", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0A77, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A78, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A79, "Cyborg", CS8409_CYBORG),
--
2.25.1
2
1
alsa-project/alsa-lib pull request #210 was opened from ginggs:
As noted in bpo-30459, PyTuple_SET_ITEM() does not return a value.
https://bugs.python.org/issue30459
Request URL : https://github.com/alsa-project/alsa-lib/pull/210
Patch URL : https://github.com/alsa-project/alsa-lib/pull/210.patch
Repository URL: https://github.com/alsa-project/alsa-lib
1
0

20 Jan '22
alsa-project/alsa-utils issue #137 was opened from int-e:
`alsamixer` supports customizing colors for the various controls using the `color` directive in the configuration file. Commit
https://github.com/alsa-project/alsa-utils/commit/5d4442b2cfe967c44b5cd74fc…
broke this feature, because it initializes curses colors *after* reading the configuration file, which overrides any colors that the configuration file may have set.
Issue URL : https://github.com/alsa-project/alsa-utils/issues/137
Repository URL: https://github.com/alsa-project/alsa-utils
1
0

[PATCH][next] ALSA: usb-audio: scarlett2: Use struct_size() helper in scarlett2_usb()
by Gustavo A. R. Silva 20 Jan '22
by Gustavo A. R. Silva 20 Jan '22
20 Jan '22
Make use of the struct_size() helper instead of an open-coded version,
in order to avoid any potential type mistakes or integer overflows that,
in the worst scenario, could lead to heap overflows.
Also, address the following sparse warnings:
sound/usb/mixer_scarlett_gen2.c:1064:28: warning: using sizeof on a flexible structure
sound/usb/mixer_scarlett_gen2.c:1065:29: warning: using sizeof on a flexible structure
Link: https://github.com/KSPP/linux/issues/160
Link: https://github.com/KSPP/linux/issues/174
Signed-off-by: Gustavo A. R. Silva <gustavoars(a)kernel.org>
---
sound/usb/mixer_scarlett_gen2.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 53ebabf42472..311413f015f0 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -1061,9 +1061,9 @@ static int scarlett2_usb(
{
struct scarlett2_data *private = mixer->private_data;
struct usb_device *dev = mixer->chip->dev;
- u16 req_buf_size = sizeof(struct scarlett2_usb_packet) + req_size;
- u16 resp_buf_size = sizeof(struct scarlett2_usb_packet) + resp_size;
struct scarlett2_usb_packet *req, *resp = NULL;
+ size_t req_buf_size = struct_size(req, data, req_size);
+ size_t resp_buf_size = struct_size(resp, data, resp_size);
int err;
req = kmalloc(req_buf_size, GFP_KERNEL);
@@ -1111,7 +1111,7 @@ static int scarlett2_usb(
usb_audio_err(
mixer->chip,
"Scarlett Gen 2/3 USB response result cmd %x was %d "
- "expected %d\n",
+ "expected %lu\n",
cmd, err, resp_buf_size);
err = -EINVAL;
goto unlock;
--
2.27.0
2
2

19 Jan '22
This patch is based on the former Andy Shevchenko's patch:
https://lore.kernel.org/lkml/20210331144526.19439-1-andriy.shevchenko@linux…
Currently platform_get_irq_optional() returns an error code even if IRQ
resource simply has not been found. It prevents the callers from being
error code agnostic in their error handling:
ret = platform_get_irq_optional(...);
if (ret < 0 && ret != -ENXIO)
return ret; // respect deferred probe
if (ret > 0)
...we get an IRQ...
All other *_optional() APIs seem to return 0 or NULL in case an optional
resource is not available. Let's follow this good example, so that the
callers would look like:
ret = platform_get_irq_optional(...);
if (ret < 0)
return ret;
if (ret > 0)
...we get an IRQ...
Reported-by: Matthias Schiffer <matthias.schiffer(a)ew.tq-group.com>
Signed-off-by: Sergey Shtylyov <s.shtylyov(a)omp.ru>
---
drivers/base/platform.c | 56 +++++++++++++++---------
drivers/char/ipmi/bt-bmc.c | 8 ++--
drivers/counter/interrupt-cnt.c | 4 +-
drivers/edac/xgene_edac.c | 2 +-
drivers/gpio/gpio-altera.c | 3 +-
drivers/gpio/gpio-mvebu.c | 2 +-
drivers/gpio/gpio-tqmx86.c | 2 +-
drivers/i2c/busses/i2c-brcmstb.c | 8 ++--
drivers/i2c/busses/i2c-ocores.c | 4 +-
drivers/mmc/host/sh_mmcif.c | 4 +-
drivers/mtd/nand/raw/brcmnand/brcmnand.c | 4 +-
drivers/net/ethernet/davicom/dm9000.c | 2 +-
drivers/net/ethernet/freescale/fec_ptp.c | 2 +-
drivers/phy/renesas/phy-rcar-gen3-usb2.c | 4 +-
drivers/platform/chrome/cros_ec_lpc.c | 2 +-
drivers/platform/x86/intel/punit_ipc.c | 2 +-
drivers/power/supply/mp2629_charger.c | 4 +-
drivers/spi/spi-hisi-sfc-v3xx.c | 2 +-
drivers/spi/spi-mtk-nor.c | 3 +-
drivers/thermal/rcar_gen3_thermal.c | 2 +-
drivers/tty/serial/8250/8250_mtk.c | 4 +-
drivers/tty/serial/sh-sci.c | 6 +--
drivers/uio/uio_pdrv_genirq.c | 2 +-
drivers/vfio/platform/vfio_platform.c | 6 ++-
sound/soc/dwc/dwc-i2s.c | 4 +-
25 files changed, 79 insertions(+), 63 deletions(-)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index fc5a933f3698..7c7b3638f02d 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -148,25 +148,7 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev,
EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname);
#endif /* CONFIG_HAS_IOMEM */
-/**
- * platform_get_irq_optional - get an optional IRQ for a device
- * @dev: platform device
- * @num: IRQ number index
- *
- * Gets an IRQ for a platform device. Device drivers should check the return
- * value for errors so as to not pass a negative integer value to the
- * request_irq() APIs. This is the same as platform_get_irq(), except that it
- * does not print an error message if an IRQ can not be obtained.
- *
- * For example::
- *
- * int irq = platform_get_irq_optional(pdev, 0);
- * if (irq < 0)
- * return irq;
- *
- * Return: non-zero IRQ number on success, negative error number on failure.
- */
-int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
+static int __platform_get_irq(struct platform_device *dev, unsigned int num)
{
int ret;
#ifdef CONFIG_SPARC
@@ -235,6 +217,38 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
return -EINVAL;
return ret;
}
+
+/**
+ * platform_get_irq_optional - get an optional IRQ for a device
+ * @dev: platform device
+ * @num: IRQ number index
+ *
+ * Gets an IRQ for a platform device. Device drivers should check the return
+ * value for errors so as to not pass a negative integer value to the
+ * request_irq() APIs. This is the same as platform_get_irq(), except that it
+ * does not print an error message if an IRQ can not be obtained and returns
+ * 0 when IRQ resource has not been found.
+ *
+ * For example::
+ *
+ * int irq = platform_get_irq_optional(pdev, 0);
+ * if (irq < 0)
+ * return irq;
+ * if (irq > 0)
+ * ...we have IRQ line defined...
+ *
+ * Return: non-zero IRQ number on success, 0 if IRQ wasn't found, negative error
+ * number on failure.
+ */
+int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
+{
+ int ret;
+
+ ret = __platform_get_irq(dev, num);
+ if (ret == -ENXIO)
+ return 0;
+ return ret;
+}
EXPORT_SYMBOL_GPL(platform_get_irq_optional);
/**
@@ -258,7 +272,7 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
{
int ret;
- ret = platform_get_irq_optional(dev, num);
+ ret = __platform_get_irq(dev, num);
if (ret < 0 && ret != -EPROBE_DEFER)
dev_err(&dev->dev, "IRQ index %u not found\n", num);
@@ -276,7 +290,7 @@ int platform_irq_count(struct platform_device *dev)
{
int ret, nr = 0;
- while ((ret = platform_get_irq_optional(dev, nr)) >= 0)
+ while ((ret = __platform_get_irq(dev, nr)) >= 0)
nr++;
if (ret == -EPROBE_DEFER)
diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
index 7450904e330a..fdc63bfa5be4 100644
--- a/drivers/char/ipmi/bt-bmc.c
+++ b/drivers/char/ipmi/bt-bmc.c
@@ -382,12 +382,14 @@ static int bt_bmc_config_irq(struct bt_bmc *bt_bmc,
bt_bmc->irq = platform_get_irq_optional(pdev, 0);
if (bt_bmc->irq < 0)
return bt_bmc->irq;
+ if (!bt_bmc->irq)
+ return 0;
rc = devm_request_irq(dev, bt_bmc->irq, bt_bmc_irq, IRQF_SHARED,
DEVICE_NAME, bt_bmc);
if (rc < 0) {
dev_warn(dev, "Unable to request IRQ %d\n", bt_bmc->irq);
- bt_bmc->irq = rc;
+ bt_bmc->irq = 0;
return rc;
}
@@ -438,7 +440,7 @@ static int bt_bmc_probe(struct platform_device *pdev)
bt_bmc_config_irq(bt_bmc, pdev);
- if (bt_bmc->irq >= 0) {
+ if (bt_bmc->irq > 0) {
dev_info(dev, "Using IRQ %d\n", bt_bmc->irq);
} else {
dev_info(dev, "No IRQ; using timer\n");
@@ -464,7 +466,7 @@ static int bt_bmc_remove(struct platform_device *pdev)
struct bt_bmc *bt_bmc = dev_get_drvdata(&pdev->dev);
misc_deregister(&bt_bmc->miscdev);
- if (bt_bmc->irq < 0)
+ if (bt_bmc->irq <= 0)
del_timer_sync(&bt_bmc->poll_timer);
return 0;
}
diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c
index 8514a87fcbee..a0564c035961 100644
--- a/drivers/counter/interrupt-cnt.c
+++ b/drivers/counter/interrupt-cnt.c
@@ -156,9 +156,7 @@ static int interrupt_cnt_probe(struct platform_device *pdev)
return -ENOMEM;
priv->irq = platform_get_irq_optional(pdev, 0);
- if (priv->irq == -ENXIO)
- priv->irq = 0;
- else if (priv->irq < 0)
+ if (priv->irq < 0)
return dev_err_probe(dev, priv->irq, "failed to get IRQ\n");
priv->gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_IN);
diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c
index 2ccd1db5e98f..0d1bdd27cd78 100644
--- a/drivers/edac/xgene_edac.c
+++ b/drivers/edac/xgene_edac.c
@@ -1917,7 +1917,7 @@ static int xgene_edac_probe(struct platform_device *pdev)
for (i = 0; i < 3; i++) {
irq = platform_get_irq_optional(pdev, i);
- if (irq < 0) {
+ if (irq <= 0) {
dev_err(&pdev->dev, "No IRQ resource\n");
rc = -EINVAL;
goto out_err;
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index b59fae993626..02a2995aa368 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/drivers/gpio/gpio-altera.c
@@ -267,8 +267,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
altera_gc->mmchip.gc.parent = &pdev->dev;
altera_gc->mapped_irq = platform_get_irq_optional(pdev, 0);
-
- if (altera_gc->mapped_irq < 0)
+ if (altera_gc->mapped_irq <= 0)
goto skip_irq;
if (of_property_read_u32(node, "altr,interrupt-type", ®)) {
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 8f429d9f3661..a72a7bfc5a92 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -1294,7 +1294,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
for (i = 0; i < 4; i++) {
int irq = platform_get_irq_optional(pdev, i);
- if (irq < 0)
+ if (irq <= 0)
continue;
irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler,
mvchip);
diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c
index 5b103221b58d..dc0f83236ce8 100644
--- a/drivers/gpio/gpio-tqmx86.c
+++ b/drivers/gpio/gpio-tqmx86.c
@@ -237,7 +237,7 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
int ret, irq;
irq = platform_get_irq_optional(pdev, 0);
- if (irq < 0 && irq != -ENXIO)
+ if (irq < 0)
return irq;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c
index 490ee3962645..69395ae27a1a 100644
--- a/drivers/i2c/busses/i2c-brcmstb.c
+++ b/drivers/i2c/busses/i2c-brcmstb.c
@@ -250,7 +250,7 @@ static int brcmstb_i2c_wait_for_completion(struct brcmstb_i2c_dev *dev)
int ret = 0;
unsigned long timeout = msecs_to_jiffies(I2C_TIMEOUT);
- if (dev->irq >= 0) {
+ if (dev->irq > 0) {
if (!wait_for_completion_timeout(&dev->done, timeout))
ret = -ETIMEDOUT;
} else {
@@ -297,7 +297,7 @@ static int brcmstb_send_i2c_cmd(struct brcmstb_i2c_dev *dev,
return rc;
/* only if we are in interrupt mode */
- if (dev->irq >= 0)
+ if (dev->irq > 0)
reinit_completion(&dev->done);
/* enable BSC CTL interrupt line */
@@ -652,7 +652,7 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE);
/* register the ISR handler */
- if (dev->irq >= 0) {
+ if (dev->irq > 0) {
rc = devm_request_irq(&pdev->dev, dev->irq, brcmstb_i2c_isr,
IRQF_SHARED,
int_name ? int_name : pdev->name,
@@ -696,7 +696,7 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
dev_info(dev->device, "%s@%dhz registered in %s mode\n",
int_name ? int_name : " ", dev->clk_freq_hz,
- (dev->irq >= 0) ? "interrupt" : "polling");
+ (dev->irq > 0) ? "interrupt" : "polling");
return 0;
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index a0af027db04c..1f4d5e52ff42 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -691,10 +691,10 @@ static int ocores_i2c_probe(struct platform_device *pdev)
if (of_device_is_compatible(pdev->dev.of_node,
"sifive,fu540-c000-i2c")) {
i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
- irq = -ENXIO;
+ irq = 0;
}
- if (irq == -ENXIO) {
+ if (!irq) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
} else {
if (irq < 0)
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index bcc595c70a9f..f558b9862032 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -1465,14 +1465,14 @@ static int sh_mmcif_probe(struct platform_device *pdev)
sh_mmcif_sync_reset(host);
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
- name = irq[1] < 0 ? dev_name(dev) : "sh_mmc:error";
+ name = irq[1] <= 0 ? dev_name(dev) : "sh_mmc:error";
ret = devm_request_threaded_irq(dev, irq[0], sh_mmcif_intr,
sh_mmcif_irqt, 0, name, host);
if (ret) {
dev_err(dev, "request_irq error (%s)\n", name);
goto err_clk;
}
- if (irq[1] >= 0) {
+ if (irq[1] > 0) {
ret = devm_request_threaded_irq(dev, irq[1],
sh_mmcif_intr, sh_mmcif_irqt,
0, "sh_mmc:int", host);
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index f75929783b94..ac222985efde 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -1521,7 +1521,7 @@ static irqreturn_t brcmnand_ctlrdy_irq(int irq, void *data)
/* check if you need to piggy back on the ctrlrdy irq */
if (ctrl->edu_pending) {
- if (irq == ctrl->irq && ((int)ctrl->edu_irq >= 0))
+ if (irq == ctrl->irq && ((int)ctrl->edu_irq > 0))
/* Discard interrupts while using dedicated edu irq */
return IRQ_HANDLED;
@@ -2956,7 +2956,7 @@ static int brcmnand_edu_setup(struct platform_device *pdev)
brcmnand_edu_init(ctrl);
ctrl->edu_irq = platform_get_irq_optional(pdev, 1);
- if (ctrl->edu_irq < 0) {
+ if (ctrl->edu_irq <= 0) {
dev_warn(dev,
"FLASH EDU enabled, using ctlrdy irq\n");
} else {
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index 0985ab216566..740c660a9411 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -1509,7 +1509,7 @@ dm9000_probe(struct platform_device *pdev)
}
db->irq_wake = platform_get_irq_optional(pdev, 1);
- if (db->irq_wake >= 0) {
+ if (db->irq_wake > 0) {
dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index d71eac7e1924..158676eda48d 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -620,7 +620,7 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx)
/* Failure to get an irq is not fatal,
* only the PTP_CLOCK_PPS clock events should stop
*/
- if (irq >= 0) {
+ if (irq > 0) {
ret = devm_request_irq(&pdev->dev, irq, fec_pps_interrupt,
0, pdev->name, ndev);
if (ret < 0)
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index 9de617ca9daa..4914d6aca208 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -439,7 +439,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
u32 val;
int ret;
- if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) {
+ if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq > 0) {
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq,
IRQF_SHARED, dev_name(channel->dev), channel);
@@ -486,7 +486,7 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
val &= ~USB2_INT_ENABLE_UCOM_INTEN;
writel(val, usb2_base + USB2_INT_ENABLE);
- if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel))
+ if (channel->irq > 0 && !rcar_gen3_is_any_rphy_initialized(channel))
free_irq(channel->irq, channel);
return 0;
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index d6306d2a096f..91686d306534 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -400,7 +400,7 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
irq = platform_get_irq_optional(pdev, 0);
if (irq > 0)
ec_dev->irq = irq;
- else if (irq != -ENXIO) {
+ else if (irq < 0) {
dev_err(dev, "couldn't retrieve IRQ number (%d)\n", irq);
return irq;
}
diff --git a/drivers/platform/x86/intel/punit_ipc.c b/drivers/platform/x86/intel/punit_ipc.c
index 66bb39fd0ef9..f3cf5ee1466f 100644
--- a/drivers/platform/x86/intel/punit_ipc.c
+++ b/drivers/platform/x86/intel/punit_ipc.c
@@ -278,7 +278,7 @@ static int intel_punit_ipc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, punit_ipcdev);
irq = platform_get_irq_optional(pdev, 0);
- if (irq < 0) {
+ if (irq <= 0) {
dev_warn(&pdev->dev, "Invalid IRQ, using polling mode\n");
} else {
ret = devm_request_irq(&pdev->dev, irq, intel_punit_ioc,
diff --git a/drivers/power/supply/mp2629_charger.c b/drivers/power/supply/mp2629_charger.c
index bdf924b73e47..51289700a7ac 100644
--- a/drivers/power/supply/mp2629_charger.c
+++ b/drivers/power/supply/mp2629_charger.c
@@ -581,9 +581,9 @@ static int mp2629_charger_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, charger);
irq = platform_get_irq_optional(to_platform_device(dev->parent), 0);
- if (irq < 0) {
+ if (irq <= 0) {
dev_err(dev, "get irq fail: %d\n", irq);
- return irq;
+ return irq < 0 ? irq : -ENXIO;
}
for (i = 0; i < MP2629_MAX_FIELD; i++) {
diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c
index d3a23b1c2a4c..476ddc081c60 100644
--- a/drivers/spi/spi-hisi-sfc-v3xx.c
+++ b/drivers/spi/spi-hisi-sfc-v3xx.c
@@ -467,7 +467,7 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
dev_err(dev, "failed to request irq%d, ret = %d\n", host->irq, ret);
host->irq = 0;
}
- } else {
+ } else if (host->irq < 0) {
host->irq = 0;
}
diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 5c93730615f8..2422b0545936 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -829,8 +829,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
mtk_nor_init(sp);
irq = platform_get_irq_optional(pdev, 0);
-
- if (irq < 0) {
+ if (irq <= 0) {
dev_warn(sp->dev, "IRQ not available.");
} else {
ret = devm_request_irq(sp->dev, irq, mtk_nor_irq_handler, 0,
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
index 43eb25b167bc..776cfed4339c 100644
--- a/drivers/thermal/rcar_gen3_thermal.c
+++ b/drivers/thermal/rcar_gen3_thermal.c
@@ -430,7 +430,7 @@ static int rcar_gen3_thermal_request_irqs(struct rcar_gen3_thermal_priv *priv,
for (i = 0; i < 2; i++) {
irq = platform_get_irq_optional(pdev, i);
- if (irq < 0)
+ if (irq <= 0)
return irq;
irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d",
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index fb65dc601b23..328ab074fd89 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -621,7 +621,7 @@ static int __maybe_unused mtk8250_suspend(struct device *dev)
serial8250_suspend_port(data->line);
pinctrl_pm_select_sleep_state(dev);
- if (irq >= 0) {
+ if (irq > 0) {
err = enable_irq_wake(irq);
if (err) {
dev_err(dev,
@@ -641,7 +641,7 @@ static int __maybe_unused mtk8250_resume(struct device *dev)
struct mtk8250_data *data = dev_get_drvdata(dev);
int irq = data->rx_wakeup_irq;
- if (irq >= 0)
+ if (irq > 0)
disable_irq_wake(irq);
pinctrl_pm_select_default_state(dev);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 89ee43061d3a..a67f8e532a73 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1926,7 +1926,7 @@ static int sci_request_irq(struct sci_port *port)
* Certain port types won't support all of the
* available interrupt sources.
*/
- if (unlikely(irq < 0))
+ if (unlikely(irq <= 0))
continue;
}
@@ -1974,7 +1974,7 @@ static void sci_free_irq(struct sci_port *port)
* Certain port types won't support all of the available
* interrupt sources.
*/
- if (unlikely(irq < 0))
+ if (unlikely(irq <= 0))
continue;
/* Check if already freed (irq was muxed) */
@@ -2901,7 +2901,7 @@ static int sci_init_single(struct platform_device *dev,
if (sci_port->irqs[0] < 0)
return -ENXIO;
- if (sci_port->irqs[1] < 0)
+ if (sci_port->irqs[1] <= 0)
for (i = 1; i < ARRAY_SIZE(sci_port->irqs); i++)
sci_port->irqs[i] = sci_port->irqs[0];
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index 63258b6accc4..7fd275fc6ceb 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -162,7 +162,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
if (!uioinfo->irq) {
ret = platform_get_irq_optional(pdev, 0);
uioinfo->irq = ret;
- if (ret == -ENXIO)
+ if (!ret)
uioinfo->irq = UIO_IRQ_NONE;
else if (ret == -EPROBE_DEFER)
return ret;
diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c
index 68a1c87066d7..cd7494933563 100644
--- a/drivers/vfio/platform/vfio_platform.c
+++ b/drivers/vfio/platform/vfio_platform.c
@@ -32,8 +32,12 @@ static struct resource *get_platform_resource(struct vfio_platform_device *vdev,
static int get_platform_irq(struct vfio_platform_device *vdev, int i)
{
struct platform_device *pdev = (struct platform_device *) vdev->opaque;
+ int ret;
- return platform_get_irq_optional(pdev, i);
+ ret = platform_get_irq_optional(pdev, i);
+ if (ret < 0)
+ return ret;
+ return ret > 0 ? ret : -ENXIO;
}
static int vfio_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 5cb58929090d..ff19c5130459 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -643,7 +643,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
irq = platform_get_irq_optional(pdev, 0);
- if (irq >= 0) {
+ if (irq > 0) {
ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0,
pdev->name, dev);
if (ret < 0) {
@@ -697,7 +697,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
}
if (!pdata) {
- if (irq >= 0) {
+ if (irq > 0) {
ret = dw_pcm_register(pdev);
dev->use_pio = true;
} else {
--
2.26.3
12
85

19 Jan '22
Check for negative values of "priv->gain" to prevent an out of bounds
access. The concern is that these might come from the user via:
-> snd_ctl_elem_write_user()
-> snd_ctl_elem_write()
-> kctl->put()
Fixes: fa8d915172b8 ("ASoC: max9759: Add Amplifier Driver")
Signed-off-by: Dan Carpenter <dan.carpenter(a)oracle.com>
---
>From static analysis. Not tested.
This patch is obviously harmless but I sometimes get confused about
these sound get()/put() functions. I have some code in Smatch which is
supposed to manually suppress warnings from snd_ctl_elem_write() but it
was four years old and has bitrotted so that's how I got this warning.
So I remember these as being false positives where Smatch gets confused
but when I searched my mailbox I just see similar patches which were
applied.
sound/soc/codecs/max9759.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/max9759.c b/sound/soc/codecs/max9759.c
index d75fd61b9032..bc57d7687f16 100644
--- a/sound/soc/codecs/max9759.c
+++ b/sound/soc/codecs/max9759.c
@@ -64,7 +64,8 @@ static int speaker_gain_control_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
struct max9759 *priv = snd_soc_component_get_drvdata(c);
- if (ucontrol->value.integer.value[0] > 3)
+ if (ucontrol->value.integer.value[0] < 0 ||
+ ucontrol->value.integer.value[0] > 3)
return -EINVAL;
priv->gain = ucontrol->value.integer.value[0];
--
2.20.1
2
1

19 Jan '22
When SND_SOC_MT8195_MT6359_RT1011_RT5682 is selected,
and GPIOLIB is not selected,
Kbuild gives the following warning:
WARNING: unmet direct dependencies detected for SND_SOC_DMIC
Depends on [n]: SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && GPIOLIB [=n]
Selected by [y]:
- SND_SOC_MT8195_MT6359_RT1011_RT5682 [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && I2C [=y] && SND_SOC_MT8195 [=y] && MTK_PMIC_WRAP [=y]
This is because SND_SOC_MT8195_MT6359_RT1011_RT5682
selects SND_SOC_DMIC without selecting or depending on
GPIOLIB, depsite SND_SOC_DMIC depending on GPIOLIB.
This unmet dependency bug was detected by Kismet,
a static analysis tool for Kconfig. Please advise
if this is not the appropriate solution.
Signed-off-by: Julian Braha <julianbraha(a)gmail.com>
---
sound/soc/mediatek/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 9306b7ca2644..0d154350f180 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -216,7 +216,7 @@ config SND_SOC_MT8195_MT6359_RT1019_RT5682
config SND_SOC_MT8195_MT6359_RT1011_RT5682
tristate "ASoC Audio driver for MT8195 with MT6359 RT1011 RT5682 codec"
- depends on I2C
+ depends on I2C && GPIOLIB
depends on SND_SOC_MT8195 && MTK_PMIC_WRAP
select SND_SOC_MT6359
select SND_SOC_RT1011
--
2.32.0
3
2
From: Daniel Baluta <daniel.baluta(a)nxp.com>
This patch series adds compress operations support. This is tested with
SOF (codec_adapter component enabled) and i.MX8/8X/8M boards.
Changes since v1:
(https://lore.kernel.org/lkml/20220113161341.371345-1-daniel.baluta@oss.nxp.…)
- Addressed review from Cezary and Pierre
- fixed layout of declaration blocks to be more consistent
- avoid using rtd and runtime simultaneously inside a function (always
used rtd and crtd)
- check return code for create_page_table
- completely remove sof_compr_stream and use snd_compr_tstmap instead to
keep compress stream related info.·
- add get_caps and get_codec_caps implementations (in patch 2)
Daniel Baluta (1):
ASoC: SOF: compr: Add compress ops implementation
Paul Olaru (1):
ASoC: SOF: compress: Implement get_caps and get_codec_caps
sound/soc/sof/compress.c | 347 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 345 insertions(+), 2 deletions(-)
--
2.27.0
3
5

[PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers
by Joerg Schambacher 19 Jan '22
by Joerg Schambacher 19 Jan '22
19 Jan '22
Adds a minimum component driver to run the amplifier in I2S master
mode only from standard audio clocks. Therefore, it only allows
44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
sample size. Digital volume control and the -6dB and +0.8dB switches
are supported.
Signed-off-by: Joerg Schambacher <joerg(a)hifiberry.com>
---
sound/soc/codecs/Kconfig | 8 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/tas5754m.c | 700 ++++++++++++++++++++++++++++++++++++
sound/soc/codecs/tas5754m.h | 260 ++++++++++++++
4 files changed, 970 insertions(+)
create mode 100644 sound/soc/codecs/tas5754m.c
create mode 100644 sound/soc/codecs/tas5754m.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..cf0584948fcf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -210,6 +210,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TAS5086
imply SND_SOC_TAS571X
imply SND_SOC_TAS5720
+ imply SND_SOC_TAS5754M
imply SND_SOC_TAS6424
imply SND_SOC_TDA7419
imply SND_SOC_TFA9879
@@ -1419,6 +1420,13 @@ config SND_SOC_TAS5720
Enable support for Texas Instruments TAS5720L/M high-efficiency mono
Class-D audio power amplifiers.
+config SND_SOC_TAS5754M
+ tristate "Texas Instruments TAS5754M Digital Input Audio amplifier"
+ depends on I2C
+ help
+ Enable support for Texas Instruments TAS5754M digital input
+ Class-D audio power amplifiers.
+
config SND_SOC_TAS6424
tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..39984900258a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -227,6 +227,7 @@ snd-soc-sti-sas-objs := sti-sas.o
snd-soc-tas5086-objs := tas5086.o
snd-soc-tas571x-objs := tas571x.o
snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas5754m-objs := tas5754m.o
snd-soc-tas6424-objs := tas6424.o
snd-soc-tda7419-objs := tda7419.o
snd-soc-tas2770-objs := tas2770.o
@@ -555,6 +556,7 @@ obj-$(CONFIG_SND_SOC_TAS2764) += snd-soc-tas2764.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS5754M) += snd-soc-tas5754m.o
obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o
obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o
obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
diff --git a/sound/soc/codecs/tas5754m.c b/sound/soc/codecs/tas5754m.c
new file mode 100644
index 000000000000..7aab9d29c46d
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.c
@@ -0,0 +1,700 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the TAS5754M Audio Amplifier
+ *
+ * Author: Joerg Schambacher <joerg(a)hifiberry.com>
+ * with fragments from Andy Liu <andy-liu(a)ti.com>
+ *
+ * The driver supports I2S master mode only with standard audio
+ * frequencies 44.1 to 192 ksps from a 24.576/22.2592MHz master
+ * clock input
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "tas5754m.h"
+
+#define TAS5754M_RATES (SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_192000 | \
+ SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_176400)
+#define TAS5754M_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct reg_default tas5754m_reg_defaults[] = {
+ { TAS5754M_RESET, 0x00 },
+ { TAS5754M_POWER, 0x00 },
+ { TAS5754M_MUTE, 0x00 },
+ { TAS5754M_DSP, 0x00 },
+ { TAS5754M_PLL_REF, 0x00 },
+ { TAS5754M_DAC_REF, 0x00 },
+ { TAS5754M_DAC_ROUTING, 0x11 },
+ { TAS5754M_DSP_PROGRAM, 0x01 },
+ { TAS5754M_CLKDET, 0x00 },
+ { TAS5754M_AUTO_MUTE, 0x00 },
+ { TAS5754M_ERROR_DETECT, 0x00 },
+ { TAS5754M_DIGITAL_VOLUME_1, 0x00 },
+ { TAS5754M_DIGITAL_VOLUME_2, 0x30 },
+ { TAS5754M_DIGITAL_VOLUME_3, 0x30 },
+ { TAS5754M_DIGITAL_MUTE_1, 0x22 },
+ { TAS5754M_DIGITAL_MUTE_2, 0x00 },
+ { TAS5754M_DIGITAL_MUTE_3, 0x07 },
+ { TAS5754M_OUTPUT_AMPLITUDE, 0x00 },
+ { TAS5754M_ANALOG_GAIN_CTRL, 0x00 },
+ { TAS5754M_UNDERVOLTAGE_PROT, 0x00 },
+ { TAS5754M_ANALOG_MUTE_CTRL, 0x00 },
+ { TAS5754M_ANALOG_GAIN_BOOST, 0x00 },
+ { TAS5754M_VCOM_CTRL_1, 0x00 },
+ { TAS5754M_VCOM_CTRL_2, 0x01 },
+ { TAS5754M_BCLK_LRCLK_CFG, 0x00 },
+ { TAS5754M_MASTER_MODE, 0x7c },
+ { TAS5754M_GPIO_PLLIN, 0x00 },
+ { TAS5754M_SYNCHRONIZE, 0x10 },
+ { TAS5754M_PLL_COEFF_P, 0x00 },
+ { TAS5754M_PLL_COEFF_J, 0x00 },
+ { TAS5754M_PLL_COEFF_DH, 0x00 },
+ { TAS5754M_PLL_COEFF_DL, 0x00 },
+ { TAS5754M_PLL_COEFF_R, 0x00 },
+ { TAS5754M_DSP_CLKDIV, 0x00 },
+ { TAS5754M_DAC_CLKDIV, 0x00 },
+ { TAS5754M_NCP_CLKDIV, 0x00 },
+ { TAS5754M_OSR_CLKDIV, 0x00 },
+ { TAS5754M_MASTER_SCLKDIV, 0x00 },
+ { TAS5754M_MASTER_LRCLKDIV, 0x00 },
+ { TAS5754M_FS_SPEED_MODE, 0x00 },
+ { TAS5754M_IDAC_1, 0x01 },
+ { TAS5754M_IDAC_2, 0x00 },
+};
+
+static bool tas5754m_readable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TAS5754M_RESET:
+ case TAS5754M_POWER:
+ case TAS5754M_MUTE:
+ case TAS5754M_PLL_EN:
+ case TAS5754M_DSP:
+ case TAS5754M_GPIO_EN:
+ case TAS5754M_BCLK_LRCLK_CFG:
+ case TAS5754M_DSP_GPIO_INPUT:
+ case TAS5754M_MASTER_MODE:
+ case TAS5754M_PLL_REF:
+ case TAS5754M_DAC_REF:
+ case TAS5754M_GPIO_PLLIN:
+ case TAS5754M_SYNCHRONIZE:
+ case TAS5754M_PLL_COEFF_P:
+ case TAS5754M_PLL_COEFF_J:
+ case TAS5754M_PLL_COEFF_DH:
+ case TAS5754M_PLL_COEFF_DL:
+ case TAS5754M_PLL_COEFF_R:
+ case TAS5754M_DSP_CLKDIV:
+ case TAS5754M_DAC_CLKDIV:
+ case TAS5754M_NCP_CLKDIV:
+ case TAS5754M_OSR_CLKDIV:
+ case TAS5754M_MASTER_SCLKDIV:
+ case TAS5754M_MASTER_LRCLKDIV:
+ case TAS5754M_FS_SPEED_MODE:
+ case TAS5754M_IDAC_1:
+ case TAS5754M_IDAC_2:
+ case TAS5754M_ERROR_DETECT:
+ case TAS5754M_I2S_1:
+ case TAS5754M_I2S_2:
+ case TAS5754M_DAC_ROUTING:
+ case TAS5754M_DSP_PROGRAM:
+ case TAS5754M_CLKDET:
+ case TAS5754M_AUTO_MUTE:
+ case TAS5754M_DIGITAL_VOLUME_1:
+ case TAS5754M_DIGITAL_VOLUME_2:
+ case TAS5754M_DIGITAL_VOLUME_3:
+ case TAS5754M_DIGITAL_MUTE_1:
+ case TAS5754M_DIGITAL_MUTE_2:
+ case TAS5754M_DIGITAL_MUTE_3:
+ case TAS5754M_GPIO_OUTPUT_0:
+ case TAS5754M_GPIO_OUTPUT_1:
+ case TAS5754M_GPIO_OUTPUT_2:
+ case TAS5754M_GPIO_CONTROL_1:
+ case TAS5754M_GPIO_CONTROL_2:
+ case TAS5754M_OVERFLOW:
+ case TAS5754M_RATE_DET_1:
+ case TAS5754M_RATE_DET_2:
+ case TAS5754M_RATE_DET_3:
+ case TAS5754M_RATE_DET_4:
+ case TAS5754M_CLOCK_STATUS:
+ case TAS5754M_ANALOG_MUTE_DET:
+ case TAS5754M_GPIN:
+ case TAS5754M_DIGITAL_MUTE_DET:
+ case TAS5754M_OUTPUT_AMPLITUDE:
+ case TAS5754M_ANALOG_GAIN_CTRL:
+ case TAS5754M_UNDERVOLTAGE_PROT:
+ case TAS5754M_ANALOG_MUTE_CTRL:
+ case TAS5754M_ANALOG_GAIN_BOOST:
+ case TAS5754M_VCOM_CTRL_1:
+ case TAS5754M_VCOM_CTRL_2:
+ case TAS5754M_CRAM_CTRL:
+ case TAS5754M_FLEX_A:
+ case TAS5754M_FLEX_B:
+ return true;
+ default:
+ return reg < 0x7f;
+ }
+}
+
+static bool tas5754m_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TAS5754M_PLL_EN:
+ case TAS5754M_OVERFLOW:
+ case TAS5754M_RATE_DET_1:
+ case TAS5754M_RATE_DET_2:
+ case TAS5754M_RATE_DET_3:
+ case TAS5754M_RATE_DET_4:
+ case TAS5754M_CLOCK_STATUS:
+ case TAS5754M_ANALOG_MUTE_DET:
+ case TAS5754M_GPIN:
+ case TAS5754M_DIGITAL_MUTE_DET:
+ case TAS5754M_CRAM_CTRL:
+ return true;
+ default:
+ return reg < 0x7f;
+ }
+}
+
+struct tas5754m_priv {
+ struct regmap *regmap;
+ struct clk *sclk;
+ int sample_len;
+ int fmt;
+ int mode;
+};
+
+static const struct regmap_range_cfg tas5754m_range = {
+ .name = "Pages",
+ .range_min = TAS5754M_VIRT_BASE,
+ .range_max = TAS5754M_MAX_REGISTER,
+ .selector_reg = TAS5754M_PAGE,
+ .selector_mask = 0x7f,
+ .window_start = 0,
+ .window_len = 128,
+};
+
+const struct regmap_config tas5754m_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .ranges = &tas5754m_range,
+ .num_ranges = 1,
+ .max_register = TAS5754M_MAX_REGISTER,
+
+ .reg_defaults = tas5754m_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tas5754m_reg_defaults),
+ .readable_reg = tas5754m_readable,
+ .volatile_reg = tas5754m_volatile,
+
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const struct snd_kcontrol_new tas5754m_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", TAS5754M_DIGITAL_VOLUME_2,
+ TAS5754M_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analog Playback Volume", TAS5754M_ANALOG_GAIN_CTRL,
+ TAS5754M_LAGN_SHIFT, TAS5754M_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Analogue Playback Boost Volume", TAS5754M_ANALOG_GAIN_BOOST,
+ TAS5754M_AGBL_SHIFT, TAS5754M_AGBR_SHIFT, 1, 0, boost_tlv),
+};
+
+static int tas5754m_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ ret = regmap_update_bits(tas5754m->regmap,
+ TAS5754M_POWER, TAS5754M_RQST, 0);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to remove standby: %d\n", ret);
+ return ret;
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ ret = regmap_update_bits(tas5754m->regmap,
+ TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to request standby: %d\n", ret);
+ return ret;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+ static const struct reg_sequence pll_settings[] = {
+ { TAS5754M_PLL_COEFF_P, 0x01 }, // P=2
+ { TAS5754M_PLL_COEFF_J, 0x08 }, // J=8
+ { TAS5754M_PLL_COEFF_DL, 0x00 }, // D12-8 = 0
+ { TAS5754M_PLL_COEFF_DH, 0x00 }, // D7-0 = 0
+ { TAS5754M_PLL_COEFF_R, 0x00 }, // R=1
+ };
+ int ret;
+
+ /* disable PLL before any clock tree change */
+ ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+ TAS5754M_PLLE, 0);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
+ return ret;
+ }
+
+ /* set DAC clock source to MCLK */
+ ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set DAC ref\n");
+ return ret;
+ }
+
+ /* run PLL at fixed ratio to MCLK */
+ ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
+ ARRAY_SIZE(pll_settings));
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set PLL ratio\n");
+ return ret;
+ }
+
+ /* set DSP divider to 2 => reg 0x01 */
+ ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set DSP divider\n");
+ return ret;
+ }
+ /* set DAC divider to 4 => reg 0x03*/
+ ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set OSDACR divider\n");
+ return ret;
+ }
+ /* set OSR divider to 1 */
+ ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set OSR divider\n");
+ return ret;
+ }
+ /* set CP divider to 4 => reg 0x03*/
+ ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set CP divider\n");
+ return ret;
+ }
+ /* finally enable PLL */
+ ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+ TAS5754M_PLLE, 1);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+ int fmt = tas5754m->fmt;
+
+ /* only I2S MASTER mode implemented */
+ if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {
+ dev_err(component->dev,
+ "DAI format not supported (I2S master only)\n");
+ return -EINVAL;
+ }
+ /* TAS5754/6m do not support inverted clocks in MASTER mode */
+ if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {
+ dev_err(component->dev, "Inverted clocks not supported\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ regmap_update_bits(tas5754m->regmap,
+ TAS5754M_BCLK_LRCLK_CFG,
+ TAS5754M_LRKO | TAS5754M_BCKO,
+ TAS5754M_LRKO | TAS5754M_BCKO);
+ /* reset CLK dividers */
+ regmap_update_bits(tas5754m->regmap,
+ TAS5754M_MASTER_MODE,
+ 0x00,
+ TAS5754M_RLRK | TAS5754M_RBCK);
+ /* ignore all clock error detection but MCLK */
+ regmap_update_bits(tas5754m->regmap,
+ TAS5754M_ERROR_DETECT,
+ TAS5754M_IPLK | TAS5754M_DCAS |
+ TAS5754M_IDCM | TAS5754M_IDSK |
+ TAS5754M_IDBK | TAS5754M_IDFS,
+ TAS5754M_IPLK | TAS5754M_DCAS |
+ TAS5754M_IDCM | TAS5754M_IDSK |
+ TAS5754M_IDBK | TAS5754M_IDFS);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+ unsigned long bclk;
+ unsigned long mclk;
+ int bclk_div;
+ int lrclk_div;
+ int osr;
+ int ret;
+
+ mclk = clk_get_rate(tas5754m->sclk);
+ bclk = tas5754m->sample_len * 2 * params_rate(params);
+ bclk_div = mclk / bclk;
+ lrclk_div = tas5754m->sample_len * 2;
+ osr = mclk / 4 / params_rate(params) / 16;
+
+ // stop LR / SCLK clocks
+ ret = regmap_update_bits(tas5754m->regmap,
+ TAS5754M_MASTER_MODE,
+ !TAS5754M_RLRK | !TAS5754M_RBCK,
+ TAS5754M_RLRK | TAS5754M_RBCK);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to stop PLL\n");
+ return ret;
+ }
+
+ // set SCLK divider
+ ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
+ bclk_div - 1);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set SCLK divider\n");
+ return ret;
+ }
+
+ // set LRCLK divider
+ ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
+ lrclk_div - 1);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set LRCLK divider\n");
+ return ret;
+ }
+
+ ret = regmap_write(tas5754m->regmap,
+ TAS5754M_OSR_CLKDIV, osr - 1);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set OSR divider\n");
+ return ret;
+ }
+
+ // restart LR / SCLK clocks
+ ret = regmap_update_bits(tas5754m->regmap,
+ TAS5754M_MASTER_MODE,
+ TAS5754M_RLRK | TAS5754M_RBCK,
+ TAS5754M_RLRK | TAS5754M_RBCK);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to restart PLL\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tas5754m_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+ int alen;
+ int ret;
+
+ switch (params_width(params)) {
+ case 16:
+ tas5754m->sample_len = 16;
+ alen = TAS5754M_ALEN_16;
+ break;
+ case 20:
+ tas5754m->sample_len = 32;
+ alen = TAS5754M_ALEN_20;
+ break;
+ case 24:
+ tas5754m->sample_len = 32;
+ alen = TAS5754M_ALEN_24;
+ break;
+ case 32:
+ tas5754m->sample_len = 32;
+ alen = TAS5754M_ALEN_32;
+ break;
+ default:
+ dev_err(component->dev, "Unsupported sample size: %d\n",
+ params_width(params));
+ return -EINVAL;
+ }
+ ret = regmap_update_bits(tas5754m->regmap, TAS5754M_I2S_1, alen, alen);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Cannot set sample size: %d\n", ret);
+ return ret;
+ }
+
+ ret = tas5754m_set_dai_mode(dai);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "DAI mode not supported: %d\n", ret);
+ return ret;
+ }
+
+ ret = tas5754m_set_clock_tree_master(dai, params);
+ if (ret != 0)
+ return ret;
+
+ switch (params_rate(params)) {
+ case 44100:
+ case 48000:
+ ret = regmap_write(tas5754m->regmap,
+ TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_48KHZ);
+ break;
+ case 88200:
+ case 96000:
+ ret = regmap_write(tas5754m->regmap,
+ TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_96KHZ);
+ break;
+ case 176400:
+ case 192000:
+ ret = regmap_write(tas5754m->regmap,
+ TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_192KHZ);
+ break;
+ default:
+ dev_err(component->dev, "Sample rate not supported: %d\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to config PLL\n");
+ return ret;
+ }
+
+ ret = tas5754m_set_dividers_master(dai, params);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+static int tas5754m_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas5754m_priv *tas5754m =
+ snd_soc_component_get_drvdata(component);
+
+ tas5754m->fmt = fmt;
+
+ return 0;
+}
+
+
+static const struct snd_soc_component_driver tas5754m_soc_component = {
+ .set_bias_level = tas5754m_set_bias_level,
+ .idle_bias_on = true,
+ .controls = tas5754m_controls,
+ .num_controls = ARRAY_SIZE(tas5754m_controls),
+};
+
+static int tas5754m_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *component = dai->component;
+
+ if (mute) {
+ snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
+ } else {
+ /* wait for stable operation before unmute */
+ usleep_range(1000, 2000);
+ snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
+ }
+ return 0;
+}
+
+static const struct snd_soc_dai_ops tas5754m_dai_ops = {
+ .mute_stream = tas5754m_mute,
+ .hw_params = tas5754m_hw_params,
+ .set_fmt = tas5754m_set_fmt,
+};
+
+static struct snd_soc_dai_driver tas5754m_dai = {
+ .name = "tas5754m-amplifier",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = TAS5754M_RATES,
+ .formats = TAS5754M_FORMATS,
+ },
+ .ops = &tas5754m_dai_ops,
+};
+
+static int tas5754m_probe(struct device *dev, struct regmap *regmap)
+{
+ struct tas5754m_priv *tas5754m;
+ int ret;
+
+ tas5754m = devm_kzalloc(dev, sizeof(struct tas5754m_priv), GFP_KERNEL);
+ if (!tas5754m)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, tas5754m);
+ tas5754m->regmap = regmap;
+
+ regmap_write(regmap, TAS5754M_RESET, TAS5754M_RSTR | TAS5754M_RSTM);
+
+ if (ret != 0) {
+ dev_err(dev, "Failed to initialize TAS5754M: %d\n", ret);
+ goto err;
+ }
+
+ tas5754m->sclk = devm_clk_get(dev, NULL);
+ if (PTR_ERR(tas5754m->sclk) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+ if (!IS_ERR(tas5754m->sclk)) {
+ ret = clk_prepare_enable(tas5754m->sclk);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+ goto err;
+ }
+ }
+
+ ret = devm_snd_soc_register_component(dev,
+ &tas5754m_soc_component, &tas5754m_dai, 1);
+ if (ret != 0) {
+ dev_err(dev, "Failed to register CODEC: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ return ret;
+
+}
+
+static int tas5754m_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ struct regmap_config config = tas5754m_regmap;
+
+ /* enable auto-increment mode */
+ config.read_flag_mask = 0x80;
+ config.write_flag_mask = 0x80;
+
+ regmap = devm_regmap_init_i2c(i2c, &config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return tas5754m_probe(&i2c->dev, regmap);
+}
+
+static int tas5754m_remove(struct device *dev)
+{
+ snd_soc_unregister_component(dev);
+
+ return 0;
+}
+
+static int tas5754m_i2c_remove(struct i2c_client *i2c)
+{
+ tas5754m_remove(&i2c->dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id tas5754m_i2c_id[] = {
+ { "tas5754m", },
+ { "tas5756m", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5754m_of_match[] = {
+ { .compatible = "ti,tas5754m", },
+ { .compatible = "ti,tas5756m", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tas5754m_of_match);
+#endif
+
+static struct i2c_driver tas5754m_i2c_driver = {
+ .probe = tas5754m_i2c_probe,
+ .remove = tas5754m_i2c_remove,
+ .id_table = tas5754m_i2c_id,
+ .driver = {
+ .name = "tas5754m",
+ .of_match_table = of_match_ptr(tas5754m_of_match),
+ },
+};
+
+module_i2c_driver(tas5754m_i2c_driver);
+
+MODULE_AUTHOR("Joerg Schambacher <joerg(a)hifiberry.com>");
+MODULE_DESCRIPTION("TAS5754M Audio Amplifier Driver - Master mode only");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5754m.h b/sound/soc/codecs/tas5754m.h
new file mode 100644
index 000000000000..c6e26dba169f
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.h
@@ -0,0 +1,260 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Driver for the TAS575xM DAC+amplifier combo devices
+ *
+ * Author: (copied from pcm512x.h)
+ * Mark Brown <broonie(a)kernel.org>
+ * Copyright 2014 Linaro Ltd
+ *
+ * Register names adapted and non available
+ * register definitions removed according
+ + to TAS5754M specification
+ * Joerg Schambacher <joerg(a)hifiberry.com>
+ */
+
+#ifndef _SND_SOC_TAS5754M
+#define _SND_SOC_TAS5754M
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define TAS5754M_VIRT_BASE 0x000
+#define TAS5754M_PAGE_LEN 0x80
+#define TAS5754M_PAGE_BASE(n) (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
+
+#define TAS5754M_PAGE 0
+
+#define TAS5754M_RESET (TAS5754M_PAGE_BASE(0) + 1)
+#define TAS5754M_POWER (TAS5754M_PAGE_BASE(0) + 2)
+#define TAS5754M_MUTE (TAS5754M_PAGE_BASE(0) + 3)
+#define TAS5754M_PLL_EN (TAS5754M_PAGE_BASE(0) + 4)
+#define TAS5754M_DSP (TAS5754M_PAGE_BASE(0) + 7)
+#define TAS5754M_GPIO_EN (TAS5754M_PAGE_BASE(0) + 8)
+#define TAS5754M_BCLK_LRCLK_CFG (TAS5754M_PAGE_BASE(0) + 9)
+#define TAS5754M_DSP_GPIO_INPUT (TAS5754M_PAGE_BASE(0) + 10)
+#define TAS5754M_MASTER_MODE (TAS5754M_PAGE_BASE(0) + 12)
+#define TAS5754M_PLL_REF (TAS5754M_PAGE_BASE(0) + 13)
+#define TAS5754M_DAC_REF (TAS5754M_PAGE_BASE(0) + 14)
+#define TAS5754M_GPIO_PLLIN (TAS5754M_PAGE_BASE(0) + 18)
+#define TAS5754M_SYNCHRONIZE (TAS5754M_PAGE_BASE(0) + 19)
+#define TAS5754M_PLL_COEFF_P (TAS5754M_PAGE_BASE(0) + 20)
+#define TAS5754M_PLL_COEFF_J (TAS5754M_PAGE_BASE(0) + 21)
+#define TAS5754M_PLL_COEFF_DH (TAS5754M_PAGE_BASE(0) + 22)
+#define TAS5754M_PLL_COEFF_DL (TAS5754M_PAGE_BASE(0) + 23)
+#define TAS5754M_PLL_COEFF_R (TAS5754M_PAGE_BASE(0) + 24)
+#define TAS5754M_DSP_CLKDIV (TAS5754M_PAGE_BASE(0) + 27)
+#define TAS5754M_DAC_CLKDIV (TAS5754M_PAGE_BASE(0) + 28)
+#define TAS5754M_NCP_CLKDIV (TAS5754M_PAGE_BASE(0) + 29)
+#define TAS5754M_OSR_CLKDIV (TAS5754M_PAGE_BASE(0) + 30)
+#define TAS5754M_MASTER_SCLKDIV (TAS5754M_PAGE_BASE(0) + 32)
+#define TAS5754M_MASTER_LRCLKDIV (TAS5754M_PAGE_BASE(0) + 33)
+#define TAS5754M_FS_SPEED_MODE (TAS5754M_PAGE_BASE(0) + 34)
+#define TAS5754M_IDAC_1 (TAS5754M_PAGE_BASE(0) + 35)
+#define TAS5754M_IDAC_2 (TAS5754M_PAGE_BASE(0) + 36)
+#define TAS5754M_ERROR_DETECT (TAS5754M_PAGE_BASE(0) + 37)
+#define TAS5754M_I2S_1 (TAS5754M_PAGE_BASE(0) + 40)
+#define TAS5754M_I2S_2 (TAS5754M_PAGE_BASE(0) + 41)
+#define TAS5754M_DAC_ROUTING (TAS5754M_PAGE_BASE(0) + 42)
+#define TAS5754M_DSP_PROGRAM (TAS5754M_PAGE_BASE(0) + 43)
+#define TAS5754M_CLKDET (TAS5754M_PAGE_BASE(0) + 44)
+#define TAS5754M_AUTO_MUTE (TAS5754M_PAGE_BASE(0) + 59)
+#define TAS5754M_DIGITAL_VOLUME_1 (TAS5754M_PAGE_BASE(0) + 60)
+#define TAS5754M_DIGITAL_VOLUME_2 (TAS5754M_PAGE_BASE(0) + 61)
+#define TAS5754M_DIGITAL_VOLUME_3 (TAS5754M_PAGE_BASE(0) + 62)
+#define TAS5754M_DIGITAL_MUTE_1 (TAS5754M_PAGE_BASE(0) + 63)
+#define TAS5754M_DIGITAL_MUTE_2 (TAS5754M_PAGE_BASE(0) + 64)
+#define TAS5754M_DIGITAL_MUTE_3 (TAS5754M_PAGE_BASE(0) + 65)
+#define TAS5754M_GPIO_OUTPUT_1 (TAS5754M_PAGE_BASE(0) + 82)
+#define TAS5754M_GPIO_OUTPUT_0 (TAS5754M_PAGE_BASE(0) + 83)
+#define TAS5754M_GPIO_OUTPUT_2 (TAS5754M_PAGE_BASE(0) + 85)
+#define TAS5754M_GPIO_CONTROL_1 (TAS5754M_PAGE_BASE(0) + 86)
+#define TAS5754M_GPIO_CONTROL_2 (TAS5754M_PAGE_BASE(0) + 87)
+#define TAS5754M_OVERFLOW (TAS5754M_PAGE_BASE(0) + 90)
+#define TAS5754M_RATE_DET_1 (TAS5754M_PAGE_BASE(0) + 91)
+#define TAS5754M_RATE_DET_2 (TAS5754M_PAGE_BASE(0) + 92)
+#define TAS5754M_RATE_DET_3 (TAS5754M_PAGE_BASE(0) + 93)
+#define TAS5754M_RATE_DET_4 (TAS5754M_PAGE_BASE(0) + 94)
+#define TAS5754M_CLOCK_STATUS (TAS5754M_PAGE_BASE(0) + 95)
+#define TAS5754M_ANALOG_MUTE_DET (TAS5754M_PAGE_BASE(0) + 108)
+#define TAS5754M_FS_MODE_MON (TAS5754M_PAGE_BASE(0) + 115)
+#define TAS5754M_GPIN (TAS5754M_PAGE_BASE(0) + 119)
+#define TAS5754M_DIGITAL_MUTE_DET (TAS5754M_PAGE_BASE(0) + 120)
+
+#define TAS5754M_OUTPUT_AMPLITUDE (TAS5754M_PAGE_BASE(1) + 1)
+#define TAS5754M_ANALOG_GAIN_CTRL (TAS5754M_PAGE_BASE(1) + 2)
+#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) + 5)
+#define TAS5754M_ANALOG_MUTE_CTRL (TAS5754M_PAGE_BASE(1) + 6)
+#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) + 7)
+#define TAS5754M_VCOM_CTRL_1 (TAS5754M_PAGE_BASE(1) + 8)
+#define TAS5754M_VCOM_CTRL_2 (TAS5754M_PAGE_BASE(1) + 9)
+
+#define TAS5754M_CRAM_CTRL (TAS5754M_PAGE_BASE(44) + 1)
+
+#define TAS5754M_FLEX_A (TAS5754M_PAGE_BASE(253) + 63)
+#define TAS5754M_FLEX_B (TAS5754M_PAGE_BASE(253) + 64)
+
+#define TAS5754M_MAX_REGISTER (TAS5754M_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define TAS5754M_RSTR (1 << 0)
+#define TAS5754M_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define TAS5754M_RQPD (1 << 0)
+#define TAS5754M_RQPD_SHIFT 0
+#define TAS5754M_RQST (1 << 4)
+#define TAS5754M_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define TAS5754M_RQMR (1 << 0)
+#define TAS5754M_RQMR_SHIFT 0
+#define TAS5754M_RQML (1 << 4)
+#define TAS5754M_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define TAS5754M_PLLE (1 << 0)
+#define TAS5754M_PLLE_SHIFT 0
+#define TAS5754M_PLCK (1 << 4)
+#define TAS5754M_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define TAS5754M_SDSL (1 << 0)
+#define TAS5754M_SDSL_SHIFT 0
+#define TAS5754M_DEMP (1 << 4)
+#define TAS5754M_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define TAS5754M_G1OE (1 << 0)
+#define TAS5754M_G2OE (1 << 1)
+#define TAS5754M_G3OE (1 << 2)
+#define TAS5754M_G4OE (1 << 3)
+#define TAS5754M_G5OE (1 << 4)
+#define TAS5754M_G6OE (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define TAS5754M_LRKO (1 << 0)
+#define TAS5754M_LRKO_SHIFT 0
+#define TAS5754M_BCKO (1 << 4)
+#define TAS5754M_BCKO_SHIFT 4
+#define TAS5754M_BCKP (1 << 5)
+#define TAS5754M_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define TAS5754M_RLRK (1 << 0)
+#define TAS5754M_RLRK_SHIFT 0
+#define TAS5754M_RBCK (1 << 1)
+#define TAS5754M_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define TAS5754M_SREF (7 << 4)
+#define TAS5754M_SREF_SHIFT 4
+#define TAS5754M_SREF_SCK (0 << 4)
+#define TAS5754M_SREF_BCK (1 << 4)
+#define TAS5754M_SREF_GPIO (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define TAS5754M_SDAC (7 << 4)
+#define TAS5754M_SDAC_SHIFT 4
+#define TAS5754M_SDAC_MCK (0 << 4)
+#define TAS5754M_SDAC_PLL (1 << 4)
+#define TAS5754M_SDAC_SCK (3 << 4)
+#define TAS5754M_SDAC_BCK (4 << 4)
+#define TAS5754M_SDAC_GPIO (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define TAS5754M_GREF (7 << 0)
+#define TAS5754M_GREF_SHIFT 0
+#define TAS5754M_GREF_GPIO1 (0 << 0)
+#define TAS5754M_GREF_GPIO2 (1 << 0)
+#define TAS5754M_GREF_GPIO3 (2 << 0)
+#define TAS5754M_GREF_GPIO4 (3 << 0)
+#define TAS5754M_GREF_GPIO5 (4 << 0)
+#define TAS5754M_GREF_GPIO6 (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define TAS5754M_RQSY (1 << 0)
+#define TAS5754M_RQSY_RESUME (0 << 0)
+#define TAS5754M_RQSY_HALT (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define TAS5754M_FSSP (3 << 0)
+#define TAS5754M_FSSP_SHIFT 0
+#define TAS5754M_FSSP_48KHZ (0 << 0)
+#define TAS5754M_FSSP_96KHZ (1 << 0)
+#define TAS5754M_FSSP_192KHZ (2 << 0)
+#define TAS5754M_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define TAS5754M_IPLK (1 << 0)
+#define TAS5754M_DCAS (1 << 1)
+#define TAS5754M_IDCM (1 << 2)
+#define TAS5754M_IDCH (1 << 3)
+#define TAS5754M_IDSK (1 << 4)
+#define TAS5754M_IDBK (1 << 5)
+#define TAS5754M_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define TAS5754M_ALEN (3 << 0)
+#define TAS5754M_ALEN_SHIFT 0
+#define TAS5754M_ALEN_16 (0 << 0)
+#define TAS5754M_ALEN_20 (1 << 0)
+#define TAS5754M_ALEN_24 (2 << 0)
+#define TAS5754M_ALEN_32 (3 << 0)
+#define TAS5754M_AFMT (3 << 4)
+#define TAS5754M_AFMT_SHIFT 4
+#define TAS5754M_AFMT_I2S (0 << 4)
+#define TAS5754M_AFMT_DSP (1 << 4)
+#define TAS5754M_AFMT_RTJ (2 << 4)
+#define TAS5754M_AFMT_LTJ (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define TAS5754M_AUPR_SHIFT 0
+#define TAS5754M_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define TAS5754M_ATMR_SHIFT 0
+#define TAS5754M_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define TAS5754M_VNDF_SHIFT 6
+#define TAS5754M_VNDS_SHIFT 4
+#define TAS5754M_VNUF_SHIFT 2
+#define TAS5754M_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define TAS5754M_VEDF_SHIFT 6
+#define TAS5754M_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define TAS5754M_ACTL_SHIFT 2
+#define TAS5754M_AMLE_SHIFT 1
+#define TAS5754M_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define TAS5754M_GxSL (31 << 0)
+#define TAS5754M_GxSL_SHIFT 0
+#define TAS5754M_GxSL_OFF (0 << 0)
+#define TAS5754M_GxSL_DSP (1 << 0)
+#define TAS5754M_GxSL_REG (2 << 0)
+#define TAS5754M_GxSL_AMUTB (3 << 0)
+#define TAS5754M_GxSL_AMUTL (4 << 0)
+#define TAS5754M_GxSL_AMUTR (5 << 0)
+#define TAS5754M_GxSL_CLKI (6 << 0)
+#define TAS5754M_GxSL_SDOUT (7 << 0)
+#define TAS5754M_GxSL_ANMUL (8 << 0)
+#define TAS5754M_GxSL_ANMUR (9 << 0)
+#define TAS5754M_GxSL_PLLLK (10 << 0)
+#define TAS5754M_GxSL_CPCLK (11 << 0)
+#define TAS5754M_GxSL_UV0_7 (14 << 0)
+#define TAS5754M_GxSL_UV0_3 (15 << 0)
+#define TAS5754M_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define TAS5754M_RAGN_SHIFT 0
+#define TAS5754M_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define TAS5754M_AGBR_SHIFT 0
+#define TAS5754M_AGBL_SHIFT 4
+
+#endif
--
2.25.1
3
4