Alsa-devel
Threads by month
- ----- 2025 -----
- June
- May
- 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
February 2020
- 130 participants
- 467 discussions

26 Feb '20
From: Jack Yu <jack.yu(a)realtek.com>
This is initial amplifier driver for rt1015.
Signed-off-by: Jack Yu <jack.yu(a)realtek.com>
---
.../devicetree/bindings/sound/rt1015.txt | 17 +
sound/soc/codecs/Kconfig | 6 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/rt1015.c | 1016 +++++++++++++++++
sound/soc/codecs/rt1015.h | 368 ++++++
5 files changed, 1409 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/rt1015.txt
create mode 100644 sound/soc/codecs/rt1015.c
create mode 100644 sound/soc/codecs/rt1015.h
diff --git a/Documentation/devicetree/bindings/sound/rt1015.txt b/Documentation/devicetree/bindings/sound/rt1015.txt
new file mode 100644
index 000000000000..fcfd02d8d32f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt1015.txt
@@ -0,0 +1,17 @@
+RT1015 Mono Class D Audio Amplifier
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt1015".
+
+- reg : The I2C address of the device.
+
+
+Example:
+
+rt1015: codec@28 {
+ compatible = "realtek,rt1015";
+ reg = <0x28>;
+};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index cdfd912d5f8f..d7475e06c3e6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -149,6 +149,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT286 if I2C
select SND_SOC_RT298 if I2C
select SND_SOC_RT1011 if I2C
+ select SND_SOC_RT1015 if I2C
select SND_SOC_RT1305 if I2C
select SND_SOC_RT1308 if I2C
select SND_SOC_RT5514 if I2C
@@ -956,6 +957,7 @@ config SND_SOC_RL6231
default y if SND_SOC_RT5677=y
default y if SND_SOC_RT5682=y
default y if SND_SOC_RT1011=y
+ default y if SND_SOC_RT1015=y
default y if SND_SOC_RT1305=y
default y if SND_SOC_RT1308=y
default m if SND_SOC_RT5514=m
@@ -972,6 +974,7 @@ config SND_SOC_RL6231
default m if SND_SOC_RT5677=m
default m if SND_SOC_RT5682=m
default m if SND_SOC_RT1011=m
+ default m if SND_SOC_RT1015=m
default m if SND_SOC_RT1305=m
default m if SND_SOC_RT1308=m
@@ -999,6 +1002,9 @@ config SND_SOC_RT298
config SND_SOC_RT1011
tristate
+config SND_SOC_RT1015
+ tristate
+
config SND_SOC_RT1305
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index ce285b33a806..3efe6a5797e2 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -152,6 +152,7 @@ snd-soc-rk3328-objs := rk3328_codec.o
snd-soc-rl6231-objs := rl6231.o
snd-soc-rl6347a-objs := rl6347a.o
snd-soc-rt1011-objs := rt1011.o
+snd-soc-rt1015-objs := rt1015.o
snd-soc-rt1305-objs := rt1305.o
snd-soc-rt1308-objs := rt1308.o
snd-soc-rt274-objs := rt274.o
@@ -446,6 +447,7 @@ obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o
+obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o
obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o
obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
new file mode 100644
index 000000000000..317c914cbfc9
--- /dev/null
+++ b/sound/soc/codecs/rt1015.c
@@ -0,0 +1,1016 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rt1015.c -- RT1015 ALSA SoC audio amplifier driver
+ *
+ * Copyright 2019 Realtek Semiconductor Corp.
+ * Author: Jack Yu <jack.yu(a)realtek.com>
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt1015.h"
+
+static const struct reg_sequence init_list[] = {
+ { 0x0000, 0x0000 },
+ { 0x0104, 0xA213 },
+ { 0x010E, 0x0058 },
+ { 0x0111, 0x2000 },
+ { 0x0322, 0xF7DF },
+ { 0x1302, 0x12F7 },
+ { 0x0336, 0x0010 },
+ { 0x04FC, 0x35CF },
+ { 0x0102, 0xed02 },
+};
+#define RT1015_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt1015_reg[] = {
+ { 0x0000, 0x0000 },
+ { 0x0004, 0xa000 },
+ { 0x0006, 0x0003 },
+ { 0x000a, 0x0802 },
+ { 0x000c, 0x0020 },
+ { 0x000e, 0x0000 },
+ { 0x0010, 0x0000 },
+ { 0x0012, 0x0000 },
+ { 0x0020, 0x8000 },
+ { 0x0022, 0x471b },
+ { 0x006a, 0x0000 },
+ { 0x006c, 0x4020 },
+ { 0x0076, 0x0000 },
+ { 0x0078, 0x0000 },
+ { 0x007a, 0x0000 },
+ { 0x007c, 0x10ec },
+ { 0x007d, 0x1015 },
+ { 0x00f0, 0x5000 },
+ { 0x00f2, 0x0774 },
+ { 0x00f3, 0x8400 },
+ { 0x00f4, 0x0000 },
+ { 0x0100, 0x0028 },
+ { 0x0102, 0xff02 },
+ { 0x0104, 0x8232 },
+ { 0x0106, 0x200c },
+ { 0x010c, 0x002f },
+ { 0x010e, 0xc000 },
+ { 0x0111, 0x0200 },
+ { 0x0112, 0x0400 },
+ { 0x0114, 0x0022 },
+ { 0x0116, 0x0000 },
+ { 0x0118, 0x0000 },
+ { 0x011a, 0x0123 },
+ { 0x011c, 0x4567 },
+ { 0x0300, 0xdddd },
+ { 0x0302, 0x0000 },
+ { 0x0311, 0x9330 },
+ { 0x0313, 0x0000 },
+ { 0x0314, 0x0000 },
+ { 0x031a, 0x00a0 },
+ { 0x031c, 0x001f },
+ { 0x031d, 0xffff },
+ { 0x031e, 0x0000 },
+ { 0x031f, 0x0000 },
+ { 0x0321, 0x0000 },
+ { 0x0322, 0x0000 },
+ { 0x0328, 0x0000 },
+ { 0x0329, 0x0000 },
+ { 0x032a, 0x0000 },
+ { 0x032b, 0x0000 },
+ { 0x032c, 0x0000 },
+ { 0x032d, 0x0000 },
+ { 0x032e, 0x030e },
+ { 0x0330, 0x0080 },
+ { 0x0332, 0x0034 },
+ { 0x0334, 0x0000 },
+ { 0x0336, 0x0000 },
+ { 0x0506, 0x04ff },
+ { 0x0508, 0x0030 },
+ { 0x050a, 0x0018 },
+ { 0x0519, 0x307f },
+ { 0x051a, 0xffff },
+ { 0x051b, 0x4000 },
+ { 0x051d, 0x0000 },
+ { 0x051f, 0x0000 },
+ { 0x0536, 0x1000 },
+ { 0x0538, 0x0000 },
+ { 0x053a, 0x0000 },
+ { 0x053c, 0x0000 },
+ { 0x053d, 0x0000 },
+ { 0x053e, 0x0000 },
+ { 0x053f, 0x0000 },
+ { 0x0540, 0x0000 },
+ { 0x0541, 0x0000 },
+ { 0x0542, 0x0000 },
+ { 0x0543, 0x0000 },
+ { 0x0544, 0x0000 },
+ { 0x0568, 0x0000 },
+ { 0x056a, 0x0000 },
+ { 0x1000, 0x0000 },
+ { 0x1002, 0x6505 },
+ { 0x1006, 0x5515 },
+ { 0x1007, 0x003f },
+ { 0x1009, 0x770f },
+ { 0x100a, 0x01ff },
+ { 0x100c, 0x0000 },
+ { 0x100d, 0x0003 },
+ { 0x1010, 0xa433 },
+ { 0x1020, 0x0000 },
+ { 0x1200, 0x3d02 },
+ { 0x1202, 0x0813 },
+ { 0x1204, 0x0211 },
+ { 0x1206, 0x0000 },
+ { 0x1208, 0x0000 },
+ { 0x120a, 0x0000 },
+ { 0x120c, 0x0000 },
+ { 0x120e, 0x0000 },
+ { 0x1210, 0x0000 },
+ { 0x1212, 0x0000 },
+ { 0x1300, 0x0701 },
+ { 0x1302, 0x12f9 },
+ { 0x1304, 0x3405 },
+ { 0x1305, 0x0844 },
+ { 0x1306, 0x1611 },
+ { 0x1308, 0x555e },
+ { 0x130a, 0x0000 },
+ { 0x130c, 0x2400},
+ { 0x130e, 0x7700 },
+ { 0x130f, 0x0000 },
+ { 0x1310, 0x0000 },
+ { 0x1312, 0x0000 },
+ { 0x1314, 0x0000 },
+ { 0x1316, 0x0000 },
+ { 0x1318, 0x0000 },
+ { 0x131a, 0x0000 },
+ { 0x1322, 0x0029 },
+ { 0x1323, 0x4a52 },
+ { 0x1324, 0x002c },
+ { 0x1325, 0x0b02 },
+ { 0x1326, 0x002d },
+ { 0x1327, 0x6b5a },
+ { 0x1328, 0x002e },
+ { 0x1329, 0xcbb2 },
+ { 0x132a, 0x0030 },
+ { 0x132b, 0x2c0b },
+ { 0x1330, 0x0031 },
+ { 0x1331, 0x8c63 },
+ { 0x1332, 0x0032 },
+ { 0x1333, 0xecbb },
+ { 0x1334, 0x0034 },
+ { 0x1335, 0x4d13 },
+ { 0x1336, 0x0037 },
+ { 0x1337, 0x0dc3 },
+ { 0x1338, 0x003d },
+ { 0x1339, 0xef7b },
+ { 0x133a, 0x0044 },
+ { 0x133b, 0xd134 },
+ { 0x133c, 0x0047 },
+ { 0x133d, 0x91e4 },
+ { 0x133e, 0x004d },
+ { 0x133f, 0xc370 },
+ { 0x1340, 0x0053 },
+ { 0x1341, 0xf4fd },
+ { 0x1342, 0x0060 },
+ { 0x1343, 0x5816 },
+ { 0x1344, 0x006c },
+ { 0x1345, 0xbb2e },
+ { 0x1346, 0x0072 },
+ { 0x1347, 0xecbb },
+ { 0x1348, 0x0076 },
+ { 0x1349, 0x5d97 },
+};
+
+static int rt1015_reg_init(struct snd_soc_component *component)
+{
+ struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+
+ regmap_multi_reg_write(rt1015->regmap, init_list, RT1015_INIT_REG_LEN);
+ return 0;
+}
+
+static bool rt1015_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT1015_RESET:
+ case RT1015_CLK_DET:
+ case RT1015_SIL_DET:
+ case RT1015_VER_ID:
+ case RT1015_VENDOR_ID:
+ case RT1015_DEVICE_ID:
+ case RT1015_PRO_ALT:
+ case RT1015_DAC3:
+ case RT1015_VBAT_TEST_OUT1:
+ case RT1015_VBAT_TEST_OUT2:
+ case RT1015_VBAT_PROT_ATT:
+ case RT1015_VBAT_DET_CODE:
+ case RT1015_SMART_BST_CTRL1:
+ case RT1015_SPK_DC_DETECT1:
+ case RT1015_SPK_DC_DETECT4:
+ case RT1015_SPK_DC_DETECT5:
+ case RT1015_DC_CALIB_CLSD1:
+ case RT1015_DC_CALIB_CLSD5:
+ case RT1015_DC_CALIB_CLSD6:
+ case RT1015_DC_CALIB_CLSD7:
+ case RT1015_DC_CALIB_CLSD8:
+ case RT1015_S_BST_TIMING_INTER1:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool rt1015_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT1015_RESET:
+ case RT1015_CLK2:
+ case RT1015_CLK3:
+ case RT1015_PLL1:
+ case RT1015_PLL2:
+ case RT1015_CLK_DET:
+ case RT1015_SIL_DET:
+ case RT1015_CUSTOMER_ID:
+ case RT1015_PCODE_FWVER:
+ case RT1015_VER_ID:
+ case RT1015_VENDOR_ID:
+ case RT1015_DEVICE_ID:
+ case RT1015_PAD_DRV1:
+ case RT1015_PAD_DRV2:
+ case RT1015_GAT_BOOST:
+ case RT1015_PRO_ALT:
+ case RT1015_MAN_I2C:
+ case RT1015_DAC1:
+ case RT1015_DAC2:
+ case RT1015_DAC3:
+ case RT1015_ADC1:
+ case RT1015_ADC2:
+ case RT1015_TDM_MASTER:
+ case RT1015_TDM_TCON:
+ case RT1015_TDM1_1:
+ case RT1015_TDM1_2:
+ case RT1015_TDM1_3:
+ case RT1015_TDM1_4:
+ case RT1015_TDM1_5:
+ case RT1015_MIXER1:
+ case RT1015_MIXER2:
+ case RT1015_ANA_PROTECT1:
+ case RT1015_ANA_CTRL_SEQ1:
+ case RT1015_ANA_CTRL_SEQ2:
+ case RT1015_VBAT_DET_DEB:
+ case RT1015_VBAT_VOLT_DET1:
+ case RT1015_VBAT_VOLT_DET2:
+ case RT1015_VBAT_TEST_OUT1:
+ case RT1015_VBAT_TEST_OUT2:
+ case RT1015_VBAT_PROT_ATT:
+ case RT1015_VBAT_DET_CODE:
+ case RT1015_PWR1:
+ case RT1015_PWR4:
+ case RT1015_PWR5:
+ case RT1015_PWR6:
+ case RT1015_PWR7:
+ case RT1015_PWR8:
+ case RT1015_PWR9:
+ case RT1015_CLASSD_SEQ:
+ case RT1015_SMART_BST_CTRL1:
+ case RT1015_SMART_BST_CTRL2:
+ case RT1015_ANA_CTRL1:
+ case RT1015_ANA_CTRL2:
+ case RT1015_SPK_VOL:
+ case RT1015_SHORT_DETTOP1:
+ case RT1015_SHORT_DETTOP2:
+ case RT1015_SPK_DC_DETECT1:
+ case RT1015_SPK_DC_DETECT2:
+ case RT1015_SPK_DC_DETECT3:
+ case RT1015_SPK_DC_DETECT4:
+ case RT1015_SPK_DC_DETECT5:
+ case RT1015_BAT_RPO_STEP1:
+ case RT1015_BAT_RPO_STEP2:
+ case RT1015_BAT_RPO_STEP3:
+ case RT1015_BAT_RPO_STEP4:
+ case RT1015_BAT_RPO_STEP5:
+ case RT1015_BAT_RPO_STEP6:
+ case RT1015_BAT_RPO_STEP7:
+ case RT1015_BAT_RPO_STEP8:
+ case RT1015_BAT_RPO_STEP9:
+ case RT1015_BAT_RPO_STEP10:
+ case RT1015_BAT_RPO_STEP11:
+ case RT1015_BAT_RPO_STEP12:
+ case RT1015_SPREAD_SPEC1:
+ case RT1015_SPREAD_SPEC2:
+ case RT1015_PAD_STATUS:
+ case RT1015_PADS_PULLING_CTRL1:
+ case RT1015_PADS_DRIVING:
+ case RT1015_SYS_RST1:
+ case RT1015_SYS_RST2:
+ case RT1015_SYS_GATING1:
+ case RT1015_TEST_MODE1:
+ case RT1015_TEST_MODE2:
+ case RT1015_TIMING_CTRL1:
+ case RT1015_PLL_INT:
+ case RT1015_TEST_OUT1:
+ case RT1015_DC_CALIB_CLSD1:
+ case RT1015_DC_CALIB_CLSD2:
+ case RT1015_DC_CALIB_CLSD3:
+ case RT1015_DC_CALIB_CLSD4:
+ case RT1015_DC_CALIB_CLSD5:
+ case RT1015_DC_CALIB_CLSD6:
+ case RT1015_DC_CALIB_CLSD7:
+ case RT1015_DC_CALIB_CLSD8:
+ case RT1015_DC_CALIB_CLSD9:
+ case RT1015_DC_CALIB_CLSD10:
+ case RT1015_CLSD_INTERNAL1:
+ case RT1015_CLSD_INTERNAL2:
+ case RT1015_CLSD_INTERNAL3:
+ case RT1015_CLSD_INTERNAL4:
+ case RT1015_CLSD_INTERNAL5:
+ case RT1015_CLSD_INTERNAL6:
+ case RT1015_CLSD_INTERNAL7:
+ case RT1015_CLSD_INTERNAL8:
+ case RT1015_CLSD_INTERNAL9:
+ case RT1015_CLSD_OCP_CTRL:
+ case RT1015_VREF_LV:
+ case RT1015_MBIAS1:
+ case RT1015_MBIAS2:
+ case RT1015_MBIAS3:
+ case RT1015_MBIAS4:
+ case RT1015_VREF_LV1:
+ case RT1015_S_BST_TIMING_INTER1:
+ case RT1015_S_BST_TIMING_INTER2:
+ case RT1015_S_BST_TIMING_INTER3:
+ case RT1015_S_BST_TIMING_INTER4:
+ case RT1015_S_BST_TIMING_INTER5:
+ case RT1015_S_BST_TIMING_INTER6:
+ case RT1015_S_BST_TIMING_INTER7:
+ case RT1015_S_BST_TIMING_INTER8:
+ case RT1015_S_BST_TIMING_INTER9:
+ case RT1015_S_BST_TIMING_INTER10:
+ case RT1015_S_BST_TIMING_INTER11:
+ case RT1015_S_BST_TIMING_INTER12:
+ case RT1015_S_BST_TIMING_INTER13:
+ case RT1015_S_BST_TIMING_INTER14:
+ case RT1015_S_BST_TIMING_INTER15:
+ case RT1015_S_BST_TIMING_INTER16:
+ case RT1015_S_BST_TIMING_INTER17:
+ case RT1015_S_BST_TIMING_INTER18:
+ case RT1015_S_BST_TIMING_INTER19:
+ case RT1015_S_BST_TIMING_INTER20:
+ case RT1015_S_BST_TIMING_INTER21:
+ case RT1015_S_BST_TIMING_INTER22:
+ case RT1015_S_BST_TIMING_INTER23:
+ case RT1015_S_BST_TIMING_INTER24:
+ case RT1015_S_BST_TIMING_INTER25:
+ case RT1015_S_BST_TIMING_INTER26:
+ case RT1015_S_BST_TIMING_INTER27:
+ case RT1015_S_BST_TIMING_INTER28:
+ case RT1015_S_BST_TIMING_INTER29:
+ case RT1015_S_BST_TIMING_INTER30:
+ case RT1015_S_BST_TIMING_INTER31:
+ case RT1015_S_BST_TIMING_INTER32:
+ case RT1015_S_BST_TIMING_INTER33:
+ case RT1015_S_BST_TIMING_INTER34:
+ case RT1015_S_BST_TIMING_INTER35:
+ case RT1015_S_BST_TIMING_INTER36:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9525, 75, 0);
+
+static const char * const rt1015_din_source_select[] = {
+ "Left",
+ "Right",
+ "Left + Right average",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1015_mono_lr_sel, RT1015_PAD_DRV2, 4,
+ rt1015_din_source_select);
+
+static const char * const rt1015_boost_mode[] = {
+ "Bypass", "Adaptive", "Fixed Adaptive"
+};
+
+static const SOC_ENUM_SINGLE_DECL(rt1015_boost_mode_enum, 0, 0,
+ rt1015_boost_mode);
+
+static int rt1015_boost_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rt1015_priv *rt1015 =
+ snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = rt1015->boost_mode;
+
+ return 0;
+}
+
+static int rt1015_boost_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rt1015_priv *rt1015 =
+ snd_soc_component_get_drvdata(component);
+
+ rt1015->boost_mode = ucontrol->value.integer.value[0];
+ if (rt1015->boost_mode == 0) {
+ /* Bypass */
+ snd_soc_component_update_bits(component,
+ RT1015_SMART_BST_CTRL1, RT1015_ABST_AUTO_EN_MASK |
+ RT1015_ABST_FIX_TGT_MASK | RT1015_BYPASS_SWR_REG_MASK,
+ RT1015_ABST_REG_MODE | RT1015_ABST_FIX_TGT_DIS |
+ RT1015_BYPASS_SWRREG_BYPASS);
+ } else if (rt1015->boost_mode == 1) {
+ /* Adaptive */
+ snd_soc_component_update_bits(component,
+ RT1015_SMART_BST_CTRL1, RT1015_ABST_AUTO_EN_MASK |
+ RT1015_ABST_FIX_TGT_MASK | RT1015_BYPASS_SWR_REG_MASK,
+ RT1015_ABST_AUTO_MODE | RT1015_ABST_FIX_TGT_DIS |
+ RT1015_BYPASS_SWRREG_PASS);
+ } else {
+ /* Fixed Adaptive */
+ snd_soc_component_update_bits(component,
+ RT1015_SMART_BST_CTRL1, RT1015_ABST_AUTO_EN_MASK |
+ RT1015_ABST_FIX_TGT_MASK | RT1015_BYPASS_SWR_REG_MASK,
+ RT1015_ABST_AUTO_MODE | RT1015_ABST_FIX_TGT_EN |
+ RT1015_BYPASS_SWRREG_PASS);
+ }
+
+ return 0;
+}
+
+static int rt5518_bypass_boost_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rt1015_priv *rt1015 =
+ snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = rt1015->bypass_boost;
+
+ return 0;
+}
+
+static int rt5518_bypass_boost_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rt1015_priv *rt1015 =
+ snd_soc_component_get_drvdata(component);
+
+ rt1015->bypass_boost = ucontrol->value.integer.value[0];
+ if (rt1015->bypass_boost == 1) {
+ snd_soc_component_write(component,
+ RT1015_PWR4, 0x00b2);
+ snd_soc_component_write(component,
+ RT1015_CLSD_INTERNAL8, 0x2008);
+ snd_soc_component_write(component,
+ RT1015_CLSD_INTERNAL9, 0x0140);
+ snd_soc_component_write(component,
+ RT1015_GAT_BOOST, 0x00fe);
+ snd_soc_component_write(component,
+ RT1015_PWR_STATE_CTRL, 0x000d);
+ msleep(500);
+ snd_soc_component_write(component,
+ RT1015_PWR_STATE_CTRL, 0x000e);
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new rt1015_snd_controls[] = {
+ SOC_SINGLE_TLV("DAC Playback Volume", RT1015_DAC1, RT1015_DAC_VOL_SFT,
+ 127, 0, dac_vol_tlv),
+ SOC_DOUBLE("DAC Playback Switch", RT1015_DAC3,
+ RT1015_DA_MUTE_SFT, RT1015_DVOL_MUTE_FLAG_SFT, 1, 1),
+ SOC_ENUM_EXT("Boost Mode", rt1015_boost_mode_enum,
+ rt1015_boost_mode_get, rt1015_boost_mode_put),
+ SOC_ENUM("Mono LR Select", rt1015_mono_lr_sel),
+ SOC_SINGLE_EXT("Bypass Boost", SND_SOC_NOPM, 0, 1, 0,
+ rt5518_bypass_boost_get, rt5518_bypass_boost_put),
+};
+
+static int rt1015_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(source->dapm);
+ struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+
+ if (rt1015->sysclk_src == RT1015_SCLK_S_PLL)
+ return 1;
+ else
+ return 0;
+}
+
+static int r1015_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (rt1015->bypass_boost == 0) {
+ snd_soc_component_write(component,
+ RT1015_SYS_RST1, 0x05f7);
+ snd_soc_component_write(component,
+ RT1015_GAT_BOOST, 0xacfe);
+ snd_soc_component_write(component,
+ RT1015_PWR9, 0xaa00);
+ snd_soc_component_write(component,
+ RT1015_GAT_BOOST, 0xecfe);
+ } else {
+ snd_soc_component_write(component,
+ RT1015_SYS_RST1, 0x05f7);
+ snd_soc_component_write(component,
+ RT1015_PWR_STATE_CTRL, 0x026e);
+ }
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ if (rt1015->bypass_boost == 0) {
+ snd_soc_component_write(component,
+ RT1015_PWR9, 0xa800);
+ snd_soc_component_write(component,
+ RT1015_SYS_RST1, 0x05f5);
+ } else {
+ snd_soc_component_write(component,
+ RT1015_PWR_STATE_CTRL, 0x0268);
+ snd_soc_component_write(component,
+ RT1015_SYS_RST1, 0x05f5);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("LDO2", RT1015_PWR1, RT1015_PWR_LDO2_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("INT RC CLK", RT1015_PWR1, RT1015_PWR_INTCLK_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ISENSE", RT1015_PWR1, RT1015_PWR_ISENSE_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("VSENSE", RT1015_PWR1, RT1015_PWR_VSENSE_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLL", RT1015_PWR1, RT1015_PWR_PLL_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BG1 BG2", RT1015_PWR1, RT1015_PWR_BG_1_2_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MBIAS BG", RT1015_PWR1, RT1015_PWR_MBIAS_BG_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("VBAT", RT1015_PWR1, RT1015_PWR_VBAT_BIT, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY("MBIAS", RT1015_PWR1, RT1015_PWR_MBIAS_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADCV", RT1015_PWR1, RT1015_PWR_ADCV_BIT, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY("MIXERV", RT1015_PWR1, RT1015_PWR_MIXERV_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("SUMV", RT1015_PWR1, RT1015_PWR_SUMV_BIT, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY("VREFLV", RT1015_PWR1, RT1015_PWR_VREFLV_BIT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC_E("DAC", NULL, RT1015_PWR1, RT1015_PWR_DAC_BIT, 0,
+ r1015_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_OUTPUT("SPO"),
+};
+
+static const struct snd_soc_dapm_route rt1015_dapm_routes[] = {
+ { "DAC", NULL, "AIFRX" },
+ { "DAC", NULL, "LDO2" },
+ { "DAC", NULL, "PLL", rt1015_is_sys_clk_from_pll},
+ { "DAC", NULL, "INT RC CLK" },
+ { "DAC", NULL, "ISENSE" },
+ { "DAC", NULL, "VSENSE" },
+ { "DAC", NULL, "BG1 BG2" },
+ { "DAC", NULL, "MBIAS BG" },
+ { "DAC", NULL, "VBAT" },
+ { "DAC", NULL, "MBIAS" },
+ { "DAC", NULL, "ADCV" },
+ { "DAC", NULL, "MIXERV" },
+ { "DAC", NULL, "SUMV" },
+ { "DAC", NULL, "VREFLV" },
+ { "SPO", NULL, "DAC" },
+};
+
+static int rt1015_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 rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+ int pre_div, bclk_ms, frame_size;
+ unsigned int val_len = 0;
+
+ rt1015->lrck = params_rate(params);
+ pre_div = rl6231_get_clk_info(rt1015->sysclk, rt1015->lrck);
+ if (pre_div < 0) {
+ dev_err(component->dev, "Unsupported clock rate\n");
+ return -EINVAL;
+ }
+
+ frame_size = snd_soc_params_to_frame_size(params);
+ if (frame_size < 0) {
+ dev_err(component->dev, "Unsupported frame size: %d\n",
+ frame_size);
+ return -EINVAL;
+ }
+
+ bclk_ms = frame_size > 32;
+ rt1015->bclk = rt1015->lrck * (32 << bclk_ms);
+
+ dev_dbg(component->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+ bclk_ms, pre_div, dai->id);
+
+ dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+ rt1015->lrck, pre_div, dai->id);
+
+ switch (params_width(params)) {
+ case 16:
+ break;
+ case 20:
+ val_len = RT1015_I2S_DL_20;
+ break;
+ case 24:
+ val_len = RT1015_I2S_DL_24;
+ break;
+ case 8:
+ val_len = RT1015_I2S_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, RT1015_TDM_MASTER,
+ RT1015_I2S_DL_MASK, val_len);
+ snd_soc_component_update_bits(component, RT1015_CLK2,
+ RT1015_FS_PD_MASK, pre_div);
+
+ return 0;
+}
+
+static int rt1015_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ unsigned int reg_val = 0, reg_val2 = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ reg_val |= RT1015_TCON_TDM_MS_M;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ reg_val |= RT1015_TCON_TDM_MS_S;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg_val2 |= RT1015_TDM_INV_BCLK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg_val |= RT1015_I2S_M_DF_LEFT;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT1015_I2S_M_DF_PCM_A;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT1015_I2S_M_DF_PCM_B;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, RT1015_TDM_MASTER,
+ RT1015_TCON_TDM_MS_MASK | RT1015_I2S_M_DF_MASK,
+ reg_val);
+ snd_soc_component_update_bits(component, RT1015_TDM1_1,
+ RT1015_TDM_INV_BCLK_MASK, reg_val2);
+
+ return 0;
+}
+
+static int rt1015_set_component_sysclk(struct snd_soc_component *component,
+ int clk_id, int source, unsigned int freq, int dir)
+{
+ struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+ unsigned int reg_val = 0;
+
+ if (freq == rt1015->sysclk && clk_id == rt1015->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT1015_SCLK_S_MCLK:
+ reg_val |= RT1015_CLK_SYS_PRE_SEL_MCLK;
+ break;
+
+ case RT1015_SCLK_S_PLL:
+ reg_val |= RT1015_CLK_SYS_PRE_SEL_PLL;
+ break;
+
+ default:
+ dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+
+ rt1015->sysclk = freq;
+ rt1015->sysclk_src = clk_id;
+
+ dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+ freq, clk_id);
+
+ snd_soc_component_update_bits(component, RT1015_CLK2,
+ RT1015_CLK_SYS_PRE_SEL_MASK, reg_val);
+
+ return 0;
+}
+
+static int rt1015_set_component_pll(struct snd_soc_component *component,
+ int pll_id, int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+ struct rl6231_pll_code pll_code;
+ int ret;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(component->dev, "PLL disabled\n");
+
+ rt1015->pll_in = 0;
+ rt1015->pll_out = 0;
+
+ return 0;
+ }
+
+ if (source == rt1015->pll_src && freq_in == rt1015->pll_in &&
+ freq_out == rt1015->pll_out)
+ return 0;
+
+ switch (source) {
+ case RT1015_PLL_S_MCLK:
+ snd_soc_component_update_bits(component, RT1015_CLK2,
+ RT1015_PLL_SEL_MASK, RT1015_PLL_SEL_PLL_SRC2);
+ break;
+
+ case RT1015_PLL_S_BCLK:
+ snd_soc_component_update_bits(component, RT1015_CLK2,
+ RT1015_PLL_SEL_MASK, RT1015_PLL_SEL_BCLK);
+ break;
+
+ default:
+ dev_err(component->dev, "Unknown PLL Source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+ if (ret < 0) {
+ dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+ return ret;
+ }
+
+ dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+ pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+ pll_code.n_code, pll_code.k_code);
+
+ snd_soc_component_write(component, RT1015_PLL1,
+ (pll_code.m_bp ? 0 : pll_code.m_code) << RT1015_PLL_M_SFT |
+ pll_code.m_bp << RT1015_PLL_M_BP_SFT | pll_code.n_code);
+ snd_soc_component_write(component, RT1015_PLL2,
+ pll_code.k_code);
+
+ rt1015->pll_in = freq_in;
+ rt1015->pll_out = freq_out;
+ rt1015->pll_src = source;
+
+ return 0;
+}
+
+static int rt1015_probe(struct snd_soc_component *component)
+{
+ struct rt1015_priv *rt1015 =
+ snd_soc_component_get_drvdata(component);
+
+ rt1015->component = component;
+
+ switch (snd_soc_component_read32(component, RT1015_VER_ID)
+ & RT1015_ID_MASK) {
+ case RT1015_ID_VERA:
+ rt1015_reg_init(component);
+ break;
+ case RT1015_ID_VERB:
+ snd_soc_component_write(component, RT1015_BAT_RPO_STEP1,
+ 0x061c);
+ break;
+ default:
+ dev_err(component->dev, "Unknown version id!\n");
+ }
+
+ return 0;
+}
+
+static void rt1015_remove(struct snd_soc_component *component)
+{
+ struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+
+ regmap_write(rt1015->regmap, RT1015_RESET, 0);
+}
+
+#define RT1015_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT1015_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+struct snd_soc_dai_ops rt1015_aif_dai_ops = {
+ .hw_params = rt1015_hw_params,
+ .set_fmt = rt1015_set_dai_fmt,
+};
+
+struct snd_soc_dai_driver rt1015_dai[] = {
+ {
+ .name = "rt1015-aif",
+ .id = 0,
+ .playback = {
+ .stream_name = "AIF Playback",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT1015_STEREO_RATES,
+ .formats = RT1015_FORMATS,
+ },
+ }
+};
+
+#ifdef CONFIG_PM
+static int rt1015_suspend(struct snd_soc_component *component)
+{
+ struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt1015->regmap, true);
+ regcache_mark_dirty(rt1015->regmap);
+
+ return 0;
+}
+
+static int rt1015_resume(struct snd_soc_component *component)
+{
+ struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt1015->regmap, false);
+ regcache_sync(rt1015->regmap);
+ return 0;
+}
+#else
+#define rt1015_suspend NULL
+#define rt1015_resume NULL
+#endif
+
+static const struct snd_soc_component_driver soc_component_dev_rt1015 = {
+ .probe = rt1015_probe,
+ .remove = rt1015_remove,
+ .suspend = rt1015_suspend,
+ .resume = rt1015_resume,
+ .controls = rt1015_snd_controls,
+ .num_controls = ARRAY_SIZE(rt1015_snd_controls),
+ .dapm_widgets = rt1015_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1015_dapm_widgets),
+ .dapm_routes = rt1015_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1015_dapm_routes),
+ .set_sysclk = rt1015_set_component_sysclk,
+ .set_pll = rt1015_set_component_pll,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
+static const struct regmap_config rt1015_regmap = {
+ .reg_bits = 16,
+ .val_bits = 16,
+ .max_register = RT1015_S_BST_TIMING_INTER36,
+ .volatile_reg = rt1015_volatile_register,
+ .readable_reg = rt1015_readable_register,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt1015_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt1015_reg),
+};
+
+static const struct i2c_device_id rt1015_i2c_id[] = {
+ { "rt1015", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt1015_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt1015_of_match[] = {
+ { .compatible = "realtek,rt1015", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt1015_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static struct acpi_device_id rt1015_acpi_match[] = {
+ {"10EC1015", 0,},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, rt1015_acpi_match);
+#endif
+
+static int rt1015_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt1015_priv *rt1015;
+ int ret;
+ unsigned int val;
+
+ rt1015 = devm_kzalloc(&i2c->dev, sizeof(struct rt1015_priv),
+ GFP_KERNEL);
+ if (rt1015 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt1015);
+
+ rt1015->regmap = devm_regmap_init_i2c(i2c, &rt1015_regmap);
+ if (IS_ERR(rt1015->regmap)) {
+ ret = PTR_ERR(rt1015->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val);
+ if ((val != RT1015_DEVICE_ID_VAL) && (val != RT1015_DEVICE_ID_VAL2)) {
+ dev_err(&i2c->dev,
+ "Device with ID register %x is not rt1015\n", val);
+ return -ENODEV;
+ }
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_rt1015,
+ rt1015_dai, ARRAY_SIZE(rt1015_dai));
+}
+
+static void rt1015_i2c_shutdown(struct i2c_client *client)
+{
+ struct rt1015_priv *rt1015 = i2c_get_clientdata(client);
+
+ regmap_write(rt1015->regmap, RT1015_RESET, 0);
+}
+
+static struct i2c_driver rt1015_i2c_driver = {
+ .driver = {
+ .name = "rt1015",
+ .of_match_table = of_match_ptr(rt1015_of_match),
+ .acpi_match_table = ACPI_PTR(rt1015_acpi_match),
+ },
+ .probe = rt1015_i2c_probe,
+ .shutdown = rt1015_i2c_shutdown,
+ .id_table = rt1015_i2c_id,
+};
+module_i2c_driver(rt1015_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT1015 driver");
+MODULE_AUTHOR("Jack Yu <jack.yu(a)realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h
new file mode 100644
index 000000000000..8d75cadaa0d5
--- /dev/null
+++ b/sound/soc/codecs/rt1015.h
@@ -0,0 +1,368 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * rt1015.h -- RT1015 ALSA SoC audio amplifier driver
+ *
+ * Copyright 2019 Realtek Semiconductor Corp.
+ * Author: Jack Yu <jack.yu(a)realtek.com>
+ *
+ * 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.
+ */
+
+#ifndef __RT1015_H__
+#define __RT1015_H__
+
+#define RT1015_DEVICE_ID_VAL 0x1011
+#define RT1015_DEVICE_ID_VAL2 0x1015
+
+#define RT1015_RESET 0x0000
+#define RT1015_CLK2 0x0004
+#define RT1015_CLK3 0x0006
+#define RT1015_PLL1 0x000a
+#define RT1015_PLL2 0x000c
+#define RT1015_CLK_DET 0x0020
+#define RT1015_SIL_DET 0x0022
+#define RT1015_CUSTOMER_ID 0x0076
+#define RT1015_PCODE_FWVER 0x0078
+#define RT1015_VER_ID 0x007a
+#define RT1015_VENDOR_ID 0x007c
+#define RT1015_DEVICE_ID 0x007d
+#define RT1015_PAD_DRV1 0x00f0
+#define RT1015_PAD_DRV2 0x00f2
+#define RT1015_GAT_BOOST 0x00f3
+#define RT1015_PRO_ALT 0x00f4
+#define RT1015_MAN_I2C 0x0100
+#define RT1015_DAC1 0x0102
+#define RT1015_DAC2 0x0104
+#define RT1015_DAC3 0x0106
+#define RT1015_ADC1 0x010c
+#define RT1015_ADC2 0x010e
+#define RT1015_TDM_MASTER 0x0111
+#define RT1015_TDM_TCON 0x0112
+#define RT1015_TDM1_1 0x0114
+#define RT1015_TDM1_2 0x0116
+#define RT1015_TDM1_3 0x0118
+#define RT1015_TDM1_4 0x011a
+#define RT1015_TDM1_5 0x011c
+#define RT1015_MIXER1 0x0300
+#define RT1015_MIXER2 0x0302
+#define RT1015_ANA_PROTECT1 0x0311
+#define RT1015_ANA_CTRL_SEQ1 0x0313
+#define RT1015_ANA_CTRL_SEQ2 0x0314
+#define RT1015_VBAT_DET_DEB 0x031a
+#define RT1015_VBAT_VOLT_DET1 0x031c
+#define RT1015_VBAT_VOLT_DET2 0x031d
+#define RT1015_VBAT_TEST_OUT1 0x031e
+#define RT1015_VBAT_TEST_OUT2 0x031f
+#define RT1015_VBAT_PROT_ATT 0x0320
+#define RT1015_VBAT_DET_CODE 0x0321
+#define RT1015_PWR1 0x0322
+#define RT1015_PWR4 0x0328
+#define RT1015_PWR5 0x0329
+#define RT1015_PWR6 0x032a
+#define RT1015_PWR7 0x032b
+#define RT1015_PWR8 0x032c
+#define RT1015_PWR9 0x032d
+#define RT1015_CLASSD_SEQ 0x032e
+#define RT1015_SMART_BST_CTRL1 0x0330
+#define RT1015_SMART_BST_CTRL2 0x0332
+#define RT1015_ANA_CTRL1 0x0334
+#define RT1015_ANA_CTRL2 0x0336
+#define RT1015_PWR_STATE_CTRL 0x0338
+#define RT1015_SPK_VOL 0x0506
+#define RT1015_SHORT_DETTOP1 0x0508
+#define RT1015_SHORT_DETTOP2 0x050a
+#define RT1015_SPK_DC_DETECT1 0x0519
+#define RT1015_SPK_DC_DETECT2 0x051a
+#define RT1015_SPK_DC_DETECT3 0x051b
+#define RT1015_SPK_DC_DETECT4 0x051d
+#define RT1015_SPK_DC_DETECT5 0x051f
+#define RT1015_BAT_RPO_STEP1 0x0536
+#define RT1015_BAT_RPO_STEP2 0x0538
+#define RT1015_BAT_RPO_STEP3 0x053a
+#define RT1015_BAT_RPO_STEP4 0x053c
+#define RT1015_BAT_RPO_STEP5 0x053d
+#define RT1015_BAT_RPO_STEP6 0x053e
+#define RT1015_BAT_RPO_STEP7 0x053f
+#define RT1015_BAT_RPO_STEP8 0x0540
+#define RT1015_BAT_RPO_STEP9 0x0541
+#define RT1015_BAT_RPO_STEP10 0x0542
+#define RT1015_BAT_RPO_STEP11 0x0543
+#define RT1015_BAT_RPO_STEP12 0x0544
+#define RT1015_SPREAD_SPEC1 0x0568
+#define RT1015_SPREAD_SPEC2 0x056a
+#define RT1015_PAD_STATUS 0x1000
+#define RT1015_PADS_PULLING_CTRL1 0x1002
+#define RT1015_PADS_DRIVING 0x1006
+#define RT1015_SYS_RST1 0x1007
+#define RT1015_SYS_RST2 0x1009
+#define RT1015_SYS_GATING1 0x100a
+#define RT1015_TEST_MODE1 0x100c
+#define RT1015_TEST_MODE2 0x100d
+#define RT1015_TIMING_CTRL1 0x100e
+#define RT1015_PLL_INT 0x1010
+#define RT1015_TEST_OUT1 0x1020
+#define RT1015_DC_CALIB_CLSD1 0x1200
+#define RT1015_DC_CALIB_CLSD2 0x1202
+#define RT1015_DC_CALIB_CLSD3 0x1204
+#define RT1015_DC_CALIB_CLSD4 0x1206
+#define RT1015_DC_CALIB_CLSD5 0x1208
+#define RT1015_DC_CALIB_CLSD6 0x120a
+#define RT1015_DC_CALIB_CLSD7 0x120c
+#define RT1015_DC_CALIB_CLSD8 0x120e
+#define RT1015_DC_CALIB_CLSD9 0x1210
+#define RT1015_DC_CALIB_CLSD10 0x1212
+#define RT1015_CLSD_INTERNAL1 0x1300
+#define RT1015_CLSD_INTERNAL2 0x1302
+#define RT1015_CLSD_INTERNAL3 0x1304
+#define RT1015_CLSD_INTERNAL4 0x1305
+#define RT1015_CLSD_INTERNAL5 0x1306
+#define RT1015_CLSD_INTERNAL6 0x1308
+#define RT1015_CLSD_INTERNAL7 0x130a
+#define RT1015_CLSD_INTERNAL8 0x130c
+#define RT1015_CLSD_INTERNAL9 0x130e
+#define RT1015_CLSD_OCP_CTRL 0x130f
+#define RT1015_VREF_LV 0x1310
+#define RT1015_MBIAS1 0x1312
+#define RT1015_MBIAS2 0x1314
+#define RT1015_MBIAS3 0x1316
+#define RT1015_MBIAS4 0x1318
+#define RT1015_VREF_LV1 0x131a
+#define RT1015_S_BST_TIMING_INTER1 0x1322
+#define RT1015_S_BST_TIMING_INTER2 0x1323
+#define RT1015_S_BST_TIMING_INTER3 0x1324
+#define RT1015_S_BST_TIMING_INTER4 0x1325
+#define RT1015_S_BST_TIMING_INTER5 0x1326
+#define RT1015_S_BST_TIMING_INTER6 0x1327
+#define RT1015_S_BST_TIMING_INTER7 0x1328
+#define RT1015_S_BST_TIMING_INTER8 0x1329
+#define RT1015_S_BST_TIMING_INTER9 0x132a
+#define RT1015_S_BST_TIMING_INTER10 0x132b
+#define RT1015_S_BST_TIMING_INTER11 0x1330
+#define RT1015_S_BST_TIMING_INTER12 0x1331
+#define RT1015_S_BST_TIMING_INTER13 0x1332
+#define RT1015_S_BST_TIMING_INTER14 0x1333
+#define RT1015_S_BST_TIMING_INTER15 0x1334
+#define RT1015_S_BST_TIMING_INTER16 0x1335
+#define RT1015_S_BST_TIMING_INTER17 0x1336
+#define RT1015_S_BST_TIMING_INTER18 0x1337
+#define RT1015_S_BST_TIMING_INTER19 0x1338
+#define RT1015_S_BST_TIMING_INTER20 0x1339
+#define RT1015_S_BST_TIMING_INTER21 0x133a
+#define RT1015_S_BST_TIMING_INTER22 0x133b
+#define RT1015_S_BST_TIMING_INTER23 0x133c
+#define RT1015_S_BST_TIMING_INTER24 0x133d
+#define RT1015_S_BST_TIMING_INTER25 0x133e
+#define RT1015_S_BST_TIMING_INTER26 0x133f
+#define RT1015_S_BST_TIMING_INTER27 0x1340
+#define RT1015_S_BST_TIMING_INTER28 0x1341
+#define RT1015_S_BST_TIMING_INTER29 0x1342
+#define RT1015_S_BST_TIMING_INTER30 0x1343
+#define RT1015_S_BST_TIMING_INTER31 0x1344
+#define RT1015_S_BST_TIMING_INTER32 0x1345
+#define RT1015_S_BST_TIMING_INTER33 0x1346
+#define RT1015_S_BST_TIMING_INTER34 0x1347
+#define RT1015_S_BST_TIMING_INTER35 0x1348
+#define RT1015_S_BST_TIMING_INTER36 0x1349
+
+/* 0x0004 */
+#define RT1015_CLK_SYS_PRE_SEL_MASK (0x3 << 14)
+#define RT1015_CLK_SYS_PRE_SEL_SFT 14
+#define RT1015_CLK_SYS_PRE_SEL_MCLK (0x0 << 14)
+#define RT1015_CLK_SYS_PRE_SEL_PLL (0x2 << 14)
+#define RT1015_PLL_SEL_MASK (0x1 << 13)
+#define RT1015_PLL_SEL_SFT 13
+#define RT1015_PLL_SEL_PLL_SRC2 (0x0 << 13)
+#define RT1015_PLL_SEL_BCLK (0x1 << 13)
+#define RT1015_FS_PD_MASK (0x7 << 4)
+#define RT1015_FS_PD_SFT 4
+
+/* 0x000a */
+#define RT1015_PLL_M_MAX 0xf
+#define RT1015_PLL_M_MASK (RT1015_PLL_M_MAX << 12)
+#define RT1015_PLL_M_SFT 12
+#define RT1015_PLL_M_BP (0x1 << 11)
+#define RT1015_PLL_M_BP_SFT 11
+#define RT1015_PLL_N_MAX 0x1ff
+#define RT1015_PLL_N_MASK (RT1015_PLL_N_MAX << 0)
+#define RT1015_PLL_N_SFT 0
+
+/* 0x000c */
+#define RT1015_PLL_BPK_MASK (0x1 << 5)
+#define RT1015_PLL_BPK (0x0 << 5)
+#define RT1015_PLL_K_MAX 0x1f
+#define RT1015_PLL_K_MASK (RT1015_PLL_K_MAX)
+#define RT1015_PLL_K_SFT 0
+
+/* 0x007a */
+#define RT1015_ID_MASK 0xff
+#define RT1015_ID_VERA 0x0
+#define RT1015_ID_VERB 0x1
+
+/* 0x0102 */
+#define RT1015_DAC_VOL_MASK (0x7f << 9)
+#define RT1015_DAC_VOL_SFT 9
+
+/* 0x0104 */
+#define RT1015_DAC_CLK (0x1 << 13)
+#define RT1015_DAC_CLK_BIT 13
+
+/* 0x0106 */
+#define RT1015_DAC_MUTE_MASK (0x1 << 15)
+#define RT1015_DA_MUTE_SFT 15
+#define RT1015_DVOL_MUTE_FLAG_SFT 12
+
+/* 0x0111 */
+#define RT1015_TCON_TDM_MS_MASK (0x1 << 14)
+#define RT1015_TCON_TDM_MS_SFT 14
+#define RT1015_TCON_TDM_MS_S (0x0 << 14)
+#define RT1015_TCON_TDM_MS_M (0x1 << 14)
+#define RT1015_I2S_DL_MASK (0x7 << 8)
+#define RT1015_I2S_DL_SFT 8
+#define RT1015_I2S_DL_16 (0x0 << 8)
+#define RT1015_I2S_DL_20 (0x1 << 8)
+#define RT1015_I2S_DL_24 (0x2 << 8)
+#define RT1015_I2S_DL_8 (0x3 << 8)
+#define RT1015_I2S_M_DF_MASK (0x7 << 0)
+#define RT1015_I2S_M_DF_SFT 0
+#define RT1015_I2S_M_DF_I2S (0x0)
+#define RT1015_I2S_M_DF_LEFT (0x1)
+#define RT1015_I2S_M_DF_PCM_A (0x2)
+#define RT1015_I2S_M_DF_PCM_B (0x3)
+#define RT1015_I2S_M_DF_PCM_A_N (0x6)
+#define RT1015_I2S_M_DF_PCM_B_N (0x7)
+
+/* TDM_tcon Setting (0x0112) */
+#define RT1015_I2S_TCON_DF_MASK (0x7 << 13)
+#define RT1015_I2S_TCON_DF_SFT 13
+#define RT1015_I2S_TCON_DF_I2S (0x0 << 13)
+#define RT1015_I2S_TCON_DF_LEFT (0x1 << 13)
+#define RT1015_I2S_TCON_DF_PCM_A (0x2 << 13)
+#define RT1015_I2S_TCON_DF_PCM_B (0x3 << 13)
+#define RT1015_I2S_TCON_DF_PCM_A_N (0x6 << 13)
+#define RT1015_I2S_TCON_DF_PCM_B_N (0x7 << 13)
+#define RT1015_TCON_BCLK_SEL_MASK (0x3 << 10)
+#define RT1015_TCON_BCLK_SEL_SFT 10
+#define RT1015_TCON_BCLK_SEL_32FS (0x0 << 10)
+#define RT1015_TCON_BCLK_SEL_64FS (0x1 << 10)
+#define RT1015_TCON_BCLK_SEL_128FS (0x2 << 10)
+#define RT1015_TCON_BCLK_SEL_256FS (0x3 << 10)
+#define RT1015_TCON_CH_LEN_MASK (0x3 << 5)
+#define RT1015_TCON_CH_LEN_SFT 5
+#define RT1015_TCON_CH_LEN_16B (0x0 << 5)
+#define RT1015_TCON_CH_LEN_20B (0x1 << 5)
+#define RT1015_TCON_CH_LEN_24B (0x2 << 5)
+#define RT1015_TCON_CH_LEN_32B (0x3 << 5)
+#define RT1015_TCON_BCLK_MST_MASK (0x1 << 4)
+#define RT1015_TCON_BCLK_MST_SFT 4
+#define RT1015_TCON_BCLK_MST_INV (0x1 << 4)
+
+/* TDM1 Setting-1 (0x0114) */
+#define RT1015_TDM_INV_BCLK_MASK (0x1 << 15)
+#define RT1015_TDM_INV_BCLK_SFT 15
+#define RT1015_TDM_INV_BCLK (0x1 << 15)
+
+/* 0x0330 */
+#define RT1015_ABST_AUTO_EN_MASK (0x1 << 13)
+#define RT1015_ABST_AUTO_MODE (0x1 << 13)
+#define RT1015_ABST_REG_MODE (0x0 << 13)
+#define RT1015_ABST_FIX_TGT_MASK (0x1 << 12)
+#define RT1015_ABST_FIX_TGT_EN (0x1 << 12)
+#define RT1015_ABST_FIX_TGT_DIS (0x0 << 12)
+#define RT1015_BYPASS_SWR_REG_MASK (0x1 << 7)
+#define RT1015_BYPASS_SWRREG_BYPASS (0x1 << 7)
+#define RT1015_BYPASS_SWRREG_PASS (0x0 << 7)
+
+/* 0x0322 */
+#define RT1015_PWR_LDO2 (0x1 << 15)
+#define RT1015_PWR_LDO2_BIT 15
+#define RT1015_PWR_DAC (0x1 << 14)
+#define RT1015_PWR_DAC_BIT 14
+#define RT1015_PWR_INTCLK (0x1 << 13)
+#define RT1015_PWR_INTCLK_BIT 13
+#define RT1015_PWR_ISENSE (0x1 << 12)
+#define RT1015_PWR_ISENSE_BIT 12
+#define RT1015_PWR_VSENSE (0x1 << 10)
+#define RT1015_PWR_VSENSE_BIT 10
+#define RT1015_PWR_PLL (0x1 << 9)
+#define RT1015_PWR_PLL_BIT 9
+#define RT1015_PWR_BG_1_2 (0x1 << 8)
+#define RT1015_PWR_BG_1_2_BIT 8
+#define RT1015_PWR_MBIAS_BG (0x1 << 7)
+#define RT1015_PWR_MBIAS_BG_BIT 7
+#define RT1015_PWR_VBAT (0x1 << 6)
+#define RT1015_PWR_VBAT_BIT 6
+#define RT1015_PWR_MBIAS (0x1 << 4)
+#define RT1015_PWR_MBIAS_BIT 4
+#define RT1015_PWR_ADCV (0x1 << 3)
+#define RT1015_PWR_ADCV_BIT 3
+#define RT1015_PWR_MIXERV (0x1 << 2)
+#define RT1015_PWR_MIXERV_BIT 2
+#define RT1015_PWR_SUMV (0x1 << 1)
+#define RT1015_PWR_SUMV_BIT 1
+#define RT1015_PWR_VREFLV (0x1 << 0)
+#define RT1015_PWR_VREFLV_BIT 0
+
+/* 0x0324 */
+#define RT1015_PWR_BASIC (0x1 << 15)
+#define RT1015_PWR_BASIC_BIT 15
+#define RT1015_PWR_SD (0x1 << 14)
+#define RT1015_PWR_SD_BIT 14
+#define RT1015_PWR_IBIAS (0x1 << 13)
+#define RT1015_PWR_IBIAS_BIT 13
+#define RT1015_PWR_VCM (0x1 << 11)
+#define RT1015_PWR_VCM_BIT 11
+
+/* 0x0328 */
+#define RT1015_PWR_SWR (0x1 << 12)
+#define RT1015_PWR_SWR_BIT 12
+
+/* 0x1300 */
+#define RT1015_PWR_CLSD (0x1 << 12)
+#define RT1015_PWR_CLSD_BIT 12
+
+/* 0x007a */
+#define RT1015_ID_MASK 0xff
+#define RT1015_ID_VERA 0x0
+#define RT1015_ID_VERB 0x1
+
+/* System Clock Source */
+enum {
+ RT1015_SCLK_S_MCLK,
+ RT1015_SCLK_S_PLL,
+};
+
+/* PLL1 Source */
+enum {
+ RT1015_PLL_S_MCLK,
+ RT1015_PLL_S_BCLK,
+};
+
+enum {
+ RT1015_AIF1,
+ RT1015_AIFS,
+};
+
+enum {
+ RT1015_VERA,
+ RT1015_VERB,
+};
+
+struct rt1015_priv {
+ struct snd_soc_component *component;
+ struct regmap *regmap;
+ int sysclk;
+ int sysclk_src;
+ int lrck;
+ int bclk;
+ int id;
+ int pll_src;
+ int pll_in;
+ int pll_out;
+ int boost_mode;
+ int bypass_boost;
+ int amp_ver;
+};
+
+#endif /* __RT1015_H__ */
--
2.24.1
3
2

Re: [PATCH v3 0/8] PCI: add and use constant PCI_STATUS_ERROR_BITS and helper pci_status_get_and_clear_errors
by Bjorn Helgaas 25 Feb '20
by Bjorn Helgaas 25 Feb '20
25 Feb '20
On Tue, Feb 25, 2020 at 03:03:05PM +0100, Heiner Kallweit wrote:
> Few drivers have own definitions for this constant, so move it to the
> PCI core. In addition there are several places where the following
> code sequence is used:
> 1. Read PCI_STATUS
> 2. Mask out non-error bits
> 3. Action based on set error bits
> 4. Write back set error bits to clear them
>
> As this is a repeated pattern, add a helper to the PCI core.
>
> Most affected drivers are network drivers. But as it's about core
> PCI functionality, I suppose the series should go through the PCI
> tree.
Makes good sense to me, thanks for doing this.
> v2:
> - fix formal issue with cover letter
> v3:
> - fix dumb typo in patch 7
>
> Heiner Kallweit (8):
> PCI: add constant PCI_STATUS_ERROR_BITS
> PCI: add pci_status_get_and_clear_errors
> r8169: use pci_status_get_and_clear_errors
> net: cassini: use pci_status_get_and_clear_errors
> net: sungem: use pci_status_get_and_clear_errors
> net: skfp: use PCI_STATUS_ERROR_BITS
> PCI: pci-bridge-emul: use PCI_STATUS_ERROR_BITS
> sound: bt87x: use pci_status_get_and_clear_errors
>
> drivers/net/ethernet/marvell/skge.h | 6 -----
> drivers/net/ethernet/marvell/sky2.h | 6 -----
> drivers/net/ethernet/realtek/r8169_main.c | 15 +++++-------
> drivers/net/ethernet/sun/cassini.c | 28 ++++++++-------------
> drivers/net/ethernet/sun/sungem.c | 30 +++++++----------------
> drivers/net/fddi/skfp/drvfbi.c | 2 +-
> drivers/net/fddi/skfp/h/skfbi.h | 5 ----
> drivers/pci/pci-bridge-emul.c | 14 ++---------
> drivers/pci/pci.c | 23 +++++++++++++++++
> include/linux/pci.h | 1 +
> include/uapi/linux/pci_regs.h | 7 ++++++
> sound/pci/bt87x.c | 7 +-----
> 12 files changed, 60 insertions(+), 84 deletions(-)
>
> --
> 2.25.1
>
>
>
1
0
On Tue, Feb 25, 2020 at 03:04:23PM +0100, Heiner Kallweit wrote:
> Few drivers use the following code sequence:
This reads like "Not very many drivers". I think "Several drivers"
would capture the sense of this better.
> 1. Read PCI_STATUS
> 2. Mask out non-error bits
> 3. Action based on error bits set
> 4. Write back set error bits to clear them
>
> As this is a repeated pattern, add a helper to the PCI core.
>
> Signed-off-by: Heiner Kallweit <hkallweit1(a)gmail.com>
> ---
> drivers/pci/pci.c | 23 +++++++++++++++++++++++
> include/linux/pci.h | 1 +
> 2 files changed, 24 insertions(+)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index d828ca835..c16b0ba2a 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -173,6 +173,29 @@ unsigned char pci_bus_max_busnr(struct pci_bus *bus)
> }
> EXPORT_SYMBOL_GPL(pci_bus_max_busnr);
>
> +/**
> + * pci_status_get_and_clear_errors - return and clear error bits in PCI_STATUS
> + * @pdev: the PCI device
> + *
> + * Returns error bits set in PCI_STATUS and clears them.
> + */
> +int pci_status_get_and_clear_errors(struct pci_dev *pdev)
> +{
> + u16 status;
> + int ret;
> +
> + ret = pci_read_config_word(pdev, PCI_STATUS, &status);
> + if (ret != PCIBIOS_SUCCESSFUL)
> + return -EIO;
> +
> + status &= PCI_STATUS_ERROR_BITS;
> + if (status)
> + pci_write_config_word(pdev, PCI_STATUS, status);
> +
> + return status;
> +}
> +EXPORT_SYMBOL_GPL(pci_status_get_and_clear_errors);
> +
> #ifdef CONFIG_HAS_IOMEM
> void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
> {
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 3840a541a..7a75aae04 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1203,6 +1203,7 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags);
> bool pci_device_is_present(struct pci_dev *pdev);
> void pci_ignore_hotplug(struct pci_dev *dev);
> struct pci_dev *pci_real_dma_dev(struct pci_dev *dev);
> +int pci_status_get_and_clear_errors(struct pci_dev *pdev);
>
> int __printf(6, 7) pci_request_irq(struct pci_dev *dev, unsigned int nr,
> irq_handler_t handler, irq_handler_t thread_fn, void *dev_id,
> --
> 2.25.1
>
>
>
>
1
0
On Tue, Feb 25, 2020 at 03:03:44PM +0100, Heiner Kallweit wrote:
Run "git log --oneline drivers/pci" and make yours match. In
particular, capitalize the first word ("Add"). Same for the other PCI
patches. I don't know the drivers/net convention, but please find and
follow that as well.
> This constant is used (with different names) in more than one driver,
> so move it to the PCI core.
The driver constants in *this* patch at least use the same name.
> Signed-off-by: Heiner Kallweit <hkallweit1(a)gmail.com>
> ---
> drivers/net/ethernet/marvell/skge.h | 6 ------
> drivers/net/ethernet/marvell/sky2.h | 6 ------
> include/uapi/linux/pci_regs.h | 7 +++++++
> 3 files changed, 7 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/ethernet/marvell/skge.h b/drivers/net/ethernet/marvell/skge.h
> index 6fa7b6a34..e149bdfe1 100644
> --- a/drivers/net/ethernet/marvell/skge.h
> +++ b/drivers/net/ethernet/marvell/skge.h
> @@ -15,12 +15,6 @@
> #define PCI_VPD_ROM_SZ 7L<<14 /* VPD ROM size 0=256, 1=512, ... */
> #define PCI_REV_DESC 1<<2 /* Reverse Descriptor bytes */
>
> -#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
> - PCI_STATUS_SIG_SYSTEM_ERROR | \
> - PCI_STATUS_REC_MASTER_ABORT | \
> - PCI_STATUS_REC_TARGET_ABORT | \
> - PCI_STATUS_PARITY)
> -
> enum csr_regs {
> B0_RAP = 0x0000,
> B0_CTST = 0x0004,
> diff --git a/drivers/net/ethernet/marvell/sky2.h b/drivers/net/ethernet/marvell/sky2.h
> index b02b65230..851d8ed34 100644
> --- a/drivers/net/ethernet/marvell/sky2.h
> +++ b/drivers/net/ethernet/marvell/sky2.h
> @@ -252,12 +252,6 @@ enum {
> };
>
>
> -#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
> - PCI_STATUS_SIG_SYSTEM_ERROR | \
> - PCI_STATUS_REC_MASTER_ABORT | \
> - PCI_STATUS_REC_TARGET_ABORT | \
> - PCI_STATUS_PARITY)
> -
> enum csr_regs {
> B0_RAP = 0x0000,
> B0_CTST = 0x0004,
> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
> index 543769048..9b84a1278 100644
> --- a/include/uapi/linux/pci_regs.h
> +++ b/include/uapi/linux/pci_regs.h
> @@ -68,6 +68,13 @@
> #define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
> #define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
>
> +#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
> + PCI_STATUS_SIG_SYSTEM_ERROR | \
> + PCI_STATUS_REC_MASTER_ABORT | \
> + PCI_STATUS_REC_TARGET_ABORT | \
> + PCI_STATUS_SIG_TARGET_ABORT | \
> + PCI_STATUS_PARITY)
This actually *adds* PCI_STATUS_SIG_TARGET_ABORT, which is not in the
driver definitions. At the very least that should be mentioned in the
commit log.
Ideally the addition would be in its own patch so it's obvious and
bisectable, but I see the problem -- the subsequent patches
consolidate things that aren't really quite the same. One alternative
would be to have preliminary patches that change the drivers
individually so they all use this new mask, then do the consolidation
afterwards.
There is pitifully little documentation about the use of include/uapi,
but AFAICT that is for the user API, and this isn't part of that. I
think this #define could go in include/linux/pci.h instead.
> +
> #define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */
> #define PCI_REVISION_ID 0x08 /* Revision ID */
> #define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
> --
> 2.25.1
>
>
>
>
1
0

[alsa-devel] [PATCH 00/10] soundwire: bus: fix race conditions, add suspend-resume
by Pierre-Louis Bossart 25 Feb '20
by Pierre-Louis Bossart 25 Feb '20
25 Feb '20
The existing mainline code for SoundWire does not handle critical race
conditions, and does not have any support for pm_runtime suspend or
clock-stop modes needed for e.g. jack detection or external VAD.
As suggested by Vinod, these patches for the bus are shared first -
with the risk that they are separated from their actual use in Intel
drivers, so reviewers might wonder why they are needed in the first
place.
For reference, the complete set of 90+ patches required for SoundWire
on Intel platforms is available here:
https://github.com/thesofproject/linux/pull/1692
These patches are not Intel-specific and are likely required for
e.g. Qualcomm-based implementations.
All the patches in this series were generated during the joint
Intel-Realtek validation effort on Intel reference designs and
form-factor devices. The support for the initialization_complete
signaling is already available in the Realtek codecs drivers merged in
the ASoC tree (rt700, rt711, rt1308, rt715)
Pierre-Louis Bossart (8):
soundwire: bus: fix race condition with probe_complete signaling
soundwire: bus: fix race condition with enumeration_complete signaling
soundwire: bus: fix race condition with initialization_complete
signaling
soundwire: bus: add PM/no-PM versions of read/write functions
soundwire: bus: write Slave Device Number without runtime_pm
soundwire: bus: add helper to clear Slave status to UNATTACHED
soundwire: bus: disable pm_runtime in sdw_slave_delete
soundwire: bus: don't treat CMD_IGNORED as error on ClockStop
Rander Wang (2):
soundwire: bus: fix io error when processing alert event
soundwire: bus: add clock stop helpers
drivers/soundwire/bus.c | 509 ++++++++++++++++++++++++++++++++--
drivers/soundwire/bus.h | 9 +
drivers/soundwire/bus_type.c | 5 +
drivers/soundwire/slave.c | 4 +
include/linux/soundwire/sdw.h | 24 ++
5 files changed, 526 insertions(+), 25 deletions(-)
--
2.20.1
2
13

25 Feb '20
From: Daniel Baluta <daniel.baluta(a)nxp.com>
On i.MX8 platforms that have a DSP the DAI handling is taken care
of by two entities:
* Application Processor (AP), which runs Linux
* DSP, which runs a firmware (typically Sound Open Firmware)
The DSP has access to DAI IP registers, but it cannot easily handle
resources like:
* clocks
* power domain management
* pinctrl
For this reason we introduce a generic FSL DAI driver which will take
care of the resources above.
---
sound/soc/fsl/Kconfig | 8 ++
sound/soc/fsl/Makefile | 2 +
sound/soc/fsl/fsl_dai.c | 276 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 286 insertions(+)
create mode 100644 sound/soc/fsl/fsl_dai.c
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 65e8cd4be930..bea8ab2c24f9 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -75,6 +75,14 @@ config SND_SOC_FSL_ESAI
This option is only useful for out-of-tree drivers since
in-tree drivers select it automatically.
+config SND_SOC_FSL_DAI
+ tristate "Generic FSL DAI support for Sound Open Firmware"
+ help
+ Say Y if you want to enable generic FSL DAI support to be used
+ with Sound Open Firmware. This module takes care of enabling
+ clocks, power domain, pinctrl for FSL DAIs. The rest of DAI
+ control is taken care of by SOF firmware.
+
config SND_SOC_FSL_MICFIL
tristate "Pulse Density Modulation Microphone Interface (MICFIL) module support"
select REGMAP_MMIO
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 8cde88c72d93..e4ed253b6657 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -20,6 +20,7 @@ snd-soc-fsl-ssi-y := fsl_ssi.o
snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o
snd-soc-fsl-spdif-objs := fsl_spdif.o
snd-soc-fsl-esai-objs := fsl_esai.o
+snd-soc-fsl-dai-objs := fsl_dai.o
snd-soc-fsl-micfil-objs := fsl_micfil.o
snd-soc-fsl-utils-objs := fsl_utils.o
snd-soc-fsl-dma-objs := fsl_dma.o
@@ -32,6 +33,7 @@ obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
+obj-$(CONFIG_SND_SOC_FSL_DAI) += snd-soc-fsl-dai.o
obj-$(CONFIG_SND_SOC_FSL_MICFIL) += snd-soc-fsl-micfil.o
obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o
diff --git a/sound/soc/fsl/fsl_dai.c b/sound/soc/fsl/fsl_dai.c
new file mode 100644
index 000000000000..f70889939801
--- /dev/null
+++ b/sound/soc/fsl/fsl_dai.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale Generic DAI driver for DSP
+//
+// Copyright 2019 NXP
+// Author: Daniel Baluta <daniel.baluta(a)nxp.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+enum fsl_dai_type {
+ FSL_DAI_TYPE_NONE,
+ FSL_DAI_TYPE_SAI,
+ FSL_DAI_TYPE_ESAI,
+};
+
+#define FSL_DAI_ESAI_CLK_NUM 4
+static const char *esai_clks[FSL_DAI_ESAI_CLK_NUM] = {
+ "core",
+ "extal",
+ "fsys",
+ "spba",
+};
+
+#define FSL_DAI_SAI_CLK_NUM 5
+static const char *sai_clks[FSL_DAI_SAI_CLK_NUM] = {
+ "bus",
+ "mclk0",
+ "mclk1",
+ "mclk2",
+ "mclk3",
+};
+
+struct fsl_dai {
+ struct platform_device *pdev;
+
+ /* DAI clocks */
+ struct clk **clks;
+ const char **clk_names;
+ int num_clks;
+
+ /* Power Domain handling */
+ int num_domains;
+ struct device **pd_dev;
+ struct device_link **link;
+
+ /* DAIS */
+ struct snd_soc_dai_driver *dai_drv;
+ int num_drv;
+};
+
+static struct snd_soc_dai_driver fsl_esai_dai = {
+ .name = "esai0",
+};
+
+static struct snd_soc_dai_driver fsl_sai_dai = {
+ .name = "sai1",
+};
+
+static const struct snd_soc_component_driver fsl_dai_component = {
+ .name = "fsl-dai",
+};
+
+static int fsl_dai_init_clocks(struct fsl_dai *dai_priv)
+{
+ struct device *dev = &dai_priv->pdev->dev;
+ int i;
+
+ dai_priv->clks = devm_kcalloc(dev, dai_priv->num_clks,
+ sizeof(*dai_priv->clks), GFP_KERNEL);
+ if (!dai_priv->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < dai_priv->num_clks; i++) {
+ dai_priv->clks[i] = devm_clk_get(dev, dai_priv->clk_names[i]);
+ if (IS_ERR(dai_priv->clks[i])) {
+ dev_dbg(dev, "Failed to get clk %s\n",
+ dai_priv->clk_names[i]);
+ dai_priv->clks[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+int fsl_get_dai_type(struct fsl_dai *dai_priv)
+{
+ struct device_node *np = dai_priv->pdev->dev.of_node;
+
+ if (of_device_is_compatible(np, "fsl,esai-dai"))
+ return FSL_DAI_TYPE_ESAI;
+
+ if (of_device_is_compatible(np, "fsl,sai-dai"))
+ return FSL_DAI_TYPE_SAI;
+
+ return FSL_DAI_TYPE_NONE;
+}
+
+static int fsl_dai_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct fsl_dai *priv;
+ int dai_type;
+ int ret;
+ int i;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->pdev = pdev;
+
+ dev_set_drvdata(&pdev->dev, priv);
+
+ dai_type = fsl_get_dai_type(priv);
+ switch (dai_type) {
+ case FSL_DAI_TYPE_ESAI:
+ priv->clk_names = esai_clks;
+ priv->num_clks = FSL_DAI_ESAI_CLK_NUM;
+ priv->dai_drv = &fsl_esai_dai;
+ priv->num_drv = 1;
+ break;
+ case FSL_DAI_TYPE_SAI:
+ priv->clk_names = sai_clks;
+ priv->num_clks = FSL_DAI_SAI_CLK_NUM;
+ priv->dai_drv = &fsl_sai_dai;
+ priv->num_drv = 1;
+ break;
+ default:
+ dev_err(&pdev->dev, "Invalid DAI type %d\n", dai_type);
+ return -EINVAL;
+ }
+
+ ret = fsl_dai_init_clocks(priv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error at init clocks\n");
+ return ret;
+ }
+
+ priv->num_domains = of_count_phandle_with_args(np, "power-domains",
+ "#power-domain-cells");
+ if (priv->num_domains < 0) {
+ dev_err(&pdev->dev, "no power-domains property in %pOF\n", np);
+ return priv->num_domains;
+ }
+
+ priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains,
+ sizeof(*priv->pd_dev), GFP_KERNEL);
+ if (!priv->pd_dev)
+ return -ENOMEM;
+
+ priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains,
+ sizeof(*priv->link), GFP_KERNEL);
+ if (!priv->link)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->num_domains; i++) {
+ priv->pd_dev[i] = dev_pm_domain_attach_by_id(&pdev->dev, i);
+ if (IS_ERR(priv->pd_dev[i])) {
+ ret = PTR_ERR(priv->pd_dev[i]);
+ goto unroll_pm;
+ }
+
+ priv->link[i] = device_link_add(&pdev->dev, priv->pd_dev[i],
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!priv->link[i]) {
+ ret = -EINVAL;
+ dev_pm_domain_detach(priv->pd_dev[i], false);
+ goto unroll_pm;
+ }
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &fsl_dai_component,
+ priv->dai_drv, priv->num_drv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register DAI ret = %d\n", ret);
+ return ret;
+ }
+ return 0;
+
+unroll_pm:
+ while (--i >= 0) {
+ device_link_del(priv->link[i]);
+ dev_pm_domain_detach(priv->pd_dev[i], false);
+ }
+ return ret;
+}
+
+static int fsl_dai_remove(struct platform_device *pdev)
+{
+ struct fsl_dai *priv = platform_get_drvdata(pdev);
+ int i;
+
+ pm_runtime_disable(&priv->pdev->dev);
+
+ for (i = 0; i < priv->num_domains; i++) {
+ device_link_del(priv->link[i]);
+ dev_pm_domain_detach(priv->pd_dev[i], false);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id fsl_dai_dt_ids[] = {
+ { .compatible = "fsl,esai-dai", },
+ { .compatible = "fsl,sai-dai", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_dai_dt_ids);
+
+#ifdef CONFIG_PM
+static int fsl_dai_runtime_resume(struct device *dev)
+{
+ struct fsl_dai *priv = dev_get_drvdata(dev);
+ int i, ret;
+
+ for (i = 0; i < priv->num_clks; i++) {
+ ret = clk_prepare_enable(priv->clks[i]);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable clk %s\n",
+ priv->clk_names[i]);
+ goto out;
+ }
+ }
+ return 0;
+out:
+ while (--i >= 0)
+ clk_disable_unprepare(priv->clks[i]);
+
+ return ret;
+}
+
+static int fsl_dai_runtime_suspend(struct device *dev)
+{
+ struct fsl_dai *priv = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < priv->num_clks; i++)
+ clk_disable_unprepare(priv->clks[i]);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops fsl_dai_pm_ops = {
+ SET_RUNTIME_PM_OPS(fsl_dai_runtime_suspend,
+ fsl_dai_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_dai_driver = {
+ .probe = fsl_dai_probe,
+ .remove = fsl_dai_remove,
+ .driver = {
+ .name = "fsl-dai",
+ .pm = &fsl_dai_pm_ops,
+ .of_match_table = fsl_dai_dt_ids,
+ },
+};
+
+module_platform_driver(fsl_dai_driver);
+
+MODULE_ALIAS("platform:fsl-dai");
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta(a)nxp.com>");
+MODULE_DESCRIPTION("FSL Generic DAI driver for DSP");
+MODULE_LICENSE("GPL v2");
--
2.17.1
4
3

25 Feb '20
From: Colin Ian King <colin.king(a)canonical.com>
The check on p->sink looks bogus, I believe it should be p->source
since the following code blocks are related to p->source. Fix
this by replacing p->sink with p->source.
Addresses-Coverity: ("Copy-paste error")
Fixes: 24c8d14192cc ("ASoC: Intel: mrfld: add DSP core controls")
Signed-off-by: Colin Ian King <colin.king(a)canonical.com>
---
[ Note: this has not been tested ]
---
sound/soc/intel/atom/sst-atom-controls.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index baef461a99f1..f883c9340eee 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -1333,7 +1333,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
dai->capture_widget->name);
w = dai->capture_widget;
snd_soc_dapm_widget_for_each_source_path(w, p) {
- if (p->connected && !p->connected(w, p->sink))
+ if (p->connected && !p->connected(w, p->source))
continue;
if (p->connect && p->source->power &&
--
2.24.0
3
2

25 Feb '20
Dear ALSA developers,
Several days ago I wrote messages here because the sound card of my new laptop
Samsung Galaxy book 12 (W720) doesn't let me listening to music. It is an
Intel Sunrine Point-LP HD audio with Realtek ACL298 chip.
After many tests, thanks to Takashi's help, internal and headset microphone
work very well but there is no sound when I play something (internal speaker
and headphones). So it seems that problem doesn't come from pin configuration
but something like COEF setup..
Thus I used qemu (with modifications of the code I did) in order to grab
communication between Windows driver and the PCI audio sound card. In
particular I extracted the VERB exchanges. Output of this job is attached to
this email:
- corbRirbBuffer2.txt: the whole VERB commands from startup to shut down
- corbStart2.txt: VERB commands during startup (before any sound is played)
- corbSound2.txt: VERB commands when output mixer is updated and a sound is
played
- corbEnd2.txt: VERB commands when the system is powered down
- similar "output" files which contains all PCI writes for these different
stages
Since I'm not familiar with the hda ALSA driver and what it is currently set
up with the current driver I don't know how to find the problem.
The only thing I did is to execute each of the startup VERBs through hda-verb
command. I saw that some of these VERBs don't return the same value as those
got under Windows.. (almost 0x020c0000).
Does someone has an idea about what's going wrong or what could I do in order
to understand what could be problem or how to debug it deeper?
Thank you for your help.
Regards,
Aurélien
1
0

25 Feb '20
Hi Heiner,
I love your patch! Yet something to improve:
[auto build test ERROR on pci/next]
[also build test ERROR on sound/for-next net-next/master net/master linus/master v5.6-rc3 next-20200224]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Heiner-Kallweit/PCI-add-and-use-co…
base: https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git next
config: arm-mvebu_v7_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 7.5.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=7.5.0 make.cross ARCH=arm
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp(a)intel.com>
All errors (new ones prefixed by >>):
>> drivers//pci/pci-bridge-emul.c:53:37: error: expected '}' before ';' token
.w1c = PCI_STATUS_ERROR_BITS << 16;
^
drivers//pci/pci-bridge-emul.c:98:37: error: expected '}' before ';' token
.w1c = PCI_STATUS_ERROR_BITS << 16;
^
vim +53 drivers//pci/pci-bridge-emul.c
40
41 static const struct pci_bridge_reg_behavior pci_regs_behavior[] = {
42 [PCI_VENDOR_ID / 4] = { .ro = ~0 },
43 [PCI_COMMAND / 4] = {
44 .rw = (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
45 PCI_COMMAND_MASTER | PCI_COMMAND_PARITY |
46 PCI_COMMAND_SERR),
47 .ro = ((PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE |
48 PCI_COMMAND_VGA_PALETTE | PCI_COMMAND_WAIT |
49 PCI_COMMAND_FAST_BACK) |
50 (PCI_STATUS_CAP_LIST | PCI_STATUS_66MHZ |
51 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MASK) << 16),
52 .rsvd = GENMASK(15, 10) | ((BIT(6) | GENMASK(3, 0)) << 16),
> 53 .w1c = PCI_STATUS_ERROR_BITS << 16;
54 },
55 [PCI_CLASS_REVISION / 4] = { .ro = ~0 },
56
57 /*
58 * Cache Line Size register: implement as read-only, we do not
59 * pretend implementing "Memory Write and Invalidate"
60 * transactions"
61 *
62 * Latency Timer Register: implemented as read-only, as "A
63 * bridge that is not capable of a burst transfer of more than
64 * two data phases on its primary interface is permitted to
65 * hardwire the Latency Timer to a value of 16 or less"
66 *
67 * Header Type: always read-only
68 *
69 * BIST register: implemented as read-only, as "A bridge that
70 * does not support BIST must implement this register as a
71 * read-only register that returns 0 when read"
72 */
73 [PCI_CACHE_LINE_SIZE / 4] = { .ro = ~0 },
74
75 /*
76 * Base Address registers not used must be implemented as
77 * read-only registers that return 0 when read.
78 */
79 [PCI_BASE_ADDRESS_0 / 4] = { .ro = ~0 },
80 [PCI_BASE_ADDRESS_1 / 4] = { .ro = ~0 },
81
82 [PCI_PRIMARY_BUS / 4] = {
83 /* Primary, secondary and subordinate bus are RW */
84 .rw = GENMASK(24, 0),
85 /* Secondary latency is read-only */
86 .ro = GENMASK(31, 24),
87 },
88
89 [PCI_IO_BASE / 4] = {
90 /* The high four bits of I/O base/limit are RW */
91 .rw = (GENMASK(15, 12) | GENMASK(7, 4)),
92
93 /* The low four bits of I/O base/limit are RO */
94 .ro = (((PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK |
95 PCI_STATUS_DEVSEL_MASK) << 16) |
96 GENMASK(11, 8) | GENMASK(3, 0)),
97
98 .w1c = PCI_STATUS_ERROR_BITS << 16;
99
100 .rsvd = ((BIT(6) | GENMASK(4, 0)) << 16),
101 },
102
103 [PCI_MEMORY_BASE / 4] = {
104 /* The high 12-bits of mem base/limit are RW */
105 .rw = GENMASK(31, 20) | GENMASK(15, 4),
106
107 /* The low four bits of mem base/limit are RO */
108 .ro = GENMASK(19, 16) | GENMASK(3, 0),
109 },
110
111 [PCI_PREF_MEMORY_BASE / 4] = {
112 /* The high 12-bits of pref mem base/limit are RW */
113 .rw = GENMASK(31, 20) | GENMASK(15, 4),
114
115 /* The low four bits of pref mem base/limit are RO */
116 .ro = GENMASK(19, 16) | GENMASK(3, 0),
117 },
118
119 [PCI_PREF_BASE_UPPER32 / 4] = {
120 .rw = ~0,
121 },
122
123 [PCI_PREF_LIMIT_UPPER32 / 4] = {
124 .rw = ~0,
125 },
126
127 [PCI_IO_BASE_UPPER16 / 4] = {
128 .rw = ~0,
129 },
130
131 [PCI_CAPABILITY_LIST / 4] = {
132 .ro = GENMASK(7, 0),
133 .rsvd = GENMASK(31, 8),
134 },
135
136 [PCI_ROM_ADDRESS1 / 4] = {
137 .rw = GENMASK(31, 11) | BIT(0),
138 .rsvd = GENMASK(10, 1),
139 },
140
141 /*
142 * Interrupt line (bits 7:0) are RW, interrupt pin (bits 15:8)
143 * are RO, and bridge control (31:16) are a mix of RW, RO,
144 * reserved and W1C bits
145 */
146 [PCI_INTERRUPT_LINE / 4] = {
147 /* Interrupt line is RW */
148 .rw = (GENMASK(7, 0) |
149 ((PCI_BRIDGE_CTL_PARITY |
150 PCI_BRIDGE_CTL_SERR |
151 PCI_BRIDGE_CTL_ISA |
152 PCI_BRIDGE_CTL_VGA |
153 PCI_BRIDGE_CTL_MASTER_ABORT |
154 PCI_BRIDGE_CTL_BUS_RESET |
155 BIT(8) | BIT(9) | BIT(11)) << 16)),
156
157 /* Interrupt pin is RO */
158 .ro = (GENMASK(15, 8) | ((PCI_BRIDGE_CTL_FAST_BACK) << 16)),
159
160 .w1c = BIT(10) << 16,
161
162 .rsvd = (GENMASK(15, 12) | BIT(4)) << 16,
163 },
164 };
165
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
1
0

Re: [linux-sunxi] [PATCH v3 1/1] drm: sun4i: hdmi: Add support for sun4i HDMI encoder audio
by Maxime Ripard 25 Feb '20
by Maxime Ripard 25 Feb '20
25 Feb '20
On Tue, Feb 25, 2020 at 11:45:28AM +0200, Stefan Mavrodiev wrote:
>
> On 1/29/20 6:34 PM, Chen-Yu Tsai wrote:
> > On Tue, Jan 28, 2020 at 10:07 PM Stefan Mavrodiev <stefan(a)olimex.com> wrote:
> > > Add HDMI audio support for the sun4i-hdmi encoder, used on
> > > the older Allwinner chips - A10, A20, A31.
> > >
> > > Most of the code is based on the BSP implementation. In it
> > > dditional formats are supported (S20_3LE and S24_LE), however
> > > there where some problems with them and only S16_LE is left.
> > >
> > > Signed-off-by: Stefan Mavrodiev <stefan(a)olimex.com>
> > > ---
> > > Changes for v3:
> > > - Instead of platfrom_driver dynammicly register/unregister card
> > > - Add Kconfig dependencies
> > > - Restrore drvdata after card unregistering
> > >
> > > Changes for v2:
> > > - Create a new platform driver instead of using the HDMI encoder
> > > - Expose a new kcontrol to the userspace holding the ELD data
> > > - Wrap all macro arguments in parentheses
> > >
> > > drivers/gpu/drm/sun4i/Kconfig | 11 +
> > > drivers/gpu/drm/sun4i/Makefile | 3 +
> > > drivers/gpu/drm/sun4i/sun4i_hdmi.h | 37 ++
> > > drivers/gpu/drm/sun4i/sun4i_hdmi_audio.c | 450 +++++++++++++++++++++++
> > > drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 14 +
> > > 5 files changed, 515 insertions(+)
> > > create mode 100644 drivers/gpu/drm/sun4i/sun4i_hdmi_audio.c
> > Since this is actually an audio driver, please include all the ALSA / ASoC
> > maintainers and mailing lists (CC-ed).
> >
> > > diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> > > index 37e90e42943f..ca2ab5d53dd4 100644
> > > --- a/drivers/gpu/drm/sun4i/Kconfig
> > > +++ b/drivers/gpu/drm/sun4i/Kconfig
> > > @@ -23,6 +23,17 @@ config DRM_SUN4I_HDMI
> > > Choose this option if you have an Allwinner SoC with an HDMI
> > > controller.
> > >
> > > +config DRM_SUN4I_HDMI_AUDIO
> > > + bool "Allwinner A10 HDMI Audio Support"
> > > + default y
> > > + depends on DRM_SUN4I_HDMI
> > > + depends on SND_SOC=y || SND_SOC=DRM_SUN4I_HDMI
> > > + select SND_PCM_ELD
> > > + select SND_SOC_GENERIC_DMAENGINE_PCM
> > > + help
> > > + Choose this option if you have an Allwinner SoC with an HDMI
> > > + controller and want to use audio.
> > > +
> > > config DRM_SUN4I_HDMI_CEC
> > > bool "Allwinner A10 HDMI CEC Support"
> > > depends on DRM_SUN4I_HDMI
> > > diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> > > index 0d04f2447b01..492bfd28ad2e 100644
> > > --- a/drivers/gpu/drm/sun4i/Makefile
> > > +++ b/drivers/gpu/drm/sun4i/Makefile
> > > @@ -5,6 +5,9 @@ sun4i-frontend-y += sun4i_frontend.o
> > > sun4i-drm-y += sun4i_drv.o
> > > sun4i-drm-y += sun4i_framebuffer.o
> > >
> > > +ifdef CONFIG_DRM_SUN4I_HDMI_AUDIO
> > > +sun4i-drm-hdmi-y += sun4i_hdmi_audio.o
> > > +endif
> > > sun4i-drm-hdmi-y += sun4i_hdmi_ddc_clk.o
> > > sun4i-drm-hdmi-y += sun4i_hdmi_enc.o
> > > sun4i-drm-hdmi-y += sun4i_hdmi_i2c.o
> > > diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi.h b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
> > > index 7ad3f06c127e..28621d289655 100644
> > > --- a/drivers/gpu/drm/sun4i/sun4i_hdmi.h
> > > +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
> > > @@ -42,7 +42,32 @@
> > > #define SUN4I_HDMI_VID_TIMING_POL_VSYNC BIT(1)
> > > #define SUN4I_HDMI_VID_TIMING_POL_HSYNC BIT(0)
> > >
> > > +#define SUN4I_HDMI_AUDIO_CTRL_REG 0x040
> > > +#define SUN4I_HDMI_AUDIO_CTRL_ENABLE BIT(31)
> > > +#define SUN4I_HDMI_AUDIO_CTRL_RESET BIT(30)
> > > +
> > > +#define SUN4I_HDMI_AUDIO_FMT_REG 0x048
> > > +#define SUN4I_HDMI_AUDIO_FMT_SRC BIT(31)
> > > +#define SUN4I_HDMI_AUDIO_FMT_LAYOUT BIT(3)
> > > +#define SUN4I_HDMI_AUDIO_FMT_CH_CFG(n) ((n) - 1)
> > > +#define SUN4I_HDMI_AUDIO_FMT_CH_CFG_MASK GENMASK(2, 0)
> > > +
> > > +#define SUN4I_HDMI_AUDIO_PCM_REG 0x4c
> > > +#define SUN4I_HDMI_AUDIO_PCM_CH_MAP(n, m) (((m) - 1) << ((n) * 4))
> > > +#define SUN4I_HDMI_AUDIO_PCM_CH_MAP_MASK(n) (GENMASK(2, 0) << ((n) * 4))
> > > +
> > > +#define SUN4I_HDMI_AUDIO_CTS_REG 0x050
> > > +#define SUN4I_HDMI_AUDIO_CTS(n) ((n) & GENMASK(19, 0))
> > > +
> > > +#define SUN4I_HDMI_AUDIO_N_REG 0x054
> > > +#define SUN4I_HDMI_AUDIO_N(n) ((n) & GENMASK(19, 0))
> > > +
> > > +#define SUN4I_HDMI_AUDIO_STAT0_REG 0x58
> > > +#define SUN4I_HDMI_AUDIO_STAT0_FREQ(n) ((n) << 24)
> > > +#define SUN4I_HDMI_AUDIO_STAT0_FREQ_MASK GENMASK(27, 24)
> > > +
> > > #define SUN4I_HDMI_AVI_INFOFRAME_REG(n) (0x080 + (n))
> > > +#define SUN4I_HDMI_AUDIO_INFOFRAME_REG(n) (0x0a0 + (n))
> > >
> > > #define SUN4I_HDMI_PAD_CTRL0_REG 0x200
> > > #define SUN4I_HDMI_PAD_CTRL0_BIASEN BIT(31)
> > > @@ -242,6 +267,11 @@ struct sun4i_hdmi_variant {
> > > bool ddc_fifo_has_dir;
> > > };
> > >
> > > +struct sun4i_hdmi_audio {
> > > + struct snd_soc_card *card;
> > > + u8 channels;
> > > +};
> > > +
> > > struct sun4i_hdmi {
> > > struct drm_connector connector;
> > > struct drm_encoder encoder;
> > > @@ -283,9 +313,14 @@ struct sun4i_hdmi {
> > > struct regmap_field *field_ddc_sda_en;
> > > struct regmap_field *field_ddc_sck_en;
> > >
> > > +
> > > struct sun4i_drv *drv;
> > >
> > > bool hdmi_monitor;
> > > + bool hdmi_audio;
> > > +
> > > + struct sun4i_hdmi_audio audio;
> > > +
> > > struct cec_adapter *cec_adap;
> > >
> > > const struct sun4i_hdmi_variant *variant;
> > > @@ -294,5 +329,7 @@ struct sun4i_hdmi {
> > > int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *clk);
> > > int sun4i_tmds_create(struct sun4i_hdmi *hdmi);
> > > int sun4i_hdmi_i2c_create(struct device *dev, struct sun4i_hdmi *hdmi);
> > > +int sun4i_hdmi_audio_create(struct sun4i_hdmi *hdmi);
> > > +void sun4i_hdmi_audio_destroy(struct sun4i_hdmi *hdmi);
> > >
> > > #endif /* _SUN4I_HDMI_H_ */
> > > diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_audio.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_audio.c
> > > new file mode 100644
> > > index 000000000000..f42f2cea4e9e
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_audio.c
> > > @@ -0,0 +1,450 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > +/*
> > > + * Copyright (C) 2020 Olimex Ltd.
> > > + * Author: Stefan Mavrodiev <stefan(a)olimex.com>
> > > + */
> > > +#include <linux/dma-mapping.h>
> > > +#include <linux/dmaengine.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of_dma.h>
> > > +#include <linux/regmap.h>
> > > +
> > > +#include <drm/drm_print.h>
> > > +
> > > +#include <sound/dmaengine_pcm.h>
> > > +#include <sound/pcm_drm_eld.h>
> > > +#include <sound/pcm_params.h>
> > > +#include <sound/soc.h>
> > > +
> > > +#include "sun4i_hdmi.h"
> > > +
> > > +static int sun4i_hdmi_audio_ctl_eld_info(struct snd_kcontrol *kcontrol,
> > > + struct snd_ctl_elem_info *uinfo)
> > > +{
> > > + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
> > > + uinfo->count = MAX_ELD_BYTES;
> > > + return 0;
> > > +}
> > > +
> > > +static int sun4i_hdmi_audio_ctl_eld_get(struct snd_kcontrol *kcontrol,
> > > + struct snd_ctl_elem_value *ucontrol)
> > > +{
> > > + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
> > > + struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
> > > + struct sun4i_hdmi *hdmi = snd_soc_card_get_drvdata(card);
> > > +
> > > + memcpy(ucontrol->value.bytes.data,
> > > + hdmi->connector.eld,
> > > + MAX_ELD_BYTES);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static const struct snd_kcontrol_new sun4i_hdmi_audio_controls[] = {
> > > + {
> > > + .access = SNDRV_CTL_ELEM_ACCESS_READ |
> > > + SNDRV_CTL_ELEM_ACCESS_VOLATILE,
> > > + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
> > > + .name = "ELD",
> > > + .info = sun4i_hdmi_audio_ctl_eld_info,
> > > + .get = sun4i_hdmi_audio_ctl_eld_get,
> > > + },
> > > +};
> > > +
> > > +static const struct snd_soc_dapm_widget sun4i_hdmi_audio_widgets[] = {
> > > + SND_SOC_DAPM_OUTPUT("TX"),
> > > +};
> > > +
> > > +static const struct snd_soc_dapm_route sun4i_hdmi_audio_routes[] = {
> > > + { "TX", NULL, "Playback" },
> > > +};
> > > +
> > > +static const struct snd_soc_component_driver sun4i_hdmi_audio_component = {
> > > + .controls = sun4i_hdmi_audio_controls,
> > > + .num_controls = ARRAY_SIZE(sun4i_hdmi_audio_controls),
> > > + .dapm_widgets = sun4i_hdmi_audio_widgets,
> > > + .num_dapm_widgets = ARRAY_SIZE(sun4i_hdmi_audio_widgets),
> > > + .dapm_routes = sun4i_hdmi_audio_routes,
> > > + .num_dapm_routes = ARRAY_SIZE(sun4i_hdmi_audio_routes),
> > > +};
> > > +
> > > +static int sun4i_hdmi_audio_startup(struct snd_pcm_substream *substream,
> > > + struct snd_soc_dai *dai)
> > > +{
> > > + struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
> > > + struct sun4i_hdmi *hdmi = snd_soc_card_get_drvdata(card);
> > > + u32 reg;
> > > + int ret;
> > > +
> > > + regmap_write(hdmi->regmap, SUN4I_HDMI_AUDIO_CTRL_REG, 0);
> > > + regmap_write(hdmi->regmap,
> > > + SUN4I_HDMI_AUDIO_CTRL_REG,
> > > + SUN4I_HDMI_AUDIO_CTRL_RESET);
> > > + ret = regmap_read_poll_timeout(hdmi->regmap,
> > > + SUN4I_HDMI_AUDIO_CTRL_REG,
> > > + reg, !reg, 100, 50000);
> > > + if (ret < 0) {
> > > + DRM_ERROR("Failed to reset HDMI Audio\n");
> > > + return ret;
> > > + }
> > > +
> > > + regmap_write(hdmi->regmap,
> > > + SUN4I_HDMI_AUDIO_CTRL_REG,
> > > + SUN4I_HDMI_AUDIO_CTRL_ENABLE);
> > > +
> > > + return snd_pcm_hw_constraint_eld(substream->runtime,
> > > + hdmi->connector.eld);
> > > +}
> > > +
> > > +static void sun4i_hdmi_audio_shutdown(struct snd_pcm_substream *substream,
> > > + struct snd_soc_dai *dai)
> > > +{
> > > + struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
> > > + struct sun4i_hdmi *hdmi = snd_soc_card_get_drvdata(card);
> > > +
> > > + regmap_write(hdmi->regmap, SUN4I_HDMI_AUDIO_CTRL_REG, 0);
> > > +}
> > > +
> > > +static int sun4i_hdmi_setup_audio_infoframes(struct sun4i_hdmi *hdmi)
> > > +{
> > > + union hdmi_infoframe frame;
> > > + u8 buffer[14];
> > > + int i, ret;
> > > +
> > > + ret = hdmi_audio_infoframe_init(&frame.audio);
> > > + if (ret < 0) {
> > > + DRM_ERROR("Failed to init HDMI audio infoframe\n");
> > > + return ret;
> > > + }
> > > +
> > > + frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
> > > + frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
> > > + frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
> > > + frame.audio.channels = hdmi->audio.channels;
> > > +
> > > + ret = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
> > > + if (ret < 0) {
> > > + DRM_ERROR("Failed to pack HDMI audio infoframe\n");
> > > + return ret;
> > > + }
> > > +
> > > + for (i = 0; i < sizeof(buffer); i++)
> > > + writeb(buffer[i],
> > > + hdmi->base + SUN4I_HDMI_AUDIO_INFOFRAME_REG(i));
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static void sun4i_hdmi_audio_set_cts_n(struct sun4i_hdmi *hdmi,
> > > + struct snd_pcm_hw_params *params)
> > > +{
> > > + struct drm_encoder *encoder = &hdmi->encoder;
> > > + struct drm_crtc *crtc = encoder->crtc;
> > > + const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> > > + u32 rate = params_rate(params);
> > > + u32 n, cts;
> > > + u64 tmp;
> > > +
> > > + /**
> > > + * Calculate Cycle Time Stamp (CTS) and Numerator (N):
> > > + *
> > > + * N = 128 * Samplerate / 1000
> > > + * CTS = (Ftdms * N) / (128 * Samplerate)
> > > + */
> > > +
> > > + n = 128 * rate / 1000;
> > > + tmp = (u64)(mode->clock * 1000) * n;
> > > + do_div(tmp, 128 * rate);
> > > + cts = tmp;
> > > +
> > > + regmap_write(hdmi->regmap,
> > > + SUN4I_HDMI_AUDIO_CTS_REG,
> > > + SUN4I_HDMI_AUDIO_CTS(cts));
> > > +
> > > + regmap_write(hdmi->regmap,
> > > + SUN4I_HDMI_AUDIO_N_REG,
> > > + SUN4I_HDMI_AUDIO_N(n));
> > > +}
> > > +
> > > +static int sun4i_hdmi_audio_set_hw_rate(struct sun4i_hdmi *hdmi,
> > > + struct snd_pcm_hw_params *params)
> > > +{
> > > + u32 rate = params_rate(params);
> > > + u32 val;
> > > +
> > > + switch (rate) {
> > > + case 44100:
> > > + val = 0x0;
> > > + break;
> > > + case 48000:
> > > + val = 0x2;
> > > + break;
> > > + case 32000:
> > > + val = 0x3;
> > > + break;
> > > + case 88200:
> > > + val = 0x8;
> > > + break;
> > > + case 96000:
> > > + val = 0x9;
> > > + break;
> > > + case 176400:
> > > + val = 0xc;
> > > + break;
> > > + case 192000:
> > > + val = 0xe;
> > > + break;
> > > + default:
> > > + return -EINVAL;
> > > + }
> > > +
> > > + regmap_update_bits(hdmi->regmap,
> > > + SUN4I_HDMI_AUDIO_STAT0_REG,
> > > + SUN4I_HDMI_AUDIO_STAT0_FREQ_MASK,
> > > + SUN4I_HDMI_AUDIO_STAT0_FREQ(val));
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int sun4i_hdmi_audio_set_hw_channels(struct sun4i_hdmi *hdmi,
> > > + struct snd_pcm_hw_params *params)
> > > +{
> > > + u32 channels = params_channels(params);
> > > +
> > > + if (channels > 8)
> > > + return -EINVAL;
> > > +
> > > + hdmi->audio.channels = channels;
> > > +
> > > + regmap_update_bits(hdmi->regmap,
> > > + SUN4I_HDMI_AUDIO_FMT_REG,
> > > + SUN4I_HDMI_AUDIO_FMT_LAYOUT,
> > > + (channels > 2) ? SUN4I_HDMI_AUDIO_FMT_LAYOUT : 0);
> > > +
> > > + regmap_update_bits(hdmi->regmap,
> > > + SUN4I_HDMI_AUDIO_FMT_REG,
> > > + SUN4I_HDMI_AUDIO_FMT_CH_CFG_MASK,
> > > + SUN4I_HDMI_AUDIO_FMT_CH_CFG(channels));
> > > +
> > > + regmap_write(hdmi->regmap, SUN4I_HDMI_AUDIO_PCM_REG, 0x76543210);
> > > +
> > > + /**
> > > + * If only one channel is required, send the same sample
> > > + * to the sink device as a left and right channel.
> > > + */
> > > + if (channels == 1)
> > > + regmap_update_bits(hdmi->regmap,
> > > + SUN4I_HDMI_AUDIO_PCM_REG,
> > > + SUN4I_HDMI_AUDIO_PCM_CH_MAP_MASK(1),
> > > + SUN4I_HDMI_AUDIO_PCM_CH_MAP(1, 1));
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int sun4i_hdmi_audio_hw_params(struct snd_pcm_substream *substream,
> > > + struct snd_pcm_hw_params *params,
> > > + struct snd_soc_dai *dai)
> > > +{
> > > + struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
> > > + struct sun4i_hdmi *hdmi = snd_soc_card_get_drvdata(card);
> > > + int ret;
> > > +
> > > + ret = sun4i_hdmi_audio_set_hw_rate(hdmi, params);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + ret = sun4i_hdmi_audio_set_hw_channels(hdmi, params);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + sun4i_hdmi_audio_set_cts_n(hdmi, params);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int sun4i_hdmi_audio_trigger(struct snd_pcm_substream *substream,
> > > + int cmd,
> > > + struct snd_soc_dai *dai)
> > > +{
> > > + struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
> > > + struct sun4i_hdmi *hdmi = snd_soc_card_get_drvdata(card);
> > > + int ret = 0;
> > > +
> > > + switch (cmd) {
> > > + case SNDRV_PCM_TRIGGER_START:
> > > + ret = sun4i_hdmi_setup_audio_infoframes(hdmi);
> > > + break;
> > > + default:
> > > + break;
> > > + }
> > > +
> > > + return ret;
> > > +}
> > > +
> > > +static const struct snd_soc_dai_ops sun4i_hdmi_audio_dai_ops = {
> > > + .startup = sun4i_hdmi_audio_startup,
> > > + .shutdown = sun4i_hdmi_audio_shutdown,
> > > + .hw_params = sun4i_hdmi_audio_hw_params,
> > > + .trigger = sun4i_hdmi_audio_trigger,
> > > +};
> > > +
> > > +static int sun4i_hdmi_audio_dai_probe(struct snd_soc_dai *dai)
> > > +{
> > > + struct snd_dmaengine_dai_dma_data *dma_data;
> > > +
> > > + dma_data = devm_kzalloc(dai->dev, sizeof(*dma_data), GFP_KERNEL);
> > > + if (!dma_data)
> > > + return -ENOMEM;
> > > +
> > > + dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> > > + dma_data->maxburst = 8;
> > > +
> > > + snd_soc_dai_init_dma_data(dai, dma_data, NULL);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static struct snd_soc_dai_driver sun4i_hdmi_audio_dai = {
> > > + .name = "HDMI",
> > > + .ops = &sun4i_hdmi_audio_dai_ops,
> > > + .probe = sun4i_hdmi_audio_dai_probe,
> > > + .playback = {
> > > + .stream_name = "Playback",
> > > + .channels_min = 1,
> > > + .channels_max = 8,
> > > + .formats = SNDRV_PCM_FMTBIT_S16_LE,
> > > + .rates = SNDRV_PCM_RATE_8000_192000,
> > > + },
> > > +};
> > > +
> > > +static const struct snd_pcm_hardware sun4i_hdmi_audio_pcm_hardware = {
> > > + .info = SNDRV_PCM_INFO_INTERLEAVED |
> > > + SNDRV_PCM_INFO_BLOCK_TRANSFER |
> > > + SNDRV_PCM_INFO_MMAP |
> > > + SNDRV_PCM_INFO_MMAP_VALID |
> > > + SNDRV_PCM_INFO_PAUSE |
> > > + SNDRV_PCM_INFO_RESUME,
> > > + .formats = SNDRV_PCM_FMTBIT_S16_LE,
> > > + .rates = SNDRV_PCM_RATE_8000_192000,
> > > + .rate_min = 8000,
> > > + .rate_max = 192000,
> > > + .channels_min = 1,
> > > + .channels_max = 8,
> > > + .buffer_bytes_max = 128 * 1024,
> > > + .period_bytes_min = 4 * 1024,
> > > + .period_bytes_max = 32 * 1024,
> > > + .periods_min = 2,
> > > + .periods_max = 8,
> > > + .fifo_size = 128,
> > > +};
> > > +
> > > +static const struct snd_dmaengine_pcm_config sun4i_hdmi_audio_pcm_config = {
> > > + .chan_names[SNDRV_PCM_STREAM_PLAYBACK] = "audio-tx",
> > > + .pcm_hardware = &sun4i_hdmi_audio_pcm_hardware,
> > > + .prealloc_buffer_size = 128 * 1024,
> > > + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
> > > +};
> > > +
> > > +struct snd_soc_card sun4i_hdmi_audio_card = {
> > > + .name = "sun4i-hdmi",
> > > +};
> > > +
> > > +int sun4i_hdmi_audio_create(struct sun4i_hdmi *hdmi)
> > > +{
> > > + struct snd_soc_card *card = &sun4i_hdmi_audio_card;
> > > + struct snd_soc_dai_link_component *comp;
> > > + struct snd_soc_dai_link *link;
> > > + int ret;
> > > +
> > > + ret = snd_dmaengine_pcm_register(hdmi->dev,
> > > + &sun4i_hdmi_audio_pcm_config, 0);
> > > + if (ret < 0) {
> > > + DRM_ERROR("Could not register PCM\n");
> > > + return ret;
> > > + }
> > > +
> > > + ret = snd_soc_register_component(hdmi->dev,
> > > + &sun4i_hdmi_audio_component,
> > > + &sun4i_hdmi_audio_dai, 1);
> > > + if (ret < 0) {
> > > + DRM_ERROR("Could not register DAI\n");
> > > + goto unregister_pcm;
> > > + }
> > > +
> > > + link = devm_kzalloc(hdmi->dev, sizeof(*link), GFP_KERNEL);
> > > + if (!link) {
> > > + ret = -ENOMEM;
> > > + goto unregister_component;
> > > + }
> > > +
> > > + comp = devm_kzalloc(hdmi->dev, sizeof(*comp) * 3, GFP_KERNEL);
> > > + if (!comp) {
> > > + ret = -ENOMEM;
> > > + goto unregister_component;
> > > + }
> > > +
> > > + link->cpus = &comp[0];
> > > + link->codecs = &comp[1];
> > > + link->platforms = &comp[2];
> > > +
> > > + link->num_cpus = 1;
> > > + link->num_codecs = 1;
> > > + link->num_platforms = 1;
> > > +
> > > + link->playback_only = 1;
> > > +
> > > + link->name = "SUN4I-HDMI";
> > > + link->stream_name = "SUN4I-HDMI PCM";
> > > +
> > > + link->codecs->name = dev_name(hdmi->dev);
> > > + link->codecs->dai_name = sun4i_hdmi_audio_dai.name;
> > > +
> > > + link->cpus->dai_name = dev_name(hdmi->dev);
> > > +
> > > + link->platforms->name = dev_name(hdmi->dev);
> > > +
> > > + link->dai_fmt = SND_SOC_DAIFMT_I2S;
> > > +
> > > + card->dai_link = link;
> > > + card->num_links = 1;
> > > + card->dev = hdmi->dev;
> > > +
> > > + hdmi->audio.card = card;
> > > +
> > > + /**
> > > + * snd_soc_register_card() will overwrite the driver_data pointer.
> > > + * So before registering the card, store the original pointer in
> > > + * card->drvdata.
> > > + */
> > > + snd_soc_card_set_drvdata(card, hdmi);
> > > + ret = snd_soc_register_card(card);
> > > + if (ret)
> > > + goto unregister_component;
> > So using ASoC with all the components IMHO is just adding dead weight. The
> > audio interface for this particular hardware is just a FIFO that needs to
> > be written to by an external DMA engine, and a bunch of controls to setup
> > the parameters of the HDMI audio stream. There's no power sequencing to do,
> > and no actual individual components to control. There's no reason you couldn't
> > use just the ALSA DMAENGINE helpers to create a simple ALSA sound card.
> >
> > (Maybe we could clean it up after it's merged? Would there be any issues
> > with backward compatibility?)
> >
> > I think the only example of this besides ASoC is the PXA2xx sound library
> > and AC97 driver:
> >
> > - sound/arm/pxa2xx-pcm-lib.c
> > - sound/arm/pxa2xx-ac97.c
>
> I'd like to hear Maxime opinion on this. I get it why it's overkill to use
> ASoC.
> However it will take only couple of lines to make the changes for v4. On the
> other
> side with dropping the ASoC, the driver must be almost rewritten. It's not
> such a big deal,
> but I want to know that this is the right thing to do.
I don't really have an opinion on this, either way is fine for me, so
if it's simpler to go for ALSA, then let's do it :)
Maxime
1
0