Alsa-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- 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
May 2017
- 129 participants
- 228 discussions
This adds a driver for the TI PCM9211 digital audio interfaces
transceiver. The driver currently only handles the receiver aspect of
the chip and supports only control of the primary I2S (MAIN) output
port. Support for AUX output is trivial to add, but wasn't done due to
missing hardware for testing. The same goes for the transmitter
functionality.
The driver uses some extra device-tree fields to allow configuration of
pin functions directly out of this driver.
Signed-off-by: Julian Scheel <julian(a)jusst.de>
---
.../devicetree/bindings/sound/pcm9211.txt | 118 ++
MAINTAINERS | 6 +
include/dt-bindings/sound/pcm9211.h | 55 +
sound/soc/codecs/Kconfig | 10 +
sound/soc/codecs/Makefile | 4 +
sound/soc/codecs/pcm9211-i2c.c | 65 +
sound/soc/codecs/pcm9211.c | 1357 ++++++++++++++++++++
sound/soc/codecs/pcm9211.h | 206 +++
8 files changed, 1821 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/pcm9211.txt
create mode 100644 include/dt-bindings/sound/pcm9211.h
create mode 100644 sound/soc/codecs/pcm9211-i2c.c
create mode 100644 sound/soc/codecs/pcm9211.c
create mode 100644 sound/soc/codecs/pcm9211.h
diff --git a/Documentation/devicetree/bindings/sound/pcm9211.txt b/Documentation/devicetree/bindings/sound/pcm9211.txt
new file mode 100644
index 000000000000..bfc29889caf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/pcm9211.txt
@@ -0,0 +1,118 @@
+PCM9211 audio CODEC
+
+This device support both I2C and SPI (configured with pin strapping
+on the board). The driver is currently implementing i2c only.
+
+Required properties:
+
+ - compatible : "ti,pcm9211"
+
+ - reg : the I2C address of the device for I2C, the chip select
+ number for SPI.
+
+ - VCCAD-supply, VCC-supply, VDDRX-supply and AVDD-supply :
+ power supplies for the device, as covered in bindings/regulator/regulator.txt
+
+Optional properties:
+
+ - clocks : A clock specifier for the clock connected to XTI. While the
+ device could work without it, this driver currently relies on it being
+ available
+
+ - clock-names : Must speficy "xti" to match the requested clock.
+
+ - reset-gpios : GPIO wired to the reset pin, if not supplied a soft-reset is
+ used as fallback
+
+ - int0-gpios : GPIO connected to interrupt0 output of the PCM9211. The
+ line can be configured to any of MPO0,1 and MPIOA,B,C0-4 and error/int0.
+ If this is specified it is used as an interrupt to notify alsa controls
+ about changes of the incoming sampling rate on DIR (spdif) as well as NPCM
+ status.
+
+ - ti,group-function: An array with size 3 specifying function for pingroups
+ A, B and C. Possible values are defined in dt-bindings/sound/pcm9211.h
+
+ - ti,mpio-a-flags-gpio: An array with size 4 specifying flags out or gpio
+ mode per pin, when function DIR_FLAGS_GPIO is selected for group a.
+ Possible values are defined in dt-bindings/sound/pcm9211.h
+
+ - ti,mpio-b-flags-gpio: An array with size 4 specifying flags out or gpio
+ mode per pin, when function DIR_FLAGS_GPIO is selected for group b.
+ Possible values are defined in dt-bindings/sound/pcm9211.h
+
+ - ti,mpio-c-flags-gpio: An array with size 4 specifying flags out or gpio
+ mode per pin, when function DIR_FLAGS_GPIO is selected for group c.
+ Possible values are defined in dt-bindings/sound/pcm9211.h
+
+ - ti,mpio-a-flag: An array with size 4 specifying flag assinged per pin,
+ when function DIR_FLAGS_GPIO is selected for group a and pin is set to
+ flags mode.
+ Possible values are defined in dt-bindings/sound/pcm9211.h
+
+ - ti,mpio-b-flag: An array with size 4 specifying flag assinged per pin,
+ when function DIR_FLAGS_GPIO is selected for group b and pin is set to
+ flags mode.
+ Possible values are defined in dt-bindings/sound/pcm9211.h
+
+ - ti,mpio-c-flag: An array with size 4 specifying flag assinged per pin,
+ when function DIR_FLAGS_GPIO is selected for group c and pin is set to
+ flags mode.
+ Possible values are defined in dt-bindings/sound/pcm9211.h
+
+ - ti,mpo-function: An array with size 2 specifying flag assinged per mpo
+ pin.
+ Possible values are defined in dt-bindings/sound/pcm9211.h
+
+ - ti,int0-function: Selects error/int0 pin function.
+ Possible values are defined in dt-bindings/sound/pcm9211.h
+
+ - ti,int1-function: Selects error/int1 pin function.
+ Possible values are defined in dt-bindings/sound/pcm9211.h
+
+Examples:
+
+ pcm9211: pcm9211@43 {
+ compatible = "ti,pcm9211";
+ reg = <0x43>;
+
+ VCCAD-supply = <®_5v0_analog>;
+ VCC-supply = <®_3v3_pll_analog>;
+ VDDRX-supply = <®_3v3>;
+ DVDD-supply = <®_3v3>;
+
+ clocks = <&xti_clk>;
+ clock-names = "xti";
+ };
+
+
+ pcm9211: pcm9211@43 {
+ compatible = "ti,pcm9211";
+ reg = <0x43>;
+
+ VCCAD-supply = <®_5v0_analog>;
+ VCC-supply = <®_3v3_pll_analog>;
+ VDDRX-supply = <®_3v3>;
+ DVDD-supply = <®_3v3>;
+
+ clocks = <&xti_clk>;
+ clock-names = "xti";
+
+ reset-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
+ int-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
+
+ ti,group-function = /bits/ 8
+ <PCM9211_MPIO_A_GROUP_BIPHASE_INPUT,
+ PCM9211_MPIO_B_GROUP_DIR_FLAGS_GPIO,
+ PCM9211_MPIO_C_GROUP_AUXIN1>;
+ ti,mpio-b-flags-gpio = /bits/ 8
+ <PCM9211_MPIO_DIR_FLAGS,
+ PCM9211_MPIO_DIR_FLAGS,
+ PCM9211_MPIO_DIR_FLAGS,
+ PCM9211_MPIO_DIR_FLAGS>;
+ ti,mpio-b-flag = /bits/ 8
+ <PCM9211_MPIO_FLAG_INT0,
+ PCM9211_MPIO_FLAG_CLKST,
+ PCM9211_MPIO_FLAG_CLKST,
+ PCM9211_MPIO_FLAG_CLKST>;
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index c2ffc96ccf4c..1f3b2e98dd9d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9985,6 +9985,12 @@ S: Supported
F: Documentation/devicetree/bindings/pci/pci-thunder-*
F: drivers/pci/host/pci-thunder-*
+PCM9211 AUDIO CODEC DRIVER
+M: Julian Scheel <julian(a)jusst.de>
+L: alsa-devel(a)alsa-project.org (moderated for non-subscribers)
+S: Maintained
+F: sound/soc/codecs/pcm9211*
+
PCMCIA SUBSYSTEM
P: Linux PCMCIA Team
L: linux-pcmcia(a)lists.infradead.org
diff --git a/include/dt-bindings/sound/pcm9211.h b/include/dt-bindings/sound/pcm9211.h
new file mode 100644
index 000000000000..6d1367f21d25
--- /dev/null
+++ b/include/dt-bindings/sound/pcm9211.h
@@ -0,0 +1,55 @@
+#ifndef __DT_PCM9211_H
+#define __DT_PCM9211_H
+
+/* INT0/ERROR select */
+#define PCM9211_ERROR_INT0_ERROR 0
+#define PCM9211_ERROR_INT0_INT0 1
+
+/* INT1/NPCM select */
+#define PCM9211_NPCM_INT1_NPCM 0
+#define PCM9211_NPCM_INT1_INT1 1
+
+/* MPIO group functions */
+#define PCM9211_MPIO_A_GROUP_BIPHASE_INPUT 0
+#define PCM9211_MPIO_A_GROUP_CLKST_VOUT_XMCK_INT0 1
+#define PCM9211_MPIO_A_GROUP_SEC_BCK_LRCK_XMCKO_INT0 2
+#define PCM9211_MPIO_A_GROUP_DIR_FLAGS_GPIO 3
+
+#define PCM9211_MPIO_B_GROUP_AUXIN2 0
+#define PCM9211_MPIO_B_GROUP_AUXOUT 1
+#define PCM9211_MPIO_B_GROUP_SAMPLING_FREQ_RES 2
+#define PCM9211_MPIO_B_GROUP_DIR_FLAGS_GPIO 3
+#define PCM9211_MPIO_B_GROUP_DIR_BCUV_BFRAME_VUC 4
+#define PCM9211_MPIO_B_GROUP_EXT_ADC_IN 5
+#define PCM9211_MPIO_B_GROUP_TEST_MODE 7
+
+#define PCM9211_MPIO_C_GROUP_AUXIN1 0
+#define PCM9211_MPIO_C_GROUP_ADC_CLOCK_DATA 1
+#define PCM9211_MPIO_C_GROUP_SAMPLING_FREQ_RES 2
+#define PCM9211_MPIO_C_GROUP_DIR_FLAGS_GPIO 3
+#define PCM9211_MPIO_C_GROUP_DIR_BCUV_BFRAME_VUC 4
+#define PCM9211_MPIO_C_GROUP_DIT_CLOCK_DATA 5
+
+/* MPIO flags/gpio select */
+#define PCM9211_MPIO_DIR_FLAGS 0
+#define PCM9211_MPIO_GPIO 1
+
+/* MPIO flags */
+#define PCM9211_MPIO_FLAG_CLKST 0
+#define PCM9211_MPIO_FLAG_EMPH 1
+#define PCM9211_MPIO_FLAG_BPSYNC 2
+#define PCM9211_MPIO_FLAG_DTSCD 3
+#define PCM9211_MPIO_FLAG_PARITY 4
+#define PCM9211_MPIO_FLAG_LOCK 5
+#define PCM9211_MPIO_FLAG_VOUT 6
+#define PCM9211_MPIO_FLAG_UOUT 7
+#define PCM9211_MPIO_FLAG_COUT 8
+#define PCM9211_MPIO_FLAG_BFRAME 9
+#define PCM9211_MPIO_FLAG_FSOUT0 10
+#define PCM9211_MPIO_FLAG_FSOUT1 11
+#define PCM9211_MPIO_FLAG_FSOUT2 12
+#define PCM9211_MPIO_FLAG_FSOUT3 13
+#define PCM9211_MPIO_FLAG_INT0 14
+#define PCM9211_MPIO_FLAG_INT1 15
+
+#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 883ed4c8a551..d7cf85ba020f 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -113,6 +113,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM5102A
select SND_SOC_PCM512x_I2C if I2C
select SND_SOC_PCM512x_SPI if SPI_MASTER
+ select SND_SOC_PCM9211_I2C if I2C
select SND_SOC_RT286 if I2C
select SND_SOC_RT298 if I2C
select SND_SOC_RT5514 if I2C
@@ -684,6 +685,15 @@ config SND_SOC_PCM512x_SPI
select SND_SOC_PCM512x
select REGMAP_SPI
+config SND_SOC_PCM9211
+ tristate
+
+config SND_SOC_PCM9211_I2C
+ tristate "Texas Instruments PCM9211 CODEC - I2C"
+ depends on I2C
+ select SND_SOC_PCM9211
+ select REGMAP_I2C
+
config SND_SOC_RL6231
tristate
default y if SND_SOC_RT5514=y
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 28a63fdaf982..a8eecee5fcfc 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -110,6 +110,8 @@ snd-soc-pcm5102a-objs := pcm5102a.o
snd-soc-pcm512x-objs := pcm512x.o
snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
+snd-soc-pcm9211-objs := pcm9211.o
+snd-soc-pcm9211-i2c-objs := pcm9211-i2c.o
snd-soc-rl6231-objs := rl6231.o
snd-soc-rl6347a-objs := rl6347a.o
snd-soc-rt286-objs := rt286.o
@@ -344,6 +346,8 @@ obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o
obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o
obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
+obj-$(CONFIG_SND_SOC_PCM9211) += snd-soc-pcm9211.o
+obj-$(CONFIG_SND_SOC_PCM9211_I2C) += snd-soc-pcm9211-i2c.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
diff --git a/sound/soc/codecs/pcm9211-i2c.c b/sound/soc/codecs/pcm9211-i2c.c
new file mode 100644
index 000000000000..e0678b280f11
--- /dev/null
+++ b/sound/soc/codecs/pcm9211-i2c.c
@@ -0,0 +1,65 @@
+/*
+ * PCM9211 codec i2c driver
+ *
+ * Copyright (C) 2017 jusst technologies GmbH / jusst.engineering
+ *
+ * Author: Julian Scheel <julian(a)jusst.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include <sound/soc.h>
+
+#include "pcm9211.h"
+
+static int pcm9211_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(i2c, &pcm9211_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return pcm9211_probe(&i2c->dev, regmap);
+}
+
+static int pcm9211_i2c_remove(struct i2c_client *i2c)
+{
+ pcm9211_remove(&i2c->dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id pcm9211_i2c_id[] = {
+ { "pcm9211", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcm9211_i2c_id);
+
+static const struct of_device_id pcm9211_of_match[] = {
+ { .compatible = "ti,pcm9211", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm9211_of_match);
+
+static struct i2c_driver pcm9211_i2c_driver = {
+ .probe = pcm9211_i2c_probe,
+ .remove = pcm9211_i2c_remove,
+ .id_table = pcm9211_i2c_id,
+ .driver = {
+ .name = "pcm9211",
+ .of_match_table = pcm9211_of_match,
+ .pm = &pcm9211_pm_ops,
+ },
+};
+module_i2c_driver(pcm9211_i2c_driver);
+
+MODULE_DESCRIPTION("PCM9211 I2C codec driver");
+MODULE_AUTHOR("Julian Scheel <julian(a)jusst.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm9211.c b/sound/soc/codecs/pcm9211.c
new file mode 100644
index 000000000000..0ab4ad551df8
--- /dev/null
+++ b/sound/soc/codecs/pcm9211.c
@@ -0,0 +1,1357 @@
+/*
+ * PCM9211 codec driver
+ *
+ * Copyright (C) 2017 jusst technologies GmbH / jusst.engineering
+ *
+ * Author; Julian Scheel <julian(a)jusst.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "pcm9211.h"
+
+#define PCM9211_MAX_SYSCLK 24576000
+
+#define PCM9211_SUPPLIES 4
+static const char *const pcm9211_supply_names[PCM9211_SUPPLIES] = {
+ "VCCAD",
+ "VCC",
+ "VDDRX",
+ "DVDD",
+};
+
+struct pcm9211_priv {
+ struct regulator_bulk_data supplies[PCM9211_SUPPLIES];
+ struct snd_pcm_hw_constraint_list rate_constraints;
+ struct delayed_work npcm_clear_work;
+ struct snd_kcontrol *preamble_ctl;
+ struct snd_kcontrol *npcm_ctl;
+ struct snd_kcontrol *rate_ctl;
+ struct snd_kcontrol *dts_ctl;
+ struct snd_soc_codec *codec;
+ struct gpio_desc *reset;
+ struct gpio_desc *int0;
+ struct regmap *regmap;
+ struct device *dev;
+ struct clk *xti;
+
+ unsigned int dir_rate;
+ unsigned long sysclk;
+ u8 burst_preamble[4];
+ u8 npcm_state;
+};
+
+static const struct regmap_range pcm9211_reg_rd_range[] = {
+ regmap_reg_range(PCM9211_ERR_OUT, PCM9211_PD_BUF1),
+ regmap_reg_range(PCM9211_SYS_RESET, PCM9211_SYS_RESET),
+ regmap_reg_range(PCM9211_ADC_CTRL1, PCM9211_ADC_CTRL1),
+ regmap_reg_range(PCM9211_ADC_L_CH_ATT, PCM9211_ADC_CTRL3),
+ regmap_reg_range(PCM9211_DIR_STATUS1, PCM9211_DIT_STATUS6),
+ regmap_reg_range(PCM9211_MAIN_AUX_MUTE, PCM9211_MPIO_C_DATA_IN),
+};
+
+static const struct regmap_access_table pcm9211_reg_rd_table = {
+ .yes_ranges = pcm9211_reg_rd_range,
+ .n_yes_ranges = ARRAY_SIZE(pcm9211_reg_rd_range),
+};
+
+static const struct regmap_range pcm9211_reg_wr_range[] = {
+ regmap_reg_range(PCM9211_ERR_OUT, PCM9211_INT1_CAUSE),
+ regmap_reg_range(PCM9211_INT_POLARITY, PCM9211_FS_CALC_TARGET),
+ regmap_reg_range(PCM9211_SYS_RESET, PCM9211_SYS_RESET),
+ regmap_reg_range(PCM9211_ADC_CTRL1, PCM9211_ADC_CTRL1),
+ regmap_reg_range(PCM9211_ADC_L_CH_ATT, PCM9211_ADC_CTRL3),
+ regmap_reg_range(PCM9211_DIT_CTRL1, PCM9211_DIT_STATUS6),
+ regmap_reg_range(PCM9211_MAIN_AUX_MUTE, PCM9211_MPIO_C_DATA_OUT),
+};
+
+static const struct regmap_access_table pcm9211_reg_wr_table = {
+ .yes_ranges = pcm9211_reg_wr_range,
+ .n_yes_ranges = ARRAY_SIZE(pcm9211_reg_wr_range),
+};
+
+static const struct regmap_range pcm9211_reg_volatile_range[] = {
+ regmap_reg_range(PCM9211_INT0_OUT, PCM9211_INT1_OUT),
+ regmap_reg_range(PCM9211_BIPHASE_INFO, PCM9211_PD_BUF1),
+ regmap_reg_range(PCM9211_DIR_STATUS1, PCM9211_DIR_STATUS6),
+};
+
+static const struct regmap_access_table pcm9211_reg_volatile_table = {
+ .yes_ranges = pcm9211_reg_volatile_range,
+ .n_yes_ranges = ARRAY_SIZE(pcm9211_reg_volatile_range),
+};
+
+static const struct reg_default pcm9211_reg_defaults[] = {
+ { PCM9211_ERR_OUT, 0x00 },
+ { PCM9211_DIR_INITIAL1, 0x00 },
+ { PCM9211_DIR_INITIAL2, 0x01 },
+ { PCM9211_DIR_INITIAL3, 0x04 },
+ { PCM9211_OSC_CTRL, 0x00 },
+ { PCM9211_ERR_CAUSE, 0x01 },
+ { PCM9211_AUTO_SEL_CAUSE, 0x01 },
+ { PCM9211_DIR_FS_RANGE, 0x00 },
+ { PCM9211_NON_PCM_DEF, 0x03 },
+ { PCM9211_DTS_CD_LD, 0x0c },
+ { PCM9211_INT0_CAUSE, 0xff },
+ { PCM9211_INT1_CAUSE, 0xff },
+ { PCM9211_INT0_OUT, 0x00 },
+ { PCM9211_INT1_OUT, 0x00 },
+ { PCM9211_INT_POLARITY, 0x00 },
+ { PCM9211_DIR_OUT_FMT, 0x04 },
+ { PCM9211_DIR_RSCLK_RATIO, 0x02 },
+ { PCM9211_XTI_SCLK_FREQ, 0x1a },
+ { PCM9211_DIR_SOURCE_BIT2, 0x22 },
+ { PCM9211_XTI_SOURCE_BIT2, 0x22 },
+ { PCM9211_DIR_INP_BIPHASE, 0xc2 },
+ { PCM9211_RECOUT0_BIPHASE, 0x02 },
+ { PCM9211_RECOUT1_BIPHASE, 0x02 },
+ { PCM9211_FS_CALC_TARGET, 0x00 },
+ { PCM9211_FS_CALC_RESULT, 0x08 },
+ { PCM9211_BIPHASE_INFO, 0x08 },
+ { PCM9211_PC_BUF0, 0x01 },
+ { PCM9211_PC_BUF1, 0x00 },
+ { PCM9211_PD_BUF0, 0x20 },
+ { PCM9211_PD_BUF1, 0x57 },
+ { PCM9211_SYS_RESET, 0x40 },
+ { PCM9211_ADC_CTRL1, 0x02 },
+ { PCM9211_ADC_L_CH_ATT, 0xd7 },
+ { PCM9211_ADC_R_CH_ATT, 0xd7 },
+ { PCM9211_ADC_CTRL2, 0x00 },
+ { PCM9211_ADC_CTRL3, 0x00 },
+ { PCM9211_DIR_STATUS1, 0x04 },
+ { PCM9211_DIR_STATUS2, 0x00 },
+ { PCM9211_DIR_STATUS3, 0x00 },
+ { PCM9211_DIR_STATUS4, 0x00 },
+ { PCM9211_DIR_STATUS5, 0x00 },
+ { PCM9211_DIR_STATUS6, 0x00 },
+ { PCM9211_DIT_CTRL1, 0x44 },
+ { PCM9211_DIT_CTRL2, 0x10 },
+ { PCM9211_DIT_CTRL3, 0x00 },
+ { PCM9211_DIT_STATUS1, 0x00 },
+ { PCM9211_DIT_STATUS2, 0x00 },
+ { PCM9211_DIT_STATUS3, 0x00 },
+ { PCM9211_DIT_STATUS4, 0x00 },
+ { PCM9211_DIT_STATUS5, 0x00 },
+ { PCM9211_DIT_STATUS6, 0x00 },
+ { PCM9211_MAIN_AUX_MUTE, 0x00 },
+ { PCM9211_MAIN_OUT_SOURCE, 0x00 },
+ { PCM9211_AUX_OUT_SOURCE, 0x00 },
+ { PCM9211_MPIO_B_MAIN_HIZ, 0x00 },
+ { PCM9211_MPIO_C_MPIO_A_HIZ, 0x0f },
+ { PCM9211_MPIO_GROUP, 0x40 },
+ { PCM9211_MPIO_A_FLAGS, 0x00 },
+ { PCM9211_MPIO_B_MPIO_C_FLAGS, 0x00 },
+ { PCM9211_MPIO_A1_A0_OUT_FLAG, 0x00 },
+ { PCM9211_MPIO_A3_A2_OUT_FLAG, 0x00 },
+ { PCM9211_MPIO_B1_B0_OUT_FLAG, 0x00 },
+ { PCM9211_MPIO_B3_B2_OUT_FLAG, 0x00 },
+ { PCM9211_MPIO_C1_C0_OUT_FLAG, 0x00 },
+ { PCM9211_MPIO_C3_C2_OUT_FLAG, 0x00 },
+ { PCM9211_MPO_1_0_FUNC, 0x3d },
+ { PCM9211_MPIO_A_B_DIR, 0x00 },
+ { PCM9211_MPIO_C_DIR, 0x00 },
+ { PCM9211_MPIO_A_B_DATA_OUT, 0x00 },
+ { PCM9211_MPIO_C_DATA_OUT, 0x00 },
+ { PCM9211_MPIO_A_B_DATA_IN, 0x00 },
+ { PCM9211_MPIO_C_DATA_IN, 0x02 },
+};
+
+const struct regmap_config pcm9211_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = PCM9211_MPIO_C_DATA_IN,
+ .wr_table = &pcm9211_reg_wr_table,
+ .rd_table = &pcm9211_reg_rd_table,
+ .volatile_table = &pcm9211_reg_volatile_table,
+ .reg_defaults = pcm9211_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(pcm9211_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(pcm9211_regmap);
+
+static const u32 adc_rates[] = { 48000, 92000 };
+static const struct snd_pcm_hw_constraint_list adc_rate_constraints = {
+ .count = ARRAY_SIZE(adc_rates),
+ .list = adc_rates,
+};
+
+static const int biphase_rates[] = {
+ 0, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100,
+ 48000, 64000, 88200, 96000, 128000, 176400, 192000
+};
+
+static const unsigned int pcm9211_sck_ratios[] = { 1, 2, 4, 8 };
+static const unsigned int pcm9211_bck_ratios[] = { 2, 4, 8, 16 };
+static const unsigned int pcm9211_lrck_ratios[] = { 128, 256, 512, 1024 };
+#define PCM9211_NUM_SCK_RATIOS ARRAY_SIZE(pcm9211_sck_ratios)
+#define PCM9211_NUM_BCK_RATIOS ARRAY_SIZE(pcm9211_bck_ratios)
+#define PCM9211_NUM_LRCK_RATIOS ARRAY_SIZE(pcm9211_lrck_ratios)
+
+static int pcm9211_main_output_port(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+ unsigned int val;
+ unsigned int port;
+ int ret;
+
+ ret = regmap_read(priv->regmap, PCM9211_MAIN_OUT_SOURCE, &val);
+ if (ret) {
+ dev_err(dev, "Failed to read selected source: %d\n", ret);
+ return ret;
+ }
+
+ port = (val & PCM9211_MOPSRC_MASK) >> PCM9211_MOPSRC_SHIFT;
+ if (port == PCM9211_MOSRC_AUTO) {
+ ret = regmap_read(priv->regmap, PCM9211_BIPHASE_INFO, &val);
+ if (ret) {
+ dev_err(dev, "Failed to read biphase information: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* Assumes that Sampling Frequency Status calculation
+ * corresponds with DIR Lock, which seems to to be exposed to
+ * any register directly
+ */
+ if ((val & PCM9211_BIPHASE_SFSST_MASK) == 0)
+ port = PCM9211_MOSRC_DIR;
+ else
+ port = PCM9211_MOSRC_ADC;
+ }
+
+ return port;
+}
+
+static int pcm9211_dir_rate(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(priv->regmap, PCM9211_BIPHASE_INFO, &val);
+ if (ret) {
+ dev_err(dev, "Failed to read biphase information: %d\n", ret);
+ return ret;
+ }
+
+ if ((val & PCM9211_BIPHASE_SFSST_MASK)) {
+ dev_dbg(dev, "Biphase Fs calculation not locked\n");
+ return 0;
+ }
+
+ return biphase_rates[(val & PCM9211_BIPHASE_SFSOUT_MASK)
+ >> PCM9211_BIPHASE_SFSOUT_SHIFT];
+}
+
+static int pcm9211_read_burst_preamble(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_raw_read(priv->regmap, PCM9211_PC_BUF0,
+ priv->burst_preamble, 4);
+ if (ret) {
+ dev_err(dev, "Failed to read burst preamble: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "Burst preamble: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ priv->burst_preamble[0], priv->burst_preamble[1],
+ priv->burst_preamble[2], priv->burst_preamble[3]);
+
+ return 0;
+}
+
+static int pcm9211_dir_rate_kctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 8000;
+ uinfo->value.integer.min = 96000;
+
+ return 0;
+}
+
+static int pcm9211_dir_rate_kctl(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct pcm9211_priv *priv = snd_soc_component_get_drvdata(component);
+ struct device *dev = priv->dev;
+
+ /* If we have an interrupt connected dir_rate is up-to-date */
+ if (!priv->int0)
+ priv->dir_rate = pcm9211_dir_rate(dev);
+
+ ucontrol->value.integer.value[0] = priv->dir_rate;
+
+ return 0;
+}
+
+#define pcm9211_dir_npcm_kctl_info snd_ctl_boolean_mono_info
+#define pcm9211_dir_npcm_kctl pcm9211_int0_kctl
+
+#define pcm9211_dir_dtscd_kctl_info snd_ctl_boolean_mono_info
+#define pcm9211_dir_dtscd_kctl pcm9211_int0_kctl
+
+static int pcm9211_int0_kctl(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct pcm9211_priv *priv = snd_soc_component_get_drvdata(component);
+ u8 mask = kcontrol->private_value & 0xff;
+ struct device *dev = priv->dev;
+ unsigned int cause;
+ int ret;
+
+ /* If interrupt line is not connected read the last interrupt state */
+ if (!priv->int0) {
+ ret = regmap_read(priv->regmap, PCM9211_INT0_OUT, &cause);
+ if (ret) {
+ dev_err(dev, "Failed to read int0 cause: %d\n", ret);
+ return IRQ_HANDLED;
+ }
+ priv->npcm_state = cause & (PCM9211_INT0_MNPCM0_MASK |
+ PCM9211_INT0_MDTSCD0_MASK);
+ }
+
+ ucontrol->value.integer.value[0] = (priv->npcm_state & mask) == mask;
+
+ return 0;
+}
+
+static int pcm9211_dir_preamble_kctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = 4;
+
+ return 0;
+}
+
+static int pcm9211_dir_preamble_kctl(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct pcm9211_priv *priv = snd_soc_component_get_drvdata(component);
+ struct device *dev = priv->dev;
+
+ /* If we have an interrupt connected preamble is up-to-date */
+ if (!priv->int0)
+ priv->dir_rate = pcm9211_read_burst_preamble(dev);
+
+ memcpy(ucontrol->value.bytes.data, priv->burst_preamble, 4);
+
+ return 0;
+}
+
+static struct snd_kcontrol* pcm9211_get_ctl(struct device *dev, const char *name)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+ struct snd_ctl_elem_id elem_id;
+
+ memset(&elem_id, 0, sizeof(elem_id));
+ elem_id.iface = SNDRV_CTL_ELEM_IFACE_PCM;
+ strcpy(elem_id.name, name);
+ return snd_ctl_find_id(priv->codec->component.card->snd_card, &elem_id);
+}
+
+static struct snd_kcontrol* pcm9211_get_rate_ctl(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+
+ if (!priv->rate_ctl)
+ priv->rate_ctl = pcm9211_get_ctl(dev, "DIR Sample Rate");
+
+ return priv->rate_ctl;
+}
+
+static struct snd_kcontrol* pcm9211_get_npcm_ctl(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+
+ if (!priv->npcm_ctl)
+ priv->npcm_ctl = pcm9211_get_ctl(dev, "DIR Non-PCM Bitstream");
+
+ return priv->npcm_ctl;
+}
+
+static struct snd_kcontrol* pcm9211_get_dtscd_ctl(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+
+ if (!priv->dts_ctl)
+ priv->dts_ctl = pcm9211_get_ctl(dev, "DIR DTS Bitstream");
+
+ return priv->dts_ctl;
+}
+
+static struct snd_kcontrol* pcm9211_get_burst_preamble_ctl(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+
+ if (!priv->preamble_ctl)
+ priv->preamble_ctl = pcm9211_get_ctl(dev, "DIR Burst Preamble");
+
+ return priv->preamble_ctl;
+}
+
+static irqreturn_t pcm9211_interrupt(int irq, void *data)
+{
+ struct pcm9211_priv *priv = data;
+ struct device *dev = priv->dev;
+
+ unsigned int cause;
+ int rate;
+ int ret;
+
+ ret = regmap_read(priv->regmap, PCM9211_INT0_OUT, &cause);
+ if (ret) {
+ dev_err(dev, "Failed to read int0 cause: %d\n", ret);
+ return IRQ_HANDLED;
+ }
+
+ if (cause & PCM9211_INT0_MFSCHG0_MASK) {
+ /* Interrupt is generated before the Fs calculation has
+ * finished. Give it time to settle.
+ */
+ usleep_range(15000, 16000);
+ rate = pcm9211_dir_rate(dev);
+
+ if (rate < 0) {
+ dev_err(dev, "Failed to retrieve DIR rate: %d\n", rate);
+ goto preamble;
+ }
+
+ if (rate == priv->dir_rate)
+ goto preamble;
+
+ priv->dir_rate = rate;
+ dev_dbg(dev, "DIR sampling rate changed to: %d\n", rate);
+
+ if (priv->codec == NULL || pcm9211_get_rate_ctl(dev) == NULL)
+ goto preamble;
+
+ snd_ctl_notify(priv->codec->component.card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &pcm9211_get_rate_ctl(dev)->id);
+ }
+
+preamble:
+ if ((cause & PCM9211_INT0_MPCRNW0_MASK)) {
+ if (pcm9211_read_burst_preamble(dev) < 0)
+ goto npcm;
+
+ if (priv->codec == NULL ||
+ pcm9211_get_burst_preamble_ctl(dev) == NULL)
+ goto dts;
+
+ snd_ctl_notify(priv->codec->component.card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &pcm9211_get_burst_preamble_ctl(dev)->id);
+ }
+
+npcm:
+ if ((cause & PCM9211_INT0_MNPCM0_MASK)) {
+ /* PCM9211 does not generate an interrupt for NPCM0 1->0
+ * transition, but continously generates interrupts as long as
+ * NPCM0 is high, so use a timeout to clear */
+ cancel_delayed_work_sync(&priv->npcm_clear_work);
+ queue_delayed_work(system_wq, &priv->npcm_clear_work,
+ msecs_to_jiffies(100));
+
+
+ if ((cause & PCM9211_INT0_MNPCM0_MASK) !=
+ (priv->npcm_state & PCM9211_INT0_MNPCM0_MASK))
+ dev_dbg(dev, "NPCM status on interrupt: %d\n",
+ (cause & PCM9211_INT0_MNPCM0_MASK) ==
+ PCM9211_INT0_MNPCM0_MASK);
+
+ priv->npcm_state = (priv->npcm_state &
+ ~PCM9211_INT0_MNPCM0_MASK) |
+ (cause & PCM9211_INT0_MNPCM0_MASK);
+
+ if (priv->codec == NULL || pcm9211_get_npcm_ctl(dev) == NULL)
+ goto dts;
+
+ snd_ctl_notify(priv->codec->component.card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &pcm9211_get_npcm_ctl(dev)->id);
+ }
+
+dts:
+ if (cause & PCM9211_INT0_MDTSCD0_MASK) {
+ dev_dbg(dev, "DTSCD status on interrupt: %d\n",
+ (cause & PCM9211_INT0_MDTSCD0_MASK) ==
+ PCM9211_INT0_MDTSCD0_MASK);
+ priv->npcm_state |= PCM9211_INT0_MDTSCD0_MASK;
+
+ if (priv->codec == NULL || pcm9211_get_dtscd_ctl(dev) == NULL)
+ return IRQ_HANDLED;
+
+ snd_ctl_notify(priv->codec->component.card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &pcm9211_get_dtscd_ctl(dev)->id);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int pcm9211_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm9211_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct device *dev = codec->dev;
+ int port;
+
+ port = pcm9211_main_output_port(dev);
+ if (port < 0) {
+ dev_err(dev, "Failed to read selected port: %d\n", port);
+ return port;
+ }
+
+ if (port == PCM9211_MOSRC_ADC)
+ return snd_pcm_hw_constraint_list(substream->runtime,
+ 0, SNDRV_PCM_HW_PARAM_RATE,
+ &adc_rate_constraints);
+
+ priv->dir_rate = pcm9211_dir_rate(dev);
+ priv->rate_constraints.count = 1;
+ priv->rate_constraints.list = &priv->dir_rate;
+ priv->rate_constraints.mask = 0;
+
+ dev_dbg(dev, "Detected biphase rate is %d Hz\n", priv->dir_rate);
+
+ return snd_pcm_hw_constraint_list(substream->runtime,
+ 0, SNDRV_PCM_HW_PARAM_RATE, &priv->rate_constraints);
+}
+
+static int pcm9211_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm9211_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct device *dev = codec->dev;
+
+ int ret;
+
+ if (freq > PCM9211_MAX_SYSCLK) {
+ dev_err(dev, "System clock greater %d is not supported\n",
+ PCM9211_MAX_SYSCLK);
+ return -EINVAL;
+ }
+
+ ret = clk_set_rate(priv->xti, freq);
+ if (ret)
+ return ret;
+
+ priv->sysclk = freq;
+
+ return 0;
+}
+
+static int pcm9211_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int format)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm9211_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct device *dev = codec->dev;
+ u32 adfmt, dirfmt;
+ int ret;
+
+ /* Configure format for ADC and DIR block, if main output source is
+ * set to AUTO the output port may switch between them at any time
+ */
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ adfmt = PCM9211_ADFMT_I2S;
+ dirfmt = PCM9211_DIR_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ adfmt = PCM9211_ADFMT_RIGHT_J;
+ dirfmt = PCM9211_DIR_FMT_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ adfmt = PCM9211_ADFMT_LEFT_J;
+ dirfmt = PCM9211_DIR_FMT_LEFT_J;
+ break;
+ default:
+ dev_err(dev, "Unsupported DAI format\n");
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(priv->regmap, PCM9211_ADC_CTRL2,
+ PCM9211_ADFMT_MASK, adfmt << PCM9211_ADFMT_SHIFT);
+ if (ret) {
+ dev_err(dev, "Failed to update ADC format: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_update_bits(priv->regmap, PCM9211_DIR_OUT_FMT,
+ PCM9211_DIR_FMT_MASK, dirfmt << PCM9211_DIR_FMT_SHIFT);
+ if (ret) {
+ dev_err(dev, "Failed to update ADC format: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pcm9211_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm9211_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct device *dev = codec->dev;
+ unsigned int sclk = 1;
+ unsigned int rate;
+ unsigned int bck;
+ unsigned int ratio;
+ unsigned int port;
+ int ret;
+ int i;
+
+ rate = params_rate(params);
+ bck = rate * 64;
+
+ port = pcm9211_main_output_port(dev);
+ if (port == PCM9211_MOSRC_ADC) {
+ switch (rate) {
+ case 48000:
+ sclk = 12288000;
+ break;
+ case 96000:
+ sclk = 24576000;
+ break;
+ default:
+ dev_err(dev, "Rate %d unsupported.\n", rate);
+ return -EINVAL;
+ }
+
+ /* Systemclock setup */
+ ratio = priv->sysclk / sclk;
+ for (i = 0; i < PCM9211_NUM_SCK_RATIOS; i++) {
+ if (pcm9211_sck_ratios[i] == ratio)
+ break;
+ }
+ if (i == PCM9211_NUM_SCK_RATIOS) {
+ dev_err(dev, "SCK divider %d is not supported\n",
+ ratio);
+ return -EINVAL;
+ }
+ ret = regmap_update_bits(priv->regmap, PCM9211_XTI_SCLK_FREQ,
+ PCM9211_XTI_XSCK_MASK,
+ i << PCM9211_XTI_XSCK_SHIFT);
+
+ if (ret) {
+ dev_err(dev, "Failed to configure SCK divider: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* Bitclock setup */
+ ratio = priv->sysclk / bck;
+ for (i = 0; i < PCM9211_NUM_BCK_RATIOS; i++) {
+ if (pcm9211_bck_ratios[i] == ratio)
+ break;
+ }
+ if (i == PCM9211_NUM_BCK_RATIOS) {
+ dev_err(dev, "BCK divider %d is not supported\n",
+ ratio);
+ return -EINVAL;
+ }
+ ret = regmap_update_bits(priv->regmap, PCM9211_XTI_SCLK_FREQ,
+ PCM9211_XTI_BCK_MASK,
+ i << PCM9211_XTI_BCK_SHIFT);
+ if (ret) {
+ dev_err(dev, "Failed to configure BCK divider: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* Frameclock setup */
+ ratio = priv->sysclk / rate;
+ for (i = 0; i < PCM9211_NUM_LRCK_RATIOS; i++) {
+ if (pcm9211_lrck_ratios[i] == ratio)
+ break;
+ }
+ if (i == PCM9211_NUM_LRCK_RATIOS) {
+ dev_err(dev, "LRCK divider %d is not supported\n",
+ ratio);
+ return -EINVAL;
+ }
+ ret = regmap_update_bits(priv->regmap, PCM9211_XTI_SCLK_FREQ,
+ PCM9211_XTI_LRCK_MASK,
+ i << PCM9211_XTI_LRCK_SHIFT);
+ if (ret) {
+ dev_err(dev, "Failed to configure LRCK divider: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int pcm9211_reset(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+ int ret;
+
+ /* Use reset gpio if available, otherwise soft-reset */
+ if (priv->reset) {
+ gpiod_set_value_cansleep(priv->reset, 0);
+ usleep_range(500, 1000);
+ gpiod_set_value_cansleep(priv->reset, 1);
+ } else {
+ ret = regmap_update_bits(priv->regmap, PCM9211_SYS_RESET,
+ PCM9211_SYS_RESET_MRST, 0);
+ if (ret) {
+ dev_err(dev, "Could not reset device: %d\n", ret);
+ return ret;
+ }
+ usleep_range(10000, 15000);
+ }
+
+ regcache_mark_dirty(priv->regmap);
+
+ return 0;
+}
+
+static int pcm9211_write_pinconfig(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+ u8 values[4];
+ int val;
+ int ret;
+ int i;
+
+ ret = of_property_read_u8_array(dev->of_node, "ti,group-function",
+ values, 3);
+ if (!ret) {
+ val = (values[0] & PCM9211_MPASEL_MASK) <<
+ PCM9211_MPASEL_SHIFT |
+ (values[1] & PCM9211_MPBSEL_MASK) <<
+ PCM9211_MPBSEL_SHIFT |
+ (values[2] & PCM9211_MPCSEL_MASK) <<
+ PCM9211_MPCSEL_SHIFT;
+ ret = regmap_write(priv->regmap, PCM9211_MPIO_GROUP, val);
+ if (ret) {
+ dev_err(dev, "Failed to write mpio group functions: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u8_array(dev->of_node, "ti,mpio-a-flags-gpio",
+ values, 4);
+ if (!ret) {
+ /* Write MPIO A flags/gpio selection */
+ for (i = 0, val = 0; i < 4; i++)
+ val |= (values[i] << PCM9211_MPAxSEL_SHIFT(i)) &
+ PCM9211_MPAxSEL_MASK(i);
+
+ ret = regmap_update_bits(priv->regmap, PCM9211_MPIO_A_FLAGS,
+ PCM9211_MPAxSEL_MASK(0) | PCM9211_MPAxSEL_MASK(1) |
+ PCM9211_MPAxSEL_MASK(2), val);
+ if (ret) {
+ dev_err(dev, "Failed to update mpio_a flags: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u8_array(dev->of_node, "ti,mpio-b-flags-gpio",
+ values, 4);
+ if (!ret) {
+ /* Write MPIO B flags/gpio selection */
+ for (i = 0, val = 0; i < 4; i++)
+ val |= (values[i] << PCM9211_MPBxSEL_SHIFT(i)) &
+ PCM9211_MPBxSEL_MASK(i);
+
+ ret = regmap_update_bits(priv->regmap,
+ PCM9211_MPIO_B_MPIO_C_FLAGS,
+ PCM9211_MPBxSEL_MASK(0) |
+ PCM9211_MPBxSEL_MASK(1) |
+ PCM9211_MPBxSEL_MASK(2), val);
+ if (ret) {
+ dev_err(dev, "Failed to update mpio_a flags: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u8_array(dev->of_node, "ti,mpio-c-flags-gpio",
+ values, 4);
+ if (!ret) {
+ /* Write MPIO B flags/gpio selection */
+ for (i = 0, val = 0; i < 4; i++)
+ val |= (values[i] << PCM9211_MPCxSEL_SHIFT(i)) &
+ PCM9211_MPCxSEL_MASK(i);
+
+ ret = regmap_update_bits(priv->regmap,
+ PCM9211_MPIO_B_MPIO_C_FLAGS,
+ PCM9211_MPCxSEL_MASK(0) |
+ PCM9211_MPCxSEL_MASK(1) |
+ PCM9211_MPCxSEL_MASK(2), val);
+ if (ret) {
+ dev_err(dev, "Failed to update mpio_a flags: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u8_array(dev->of_node, "ti,mpio-a-flag",
+ values, 4);
+ if (!ret) {
+ /* Write MPIO A flag selection */
+ for (i = 0, val = 0; i < 2; i++)
+ val |= (values[i] <<
+ PCM9211_MPIO_ABCx_FLAG_SHIFT(i)) &
+ PCM9211_MPIO_ABCx_FLAG_MASK(i);
+ ret = regmap_write(priv->regmap, PCM9211_MPIO_A1_A0_OUT_FLAG,
+ val);
+ if (ret) {
+ dev_err(dev, "Failed to update mpio_a1/0 flags: %d\n",
+ ret);
+ return ret;
+ }
+
+ for (i = 2, val = 0; i < 4; i++)
+ val |= (values[i] <<
+ PCM9211_MPIO_ABCx_FLAG_SHIFT(i)) &
+ PCM9211_MPIO_ABCx_FLAG_MASK(i);
+ ret = regmap_write(priv->regmap, PCM9211_MPIO_A3_A2_OUT_FLAG,
+ val);
+ if (ret) {
+ dev_err(dev, "Failed to update mpio_a3/2 flags: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u8_array(dev->of_node, "ti,mpio-b-flag",
+ values, 4);
+ if (!ret) {
+ /* Write MPIO B flag selection */
+ for (i = 0, val = 0; i < 2; i++)
+ val |= (values[i] << PCM9211_MPIO_ABCx_FLAG_SHIFT(i)) &
+ PCM9211_MPIO_ABCx_FLAG_MASK(i);
+ ret = regmap_write(priv->regmap, PCM9211_MPIO_B1_B0_OUT_FLAG,
+ val);
+ if (ret) {
+ dev_err(dev, "Failed to update mpio_b1/0 flags: %d\n",
+ ret);
+ return ret;
+ }
+
+ for (i = 2, val = 0; i < 4; i++)
+ val |= (values[i] << PCM9211_MPIO_ABCx_FLAG_SHIFT(i)) &
+ PCM9211_MPIO_ABCx_FLAG_MASK(i);
+ ret = regmap_write(priv->regmap, PCM9211_MPIO_B3_B2_OUT_FLAG,
+ val);
+ if (ret) {
+ dev_err(dev, "Failed to update mpio_b3/2 flags: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u8_array(dev->of_node, "ti,mpio-c-flag",
+ values, 4);
+ if (!ret) {
+ /* Write MPIO C flag selection */
+ for (i = 0, val = 0; i < 2; i++)
+ val |= (values[i] << PCM9211_MPIO_ABCx_FLAG_SHIFT(i)) &
+ PCM9211_MPIO_ABCx_FLAG_MASK(i);
+ ret = regmap_write(priv->regmap, PCM9211_MPIO_C1_C0_OUT_FLAG,
+ val);
+ if (ret) {
+ dev_err(dev, "Failed to update mpio_c1/0 flags: %d\n",
+ ret);
+ return ret;
+ }
+
+ for (i = 2, val = 0; i < 4; i++)
+ val |= (values[i] << PCM9211_MPIO_ABCx_FLAG_SHIFT(i)) &
+ PCM9211_MPIO_ABCx_FLAG_MASK(i);
+ ret = regmap_write(priv->regmap, PCM9211_MPIO_C3_C2_OUT_FLAG,
+ val);
+ if (ret) {
+ dev_err(dev, "Failed to update mpio_c3/2 flags: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u8_array(dev->of_node, "ti,mpo-function",
+ values, 2);
+ if (!ret) {
+ /* Write MPO function selection */
+ for (i = 0, val = 0; i < 2; i++)
+ val |= (values[i] << PCM9211_MPOxOUT_SHIFT(i)) &
+ PCM9211_MPOxOUT_MASK(i);
+ ret = regmap_write(priv->regmap, PCM9211_MPO_1_0_FUNC, val);
+ if (ret) {
+ dev_err(dev, "Failed to update mpo function selection: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u8(dev->of_node, "ti,int0-function", values);
+ if (!ret) {
+ val = values[0] ? PCM9211_ERROR_INT0_MASK : 0;
+ ret = regmap_update_bits(priv->regmap, PCM9211_ERR_OUT,
+ PCM9211_ERROR_INT0_MASK, val);
+ if (ret) {
+ dev_err(dev, "Failed to update int0 function selection: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u8(dev->of_node, "ti,int1-function", values);
+ if (!ret) {
+ val = values[0] ? PCM9211_NPCM_INT1_MASK : 0;
+ ret = regmap_update_bits(priv->regmap, PCM9211_ERR_OUT,
+ PCM9211_NPCM_INT1_MASK, val);
+ if (ret) {
+ dev_err(dev, "Failed to update int1 function selection: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void pcm9211_npcm_clear_work(struct work_struct *work)
+{
+ struct pcm9211_priv *priv = container_of(work, struct pcm9211_priv,
+ npcm_clear_work.work);
+ u8 old_state = priv->npcm_state;
+ struct device *dev = priv->dev;
+
+ /* Clear NPCM & DTSCD, as DTSCD is only valid as long as NPCM is */
+ priv->npcm_state &= ~(PCM9211_INT0_MNPCM0_MASK |
+ PCM9211_INT0_MDTSCD0_MASK);
+
+ dev_dbg(dev, "Clear NPCM flag after timeout\n");
+
+ if (priv->codec == NULL || pcm9211_get_dtscd_ctl(dev) == NULL ||
+ pcm9211_get_npcm_ctl(dev) == NULL)
+ return;
+
+ if (old_state & PCM9211_INT0_MNPCM0_MASK)
+ snd_ctl_notify(priv->codec->component.card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &pcm9211_get_npcm_ctl(dev)->id);
+
+ if (old_state & PCM9211_INT0_MDTSCD0_MASK)
+ snd_ctl_notify(priv->codec->component.card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &pcm9211_get_dtscd_ctl(dev)->id);
+}
+
+static int pcm9211_soc_probe(struct snd_soc_codec *codec)
+{
+ struct pcm9211_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ priv->codec = codec;
+
+ return 0;
+}
+
+/* Simple Controls */
+static const DECLARE_TLV_DB_SCALE(pcm9211_adc_tlv, -10050, 50, 1);
+static const char *const pcm9211_main_outputs[] = { "AUTO", "DIR", "ADC",
+ "AUXIN0", "AUXIN1", "AUXIN2" };
+static const struct soc_enum pcm9211_main_sclk_enum =
+ SOC_ENUM_SINGLE(PCM9211_MAIN_OUT_SOURCE, 4, 4, pcm9211_main_outputs);
+
+static const struct snd_kcontrol_new pcm9211_snd_controls[] = {
+ SOC_DOUBLE_R_RANGE_TLV("ADC Attenuation",
+ PCM9211_ADC_L_CH_ATT,
+ PCM9211_ADC_R_CH_ATT,
+ 0, 14, 255, 0, pcm9211_adc_tlv),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "DIR Sample Rate",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = pcm9211_dir_rate_kctl_info,
+ .get = pcm9211_dir_rate_kctl,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "DIR Non-PCM Bitstream",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = pcm9211_dir_npcm_kctl_info,
+ .get = pcm9211_dir_npcm_kctl,
+ .private_value = PCM9211_INT0_MNPCM0_MASK,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "DIR DTS Bitstream",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = pcm9211_dir_dtscd_kctl_info,
+ .get = pcm9211_dir_dtscd_kctl,
+ .private_value = PCM9211_INT0_MDTSCD0_MASK,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "DIR Burst Preamble",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = pcm9211_dir_preamble_kctl_info,
+ .get = pcm9211_dir_preamble_kctl,
+ },
+ SOC_ENUM("MAIN SCLK Output Select", pcm9211_main_sclk_enum),
+};
+
+/* DAPM Controls */
+static const char *const pcm9211_dir_inputs[] = { "RXIN0", "RXIN1", "RXIN2",
+ "RXIN3", "RXIN4", "RXIN5", "RXIN6", "RXIN7" };
+static const struct soc_enum pcm9211_dir_mux_enum =
+ SOC_ENUM_SINGLE(PCM9211_DIR_INP_BIPHASE, 0, 8, pcm9211_dir_inputs);
+static const struct snd_kcontrol_new pcm9211_dir_mux_control =
+ SOC_DAPM_ENUM("DIR Input Select", pcm9211_dir_mux_enum);
+
+static const struct soc_enum pcm9211_main_out_enum =
+ SOC_ENUM_SINGLE(PCM9211_MAIN_OUT_SOURCE, 0, 4, pcm9211_main_outputs);
+static const struct snd_kcontrol_new pcm9211_main_out_control =
+ SOC_DAPM_ENUM("MAIN Output Select", pcm9211_main_out_enum);
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget pcm9211_dapm_widgets[] = {
+ /* Inputs */
+ SND_SOC_DAPM_INPUT("RXIN0"),
+ SND_SOC_DAPM_INPUT("RXIN1"),
+ SND_SOC_DAPM_INPUT("RXIN2"),
+ SND_SOC_DAPM_INPUT("RXIN3"),
+ SND_SOC_DAPM_INPUT("RXIN4"),
+ SND_SOC_DAPM_INPUT("RXIN5"),
+ SND_SOC_DAPM_INPUT("RXIN6"),
+ SND_SOC_DAPM_INPUT("RXIN7"),
+ SND_SOC_DAPM_INPUT("VINL"),
+ SND_SOC_DAPM_INPUT("VINR"),
+
+ SND_SOC_DAPM_ADC("ADC", NULL, PCM9211_SYS_RESET,
+ PCM9211_SYS_RESET_ADDIS_SHIFT, 1),
+
+ /* Processing */
+ SND_SOC_DAPM_AIF_IN("DIR", NULL, 0, PCM9211_SYS_RESET,
+ PCM9211_SYS_RESET_RXDIS_SHIFT, 1),
+ SND_SOC_DAPM_MIXER("AUTO", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Internal routing */
+ SND_SOC_DAPM_MUX("DIR Input Mux", SND_SOC_NOPM, 0, 0,
+ &pcm9211_dir_mux_control),
+ SND_SOC_DAPM_MUX("MAIN Output Mux", SND_SOC_NOPM, 0, 0,
+ &pcm9211_main_out_control),
+
+ /* Outputs */
+ SND_SOC_DAPM_OUTPUT("MAIN"),
+};
+
+/* DAPM Routing */
+static const struct snd_soc_dapm_route pcm9211_dapm_routes[] = {
+ { "DIR Input Mux", "RXIN0", "RXIN0" },
+ { "DIR Input Mux", "RXIN1", "RXIN1" },
+ { "DIR Input Mux", "RXIN2", "RXIN2" },
+ { "DIR Input Mux", "RXIN3", "RXIN3" },
+ { "DIR Input Mux", "RXIN4", "RXIN4" },
+ { "DIR Input Mux", "RXIN5", "RXIN5" },
+ { "DIR Input Mux", "RXIN6", "RXIN6" },
+ { "DIR Input Mux", "RXIN7", "RXIN7" },
+
+ { "ADC", NULL, "VINL" },
+ { "ADC", NULL, "VINR" },
+
+ { "DIR", NULL, "DIR Input Mux" },
+ { "AUTO", NULL, "DIR" },
+ { "AUTO", NULL, "ADC" },
+
+ { "MAIN Output Mux", "DIR", "DIR" },
+ { "MAIN Output Mux", "ADC", "ADC" },
+ { "MAIN Output Mux", "AUTO", "AUTO" },
+
+ { "MAIN", NULL, "MAIN Output Mux" },
+};
+
+static struct snd_soc_dai_ops pcm9211_dai_ops = {
+ .startup = pcm9211_startup,
+ .hw_params = pcm9211_hw_params,
+ .set_sysclk = pcm9211_set_dai_sysclk,
+ .set_fmt = pcm9211_set_dai_fmt,
+};
+
+/* BCLK is always 64 * FS == 32 bit/channel */
+#define PCM9211_FORMATS SNDRV_PCM_FMTBIT_S32_LE
+struct snd_soc_dai_driver pcm9211_dai = {
+ .name = "pcm9211-hifi",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = PCM9211_FORMATS,
+ },
+ .ops = &pcm9211_dai_ops,
+};
+
+static const struct snd_soc_codec_driver pcm9211_driver = {
+ .probe = pcm9211_soc_probe,
+ .component_driver = {
+ .controls = pcm9211_snd_controls,
+ .num_controls = ARRAY_SIZE(pcm9211_snd_controls),
+ .dapm_widgets = pcm9211_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcm9211_dapm_widgets),
+ .dapm_routes = pcm9211_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(pcm9211_dapm_routes),
+ },
+};
+
+int pcm9211_probe(struct device *dev, struct regmap *regmap)
+{
+ struct pcm9211_priv *priv;
+ unsigned int cause;
+ int ret;
+ int i;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->dev = dev;
+ priv->regmap = regmap;
+
+ priv->xti = devm_clk_get(dev, "xti");
+ if (IS_ERR(priv->xti)) {
+ ret = PTR_ERR(priv->xti);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get clock 'xti': %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(priv->xti);
+ if (ret) {
+ dev_err(dev, "Failed to enable xti clock: %d\n", ret);
+ return ret;
+ }
+
+ priv->sysclk = clk_get_rate(priv->xti);
+ if (priv->sysclk > PCM9211_MAX_SYSCLK) {
+ dev_err(dev, "xti clock rate (%lu) exceeds supported max %u\n",
+ priv->sysclk, PCM9211_MAX_SYSCLK);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(priv->supplies); i++)
+ priv->supplies[i].supply = pcm9211_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
+ priv->supplies);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
+ priv->supplies);
+ if (ret) {
+ dev_err(dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset)) {
+ ret = PTR_ERR(priv->reset);
+ dev_err(dev, "Failed to get reset gpio: %d\n", ret);
+ return ret;
+ }
+
+ pcm9211_reset(dev);
+
+ priv->int0 = devm_gpiod_get_optional(dev, "int0", GPIOD_IN);
+ if (IS_ERR(priv->reset)) {
+ ret = PTR_ERR(priv->reset);
+ dev_err(dev, "Failed to get reset gpio: %d\n", ret);
+ return ret;
+ }
+
+ if (priv->int0) {
+ int irq = gpiod_to_irq(priv->int0);
+
+ if (irq < 0) {
+ dev_err(dev, "Configured 'int0' gpio cannot be used as IRQ: %d\n",
+ irq);
+ return irq;
+ }
+
+ INIT_DELAYED_WORK(&priv->npcm_clear_work,
+ pcm9211_npcm_clear_work);
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ pcm9211_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "pcm9211", priv);
+ if (ret) {
+ dev_err(dev, "Failed to request irq: %d\n", ret);
+ return ret;
+ }
+
+ /* Set interrupt to use positive polarity */
+ ret = regmap_update_bits(priv->regmap, PCM9211_INT_POLARITY,
+ PCM9211_INT0_POLARITY_POS_MASK,
+ PCM9211_INT0_POLARITY_POS_MASK);
+ if (ret) {
+ dev_err(dev, "Failed to configure int0 polaroty: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = pcm9211_write_pinconfig(dev);
+ if (ret)
+ return ret;
+
+ /* Unmap NPCM, DTS, Burst Preamble and Fs change interrupt */
+ ret = regmap_update_bits(priv->regmap, PCM9211_INT0_CAUSE,
+ PCM9211_INT0_MNPCM0_MASK | PCM9211_INT0_MDTSCD0_MASK |
+ PCM9211_INT0_MPCRNW0_MASK | PCM9211_INT0_MFSCHG0_MASK,
+ 0);
+ if (ret) {
+ dev_err(dev, "Failed to unmask interrupt causes: %d\n", ret);
+ return ret;
+ }
+
+ /* Enable DTSCD detection */
+ ret = regmap_update_bits(priv->regmap, PCM9211_NON_PCM_DEF,
+ PCM9211_NON_PCM_DTS_CD_DET_MASK,
+ PCM9211_NON_PCM_DTS_CD_DET_MASK);
+ if (ret) {
+ dev_err(dev, "Failed to enable DTSCD detection: %d\n", ret);
+ return ret;
+ }
+
+ /* Read initial sampling rate and npcm state */
+ priv->dir_rate = pcm9211_dir_rate(dev);
+ ret = regmap_read(priv->regmap, PCM9211_INT0_OUT, &cause);
+ if (ret) {
+ dev_err(dev, "Failed to read int0 cause: %d\n", ret);
+ return IRQ_HANDLED;
+ }
+ priv->npcm_state = cause;
+
+ ret = snd_soc_register_codec(dev, &pcm9211_driver, &pcm9211_dai, 1);
+ if (ret) {
+ dev_err(dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pcm9211_probe);
+
+void pcm9211_remove(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+
+ snd_soc_unregister_codec(dev);
+ pm_runtime_disable(dev);
+ regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+ clk_disable_unprepare(priv->xti);
+}
+EXPORT_SYMBOL_GPL(pcm9211_remove);
+
+#ifdef CONFIG_PM
+static int pcm9211_runtime_resume(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(priv->xti);
+ if (ret) {
+ dev_err(dev, "Failed to enable xti clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+ if (ret) {
+ dev_err(dev, "Failed to enable supplies: %d\n", ret);
+ goto err_reg;
+ }
+
+ ret = pcm9211_reset(dev);
+ if (ret) {
+ dev_err(dev, "Failed to reset device: %d\n", ret);
+ goto err;
+ }
+
+ regcache_cache_only(priv->regmap, false);
+ regcache_mark_dirty(priv->regmap);
+
+ ret = regcache_sync(priv->regmap);
+ if (ret) {
+ dev_err(dev, "Failed to sync regmap: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+err_reg:
+ clk_disable_unprepare(priv->xti);
+
+ return ret;
+}
+
+static int pcm9211_runtime_suspend(struct device *dev)
+{
+ struct pcm9211_priv *priv = dev_get_drvdata(dev);
+
+ regcache_cache_only(priv->regmap, true);
+ regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+ clk_disable_unprepare(priv->xti);
+
+ return 0;
+}
+#endif
+
+const struct dev_pm_ops pcm9211_pm_ops = {
+ SET_RUNTIME_PM_OPS(pcm9211_runtime_suspend, pcm9211_runtime_resume,
+ NULL)
+};
+EXPORT_SYMBOL_GPL(pcm9211_pm_ops);
+
+MODULE_DESCRIPTION("PCM9211 codec driver");
+MODULE_AUTHOR("Julian Scheel <julian(a)jusst.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm9211.h b/sound/soc/codecs/pcm9211.h
new file mode 100644
index 000000000000..3ad9e9e9419a
--- /dev/null
+++ b/sound/soc/codecs/pcm9211.h
@@ -0,0 +1,206 @@
+/*
+ * PCM9211 codec driver header
+ *
+ * Copyright (C) 2017 jusst technologies GmbH / jusst.engineering
+ *
+ * Author: Julian Scheel <julian(a)jusst.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef __PCM9211_H_
+#define __PCM9211_H_
+
+extern const struct dev_pm_ops pcm9211_pm_ops;
+extern const struct regmap_config pcm9211_regmap;
+
+extern int pcm9211_probe(struct device *dev, struct regmap *regmap);
+extern void pcm9211_remove(struct device *dev);
+
+/* Register definitions */
+#define PCM9211_ERR_OUT 0x20
+#define PCM9211_DIR_INITIAL1 0x21
+#define PCM9211_DIR_INITIAL2 0x22
+#define PCM9211_DIR_INITIAL3 0x23
+#define PCM9211_OSC_CTRL 0x24
+#define PCM9211_ERR_CAUSE 0x25
+#define PCM9211_AUTO_SEL_CAUSE 0x26
+#define PCM9211_DIR_FS_RANGE 0x27
+#define PCM9211_NON_PCM_DEF 0x28
+#define PCM9211_DTS_CD_LD 0x29
+#define PCM9211_INT0_CAUSE 0x2a
+#define PCM9211_INT1_CAUSE 0x2b
+#define PCM9211_INT0_OUT 0x2c
+#define PCM9211_INT1_OUT 0x2d
+#define PCM9211_INT_POLARITY 0x2e
+#define PCM9211_DIR_OUT_FMT 0x2f
+#define PCM9211_DIR_RSCLK_RATIO 0x30
+#define PCM9211_XTI_SCLK_FREQ 0x31
+#define PCM9211_DIR_SOURCE_BIT2 0x32
+#define PCM9211_XTI_SOURCE_BIT2 0x33
+#define PCM9211_DIR_INP_BIPHASE 0x34
+#define PCM9211_RECOUT0_BIPHASE 0x35
+#define PCM9211_RECOUT1_BIPHASE 0x36
+#define PCM9211_FS_CALC_TARGET 0x37
+#define PCM9211_FS_CALC_RESULT 0x38
+#define PCM9211_BIPHASE_INFO 0x39
+#define PCM9211_PC_BUF0 0x3a
+#define PCM9211_PC_BUF1 0x3b
+#define PCM9211_PD_BUF0 0x3c
+#define PCM9211_PD_BUF1 0x3d
+
+#define PCM9211_SYS_RESET 0x40
+
+#define PCM9211_ADC_CTRL1 0x42
+
+#define PCM9211_ADC_L_CH_ATT 0x46
+#define PCM9211_ADC_R_CH_ATT 0x47
+#define PCM9211_ADC_CTRL2 0x48
+#define PCM9211_ADC_CTRL3 0x49
+
+#define PCM9211_DIR_STATUS1 0x5a
+#define PCM9211_DIR_STATUS2 0x5b
+#define PCM9211_DIR_STATUS3 0x5c
+#define PCM9211_DIR_STATUS4 0x5d
+#define PCM9211_DIR_STATUS5 0x5e
+#define PCM9211_DIR_STATUS6 0x5f
+#define PCM9211_DIT_CTRL1 0x60
+#define PCM9211_DIT_CTRL2 0x61
+#define PCM9211_DIT_CTRL3 0x62
+#define PCM9211_DIT_STATUS1 0x63
+#define PCM9211_DIT_STATUS2 0x64
+#define PCM9211_DIT_STATUS3 0x65
+#define PCM9211_DIT_STATUS4 0x66
+#define PCM9211_DIT_STATUS5 0x67
+#define PCM9211_DIT_STATUS6 0x68
+
+#define PCM9211_MAIN_AUX_MUTE 0x6a
+#define PCM9211_MAIN_OUT_SOURCE 0x6b
+#define PCM9211_AUX_OUT_SOURCE 0x6c
+#define PCM9211_MPIO_B_MAIN_HIZ 0x6d
+#define PCM9211_MPIO_C_MPIO_A_HIZ 0x6e
+#define PCM9211_MPIO_GROUP 0x6f
+#define PCM9211_MPIO_A_FLAGS 0x70
+#define PCM9211_MPIO_B_MPIO_C_FLAGS 0x71
+#define PCM9211_MPIO_A1_A0_OUT_FLAG 0x72
+#define PCM9211_MPIO_A3_A2_OUT_FLAG 0x73
+#define PCM9211_MPIO_B1_B0_OUT_FLAG 0x74
+#define PCM9211_MPIO_B3_B2_OUT_FLAG 0x75
+#define PCM9211_MPIO_C1_C0_OUT_FLAG 0x76
+#define PCM9211_MPIO_C3_C2_OUT_FLAG 0x77
+#define PCM9211_MPO_1_0_FUNC 0x78
+#define PCM9211_MPIO_A_B_DIR 0x79
+#define PCM9211_MPIO_C_DIR 0x7a
+#define PCM9211_MPIO_A_B_DATA_OUT 0x7b
+#define PCM9211_MPIO_C_DATA_OUT 0x7c
+#define PCM9211_MPIO_A_B_DATA_IN 0x7d
+#define PCM9211_MPIO_C_DATA_IN 0x7e
+
+
+/* Register field values (only used ones) */
+
+/* PCM9211_ERR_OUT */
+#define PCM9211_ERROR_INT0_MASK BIT(2)
+#define PCM9211_NPCM_INT1_MASK BIT(0)
+
+/* PCM9211_NON_PCM_DEF */
+#define PCM9211_NON_PCM_DTS_CD_DET_MASK BIT(2)
+
+/* PCM9211_INT0_CAUSE */
+#define PCM9211_INT0_MNPCM0_MASK BIT(6)
+#define PCM9211_INT0_MDTSCD0_MASK BIT(4)
+#define PCM9211_INT0_MPCRNW0_MASK BIT(2)
+#define PCM9211_INT0_MFSCHG0_MASK BIT(1)
+
+/* PCM9211_INT_POLARITY */
+#define PCM9211_INT0_POLARITY_POS_MASK BIT(2)
+
+/* PCM9211_DIR_OUT_FMT */
+#define PCM9211_DIR_FMT_MASK 0x7
+#define PCM9211_DIR_FMT_SHIFT 0
+
+#define PCM9211_DIR_FMT_I2S 4
+#define PCM9211_DIR_FMT_LEFT_J 5
+#define PCM9211_DIR_FMT_RIGHT_J 0
+
+/* PCM9211_XTI_SCLK_FREQ */
+#define PCM9211_XTI_XSCK_SHIFT 4
+#define PCM9211_XTI_XSCK_MASK (0x3 << PCM9211_XTI_XSCK_SHIFT)
+#define PCM9211_XTI_BCK_SHIFT 2
+#define PCM9211_XTI_BCK_MASK (0x3 << PCM9211_XTI_BCK_SHIFT)
+#define PCM9211_XTI_LRCK_SHIFT 0
+#define PCM9211_XTI_LRCK_MASK (0x3 << PCM9211_XTI_LRCK_SHIFT)
+
+
+/* PCM9211_BIPHASE_INFO */
+#define PCM9211_BIPHASE_SFSST_SHIFT 7
+#define PCM9211_BIPHASE_SFSST_MASK BIT(PCM9211_BIPHASE_SFSST_SHIFT)
+#define PCM9211_BIPHASE_SFSOUT_SHIFT 0
+#define PCM9211_BIPHASE_SFSOUT_MASK (0xf << PCM9211_BIPHASE_SFSOUT_SHIFT)
+
+
+/* PCM9211_SYS_RESET */
+#define PCM9211_SYS_RESET_MRST BIT(7)
+#define PCM9211_SYS_RESET_RXDIS_SHIFT 4
+#define PCM9211_SYS_RESET_ADDIS_SHIFT 5
+
+
+/* PCM9211_ADC_CTRL2 */
+#define PCM9211_ADFMT_MASK 0x3
+#define PCM9211_ADFMT_SHIFT 0
+
+#define PCM9211_ADFMT_I2S 0
+#define PCM9211_ADFMT_LEFT_J 1
+#define PCM9211_ADFMT_RIGHT_J 2
+
+
+/* PCM9211_MAIN_OUT_SOURCE */
+#define PCM9211_MOSSRC_SHIFT 4
+#define PCM9211_MOPSRC_SHIFT 0
+#define PCM9211_MOSRC_MASK 0x7
+#define PCM9211_MOSSRC_MASK \
+ (PCM9211_MOSRC_MASK << PCM9211_MOSSRC_SHIFT)
+#define PCM9211_MOPSRC_MASK \
+ (PCM9211_MOSRC_MASK << PCM9211_MOPSRC_SHIFT)
+
+#define PCM9211_MOSRC_AUTO 0
+#define PCM9211_MOSRC_DIR 1
+#define PCM9211_MOSRC_ADC 2
+#define PCM9211_MOSRC_AUXIN0 3
+#define PCM9211_MOSRC_AUXIN1 4
+#define PCM9211_MOSRC_AUXIN2 5
+
+
+/* PCM9211_MPIO_GROUP */
+#define PCM9211_MPASEL_SHIFT 6
+#define PCM9211_MPASEL_MASK (0x2 << PCM9211_MPASEL_SHIFT)
+#define PCM9211_MPBSEL_SHIFT 3
+#define PCM9211_MPBSEL_MASK (0x7 << PCM9211_MPBSEL_SHIFT)
+#define PCM9211_MPCSEL_SHIFT 0
+#define PCM9211_MPCSEL_MASK (0x7 << PCM9211_MPCSEL_SHIFT)
+
+
+/* PCM9211_MPIO_A_FLAGS */
+#define PCM9211_MPAxSEL_SHIFT(x) (x)
+#define PCM9211_MPAxSEL_MASK(x) BIT(PCM9211_MPAxSEL_SHIFT(x))
+
+
+/* PCM9211_MPIO_B_MPIO_C_FLAGS */
+#define PCM9211_MPBxSEL_SHIFT(x) ((x) + 4)
+#define PCM9211_MPBxSEL_MASK(x) BIT(PCM9211_MPBxSEL_SHIFT(x))
+#define PCM9211_MPCxSEL_SHIFT(x) (x)
+#define PCM9211_MPCxSEL_MASK(x) BIT(PCM9211_MPCxSEL_SHIFT(x))
+
+
+/* PCM9211_MPIO_A1_A0_OUT_FLAG..PCM9211_MPIO_C3_C2_OUT_FLAG */
+#define PCM9211_MPIO_ABCx_FLAG_SHIFT(x) (((x) % 2) * 4)
+#define PCM9211_MPIO_ABCx_FLAG_MASK(x) (0xf << PCM9211_MPIO_ABCx_FLAG_SHIFT(x))
+
+
+/* PCM9211_MPO_1_0_FUNC */
+#define PCM9211_MPOxOUT_SHIFT(x) ((x) * 4)
+#define PCM9211_MPOxOUT_MASK(x) (0xf << PCM9211_MPOxOUT_SHIFT(x))
+
+#endif
--
2.12.2
2
2
Hello, ever since kernel 4.4.0-77, there seems to be
a limit on the ALSA HR timer, I can't set it above 1000Hz
(snd_timer_params() fails with -22 invalid argument).
I used to be able to set the rate much higher than that.
Been observed in two completely different distros, one with
a much newer kernel. How can I overcome this limit?
Thanks.
2
3
This patch-set handles the SPI/I2S IP on STM32 platforms.
It applies to STM32 platforms implementing version 2 of SPI/I2S IP like STM32H7 series.
The SPI/I2S block is a serial peripheral interface (SPI), which can also be configured to work on I2S/PCM mode.
ASoC STM32 I2S driver only supports this I2S/PCM mode.
The I2S/PCM interface can either support full duplex or half-duplex communication
(transmitter or receiver only). The change of mode requires to stop the interface.
This means that the two audio paths cannot be basically managed independently.
The driver supports playback and capture through a single bidirectionnal DAI.
In the first version of the driver, playback and capture paths are made mutually exclusive.
A second patch introduces support of full duplex mode.
In this implementation the interface is systematically configured in full-duplex mode
from hardware point of view. So, when managing a single audio path, the interface
is not configured as transmit or receive only, as it should be.
This restriction is handled by masking underrun/overrun errors from the unused path.
The I2S/PCM interface supports four audio standards:
I2S Philips standard, MSB justified standard, LSB justified standard, PCM standard
PCM standard is declined in two versions, PCM short and long,
according frame synchronization duration.
These standards can be mapped to ASoC standards as follows:
- I2S: i2s
- MSB justified standard: left_j
- LSB justified standard: right_j
- PCM short: dsp_a
PCM long format is not exposed as it does not match supported ASoC standards.
v3 -> v4
- update example in dt bindings
olivier moysan (3):
dt-bindings: Document STM32 I2S bindings
ASoC: stm32: Add I2S driver
ASoC: stm32: Add full duplex support to i2s
.../devicetree/bindings/sound/st,stm32-i2s.txt | 62 ++
sound/soc/stm/Kconfig | 2 +-
sound/soc/stm/Makefile | 4 +
sound/soc/stm/stm32_i2s.c | 946 +++++++++++++++++++++
4 files changed, 1013 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.txt
create mode 100644 sound/soc/stm/stm32_i2s.c
--
1.9.1
3
7
ALSA driver series for devices of Gravis Ultra Sound includes local
variable 'snd_gf1_pcm_use_dma'. Although this is a flag to change
behaviours of local implementations for 'struct snd_pcm_ops.copy' and
'struct snd_pcm_ops.silence', it's invariable during module lifetime.
This commit removes this local variable and the relevant operations.
Signed-off-by: Takashi Sakamoto <o-takashi(a)sakamocchi.jp>
---
sound/isa/gus/gus_pcm.c | 49 ++++++++++++++++++++++---------------------------
1 file changed, 22 insertions(+), 27 deletions(-)
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index 33c1891f469a..0cc3f272edf1 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -61,8 +61,6 @@ struct gus_pcm_private {
int final_volume;
};
-static int snd_gf1_pcm_use_dma = 1;
-
static void snd_gf1_pcm_block_change_ack(struct snd_gus_card * gus, void *private_data)
{
struct gus_pcm_private *pcmp = private_data;
@@ -363,7 +361,9 @@ static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct gus_pcm_private *pcmp = runtime->private_data;
+ struct snd_gus_card *gus = pcmp->gus;
unsigned int bpos, len;
+ int w16, invert;
bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2));
len = samples_to_bytes(runtime, count);
@@ -373,18 +373,14 @@ static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream,
return -EIO;
if (copy_from_user(runtime->dma_area + bpos, src, len))
return -EFAULT;
- if (snd_gf1_pcm_use_dma && len > 32) {
- return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len);
- } else {
- struct snd_gus_card *gus = pcmp->gus;
- int err, w16, invert;
-
- w16 = (snd_pcm_format_width(runtime->format) == 16);
- invert = snd_pcm_format_unsigned(runtime->format);
- if ((err = snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos, pcmp->memory + bpos, len, w16, invert)) < 0)
- return err;
- }
- return 0;
+ if (len > 32)
+ return snd_gf1_pcm_block_change(substream, bpos,
+ pcmp->memory + bpos, len);
+
+ w16 = (snd_pcm_format_width(runtime->format) == 16);
+ invert = snd_pcm_format_unsigned(runtime->format);
+ return snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos,
+ pcmp->memory + bpos, len, w16, invert);
}
static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream,
@@ -394,7 +390,9 @@ static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct gus_pcm_private *pcmp = runtime->private_data;
+ struct snd_gus_card *gus = pcmp->gus;
unsigned int bpos, len;
+ int w16, invert;
bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2));
len = samples_to_bytes(runtime, count);
@@ -402,19 +400,16 @@ static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream,
return -EIO;
if (snd_BUG_ON(bpos + len > pcmp->dma_size))
return -EIO;
- snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos, count);
- if (snd_gf1_pcm_use_dma && len > 32) {
- return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len);
- } else {
- struct snd_gus_card *gus = pcmp->gus;
- int err, w16, invert;
-
- w16 = (snd_pcm_format_width(runtime->format) == 16);
- invert = snd_pcm_format_unsigned(runtime->format);
- if ((err = snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos, pcmp->memory + bpos, len, w16, invert)) < 0)
- return err;
- }
- return 0;
+ snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos,
+ count);
+ if (len > 32)
+ return snd_gf1_pcm_block_change(substream, bpos,
+ pcmp->memory + bpos, len);
+
+ w16 = (snd_pcm_format_width(runtime->format) == 16);
+ invert = snd_pcm_format_unsigned(runtime->format);
+ return snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos,
+ pcmp->memory + bpos, len, w16, invert);
}
static int snd_gf1_pcm_playback_hw_params(struct snd_pcm_substream *substream,
--
2.11.0
2
1
[alsa-devel] [RESEND PATCH] ASoC: da7218: Fix incorrect usage of bitwise '&' operator for SRM check
by Adam Thomson 23 May '17
by Adam Thomson 23 May '17
23 May '17
In the SRM lock check section of code the '&' bitwise operator is
used as part of checking lock status. Functionally the code works
as intended, but the conditional statement is a boolean comparison
so should really use '&&' logical operator instead. This commit
rectifies this discrepancy.
Signed-off-by: Adam Thomson <Adam.Thomson.Opensource(a)diasemi.com>
Reviewed-by: Takashi Sakamoto <o-takashi(a)sakamocchi.jp>
---
sound/soc/codecs/da7218.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index d256ebf..6e1940e 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -1457,7 +1457,7 @@ static int da7218_dai_event(struct snd_soc_dapm_widget *w,
++i;
msleep(DA7218_SRM_CHECK_DELAY);
}
- } while ((i < DA7218_SRM_CHECK_TRIES) & (!success));
+ } while ((i < DA7218_SRM_CHECK_TRIES) && (!success));
if (!success)
dev_warn(codec->dev, "SRM failed to lock\n");
--
1.9.1
1
0
Hop, step... before jump.
This is a patch series based on the previous one ("[PATCH 00/16] ALSA:
Convert to new copy_silence PCM ops"), as the second step for killing
set_fs(). It extends the PCM buffer-copy helper functions to allow
in-kernel buffer copy via the new PCM ops, as well as some code
refactoring.
Once when these are implemented, the set_fs() can be eliminated by
simply replacing with these new helpers.
The latest patches are found in topic/kill-set_fs branch in sound git
tree.
Takashi
===
Takashi Iwai (4):
ALSA: pcm: Shuffle code
ALSA: pcm: Call directly the common read/write helpers
ALSA: pcm: Provide read/write helpers for in-kernel buffer transfer
ALSA: pcm: Split PCM transfer codes
include/sound/pcm.h | 81 ++++++++--
sound/core/pcm_lib.c | 410 ++++++++++++++++++++++++++-------------------------
2 files changed, 282 insertions(+), 209 deletions(-)
--
2.13.0
1
4
[alsa-devel] [PATCH] ALSA: hda - apply STAC_9200_DELL_M22 quirk for Dell Latitude D430
by Alexander Tsoy 23 May '17
by Alexander Tsoy 23 May '17
23 May '17
This model is actually called 92XXM2-8 in Windows driver. But since pin
configs for M22 and M28 are identical, just reuse M22 quirk.
Fixes external microphone (tested) and probably docking station ports
(not tested).
Signed-off-by: Alexander Tsoy <alexander(a)tsoy.me>
---
sound/pci/hda/patch_sigmatel.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index faa3d38bac0b..6cefdf6c0b75 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -1559,6 +1559,8 @@ static const struct snd_pci_quirk stac9200_fixup_tbl[] = {
"Dell Inspiron 1501", STAC_9200_DELL_M26),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
"unknown Dell", STAC_9200_DELL_M26),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0201,
+ "Dell Latitude D430", STAC_9200_DELL_M22),
/* Panasonic */
SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
/* Gateway machines needs EAPD to be set on resume */
--
2.13.0
2
1
23 May '17
PCM core code has a few usages of set_fs(), mostly for two codepaths:
- The DELAY ioctl call from pcm_compat.c
- The ioctl wrapper in kernel context for PCM OSS and other
This patch removes the set_fs() usage in these places by a slight code
refactoring. For the former point, snd_pcm_delay() is changed to
return the value directly instead of putting the value to the given
address. Each caller stores the result in an appropriate manner.
For fixing the latter, snd_pcm_lib_kernel_ioctl() is changed to call
the functions directly as well. For achieving it, now the function
accepts only the limited set of ioctls that have been used, so far.
The primary user of this function is the PCM OSS layer, and the only
other user is USB UAC1 gadget driver. Both drivers don't need the
full set of ioctls.
Signed-off-by: Takashi Iwai <tiwai(a)suse.de>
---
sound/core/pcm_compat.c | 12 ++----
sound/core/pcm_native.c | 102 ++++++++++++++++++++++++++++++------------------
2 files changed, 67 insertions(+), 47 deletions(-)
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 1f64ab0c2a95..8a0f8d51e95d 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -27,17 +27,13 @@ static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream,
s32 __user *src)
{
snd_pcm_sframes_t delay;
- mm_segment_t fs;
- int err;
- fs = snd_enter_user();
- err = snd_pcm_delay(substream, &delay);
- snd_leave_user(fs);
- if (err < 0)
- return err;
+ delay = snd_pcm_delay(substream);
+ if (delay < 0)
+ return delay;
if (put_user(delay, src))
return -EFAULT;
- return err;
+ return 0;
}
static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream,
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index f3a3580eb44c..c6de8976fbd6 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -181,20 +181,6 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore);
-static inline mm_segment_t snd_enter_user(void)
-{
- mm_segment_t fs = get_fs();
- set_fs(get_ds());
- return fs;
-}
-
-static inline void snd_leave_user(mm_segment_t fs)
-{
- set_fs(fs);
-}
-
-
-
int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
{
struct snd_pcm_runtime *runtime;
@@ -1081,6 +1067,7 @@ static const struct action_ops snd_pcm_action_start = {
* @substream: the PCM substream instance
*
* Return: Zero if successful, or a negative error code.
+ * The stream lock must be acquired before calling this function.
*/
int snd_pcm_start(struct snd_pcm_substream *substream)
{
@@ -1088,6 +1075,13 @@ int snd_pcm_start(struct snd_pcm_substream *substream)
SNDRV_PCM_STATE_RUNNING);
}
+/* take the stream lock and start the streams */
+static int snd_pcm_start_lock_irq(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream,
+ SNDRV_PCM_STATE_RUNNING);
+}
+
/*
* stop callbacks
*/
@@ -2658,8 +2652,7 @@ static int snd_pcm_hwsync(struct snd_pcm_substream *substream)
return err;
}
-static int snd_pcm_delay(struct snd_pcm_substream *substream,
- snd_pcm_sframes_t __user *res)
+static snd_pcm_sframes_t snd_pcm_delay(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
@@ -2693,10 +2686,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
break;
}
snd_pcm_stream_unlock_irq(substream);
- if (!err)
- if (put_user(n, res))
- err = -EFAULT;
- return err;
+ return err < 0 ? err : n;
}
static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
@@ -2784,7 +2774,7 @@ static int snd_pcm_common_ioctl1(struct file *file,
case SNDRV_PCM_IOCTL_RESET:
return snd_pcm_reset(substream);
case SNDRV_PCM_IOCTL_START:
- return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING);
+ return snd_pcm_start_lock_irq(substream);
case SNDRV_PCM_IOCTL_LINK:
return snd_pcm_link(substream, (int)(unsigned long) arg);
case SNDRV_PCM_IOCTL_UNLINK:
@@ -2796,7 +2786,16 @@ static int snd_pcm_common_ioctl1(struct file *file,
case SNDRV_PCM_IOCTL_HWSYNC:
return snd_pcm_hwsync(substream);
case SNDRV_PCM_IOCTL_DELAY:
- return snd_pcm_delay(substream, arg);
+ {
+ snd_pcm_sframes_t delay = snd_pcm_delay(substream);
+ snd_pcm_sframes_t __user *res = arg;
+
+ if (delay < 0)
+ return delay;
+ if (put_user(delay, res))
+ return -EFAULT;
+ return 0;
+ }
case SNDRV_PCM_IOCTL_SYNC_PTR:
return snd_pcm_sync_ptr(substream, arg);
#ifdef CONFIG_SND_SUPPORT_OLD_API
@@ -3010,30 +3009,55 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
(void __user *)arg);
}
+/**
+ * snd_pcm_kernel_ioctl - Execute PCM ioctl in the kernel-space
+ * @substream: PCM substream
+ * @cmd: IOCTL cmd
+ * @arg: IOCTL argument
+ *
+ * The function is provided primarily for OSS layer and USB gadget drivers,
+ * and it allows only the limited set of ioctls (hw_params, sw_params,
+ * prepare, start, drain, drop, forward).
+ */
int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
- mm_segment_t fs;
- int result;
+ snd_pcm_uframes_t *frames = arg;
+ snd_pcm_sframes_t result;
- fs = snd_enter_user();
- switch (substream->stream) {
- case SNDRV_PCM_STREAM_PLAYBACK:
- result = snd_pcm_playback_ioctl1(NULL, substream, cmd,
- (void __user *)arg);
- break;
- case SNDRV_PCM_STREAM_CAPTURE:
- result = snd_pcm_capture_ioctl1(NULL, substream, cmd,
- (void __user *)arg);
- break;
+ switch (cmd) {
+ case SNDRV_PCM_IOCTL_FORWARD:
+ {
+ /* provided only for OSS; capture-only and no value returned */
+ if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+ return -EINVAL;
+ result = snd_pcm_capture_forward(substream, *frames);
+ return result < 0 ? result : 0;
+ }
+ case SNDRV_PCM_IOCTL_HW_PARAMS:
+ return snd_pcm_hw_params(substream, arg);
+ case SNDRV_PCM_IOCTL_SW_PARAMS:
+ return snd_pcm_sw_params(substream, arg);
+ case SNDRV_PCM_IOCTL_PREPARE:
+ return snd_pcm_prepare(substream, NULL);
+ case SNDRV_PCM_IOCTL_START:
+ return snd_pcm_start_lock_irq(substream);
+ case SNDRV_PCM_IOCTL_DRAIN:
+ return snd_pcm_drain(substream, NULL);
+ case SNDRV_PCM_IOCTL_DROP:
+ return snd_pcm_drop(substream);
+ case SNDRV_PCM_IOCTL_DELAY:
+ {
+ result = snd_pcm_delay(substream);
+ if (result < 0)
+ return result;
+ *frames = result;
+ return 0;
+ }
default:
- result = -EINVAL;
- break;
+ return -EINVAL;
}
- snd_leave_user(fs);
- return result;
}
-
EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
--
2.13.0
2
1
[alsa-devel] [PATCH] ALSA: control: Simplify snd_ctl_elem_list() implementation
by Takashi Iwai 22 May '17
by Takashi Iwai 22 May '17
22 May '17
This patch simplifies the code of snd_ctl_elem_list() in the following
ways:
- Avoid a vmalloc() temporary buffer but do copy in each iteration;
the vmalloc buffer was introduced at the time we took the spinlock
for the ctl element management.
- Use the standard list_for_each_entry() macro
- Merge two loops into one;
it used to be a loop for skipping until offset becomes zero and
another loop to copy the data. They can be folded into a single
loop easily.
Signed-off-by: Takashi Iwai <tiwai(a)suse.de>
---
sound/core/control.c | 66 +++++++++++++++++++---------------------------------
1 file changed, 24 insertions(+), 42 deletions(-)
diff --git a/sound/core/control.c b/sound/core/control.c
index c109b82eef4b..47080da8451a 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -747,11 +747,11 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
static int snd_ctl_elem_list(struct snd_card *card,
struct snd_ctl_elem_list __user *_list)
{
- struct list_head *plist;
struct snd_ctl_elem_list list;
struct snd_kcontrol *kctl;
- struct snd_ctl_elem_id *dst, *id;
+ struct snd_ctl_elem_id id;
unsigned int offset, space, jidx;
+ int err = 0;
if (copy_from_user(&list, _list, sizeof(list)))
return -EFAULT;
@@ -760,52 +760,34 @@ static int snd_ctl_elem_list(struct snd_card *card,
/* try limit maximum space */
if (space > 16384)
return -ENOMEM;
+ down_read(&card->controls_rwsem);
+ list.count = card->controls_count;
+ list.used = 0;
if (space > 0) {
- /* allocate temporary buffer for atomic operation */
- dst = vmalloc(space * sizeof(struct snd_ctl_elem_id));
- if (dst == NULL)
- return -ENOMEM;
- down_read(&card->controls_rwsem);
- list.count = card->controls_count;
- plist = card->controls.next;
- while (plist != &card->controls) {
- if (offset == 0)
- break;
- kctl = snd_kcontrol(plist);
- if (offset < kctl->count)
- break;
- offset -= kctl->count;
- plist = plist->next;
- }
- list.used = 0;
- id = dst;
- while (space > 0 && plist != &card->controls) {
- kctl = snd_kcontrol(plist);
- for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {
- snd_ctl_build_ioff(id, kctl, jidx);
- id++;
- space--;
+ list_for_each_entry(kctl, &card->controls, list) {
+ if (offset >= kctl->count) {
+ offset -= kctl->count;
+ continue;
+ }
+ for (jidx = offset; jidx < kctl->count; jidx++) {
+ snd_ctl_build_ioff(&id, kctl, jidx);
+ if (copy_to_user(list.pids + list.used, &id,
+ sizeof(id))) {
+ err = -EFAULT;
+ goto out;
+ }
list.used++;
+ if (!--space)
+ goto out;
}
- plist = plist->next;
offset = 0;
}
- up_read(&card->controls_rwsem);
- if (list.used > 0 &&
- copy_to_user(list.pids, dst,
- list.used * sizeof(struct snd_ctl_elem_id))) {
- vfree(dst);
- return -EFAULT;
- }
- vfree(dst);
- } else {
- down_read(&card->controls_rwsem);
- list.count = card->controls_count;
- up_read(&card->controls_rwsem);
}
- if (copy_to_user(_list, &list, sizeof(list)))
- return -EFAULT;
- return 0;
+ out:
+ up_read(&card->controls_rwsem);
+ if (!err && copy_to_user(_list, &list, sizeof(list)))
+ err = -EFAULT;
+ return err;
}
static bool validate_element_member_dimension(struct snd_ctl_elem_info *info)
--
2.13.0
2
2
22 May '17
acpi_evaluate_dsm() and friends take a pointer to a raw buffer of 16
bytes. Instead we convert them to use uuid_le type. At the same time we
convert current users.
acpi_str_to_uuid() becomes useless after the conversion and it's safe to
get rid of it.
The conversion fixes a potential bug in int340x_thermal as well since
we have to use memcmp() on binary data.
Cc: Rafael J. Wysocki <rjw(a)rjwysocki.net>
Cc: Mika Westerberg <mika.westerberg(a)linux.intel.com>
Cc: Borislav Petkov <bp(a)suse.de>
Cc: Dan Williams <dan.j.williams(a)intel.com>
Cc: Amir Goldstein <amir73il(a)gmail.com>
Cc: Jarkko Sakkinen <jarkko.sakkinen(a)linux.intel.com>
Cc: Jani Nikula <jani.nikula(a)linux.intel.com>
Cc: Ben Skeggs <bskeggs(a)redhat.com>
Cc: Benjamin Tissoires <benjamin.tissoires(a)redhat.com>
Cc: Joerg Roedel <joro(a)8bytes.org>
Cc: Adrian Hunter <adrian.hunter(a)intel.com>
Cc: Yisen Zhuang <yisen.zhuang(a)huawei.com>
Cc: Bjorn Helgaas <bhelgaas(a)google.com>
Cc: Zhang Rui <rui.zhang(a)intel.com>
Cc: Felipe Balbi <balbi(a)kernel.org>
Cc: Mathias Nyman <mathias.nyman(a)intel.com>
Cc: Heikki Krogerus <heikki.krogerus(a)linux.intel.com>
Cc: Liam Girdwood <lgirdwood(a)gmail.com>
Cc: Mark Brown <broonie(a)kernel.org>
Signed-off-by: Andy Shevchenko <andriy.shevchenko(a)linux.intel.com>
---
drivers/acpi/acpi_extlog.c | 10 +++---
drivers/acpi/bus.c | 29 ++--------------
drivers/acpi/nfit/core.c | 40 +++++++++++-----------
drivers/acpi/nfit/nfit.h | 3 +-
drivers/acpi/utils.c | 4 +--
drivers/char/tpm/tpm_crb.c | 9 +++--
drivers/char/tpm/tpm_ppi.c | 20 +++++------
drivers/gpu/drm/i915/intel_acpi.c | 14 +++-----
drivers/gpu/drm/nouveau/nouveau_acpi.c | 20 +++++------
drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c | 9 +++--
drivers/hid/i2c-hid/i2c-hid.c | 9 +++--
drivers/iommu/dmar.c | 11 +++---
drivers/mmc/host/sdhci-pci-core.c | 9 +++--
drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c | 15 ++++----
drivers/pci/pci-acpi.c | 11 +++---
drivers/pci/pci-label.c | 4 +--
drivers/thermal/int340x_thermal/int3400_thermal.c | 8 ++---
drivers/usb/dwc3/dwc3-pci.c | 6 ++--
drivers/usb/host/xhci-pci.c | 9 +++--
drivers/usb/misc/ucsi.c | 2 +-
drivers/usb/typec/typec_wcove.c | 4 +--
include/acpi/acpi_bus.h | 9 ++---
include/linux/acpi.h | 4 +--
include/linux/pci-acpi.h | 2 +-
sound/soc/intel/skylake/skl-nhlt.c | 7 ++--
tools/testing/nvdimm/test/iomap.c | 2 +-
tools/testing/nvdimm/test/nfit.c | 2 +-
27 files changed, 116 insertions(+), 156 deletions(-)
diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c
index 502ea4dc2080..69d6140b6afa 100644
--- a/drivers/acpi/acpi_extlog.c
+++ b/drivers/acpi/acpi_extlog.c
@@ -182,17 +182,17 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
static bool __init extlog_get_l1addr(void)
{
- u8 uuid[16];
+ uuid_le uuid;
acpi_handle handle;
union acpi_object *obj;
- acpi_str_to_uuid(extlog_dsm_uuid, uuid);
-
+ if (uuid_le_to_bin(extlog_dsm_uuid, &uuid))
+ return false;
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
return false;
- if (!acpi_check_dsm(handle, uuid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR))
+ if (!acpi_check_dsm(handle, &uuid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR))
return false;
- obj = acpi_evaluate_dsm_typed(handle, uuid, EXTLOG_DSM_REV,
+ obj = acpi_evaluate_dsm_typed(handle, &uuid, EXTLOG_DSM_REV,
EXTLOG_FN_ADDR, NULL, ACPI_TYPE_INTEGER);
if (!obj) {
return false;
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 784bda663d16..e8130a4873e9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -196,42 +196,19 @@ static void acpi_print_osc_error(acpi_handle handle,
pr_debug("\n");
}
-acpi_status acpi_str_to_uuid(char *str, u8 *uuid)
-{
- int i;
- static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21,
- 24, 26, 28, 30, 32, 34};
-
- if (strlen(str) != 36)
- return AE_BAD_PARAMETER;
- for (i = 0; i < 36; i++) {
- if (i == 8 || i == 13 || i == 18 || i == 23) {
- if (str[i] != '-')
- return AE_BAD_PARAMETER;
- } else if (!isxdigit(str[i]))
- return AE_BAD_PARAMETER;
- }
- for (i = 0; i < 16; i++) {
- uuid[i] = hex_to_bin(str[opc_map_to_uuid[i]]) << 4;
- uuid[i] |= hex_to_bin(str[opc_map_to_uuid[i] + 1]);
- }
- return AE_OK;
-}
-EXPORT_SYMBOL_GPL(acpi_str_to_uuid);
-
acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
{
acpi_status status;
struct acpi_object_list input;
union acpi_object in_params[4];
union acpi_object *out_obj;
- u8 uuid[16];
+ uuid_le uuid;
u32 errors;
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
if (!context)
return AE_ERROR;
- if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid)))
+ if (uuid_le_to_bin(context->uuid_str, &uuid))
return AE_ERROR;
context->ret.length = ACPI_ALLOCATE_BUFFER;
context->ret.pointer = NULL;
@@ -241,7 +218,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
input.pointer = in_params;
in_params[0].type = ACPI_TYPE_BUFFER;
in_params[0].buffer.length = 16;
- in_params[0].buffer.pointer = uuid;
+ in_params[0].buffer.pointer = (u8 *)&uuid;
in_params[1].type = ACPI_TYPE_INTEGER;
in_params[1].integer.value = context->rev;
in_params[2].type = ACPI_TYPE_INTEGER;
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 0f7982a1caaf..bd3e45ede056 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -74,11 +74,11 @@ struct nfit_table_prev {
struct list_head flushes;
};
-static u8 nfit_uuid[NFIT_UUID_MAX][16];
+static uuid_le nfit_uuid[NFIT_UUID_MAX];
-const u8 *to_nfit_uuid(enum nfit_uuids id)
+const uuid_le *to_nfit_uuid(enum nfit_uuids id)
{
- return nfit_uuid[id];
+ return &nfit_uuid[id];
}
EXPORT_SYMBOL(to_nfit_uuid);
@@ -207,7 +207,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
u32 offset, fw_status = 0;
acpi_handle handle;
unsigned int func;
- const u8 *uuid;
+ const uuid_le *uuid;
int rc, i;
func = cmd;
@@ -394,7 +394,7 @@ int nfit_spa_type(struct acpi_nfit_system_address *spa)
int i;
for (i = 0; i < NFIT_UUID_MAX; i++)
- if (memcmp(to_nfit_uuid(i), spa->range_guid, 16) == 0)
+ if (!uuid_le_cmp_pp(to_nfit_uuid(i), (uuid_le *)spa->range_guid))
return i;
return -1;
}
@@ -1400,7 +1400,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
struct acpi_device *adev, *adev_dimm;
struct device *dev = acpi_desc->dev;
unsigned long dsm_mask;
- const u8 *uuid;
+ const uuid_le *uuid = to_nfit_uuid(NFIT_DEV_DIMM);
int i;
int family = -1;
@@ -1596,7 +1596,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
{
struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
- const u8 *uuid = to_nfit_uuid(NFIT_DEV_BUS);
+ const uuid_le *uuid = to_nfit_uuid(NFIT_DEV_BUS);
struct acpi_device *adev;
int i;
@@ -3036,19 +3036,19 @@ static __init int nfit_init(void)
BUILD_BUG_ON(sizeof(struct acpi_nfit_control_region) != 80);
BUILD_BUG_ON(sizeof(struct acpi_nfit_data_region) != 40);
- acpi_str_to_uuid(UUID_VOLATILE_MEMORY, nfit_uuid[NFIT_SPA_VOLATILE]);
- acpi_str_to_uuid(UUID_PERSISTENT_MEMORY, nfit_uuid[NFIT_SPA_PM]);
- acpi_str_to_uuid(UUID_CONTROL_REGION, nfit_uuid[NFIT_SPA_DCR]);
- acpi_str_to_uuid(UUID_DATA_REGION, nfit_uuid[NFIT_SPA_BDW]);
- acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_VDISK]);
- acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_CD, nfit_uuid[NFIT_SPA_VCD]);
- acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_PDISK]);
- acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]);
- acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]);
- acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]);
- acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE1, nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);
- acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE2, nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
- acpi_str_to_uuid(UUID_NFIT_DIMM_N_MSFT, nfit_uuid[NFIT_DEV_DIMM_N_MSFT]);
+ uuid_le_to_bin(UUID_VOLATILE_MEMORY, &nfit_uuid[NFIT_SPA_VOLATILE]);
+ uuid_le_to_bin(UUID_PERSISTENT_MEMORY, &nfit_uuid[NFIT_SPA_PM]);
+ uuid_le_to_bin(UUID_CONTROL_REGION, &nfit_uuid[NFIT_SPA_DCR]);
+ uuid_le_to_bin(UUID_DATA_REGION, &nfit_uuid[NFIT_SPA_BDW]);
+ uuid_le_to_bin(UUID_VOLATILE_VIRTUAL_DISK, &nfit_uuid[NFIT_SPA_VDISK]);
+ uuid_le_to_bin(UUID_VOLATILE_VIRTUAL_CD, &nfit_uuid[NFIT_SPA_VCD]);
+ uuid_le_to_bin(UUID_PERSISTENT_VIRTUAL_DISK, &nfit_uuid[NFIT_SPA_PDISK]);
+ uuid_le_to_bin(UUID_PERSISTENT_VIRTUAL_CD, &nfit_uuid[NFIT_SPA_PCD]);
+ uuid_le_to_bin(UUID_NFIT_BUS, &nfit_uuid[NFIT_DEV_BUS]);
+ uuid_le_to_bin(UUID_NFIT_DIMM, &nfit_uuid[NFIT_DEV_DIMM]);
+ uuid_le_to_bin(UUID_NFIT_DIMM_N_HPE1, &nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);
+ uuid_le_to_bin(UUID_NFIT_DIMM_N_HPE2, &nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
+ uuid_le_to_bin(UUID_NFIT_DIMM_N_MSFT, &nfit_uuid[NFIT_DEV_DIMM_N_MSFT]);
nfit_wq = create_singlethread_workqueue("nfit");
if (!nfit_wq)
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h
index 58fb7d68e04a..2f233b28709f 100644
--- a/drivers/acpi/nfit/nfit.h
+++ b/drivers/acpi/nfit/nfit.h
@@ -18,7 +18,6 @@
#include <linux/libnvdimm.h>
#include <linux/ndctl.h>
#include <linux/types.h>
-#include <linux/uuid.h>
#include <linux/acpi.h>
#include <acpi/acuuid.h>
@@ -237,7 +236,7 @@ static inline struct acpi_nfit_desc *to_acpi_desc(
return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
}
-const u8 *to_nfit_uuid(enum nfit_uuids id);
+const uuid_le *to_nfit_uuid(enum nfit_uuids id);
int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz);
void acpi_nfit_shutdown(void *data);
void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event);
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 27d0dcfcf47d..bbe8a950e508 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -625,7 +625,7 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
* some old BIOSes do expect a buffer or an integer etc.
*/
union acpi_object *
-acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 func,
+acpi_evaluate_dsm(acpi_handle handle, const uuid_le *uuid, u64 rev, u64 func,
union acpi_object *argv4)
{
acpi_status ret;
@@ -674,7 +674,7 @@ EXPORT_SYMBOL(acpi_evaluate_dsm);
* functions. Currently only support 64 functions at maximum, should be
* enough for now.
*/
-bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs)
+bool acpi_check_dsm(acpi_handle handle, const uuid_le *uuid, u64 rev, u64 funcs)
{
int i;
u64 mask = 0;
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index b917b9d5f710..f789f7e5a17d 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -27,10 +27,9 @@
#define ACPI_SIG_TPM2 "TPM2"
-static const u8 CRB_ACPI_START_UUID[] = {
- /* 0000 */ 0xAB, 0x6C, 0xBF, 0x6B, 0x63, 0x54, 0x14, 0x47,
- /* 0008 */ 0xB7, 0xCD, 0xF0, 0x20, 0x3C, 0x03, 0x68, 0xD4
-};
+static const uuid_le crb_acpi_start_uuid =
+ UUID_LE(0x6BBF6CAB, 0x5463, 0x4714,
+ 0xB7, 0xCD, 0xF0, 0x20, 0x3C, 0x03, 0x68, 0xD4);
enum crb_defaults {
CRB_ACPI_START_REVISION_ID = 1,
@@ -266,7 +265,7 @@ static int crb_do_acpi_start(struct tpm_chip *chip)
int rc;
obj = acpi_evaluate_dsm(chip->acpi_dev_handle,
- CRB_ACPI_START_UUID,
+ &crb_acpi_start_uuid,
CRB_ACPI_START_REVISION_ID,
CRB_ACPI_START_INDEX,
NULL);
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c
index 692a2c6ae036..7cf682426361 100644
--- a/drivers/char/tpm/tpm_ppi.c
+++ b/drivers/char/tpm/tpm_ppi.c
@@ -32,20 +32,16 @@
#define PPI_VS_REQ_START 128
#define PPI_VS_REQ_END 255
-static const u8 tpm_ppi_uuid[] = {
- 0xA6, 0xFA, 0xDD, 0x3D,
- 0x1B, 0x36,
- 0xB4, 0x4E,
- 0xA4, 0x24,
- 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
-};
+static const uuid_le tpm_ppi_uuid =
+ UUID_LE(0x3DDDFAA6, 0x361B, 0x4EB4,
+ 0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53);
static inline union acpi_object *
tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
union acpi_object *argv4)
{
BUG_ON(!ppi_handle);
- return acpi_evaluate_dsm_typed(ppi_handle, tpm_ppi_uuid,
+ return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_uuid,
TPM_PPI_REVISION_ID,
func, argv4, type);
}
@@ -107,7 +103,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
* is updated with function index from SUBREQ to SUBREQ2 since PPI
* version 1.1
*/
- if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
+ if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_uuid,
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2))
func = TPM_PPI_FN_SUBREQ2;
@@ -268,7 +264,7 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
"User not required",
};
- if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
+ if (!acpi_check_dsm(dev_handle, &tpm_ppi_uuid, TPM_PPI_REVISION_ID,
1 << TPM_PPI_FN_GETOPR))
return -EPERM;
@@ -341,12 +337,12 @@ void tpm_add_ppi(struct tpm_chip *chip)
if (!chip->acpi_dev_handle)
return;
- if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
+ if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_uuid,
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
return;
/* Cache PPI version string. */
- obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid,
+ obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_uuid,
TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
NULL, ACPI_TYPE_STRING);
if (obj) {
diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c
index eb638a1e69d2..72bfe6ceadf8 100644
--- a/drivers/gpu/drm/i915/intel_acpi.c
+++ b/drivers/gpu/drm/i915/intel_acpi.c
@@ -15,13 +15,9 @@ static struct intel_dsm_priv {
acpi_handle dhandle;
} intel_dsm_priv;
-static const u8 intel_dsm_guid[] = {
- 0xd3, 0x73, 0xd8, 0x7e,
- 0xd0, 0xc2,
- 0x4f, 0x4e,
- 0xa8, 0x54,
- 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
-};
+static const uuid_le intel_dsm_guid =
+ UUID_LE(0x7ed873d3, 0xc2d0, 0x4e4f,
+ 0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c);
static char *intel_dsm_port_name(u8 id)
{
@@ -80,7 +76,7 @@ static void intel_dsm_platform_mux_info(void)
int i;
union acpi_object *pkg, *connector_count;
- pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, intel_dsm_guid,
+ pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, &intel_dsm_guid,
INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO,
NULL, ACPI_TYPE_PACKAGE);
if (!pkg) {
@@ -118,7 +114,7 @@ static bool intel_dsm_pci_probe(struct pci_dev *pdev)
if (!dhandle)
return false;
- if (!acpi_check_dsm(dhandle, intel_dsm_guid, INTEL_DSM_REVISION_ID,
+ if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID,
1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) {
DRM_DEBUG_KMS("no _DSM method for intel device\n");
return false;
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 39468c218027..faea23276d4a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -60,15 +60,13 @@ bool nouveau_is_v1_dsm(void) {
}
#ifdef CONFIG_VGA_SWITCHEROO
-static const char nouveau_dsm_muid[] = {
- 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
- 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
-};
+static const uuid_le nouveau_dsm_muid =
+ UUID_LE(0x9D95A0A0, 0x0060, 0x4D48,
+ 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4);
-static const char nouveau_op_dsm_muid[] = {
- 0xF8, 0xD8, 0x86, 0xA4, 0xDA, 0x0B, 0x1B, 0x47,
- 0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0,
-};
+static const uuid_le nouveau_op_dsm_muid =
+ UUID_LE(0xA486D8F8, 0x0BDA, 0x471B,
+ 0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0);
static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
{
@@ -86,7 +84,7 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
args_buff[i] = (arg >> i * 8) & 0xFF;
*result = 0;
- obj = acpi_evaluate_dsm_typed(handle, nouveau_op_dsm_muid, 0x00000100,
+ obj = acpi_evaluate_dsm_typed(handle, &nouveau_op_dsm_muid, 0x00000100,
func, &argv4, ACPI_TYPE_BUFFER);
if (!obj) {
acpi_handle_info(handle, "failed to evaluate _DSM\n");
@@ -138,7 +136,7 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg)
.integer.value = arg,
};
- obj = acpi_evaluate_dsm_typed(handle, nouveau_dsm_muid, 0x00000102,
+ obj = acpi_evaluate_dsm_typed(handle, &nouveau_dsm_muid, 0x00000102,
func, &argv4, ACPI_TYPE_INTEGER);
if (!obj) {
acpi_handle_info(handle, "failed to evaluate _DSM\n");
@@ -259,7 +257,7 @@ static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out
if (!acpi_has_method(dhandle, "_DSM"))
return;
- supports_mux = acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102,
+ supports_mux = acpi_check_dsm(dhandle, &nouveau_dsm_muid, 0x00000102,
1 << NOUVEAU_DSM_POWER);
optimus_funcs = nouveau_dsm_get_optimus_functions(dhandle);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c
index e3e2f5e83815..cc95b8150a86 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c
@@ -81,10 +81,9 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version)
{
struct nvkm_subdev *subdev = &mxm->subdev;
struct nvkm_device *device = subdev->device;
- static char muid[] = {
- 0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C,
- 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65
- };
+ static uuid_le muid =
+ UUID_LE(0x4004A400, 0x917D, 0x4CF2,
+ 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65);
u32 mxms_args[] = { 0x00000000 };
union acpi_object argv4 = {
.buffer.type = ACPI_TYPE_BUFFER,
@@ -105,7 +104,7 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version)
* unless you pass in exactly the version it supports..
*/
rev = (version & 0xf0) << 4 | (version & 0x0f);
- obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4);
+ obj = acpi_evaluate_dsm(handle, &muid, rev, 0x00000010, &argv4);
if (!obj) {
nvkm_debug(subdev, "DSM MXMS failed\n");
return false;
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 8daa8ce64ebb..f83bd717cdd5 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -872,10 +872,9 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
static int i2c_hid_acpi_pdata(struct i2c_client *client,
struct i2c_hid_platform_data *pdata)
{
- static u8 i2c_hid_guid[] = {
- 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45,
- 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
- };
+ static uuid_le i2c_hid_guid =
+ UUID_LE(0x3CDFF6F7, 0x4267, 0x4555,
+ 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE);
union acpi_object *obj;
struct acpi_device *adev;
acpi_handle handle;
@@ -884,7 +883,7 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
if (!handle || acpi_bus_get_device(handle, &adev))
return -ENODEV;
- obj = acpi_evaluate_dsm_typed(handle, i2c_hid_guid, 1, 1, NULL,
+ obj = acpi_evaluate_dsm_typed(handle, &i2c_hid_guid, 1, 1, NULL,
ACPI_TYPE_INTEGER);
if (!obj) {
dev_err(&client->dev, "device _DSM execution failed\n");
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index cbf7763d8091..420d51b286ad 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -1808,10 +1808,9 @@ IOMMU_INIT_POST(detect_intel_iommu);
* for Directed-IO Architecture Specifiction, Rev 2.2, Section 8.8
* "Remapping Hardware Unit Hot Plug".
*/
-static u8 dmar_hp_uuid[] = {
- /* 0000 */ 0xA6, 0xA3, 0xC1, 0xD8, 0x9B, 0xBE, 0x9B, 0x4C,
- /* 0008 */ 0x91, 0xBF, 0xC3, 0xCB, 0x81, 0xFC, 0x5D, 0xAF
-};
+static uuid_le dmar_hp_uuid =
+ UUID_LE(0xD8C1A3A6, 0xBE9B, 0x4C9B,
+ 0x91, 0xBF, 0xC3, 0xCB, 0x81, 0xFC, 0x5D, 0xAF);
/*
* Currently there's only one revision and BIOS will not check the revision id,
@@ -1824,7 +1823,7 @@ static u8 dmar_hp_uuid[] = {
static inline bool dmar_detect_dsm(acpi_handle handle, int func)
{
- return acpi_check_dsm(handle, dmar_hp_uuid, DMAR_DSM_REV_ID, 1 << func);
+ return acpi_check_dsm(handle, &dmar_hp_uuid, DMAR_DSM_REV_ID, 1 << func);
}
static int dmar_walk_dsm_resource(acpi_handle handle, int func,
@@ -1843,7 +1842,7 @@ static int dmar_walk_dsm_resource(acpi_handle handle, int func,
if (!dmar_detect_dsm(handle, func))
return 0;
- obj = acpi_evaluate_dsm_typed(handle, dmar_hp_uuid, DMAR_DSM_REV_ID,
+ obj = acpi_evaluate_dsm_typed(handle, &dmar_hp_uuid, DMAR_DSM_REV_ID,
func, NULL, ACPI_TYPE_BUFFER);
if (!obj)
return -ENODEV;
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 92fc3f7c538d..262b8c320d7c 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -404,10 +404,9 @@ struct intel_host {
bool d3_retune;
};
-const u8 intel_dsm_uuid[] = {
- 0xA5, 0x3E, 0xC1, 0xF6, 0xCD, 0x65, 0x1F, 0x46,
- 0xAB, 0x7A, 0x29, 0xF7, 0xE8, 0xD5, 0xBD, 0x61,
-};
+const uuid_le intel_dsm_uuid =
+ UUID_LE(0xF6C13EA5, 0x65CD, 0x461F,
+ 0xAB, 0x7A, 0x29, 0xF7, 0xE8, 0xD5, 0xBD, 0x61);
static int __intel_dsm(struct intel_host *intel_host, struct device *dev,
unsigned int fn, u32 *result)
@@ -416,7 +415,7 @@ static int __intel_dsm(struct intel_host *intel_host, struct device *dev,
int err = 0;
size_t len;
- obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), intel_dsm_uuid, 0, fn, NULL);
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &intel_dsm_uuid, 0, fn, NULL);
if (!obj)
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
index e13aa064a8e9..02842fe7f1d0 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
@@ -29,10 +29,9 @@ enum _dsm_rst_type {
HNS_ROCE_RESET_FUNC = 0x7,
};
-const u8 hns_dsaf_acpi_dsm_uuid[] = {
- 0x1A, 0xAA, 0x85, 0x1A, 0x93, 0xE2, 0x5E, 0x41,
- 0x8E, 0x28, 0x8D, 0x69, 0x0A, 0x0F, 0x82, 0x0A
-};
+const uuid_le hns_dsaf_acpi_dsm_uuid =
+ UUID_LE(0x1A85AA1A, 0xE293, 0x415E,
+ 0x8E, 0x28, 0x8D, 0x69, 0x0A, 0x0F, 0x82, 0x0A);
static void dsaf_write_sub(struct dsaf_device *dsaf_dev, u32 reg, u32 val)
{
@@ -151,7 +150,7 @@ static void hns_dsaf_acpi_srst_by_port(struct dsaf_device *dsaf_dev, u8 op_type,
argv4.package.elements = obj_args;
obj = acpi_evaluate_dsm(ACPI_HANDLE(dsaf_dev->dev),
- hns_dsaf_acpi_dsm_uuid, 0, op_type, &argv4);
+ &hns_dsaf_acpi_dsm_uuid, 0, op_type, &argv4);
if (!obj) {
dev_warn(dsaf_dev->dev, "reset port_type%d port%d fail!",
port_type, port);
@@ -434,7 +433,7 @@ static phy_interface_t hns_mac_get_phy_if_acpi(struct hns_mac_cb *mac_cb)
argv4.package.elements = &obj_args,
obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dev),
- hns_dsaf_acpi_dsm_uuid, 0,
+ &hns_dsaf_acpi_dsm_uuid, 0,
HNS_OP_GET_PORT_TYPE_FUNC, &argv4);
if (!obj || obj->type != ACPI_TYPE_INTEGER)
@@ -474,7 +473,7 @@ int hns_mac_get_sfp_prsnt_acpi(struct hns_mac_cb *mac_cb, int *sfp_prsnt)
argv4.package.elements = &obj_args,
obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dev),
- hns_dsaf_acpi_dsm_uuid, 0,
+ &hns_dsaf_acpi_dsm_uuid, 0,
HNS_OP_GET_SFP_STAT_FUNC, &argv4);
if (!obj || obj->type != ACPI_TYPE_INTEGER)
@@ -565,7 +564,7 @@ hns_mac_config_sds_loopback_acpi(struct hns_mac_cb *mac_cb, bool en)
argv4.package.elements = obj_args;
obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dsaf_dev->dev),
- hns_dsaf_acpi_dsm_uuid, 0,
+ &hns_dsaf_acpi_dsm_uuid, 0,
HNS_OP_SERDES_LP_FUNC, &argv4);
if (!obj) {
dev_warn(mac_cb->dsaf_dev->dev, "set port%d serdes lp fail!",
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 001860361434..eb612123e0dd 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -24,10 +24,9 @@
* The UUID is defined in the PCI Firmware Specification available here:
* https://www.pcisig.com/members/downloads/pcifw_r3_1_13Dec10.pdf
*/
-const u8 pci_acpi_dsm_uuid[] = {
- 0xd0, 0x37, 0xc9, 0xe5, 0x53, 0x35, 0x7a, 0x4d,
- 0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d
-};
+const uuid_le pci_acpi_dsm_uuid =
+ UUID_LE(0xe5c937d0, 0x3553, 0x4d7a,
+ 0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d);
#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64)
static int acpi_get_rc_addr(struct acpi_device *adev, struct resource *res)
@@ -680,7 +679,7 @@ void acpi_pci_add_bus(struct pci_bus *bus)
if (!pci_is_root_bus(bus))
return;
- obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), pci_acpi_dsm_uuid, 3,
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_uuid, 3,
RESET_DELAY_DSM, NULL);
if (!obj)
return;
@@ -745,7 +744,7 @@ static void pci_acpi_optimize_delay(struct pci_dev *pdev,
if (bridge->ignore_reset_delay)
pdev->d3cold_delay = 0;
- obj = acpi_evaluate_dsm(handle, pci_acpi_dsm_uuid, 3,
+ obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_uuid, 3,
FUNCTION_DELAY_DSM, NULL);
if (!obj)
return;
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
index 51357377efbc..a2c04229f1dc 100644
--- a/drivers/pci/pci-label.c
+++ b/drivers/pci/pci-label.c
@@ -172,7 +172,7 @@ static int dsm_get_label(struct device *dev, char *buf,
if (!handle)
return -1;
- obj = acpi_evaluate_dsm(handle, pci_acpi_dsm_uuid, 0x2,
+ obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_uuid, 0x2,
DEVICE_LABEL_DSM, NULL);
if (!obj)
return -1;
@@ -212,7 +212,7 @@ static bool device_has_dsm(struct device *dev)
if (!handle)
return false;
- return !!acpi_check_dsm(handle, pci_acpi_dsm_uuid, 0x2,
+ return !!acpi_check_dsm(handle, &pci_acpi_dsm_uuid, 0x2,
1 << DEVICE_LABEL_DSM);
}
diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c
index 9413c4abf0b9..c0eb3bb19b23 100644
--- a/drivers/thermal/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3400_thermal.c
@@ -23,7 +23,7 @@ enum int3400_thermal_uuid {
INT3400_THERMAL_MAXIMUM_UUID,
};
-static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
+static const char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
"42A441D6-AE6A-462b-A84B-4A8CE79027D3",
"3A95C389-E4B8-4629-A526-C52C88626BAE",
"97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
@@ -141,10 +141,10 @@ static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv)
}
for (j = 0; j < INT3400_THERMAL_MAXIMUM_UUID; j++) {
- u8 uuid[16];
+ uuid_le u;
- acpi_str_to_uuid(int3400_thermal_uuids[j], uuid);
- if (!strncmp(uuid, objb->buffer.pointer, 16)) {
+ uuid_le_to_bin(int3400_thermal_uuids[j], &u);
+ if (!uuid_le_cmp(*(uuid_le *)objb->buffer.pointer), u) {
priv->uuid_bitmap |= (1 << j);
break;
}
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index a15ec71d0423..6b5284ec76df 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -56,7 +56,7 @@ struct dwc3_pci {
struct platform_device *dwc3;
struct pci_dev *pci;
- u8 uuid[16];
+ uuid_le uuid;
unsigned int has_dsm_for_pm:1;
};
@@ -118,7 +118,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
pdev->device == PCI_DEVICE_ID_INTEL_BXT_M) {
- acpi_str_to_uuid(PCI_INTEL_BXT_DSM_UUID, dwc->uuid);
+ uuid_le_to_bin(PCI_INTEL_BXT_DSM_UUID, &dwc->uuid);
dwc->has_dsm_for_pm = true;
}
@@ -288,7 +288,7 @@ static int dwc3_pci_dsm(struct dwc3_pci *dwc, int param)
tmp.type = ACPI_TYPE_INTEGER;
tmp.integer.value = param;
- obj = acpi_evaluate_dsm(ACPI_HANDLE(&dwc->pci->dev), dwc->uuid,
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(&dwc->pci->dev), &dwc->uuid,
1, PCI_INTEL_BXT_FUNC_PMU_PWR, &argv4);
if (!obj) {
dev_err(&dwc->pci->dev, "failed to evaluate _DSM\n");
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 7b86508ac8cf..93b4f0de9418 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -210,13 +210,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
#ifdef CONFIG_ACPI
static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
{
- static const u8 intel_dsm_uuid[] = {
- 0xb7, 0x0c, 0x34, 0xac, 0x01, 0xe9, 0xbf, 0x45,
- 0xb7, 0xe6, 0x2b, 0x34, 0xec, 0x93, 0x1e, 0x23,
- };
+ static const uuid_le intel_dsm_uuid =
+ UUID_LE(0xac340cb7, 0xe901, 0x45bf,
+ 0xb7, 0xe6, 0x2b, 0x34, 0xec, 0x93, 0x1e, 0x23);
union acpi_object *obj;
- obj = acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1,
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), &intel_dsm_uuid, 3, 1,
NULL);
ACPI_FREE(obj);
}
diff --git a/drivers/usb/misc/ucsi.c b/drivers/usb/misc/ucsi.c
index 07397bddefa3..49e32ffbe59f 100644
--- a/drivers/usb/misc/ucsi.c
+++ b/drivers/usb/misc/ucsi.c
@@ -61,7 +61,7 @@ static int ucsi_acpi_cmd(struct ucsi *ucsi, struct ucsi_control *ctrl)
ucsi->data->ctrl.raw_cmd = ctrl->raw_cmd;
- obj = acpi_evaluate_dsm(ACPI_HANDLE(ucsi->dev), uuid.b, 1, 1, NULL);
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(ucsi->dev), &uuid, 1, 1, NULL);
if (!obj) {
dev_err(ucsi->dev, "%s: failed to evaluate _DSM\n", __func__);
return -EIO;
diff --git a/drivers/usb/typec/typec_wcove.c b/drivers/usb/typec/typec_wcove.c
index d5a7b21fa3f1..5ce93e0a15ca 100644
--- a/drivers/usb/typec/typec_wcove.c
+++ b/drivers/usb/typec/typec_wcove.c
@@ -118,7 +118,7 @@ static int wcove_typec_func(struct wcove_typec *wcove,
tmp.type = ACPI_TYPE_INTEGER;
tmp.integer.value = param;
- obj = acpi_evaluate_dsm(ACPI_HANDLE(wcove->dev), uuid.b, 1, func,
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(wcove->dev), &uuid, 1, func,
&argv4);
if (!obj) {
dev_err(wcove->dev, "%s: failed to evaluate _DSM\n", __func__);
@@ -314,7 +314,7 @@ static int wcove_typec_probe(struct platform_device *pdev)
if (ret)
return ret;
- if (!acpi_check_dsm(ACPI_HANDLE(&pdev->dev), uuid.b, 0, 0x1f)) {
+ if (!acpi_check_dsm(ACPI_HANDLE(&pdev->dev), &uuid, 0, 0x1f)) {
dev_err(&pdev->dev, "Missing _DSM functions\n");
return -ENODEV;
}
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 197f3fffc9a7..0682942d6a76 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -61,13 +61,14 @@ bool acpi_ata_match(acpi_handle handle);
bool acpi_bay_match(acpi_handle handle);
bool acpi_dock_match(acpi_handle handle);
-bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs);
-union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid,
+bool acpi_check_dsm(acpi_handle handle, const uuid_le *uuid, u64 rev, u64 funcs);
+union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const uuid_le *uuid,
u64 rev, u64 func, union acpi_object *argv4);
static inline union acpi_object *
-acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, u64 rev, u64 func,
- union acpi_object *argv4, acpi_object_type type)
+acpi_evaluate_dsm_typed(acpi_handle handle, const uuid_le *uuid, u64 rev,
+ u64 func, union acpi_object *argv4,
+ acpi_object_type type)
{
union acpi_object *obj;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 137e4a3d89c5..66d135003780 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -39,6 +39,7 @@
#include <linux/dynamic_debug.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/uuid.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -457,7 +458,6 @@ struct acpi_osc_context {
struct acpi_buffer ret; /* free by caller if success */
};
-acpi_status acpi_str_to_uuid(char *str, u8 *uuid);
acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
/* Indexes into _OSC Capabilities Buffer (DWORDs 2 & 3 are device-specific) */
@@ -741,7 +741,7 @@ static inline bool acpi_driver_match_device(struct device *dev,
}
static inline union acpi_object *acpi_evaluate_dsm(acpi_handle handle,
- const u8 *uuid,
+ const uuid_le *uuid,
int rev, int func,
union acpi_object *argv4)
{
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 7a4e83a8c89c..917a6ad0f24d 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -105,7 +105,7 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
#endif
-extern const u8 pci_acpi_dsm_uuid[];
+extern const uuid_le pci_acpi_dsm_uuid;
#define DEVICE_LABEL_DSM 0x07
#define RESET_DELAY_DSM 0x08
#define FUNCTION_DELAY_DSM 0x09
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index e3f06672fd6d..b95f659dced5 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -21,8 +21,9 @@
#include "skl.h"
/* Unique identification for getting NHLT blobs */
-static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45,
- 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53};
+static uuid_le osc_uuid =
+ UUID_LE(0xA69F886E, 0x6CEB, 0x4594,
+ 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53);
struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
{
@@ -37,7 +38,7 @@ struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
return NULL;
}
- obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL);
+ obj = acpi_evaluate_dsm(handle, &osc_uuid, 1, 1, NULL);
if (obj && obj->type == ACPI_TYPE_BUFFER) {
nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer;
nhlt_table = (struct nhlt_acpi_table *)
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c
index 64cae1a5deff..f190f22c53dd 100644
--- a/tools/testing/nvdimm/test/iomap.c
+++ b/tools/testing/nvdimm/test/iomap.c
@@ -370,7 +370,7 @@ acpi_status __wrap_acpi_evaluate_object(acpi_handle handle, acpi_string path,
}
EXPORT_SYMBOL(__wrap_acpi_evaluate_object);
-union acpi_object * __wrap_acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid,
+union acpi_object * __wrap_acpi_evaluate_dsm(acpi_handle handle, const uuid_le *uuid,
u64 rev, u64 func, union acpi_object *argv4)
{
union acpi_object *obj = ERR_PTR(-ENXIO);
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index c2187178fb13..145f6ee0234f 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -1559,7 +1559,7 @@ static unsigned long nfit_ctl_handle;
union acpi_object *result;
static union acpi_object *nfit_test_evaluate_dsm(acpi_handle handle,
- const u8 *uuid, u64 rev, u64 func, union acpi_object *argv4)
+ const uuid_le *uuid, u64 rev, u64 func, union acpi_object *argv4)
{
if (handle != &nfit_ctl_handle)
return ERR_PTR(-ENXIO);
--
2.11.0
13
17