Alsa-devel
Threads by month
- ----- 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
October 2010
- 143 participants
- 295 discussions
16 Oct '10
Hi,
This patch-set is a 2nd version for new S/PDIF common driver that supports
S/PDIF PCM audio on S5PC100, S5PC110 and S5PV210.
This patch-set is based on two different branches that :-
o ARM patches are based on Kukjin Kim's git branch 'for-next'
(commit id - 64dcc6aef86593e478cf297a8508e55b54cceaf8)
o ASoC patches are based on Mark Brown's git branch 'for-next'
(commit id - fe3e2e7ff2da41bd7a985c4c206e05a95ebe7a6b)
This patch-set updates followings from the 1st submit :-
o Add EPLL enable and get_rate function as common EPLL function
o Add EPLL rate change warning
o Fix S/PDIF's audio clock divider set dynamically at CPU driver
o Move S/PDIF specific register macros and structure into CPU driver
This patch-set contains followings :-
o To Kukjin Kim and Ben Dooks,
- [PATCH v2 1/6] ARM: S5P: Reduce duplicated EPLL control codes
- [PATCH v2 2/6] ARM: S5PV210: Fix wrong EPLL rate getting on setup clocks
- [PATCH v2 3/6] ARM: S5PV210: Add EPLL clock operations
- [PATCH v2 4/6] ARM: S5P: Add EPLL rate change warning
o To Jassi Brar, Mark Brown and Liam Girdwood,
- [PATCH v2 5/6] ASoC: SAMSUNG: Add S/PDIF CPU driver
- [PATCH v2 6/6] ASoC: SAMSUNG: Add Machine driver for S/PDIF PCM audio
Best Regards,
Claude(Seungwhan Youn)
5
16
This patch adds the MAX98088 CODEC driver.
Signed-off-by: Peter Hsiang <peter.hsiang(a)maxim-ic.com>
---
include/sound/max98088.h | 54 +
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/max98088.c | 2355 +++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/max98088.h | 190 ++++
5 files changed, 2605 insertions(+), 0 deletions(-)
create mode 100644 include/sound/max98088.h
create mode 100644 sound/soc/codecs/max98088.c
create mode 100644 sound/soc/codecs/max98088.h
diff --git a/include/sound/max98088.h b/include/sound/max98088.h
new file mode 100644
index 0000000..30652be
--- /dev/null
+++ b/include/sound/max98088.h
@@ -0,0 +1,54 @@
+/*
+ * Platform data for MAX98088
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __SOUND_MAX98088_PDATA_H__
+#define __SOUND_MAX98088_PDATA_H__
+
+#define EQ_CFG_MAX 32
+
+/* Equalizer filter response configuration */
+struct max98088_eq_cfg {
+ const char *name;
+ unsigned int rate;
+ u16 band1[5];
+ u16 band2[5];
+ u16 band3[5];
+ u16 band4[5];
+ u16 band5[5];
+};
+
+/* codec platform data */
+struct max98088_pdata {
+
+ /* Equalizers for DAI1 and DAI2 */
+ struct max98088_eq_cfg *eq1_cfg;
+ struct max98088_eq_cfg *eq2_cfg;
+ unsigned int eq1_cfgcnt;
+ unsigned int eq2_cfgcnt;
+
+ /* Receiver output can be configured as power amplifier or LINE out */
+ /* Set receiver_mode to:
+ * 0 = amplifier output, or
+ * 1 = LINE level output
+ */
+ unsigned int receiver_mode:1;
+
+ /* Analog/digital microphone configuration:
+ * 0 = analog microphone input (normal setting)
+ * 1 = digital microphone input
+ */
+ unsigned int digmic_left_mode:1;
+ unsigned int digmic_right_mode:1;
+
+};
+
+#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4ccc2b7..4e6713c 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -27,6 +27,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS4270 if I2C
select SND_SOC_DA7210 if I2C
select SND_SOC_JZ4740 if SOC_JZ4740
+ select SND_SOC_MAX98088 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_PCM3008
select SND_SOC_SPDIF
@@ -157,6 +158,9 @@ config SND_SOC_L3
config SND_SOC_DA7210
tristate
+config SND_SOC_MAX98088
+ tristate
+
config SND_SOC_PCM3008
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 23e7e2c..7184611 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -15,6 +15,7 @@ snd-soc-cs4270-objs := cs4270.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-l3-objs := l3.o
+snd-soc-max98088-objs := max98088.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-spdif-objs := spdif_transciever.o
snd-soc-ssm2602-objs := ssm2602.o
@@ -88,6 +89,7 @@ obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
new file mode 100644
index 0000000..52f57d5
--- /dev/null
+++ b/sound/soc/codecs/max98088.c
@@ -0,0 +1,2355 @@
+/*
+ * max98088.c -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
+#include <sound/max98088.h>
+#include "max98088.h"
+
+/* Configurations associated with each channel of DAI stream */
+struct max98088_cdata {
+ unsigned int rate;
+ unsigned int fmt;
+ int eq_textcnt;
+ const char *eq_texts[EQ_CFG_MAX];
+ int eq_sel;
+ struct soc_enum eq_enum;
+};
+
+/* Codec private data */
+struct max98088_priv {
+ u8 reg_cache[M98088_REG_CNT];
+ void *control_data;
+ struct max98088_pdata *pdata;
+
+ unsigned int sysclk;
+ struct max98088_cdata dai[2];
+ u8 power_state;
+ unsigned int ex_mode;
+ unsigned int digmic;
+ unsigned int mic1pre;
+ unsigned int mic2pre;
+ unsigned int extmic_mode;
+};
+
+static const u8 max98088_reg[M98088_REG_CNT] = {
+ 0x00, /* 00 IRQ status */
+ 0x00, /* 01 MIC status */
+ 0x00, /* 02 jack status */
+ 0x00, /* 03 battery voltage */
+ 0x00, /* 04 */
+ 0x00, /* 05 */
+ 0x00, /* 06 */
+ 0x00, /* 07 */
+ 0x00, /* 08 */
+ 0x00, /* 09 */
+ 0x00, /* 0A */
+ 0x00, /* 0B */
+ 0x00, /* 0C */
+ 0x00, /* 0D */
+ 0x00, /* 0E */
+ 0x00, /* 0F interrupt enable */
+
+ 0x00, /* 10 master clock */
+ 0x00, /* 11 DAI1 clock mode */
+ 0x00, /* 12 DAI1 clock control */
+ 0x00, /* 13 DAI1 clock control */
+ 0x00, /* 14 DAI1 format */
+ 0x00, /* 15 DAI1 clock */
+ 0x00, /* 16 DAI1 config */
+ 0x00, /* 17 DAI1 TDM */
+ 0x00, /* 18 DAI1 filters */
+ 0x00, /* 19 DAI2 clock mode */
+ 0x00, /* 1A DAI2 clock control */
+ 0x00, /* 1B DAI2 clock control */
+ 0x00, /* 1C DAI2 format */
+ 0x00, /* 1D DAI2 clock */
+ 0x00, /* 1E DAI2 config */
+ 0x00, /* 1F DAI2 TDM */
+
+ 0x00, /* 20 DAI2 filters */
+ 0x00, /* 21 data config */
+ 0x00, /* 22 DAC mixer */
+ 0x00, /* 23 left ADC mixer */
+ 0x00, /* 24 right ADC mixer */
+ 0x00, /* 25 left HP mixer */
+ 0x00, /* 26 right HP mixer */
+ 0x00, /* 27 HP control */
+ 0x00, /* 28 left REC mixer */
+ 0x00, /* 29 right REC mixer */
+ 0x00, /* 2A REC control */
+ 0x00, /* 2B left SPK mixer */
+ 0x00, /* 2C right SPK mixer */
+ 0x00, /* 2D SPK control */
+ 0x00, /* 2E sidetone */
+ 0x00, /* 2F DAI1 playback level */
+
+ 0x00, /* 30 DAI1 playback level */
+ 0x00, /* 31 DAI2 playback level */
+ 0x00, /* 32 DAI2 playbakc level */
+ 0x00, /* 33 left ADC level */
+ 0x00, /* 34 right ADC level */
+ 0x00, /* 35 MIC1 level */
+ 0x00, /* 36 MIC2 level */
+ 0x00, /* 37 INA level */
+ 0x00, /* 38 INB level */
+ 0x00, /* 39 left HP volume */
+ 0x00, /* 3A right HP volume */
+ 0x00, /* 3B left REC volume */
+ 0x00, /* 3C right REC volume */
+ 0x00, /* 3D left SPK volume */
+ 0x00, /* 3E right SPK volume */
+ 0x00, /* 3F MIC config */
+
+ 0x00, /* 40 MIC threshold */
+ 0x00, /* 41 excursion limiter filter */
+ 0x00, /* 42 excursion limiter threshold */
+ 0x00, /* 43 ALC */
+ 0x00, /* 44 power limiter threshold */
+ 0x00, /* 45 power limiter config */
+ 0x00, /* 46 distortion limiter config */
+ 0x00, /* 47 audio input */
+ 0x00, /* 48 microphone */
+ 0x00, /* 49 level control */
+ 0x00, /* 4A bypass switches */
+ 0x00, /* 4B jack detect */
+ 0x00, /* 4C input enable */
+ 0x00, /* 4D output enable */
+ 0xF0, /* 4E bias control */
+ 0x00, /* 4F DAC power */
+
+ 0x0F, /* 50 DAC power */
+ 0x00, /* 51 system */
+ 0x00, /* 52 DAI1 EQ1 */
+ 0x00, /* 53 DAI1 EQ1 */
+ 0x00, /* 54 DAI1 EQ1 */
+ 0x00, /* 55 DAI1 EQ1 */
+ 0x00, /* 56 DAI1 EQ1 */
+ 0x00, /* 57 DAI1 EQ1 */
+ 0x00, /* 58 DAI1 EQ1 */
+ 0x00, /* 59 DAI1 EQ1 */
+ 0x00, /* 5A DAI1 EQ1 */
+ 0x00, /* 5B DAI1 EQ1 */
+ 0x00, /* 5C DAI1 EQ2 */
+ 0x00, /* 5D DAI1 EQ2 */
+ 0x00, /* 5E DAI1 EQ2 */
+ 0x00, /* 5F DAI1 EQ2 */
+
+ 0x00, /* 60 DAI1 EQ2 */
+ 0x00, /* 61 DAI1 EQ2 */
+ 0x00, /* 62 DAI1 EQ2 */
+ 0x00, /* 63 DAI1 EQ2 */
+ 0x00, /* 64 DAI1 EQ2 */
+ 0x00, /* 65 DAI1 EQ2 */
+ 0x00, /* 66 DAI1 EQ3 */
+ 0x00, /* 67 DAI1 EQ3 */
+ 0x00, /* 68 DAI1 EQ3 */
+ 0x00, /* 69 DAI1 EQ3 */
+ 0x00, /* 6A DAI1 EQ3 */
+ 0x00, /* 6B DAI1 EQ3 */
+ 0x00, /* 6C DAI1 EQ3 */
+ 0x00, /* 6D DAI1 EQ3 */
+ 0x00, /* 6E DAI1 EQ3 */
+ 0x00, /* 6F DAI1 EQ3 */
+
+ 0x00, /* 70 DAI1 EQ4 */
+ 0x00, /* 71 DAI1 EQ4 */
+ 0x00, /* 72 DAI1 EQ4 */
+ 0x00, /* 73 DAI1 EQ4 */
+ 0x00, /* 74 DAI1 EQ4 */
+ 0x00, /* 75 DAI1 EQ4 */
+ 0x00, /* 76 DAI1 EQ4 */
+ 0x00, /* 77 DAI1 EQ4 */
+ 0x00, /* 78 DAI1 EQ4 */
+ 0x00, /* 79 DAI1 EQ4 */
+ 0x00, /* 7A DAI1 EQ5 */
+ 0x00, /* 7B DAI1 EQ5 */
+ 0x00, /* 7C DAI1 EQ5 */
+ 0x00, /* 7D DAI1 EQ5 */
+ 0x00, /* 7E DAI1 EQ5 */
+ 0x00, /* 7F DAI1 EQ5 */
+
+ 0x00, /* 80 DAI1 EQ5 */
+ 0x00, /* 81 DAI1 EQ5 */
+ 0x00, /* 82 DAI1 EQ5 */
+ 0x00, /* 83 DAI1 EQ5 */
+ 0x00, /* 84 DAI2 EQ1 */
+ 0x00, /* 85 DAI2 EQ1 */
+ 0x00, /* 86 DAI2 EQ1 */
+ 0x00, /* 87 DAI2 EQ1 */
+ 0x00, /* 88 DAI2 EQ1 */
+ 0x00, /* 89 DAI2 EQ1 */
+ 0x00, /* 8A DAI2 EQ1 */
+ 0x00, /* 8B DAI2 EQ1 */
+ 0x00, /* 8C DAI2 EQ1 */
+ 0x00, /* 8D DAI2 EQ1 */
+ 0x00, /* 8E DAI2 EQ2 */
+ 0x00, /* 8F DAI2 EQ2 */
+
+ 0x00, /* 90 DAI2 EQ2 */
+ 0x00, /* 91 DAI2 EQ2 */
+ 0x00, /* 92 DAI2 EQ2 */
+ 0x00, /* 93 DAI2 EQ2 */
+ 0x00, /* 94 DAI2 EQ2 */
+ 0x00, /* 95 DAI2 EQ2 */
+ 0x00, /* 96 DAI2 EQ2 */
+ 0x00, /* 97 DAI2 EQ2 */
+ 0x00, /* 98 DAI2 EQ3 */
+ 0x00, /* 99 DAI2 EQ3 */
+ 0x00, /* 9A DAI2 EQ3 */
+ 0x00, /* 9B DAI2 EQ3 */
+ 0x00, /* 9C DAI2 EQ3 */
+ 0x00, /* 9D DAI2 EQ3 */
+ 0x00, /* 9E DAI2 EQ3 */
+ 0x00, /* 9F DAI2 EQ3 */
+
+ 0x00, /* A0 DAI2 EQ3 */
+ 0x00, /* A1 DAI2 EQ3 */
+ 0x00, /* A2 DAI2 EQ4 */
+ 0x00, /* A3 DAI2 EQ4 */
+ 0x00, /* A4 DAI2 EQ4 */
+ 0x00, /* A5 DAI2 EQ4 */
+ 0x00, /* A6 DAI2 EQ4 */
+ 0x00, /* A7 DAI2 EQ4 */
+ 0x00, /* A8 DAI2 EQ4 */
+ 0x00, /* A9 DAI2 EQ4 */
+ 0x00, /* AA DAI2 EQ4 */
+ 0x00, /* AB DAI2 EQ4 */
+ 0x00, /* AC DAI2 EQ5 */
+ 0x00, /* AD DAI2 EQ5 */
+ 0x00, /* AE DAI2 EQ5 */
+ 0x00, /* AF DAI2 EQ5 */
+
+ 0x00, /* B0 DAI2 EQ5 */
+ 0x00, /* B1 DAI2 EQ5 */
+ 0x00, /* B2 DAI2 EQ5 */
+ 0x00, /* B3 DAI2 EQ5 */
+ 0x00, /* B4 DAI2 EQ5 */
+ 0x00, /* B5 DAI2 EQ5 */
+ 0x00, /* B6 DAI1 biquad */
+ 0x00, /* B7 DAI1 biquad */
+ 0x00, /* B8 DAI1 biquad */
+ 0x00, /* B9 DAI1 biquad */
+ 0x00, /* BA DAI1 biquad */
+ 0x00, /* BB DAI1 biquad */
+ 0x00, /* BC DAI1 biquad */
+ 0x00, /* BD DAI1 biquad */
+ 0x00, /* BE DAI1 biquad */
+ 0x00, /* BF DAI1 biquad */
+
+ 0x00, /* C0 DAI2 biquad */
+ 0x00, /* C1 DAI2 biquad */
+ 0x00, /* C2 DAI2 biquad */
+ 0x00, /* C3 DAI2 biquad */
+ 0x00, /* C4 DAI2 biquad */
+ 0x00, /* C5 DAI2 biquad */
+ 0x00, /* C6 DAI2 biquad */
+ 0x00, /* C7 DAI2 biquad */
+ 0x00, /* C8 DAI2 biquad */
+ 0x00, /* C9 DAI2 biquad */
+ 0x00, /* CA */
+ 0x00, /* CB */
+ 0x00, /* CC */
+ 0x00, /* CD */
+ 0x00, /* CE */
+ 0x00, /* CF */
+
+ 0x00, /* D0 */
+ 0x00, /* D1 */
+ 0x00, /* D2 */
+ 0x00, /* D3 */
+ 0x00, /* D4 */
+ 0x00, /* D5 */
+ 0x00, /* D6 */
+ 0x00, /* D7 */
+ 0x00, /* D8 */
+ 0x00, /* D9 */
+ 0x00, /* DA */
+ 0x70, /* DB */
+ 0x00, /* DC */
+ 0x00, /* DD */
+ 0x00, /* DE */
+ 0x00, /* DF */
+
+ 0x00, /* E0 */
+ 0x00, /* E1 */
+ 0x00, /* E2 */
+ 0x00, /* E3 */
+ 0x00, /* E4 */
+ 0x00, /* E5 */
+ 0x00, /* E6 */
+ 0x00, /* E7 */
+ 0x00, /* E8 */
+ 0x00, /* E9 */
+ 0x00, /* EA */
+ 0x00, /* EB */
+ 0x00, /* EC */
+ 0x00, /* ED */
+ 0x00, /* EE */
+ 0x00, /* EF */
+
+ 0x00, /* F0 */
+ 0x00, /* F1 */
+ 0x00, /* F2 */
+ 0x00, /* F3 */
+ 0x00, /* F4 */
+ 0x00, /* F5 */
+ 0x00, /* F6 */
+ 0x00, /* F7 */
+ 0x00, /* F8 */
+ 0x00, /* F9 */
+ 0x00, /* FA */
+ 0x00, /* FB */
+ 0x00, /* FC */
+ 0x00, /* FD */
+ 0x00, /* FE */
+ 0x00, /* FF */
+};
+
+static struct {
+ int readable;
+ int writable;
+ int vol;
+} max98088_access[M98088_REG_CNT] = {
+ { 0xFF, 0xFF, 1 }, /* 00 IRQ status */
+ { 0xFF, 0x00, 1 }, /* 01 MIC status */
+ { 0xFF, 0x00, 1 }, /* 02 jack status */
+ { 0x1F, 0x1F, 1 }, /* 03 battery voltage */
+ { 0xFF, 0xFF, 0 }, /* 04 */
+ { 0xFF, 0xFF, 0 }, /* 05 */
+ { 0xFF, 0xFF, 0 }, /* 06 */
+ { 0xFF, 0xFF, 0 }, /* 07 */
+ { 0xFF, 0xFF, 0 }, /* 08 */
+ { 0xFF, 0xFF, 0 }, /* 09 */
+ { 0xFF, 0xFF, 0 }, /* 0A */
+ { 0xFF, 0xFF, 0 }, /* 0B */
+ { 0xFF, 0xFF, 0 }, /* 0C */
+ { 0xFF, 0xFF, 0 }, /* 0D */
+ { 0xFF, 0xFF, 0 }, /* 0E */
+ { 0xFF, 0xFF, 0 }, /* 0F interrupt enable */
+
+ { 0xFF, 0xFF, 0 }, /* 10 master clock */
+ { 0xFF, 0xFF, 0 }, /* 11 DAI1 clock mode */
+ { 0xFF, 0xFF, 0 }, /* 12 DAI1 clock control */
+ { 0xFF, 0xFF, 0 }, /* 13 DAI1 clock control */
+ { 0xFF, 0xFF, 0 }, /* 14 DAI1 format */
+ { 0xFF, 0xFF, 0 }, /* 15 DAI1 clock */
+ { 0xFF, 0xFF, 0 }, /* 16 DAI1 config */
+ { 0xFF, 0xFF, 0 }, /* 17 DAI1 TDM */
+ { 0xFF, 0xFF, 0 }, /* 18 DAI1 filters */
+ { 0xFF, 0xFF, 0 }, /* 19 DAI2 clock mode */
+ { 0xFF, 0xFF, 0 }, /* 1A DAI2 clock control */
+ { 0xFF, 0xFF, 0 }, /* 1B DAI2 clock control */
+ { 0xFF, 0xFF, 0 }, /* 1C DAI2 format */
+ { 0xFF, 0xFF, 0 }, /* 1D DAI2 clock */
+ { 0xFF, 0xFF, 0 }, /* 1E DAI2 config */
+ { 0xFF, 0xFF, 0 }, /* 1F DAI2 TDM */
+
+ { 0xFF, 0xFF, 0 }, /* 20 DAI2 filters */
+ { 0xFF, 0xFF, 0 }, /* 21 data config */
+ { 0xFF, 0xFF, 0 }, /* 22 DAC mixer */
+ { 0xFF, 0xFF, 0 }, /* 23 left ADC mixer */
+ { 0xFF, 0xFF, 0 }, /* 24 right ADC mixer */
+ { 0xFF, 0xFF, 0 }, /* 25 left HP mixer */
+ { 0xFF, 0xFF, 0 }, /* 26 right HP mixer */
+ { 0xFF, 0xFF, 0 }, /* 27 HP control */
+ { 0xFF, 0xFF, 0 }, /* 28 left REC mixer */
+ { 0xFF, 0xFF, 0 }, /* 29 right REC mixer */
+ { 0xFF, 0xFF, 0 }, /* 2A REC control */
+ { 0xFF, 0xFF, 0 }, /* 2B left SPK mixer */
+ { 0xFF, 0xFF, 0 }, /* 2C right SPK mixer */
+ { 0xFF, 0xFF, 0 }, /* 2D SPK control */
+ { 0xFF, 0xFF, 0 }, /* 2E sidetone */
+ { 0xFF, 0xFF, 0 }, /* 2F DAI1 playback level */
+
+ { 0xFF, 0xFF, 0 }, /* 30 DAI1 playback level */
+ { 0xFF, 0xFF, 0 }, /* 31 DAI2 playback level */
+ { 0xFF, 0xFF, 0 }, /* 32 DAI2 playbakc level */
+ { 0xFF, 0xFF, 0 }, /* 33 left ADC level */
+ { 0xFF, 0xFF, 0 }, /* 34 right ADC level */
+ { 0xFF, 0xFF, 0 }, /* 35 MIC1 level */
+ { 0xFF, 0xFF, 0 }, /* 36 MIC2 level */
+ { 0xFF, 0xFF, 0 }, /* 37 INA level */
+ { 0xFF, 0xFF, 0 }, /* 38 INB level */
+ { 0xFF, 0xFF, 0 }, /* 39 left HP volume */
+ { 0xFF, 0xFF, 0 }, /* 3A right HP volume */
+ { 0xFF, 0xFF, 0 }, /* 3B left REC volume */
+ { 0xFF, 0xFF, 0 }, /* 3C right REC volume */
+ { 0xFF, 0xFF, 0 }, /* 3D left SPK volume */
+ { 0xFF, 0xFF, 0 }, /* 3E right SPK volume */
+ { 0xFF, 0xFF, 0 }, /* 3F MIC config */
+
+ { 0xFF, 0xFF, 0 }, /* 40 MIC threshold */
+ { 0xFF, 0xFF, 0 }, /* 41 excursion limiter filter */
+ { 0xFF, 0xFF, 0 }, /* 42 excursion limiter threshold */
+ { 0xFF, 0xFF, 0 }, /* 43 ALC */
+ { 0xFF, 0xFF, 0 }, /* 44 power limiter threshold */
+ { 0xFF, 0xFF, 0 }, /* 45 power limiter config */
+ { 0xFF, 0xFF, 0 }, /* 46 distortion limiter config */
+ { 0xFF, 0xFF, 0 }, /* 47 audio input */
+ { 0xFF, 0xFF, 0 }, /* 48 microphone */
+ { 0xFF, 0xFF, 0 }, /* 49 level control */
+ { 0xFF, 0xFF, 0 }, /* 4A bypass switches */
+ { 0xFF, 0xFF, 0 }, /* 4B jack detect */
+ { 0xFF, 0xFF, 0 }, /* 4C input enable */
+ { 0xFF, 0xFF, 0 }, /* 4D output enable */
+ { 0xFF, 0xFF, 0 }, /* 4E bias control */
+ { 0xFF, 0xFF, 0 }, /* 4F DAC power */
+
+ { 0xFF, 0xFF, 0 }, /* 50 DAC power */
+ { 0xFF, 0xFF, 0 }, /* 51 system */
+ { 0xFF, 0xFF, 0 }, /* 52 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 53 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 54 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 55 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 56 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 57 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 58 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 59 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5A DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5B DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5C DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5D DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5E DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5F DAI1 EQ2 */
+
+ { 0xFF, 0xFF, 0 }, /* 60 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 61 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 62 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 63 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 64 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 65 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 66 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 67 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 68 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 69 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6A DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6B DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6C DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6D DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6E DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6F DAI1 EQ3 */
+
+ { 0xFF, 0xFF, 0 }, /* 70 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 71 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 72 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 73 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 74 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 75 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 76 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 77 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 78 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 79 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 7A DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7B DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7C DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7D DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7E DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7F DAI1 EQ5 */
+
+ { 0xFF, 0xFF, 0 }, /* 80 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 81 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 82 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 83 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 84 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 85 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 86 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 87 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 88 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 89 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8A DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8B DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8C DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8D DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8E DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 8F DAI2 EQ2 */
+
+ { 0xFF, 0xFF, 0 }, /* 90 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 91 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 92 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 93 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 94 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 95 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 96 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 97 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 98 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 99 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9A DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9B DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9C DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9D DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9E DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9F DAI2 EQ3 */
+
+ { 0xFF, 0xFF, 0 }, /* A0 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* A1 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* A2 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A3 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A4 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A5 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A6 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A7 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A8 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A9 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AA DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AB DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AC DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AD DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AE DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AF DAI2 EQ5 */
+
+ { 0xFF, 0xFF, 0 }, /* B0 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B1 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B2 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B3 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B4 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B5 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B6 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B7 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B8 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B9 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BA DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BB DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BC DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BD DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BE DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BF DAI1 biquad */
+
+ { 0xFF, 0xFF, 0 }, /* C0 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C1 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C2 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C3 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C4 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C5 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C6 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C7 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C8 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C9 DAI2 biquad */
+ { 0x00, 0x00, 0 }, /* CA */
+ { 0x00, 0x00, 0 }, /* CB */
+ { 0x00, 0x00, 0 }, /* CC */
+ { 0x00, 0x00, 0 }, /* CD */
+ { 0x00, 0x00, 0 }, /* CE */
+ { 0x00, 0x00, 0 }, /* CF */
+
+ { 0x00, 0x00, 0 }, /* D0 */
+ { 0x00, 0x00, 0 }, /* D1 */
+ { 0x00, 0x00, 0 }, /* D2 */
+ { 0x00, 0x00, 0 }, /* D3 */
+ { 0x00, 0x00, 0 }, /* D4 */
+ { 0x00, 0x00, 0 }, /* D5 */
+ { 0x00, 0x00, 0 }, /* D6 */
+ { 0x00, 0x00, 0 }, /* D7 */
+ { 0x00, 0x00, 0 }, /* D8 */
+ { 0x00, 0x00, 0 }, /* D9 */
+ { 0x00, 0x00, 0 }, /* DA */
+ { 0x00, 0x00, 0 }, /* DB */
+ { 0x00, 0x00, 0 }, /* DC */
+ { 0x00, 0x00, 0 }, /* DD */
+ { 0x00, 0x00, 0 }, /* DE */
+ { 0x00, 0x00, 0 }, /* DF */
+
+ { 0x00, 0x00, 0 }, /* E0 */
+ { 0x00, 0x00, 0 }, /* E1 */
+ { 0x00, 0x00, 0 }, /* E2 */
+ { 0x00, 0x00, 0 }, /* E3 */
+ { 0x00, 0x00, 0 }, /* E4 */
+ { 0x00, 0x00, 0 }, /* E5 */
+ { 0x00, 0x00, 0 }, /* E6 */
+ { 0x00, 0x00, 0 }, /* E7 */
+ { 0x00, 0x00, 0 }, /* E8 */
+ { 0x00, 0x00, 0 }, /* E9 */
+ { 0x00, 0x00, 0 }, /* EA */
+ { 0x00, 0x00, 0 }, /* EB */
+ { 0x00, 0x00, 0 }, /* EC */
+ { 0x00, 0x00, 0 }, /* ED */
+ { 0x00, 0x00, 0 }, /* EE */
+ { 0x00, 0x00, 0 }, /* EF */
+
+ { 0x00, 0x00, 0 }, /* F0 */
+ { 0x00, 0x00, 0 }, /* F1 */
+ { 0x00, 0x00, 0 }, /* F2 */
+ { 0x00, 0x00, 0 }, /* F3 */
+ { 0x00, 0x00, 0 }, /* F4 */
+ { 0x00, 0x00, 0 }, /* F5 */
+ { 0x00, 0x00, 0 }, /* F6 */
+ { 0x00, 0x00, 0 }, /* F7 */
+ { 0x00, 0x00, 0 }, /* F8 */
+ { 0x00, 0x00, 0 }, /* F9 */
+ { 0x00, 0x00, 0 }, /* FA */
+ { 0x00, 0x00, 0 }, /* FB */
+ { 0x00, 0x00, 0 }, /* FC */
+ { 0x00, 0x00, 0 }, /* FD */
+ { 0x00, 0x00, 0 }, /* FE */
+ { 0xFF, 0x00, 1 }, /* FF */
+};
+
+static int max98088_volatile_register(unsigned int reg)
+{
+ return max98088_access[reg].vol;
+}
+
+static int max98088_hw_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ u8 data[2];
+
+ data[0] = reg;
+ data[1] = value;
+ if (codec->hw_write(codec->control_data, data, 2) == 2)
+ return 0;
+ else
+ return -EIO;
+}
+
+/*
+ * For kernels compiled without unsigned long long int division
+ */
+unsigned long long int ulldiv(unsigned long long int dividend,
+ unsigned long long int divisor)
+{
+ unsigned long long int quotient = 0;
+ int shift = 1;
+
+ BUG_ON(divisor == 0);
+
+ /* Result is 1.0 if divisor and dividend are equal */
+ if (divisor == dividend)
+ return 1;
+
+ /* Normalize divisor */
+ while (!(divisor & 0x8000000000000000ULL)) {
+ divisor <<= 1;
+ ++shift;
+ }
+
+ /* Shift and subtract */
+ while (shift--) {
+ quotient <<= 1;
+
+ if (divisor <= dividend) {
+ dividend -= divisor;
+ ++quotient;
+ }
+ divisor >>= 1;
+ }
+
+ /* Round up */
+ if (dividend > divisor)
+ ++quotient;
+
+ return quotient;
+}
+
+#define INA1_PGA_BIT 0x01
+#define INA2_PGA_BIT 0x02
+#define INB1_PGA_BIT 0x04
+#define INB2_PGA_BIT 0x08
+/*
+ * The INx1 and INx2 PGAs share a power control signal.
+ * This function OR's the two power events to keep an unpowered INx
+ * from turning off it's counterpart.
+ * The control names are used to identify the PGA.
+ */
+static int max98088_pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ u8 *state = &max98088->power_state;
+ unsigned int val;
+ unsigned int pga;
+ unsigned int mask;
+
+ BUG_ON(w->reg != M98088_REG_4C_PWR_EN_IN);
+
+ if (strncmp(w->name, "INA1", 4) == 0) {
+ pga = INA1_PGA_BIT;
+ mask = INA1_PGA_BIT | INA2_PGA_BIT;
+ } else if (strncmp(w->name, "INA2", 4) == 0) {
+ pga = INA2_PGA_BIT;
+ mask = INA1_PGA_BIT | INA2_PGA_BIT;
+ } else if (strncmp(w->name, "INB1", 4) == 0) {
+ pga = INB1_PGA_BIT;
+ mask = INB1_PGA_BIT | INB2_PGA_BIT;
+ } else if (strncmp(w->name, "INB2", 4) == 0) {
+ pga = INB2_PGA_BIT;
+ mask = INB1_PGA_BIT | INB2_PGA_BIT;
+ } else {
+ return -EINVAL;
+ }
+
+ if (event == SND_SOC_DAPM_POST_PMU) {
+ /* ON */
+ *state |= pga;
+
+ /* Turn on, avoiding unnecessary writes */
+ val = snd_soc_read(codec, w->reg);
+ if (!(val & (1 << w->shift))) {
+ val |= (1 << w->shift);
+ snd_soc_write(codec, w->reg, val);
+ }
+ } else if (event == SND_SOC_DAPM_POST_PMD) {
+ /* OFF */
+ *state &= ~pga;
+
+ /* Turn off if both are off, avoiding unnecessary writes */
+ if (!(*state & mask)) {
+ val = snd_soc_read(codec, w->reg);
+ if (val & (1 << w->shift)) {
+ val &= ~(1 << w->shift);
+ snd_soc_write(codec, w->reg, val);
+ }
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+ unsigned int band, u16 *coefs)
+{
+ unsigned int eq_reg;
+ unsigned int i;
+
+ BUG_ON(band > 4);
+ BUG_ON(dai > 1);
+
+ /* Load the base register address */
+ eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE;
+
+ /* Add the band address offset, note adjustment for word address */
+ eq_reg += band * (M98088_COEFS_PER_BAND << 1);
+
+ /* Step through the registers and coefs */
+ for (i = 0; i < M98088_COEFS_PER_BAND; i++) {
+ snd_soc_write(codec, eq_reg++, M98088_BYTE1(coefs[i]));
+ snd_soc_write(codec, eq_reg++, M98088_BYTE0(coefs[i]));
+ }
+
+ return;
+}
+
+/*
+ * Excursion limiter modes
+ */
+static const char *max98088_ex_mode[] = {
+ "Off",
+ "100Hz",
+ "400Hz",
+ "600Hz",
+ "800Hz",
+ "1000Hz",
+ "200-400Hz",
+ "400-600Hz",
+ "400-800Hz",
+};
+
+static const unsigned int ex_mode_table[] = {
+ 0x00, /* disabled */
+ (0<<4)|3, /* 100Hz */
+ (1<<4)|0, /* 400Hz */
+ (2<<4)|0, /* 600Hz */
+ (3<<4)|0, /* 800Hz */
+ (4<<4)|0, /* 1000Hz */
+ (1<<4)|1, /* 200-400Hz */
+ (2<<4)|2, /* 400-600Hz */
+ (3<<4)|2, /* 400-800Hz */
+};
+
+static const struct soc_enum max98088_ex_mode_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98088_ex_mode), max98088_ex_mode),
+};
+
+static int max98088_ex_mode_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->ex_mode;
+ int sel = ucontrol->value.integer.value[0];
+
+ if (sel >= ARRAY_SIZE(ex_mode_table))
+ return -EINVAL;
+
+ *mode = ucontrol->value.integer.value[0];
+ snd_soc_write(codec, M98088_REG_41_SPKDHP,
+ ex_mode_table[*mode]);
+
+ return 0;
+}
+
+static int max98088_ex_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->ex_mode;
+
+ ucontrol->value.integer.value[0] = *mode;
+ return 0;
+}
+
+static const char *max98088_ex_thresh[] = { /* volts PP */
+ "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
+static const struct soc_enum max98088_ex_thresh_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_42_SPKDHP_THRESH, 0, 8,
+ max98088_ex_thresh),
+};
+
+static const char *max98088_fltr_mode[] = {"Voice", "Music" };
+static const struct soc_enum max98088_filter_mode_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 7, 2, max98088_fltr_mode),
+};
+
+static const char *max98088_dai1_fltr[] = {
+ "Off", "fc=258/fs=16k", "fc=500/fs=16k",
+ "fc=258/fs=8k", "fc=500/fs=8k", "fc=200"};
+static const struct soc_enum max98088_dai1_dac_filter_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 0, 6, max98088_dai1_fltr),
+};
+static const struct soc_enum max98088_dai1_adc_filter_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 4, 6, max98088_dai1_fltr),
+};
+
+static const char *max98088_micpre[] = {
+ "0dB",
+ "20dB",
+ "30dB",
+};
+
+static const struct soc_enum max98088_micpre_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98088_micpre), max98088_micpre),
+};
+
+static const char *max98088_extmic[] = {
+ "Off",
+ "MIC1",
+ "MIC2",
+};
+
+static const struct soc_enum max98088_extmic_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98088_extmic), max98088_extmic),
+};
+
+static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->mic1pre;
+ int sel = ucontrol->value.integer.value[0];
+
+ if (sel >= ARRAY_SIZE(max98088_micpre))
+ return -EINVAL;
+
+ *mode = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->mic1pre;
+
+ ucontrol->value.integer.value[0] = *mode;
+ return 0;
+}
+
+static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->mic2pre;
+ int sel = ucontrol->value.integer.value[0];
+
+ if (sel >= ARRAY_SIZE(max98088_micpre))
+ return -EINVAL;
+
+ *mode = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->mic2pre;
+
+ ucontrol->value.integer.value[0] = *mode;
+ return 0;
+}
+
+static int max98088_extmic_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->extmic_mode;
+ int sel = ucontrol->value.integer.value[0];
+
+ if (sel >= ARRAY_SIZE(max98088_extmic))
+ return -EINVAL;
+
+ *mode = sel;
+ snd_soc_update_bits(codec, M98088_REG_48_CFG_MIC,
+ M98088_EXTMIC_MASK, sel);
+
+ return 0;
+}
+
+static int max98088_extmic_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->extmic_mode;
+
+ ucontrol->value.integer.value[0] = *mode;
+ return 0;
+}
+
+static const struct snd_kcontrol_new max98088_snd_controls[] = {
+
+ /* Analog outputs */
+
+ SOC_DOUBLE_R("Headphone Volume", M98088_REG_39_LVL_HP_L,
+ M98088_REG_3A_LVL_HP_R, 0, 31, 0),
+ SOC_DOUBLE_R("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
+ M98088_REG_3E_LVL_SPK_R, 0, 31, 0),
+ SOC_DOUBLE_R("Receiver Volume", M98088_REG_3B_LVL_REC_L,
+ M98088_REG_3C_LVL_REC_R, 0, 31, 0),
+
+ SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L,
+ M98088_REG_3A_LVL_HP_R, 7, 1, 1),
+ SOC_DOUBLE_R("Speaker Switch", M98088_REG_3D_LVL_SPK_L,
+ M98088_REG_3E_LVL_SPK_R, 7, 1, 1),
+ SOC_DOUBLE_R("Receiver Switch", M98088_REG_3B_LVL_REC_L,
+ M98088_REG_3C_LVL_REC_R, 7, 1, 1),
+
+ /* Analog inputs */
+
+ SOC_SINGLE("MIC1 Volume", M98088_REG_35_LVL_MIC1, 0, 31, 1),
+ SOC_SINGLE("MIC2 Volume", M98088_REG_36_LVL_MIC2, 0, 31, 1),
+
+ SOC_ENUM_EXT("MIC1 Boost Volume", max98088_micpre_enum,
+ max98088_mic1pre_get, max98088_mic1pre_set),
+
+ SOC_ENUM_EXT("MIC2 Boost Volume", max98088_micpre_enum,
+ max98088_mic2pre_get, max98088_mic2pre_set),
+
+ SOC_ENUM_EXT("Ext MIC Switch", max98088_extmic_enum,
+ max98088_extmic_get, max98088_extmic_set),
+
+ SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1),
+ SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1),
+
+ /* ADC input digital gains and volume controls */
+
+ SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0),
+ SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0),
+
+ SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0),
+ SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0),
+
+ /* Equalizer */
+
+ SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
+ SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
+
+ /* Excursion limiter */
+
+ SOC_ENUM_EXT("EX Limiter Mode", max98088_ex_mode_enum,
+ max98088_ex_mode_get, max98088_ex_mode_set),
+ SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
+
+ /* Voice/music filters */
+
+ SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
+ SOC_ENUM("DAI1 DAC Filter", max98088_dai1_dac_filter_enum),
+ SOC_ENUM("DAI1 ADC Filter", max98088_dai1_adc_filter_enum),
+ SOC_SINGLE("DAI2 DC Block Switch", M98088_REG_20_DAI2_FILTERS,
+ 0, 1, 0),
+
+ /* Automatic level control (for both DAI1/DAI2) */
+
+ SOC_SINGLE("ALC Switch", M98088_REG_43_SPKALC_COMP, 7, 1, 0),
+ SOC_SINGLE("ALC Threshold", M98088_REG_43_SPKALC_COMP, 0, 7, 0),
+ SOC_SINGLE("ALC Multiband", M98088_REG_43_SPKALC_COMP, 3, 1, 0),
+ SOC_SINGLE("ALC Release Time", M98088_REG_43_SPKALC_COMP, 4, 7, 0),
+
+ /* Power limiter */
+
+ SOC_SINGLE("PWR Limiter Threshold", M98088_REG_44_PWRLMT_CFG,
+ 4, 15, 0),
+ SOC_SINGLE("PWR Limiter Weight", M98088_REG_44_PWRLMT_CFG, 0, 7, 0),
+ SOC_SINGLE("PWR Limiter Time1", M98088_REG_45_PWRLMT_TIME, 0, 15, 0),
+ SOC_SINGLE("PWR Limiter Time2", M98088_REG_45_PWRLMT_TIME, 4, 15, 0),
+
+ /* THD distortion limiter */
+
+ SOC_SINGLE("THD Limiter Threshold", M98088_REG_46_THDLMT_CFG, 4, 15, 0),
+ SOC_SINGLE("THD Limiter Time", M98088_REG_46_THDLMT_CFG, 0, 7, 0),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 4, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 4, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_25_MIX_HP_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_25_MIX_HP_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_25_MIX_HP_LEFT, 4, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_26_MIX_HP_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_26_MIX_HP_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_26_MIX_HP_RIGHT, 4, 1, 0),
+};
+
+/* Left earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_28_MIX_REC_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_28_MIX_REC_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_28_MIX_REC_LEFT, 4, 1, 0),
+};
+
+/* Right earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_29_MIX_REC_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_29_MIX_REC_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_29_MIX_REC_RIGHT, 4, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98088_left_ADC_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_23_MIX_ADC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_23_MIX_ADC_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_23_MIX_ADC_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_23_MIX_ADC_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_23_MIX_ADC_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_23_MIX_ADC_LEFT, 0, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 0, 1, 0),
+};
+
+static int max98088_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 status;
+
+ BUG_ON(event != SND_SOC_DAPM_PRE_PMD);
+
+ /* powering down headphone gracefully */
+ status = snd_soc_read(codec, M98088_REG_4D_PWR_EN_OUT);
+ if ((status & M98088_HPEN) == M98088_HPEN) {
+ max98088_hw_write(codec, M98088_REG_4D_PWR_EN_OUT,
+ (status & ~M98088_HPEN));
+ }
+ schedule_timeout(msecs_to_jiffies(20));
+
+ return 0;
+}
+
+static int max98088_mic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (w->reg == M98088_REG_35_LVL_MIC1) {
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+ (1+max98088->mic1pre)<<M98088_MICPRE_SHIFT);
+ } else {
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+ (1+max98088->mic2pre)<<M98088_MICPRE_SHIFT);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* DAPM widgets top level */
+static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
+
+ SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0),
+ SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0),
+
+ SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+ M98088_REG_4D_PWR_EN_OUT, 1, 0),
+ SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+ M98088_REG_4D_PWR_EN_OUT, 0, 0),
+ SND_SOC_DAPM_DAC("DACL2", "Aux Playback",
+ M98088_REG_4D_PWR_EN_OUT, 1, 0),
+ SND_SOC_DAPM_DAC("DACR2", "Aux Playback",
+ M98088_REG_4D_PWR_EN_OUT, 0, 0),
+
+ SND_SOC_DAPM_PGA_E("HP Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 7, 0, NULL, 0, max98088_hp_event, SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_E("HP Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 6, 0, NULL, 0, max98088_hp_event, SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_PGA("SPK Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("SPK Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("REC Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("REC Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_hp_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_hp_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_hp_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_hp_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left SPK Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_speaker_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_speaker_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right SPK Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_speaker_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_speaker_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left REC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_rec_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_rec_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right REC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_rec_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_rec_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_ADC_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_ADC_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_ADC_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_ADC_mixer_controls)),
+
+ SND_SOC_DAPM_PGA_E("MIC1 Input", M98088_REG_35_LVL_MIC1,
+ 5, 0, NULL, 0, max98088_mic_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("MIC2 Input", M98088_REG_36_LVL_MIC2,
+ 5, 0, NULL, 0, max98088_mic_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INA1 Input", M98088_REG_4C_PWR_EN_IN,
+ 7, 0, NULL, 0, max98088_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INA2 Input", M98088_REG_4C_PWR_EN_IN,
+ 7, 0, NULL, 0, max98088_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INB1 Input", M98088_REG_4C_PWR_EN_IN,
+ 6, 0, NULL, 0, max98088_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INB2 Input", M98088_REG_4C_PWR_EN_IN,
+ 6, 0, NULL, 0, max98088_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
+
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+ SND_SOC_DAPM_OUTPUT("RECL"),
+ SND_SOC_DAPM_OUTPUT("RECR"),
+
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("INA1"),
+ SND_SOC_DAPM_INPUT("INA2"),
+ SND_SOC_DAPM_INPUT("INB1"),
+ SND_SOC_DAPM_INPUT("INB2"),
+};
+
+/* DAPM AUDIO_MAP: */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Left headphone output mixer */
+ {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left HP Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left HP Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left HP Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left HP Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left HP Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left HP Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left HP Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right headphone output mixer */
+ {"Right HP Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right HP Mixer", "Left DAC2 Switch", "DACL2" },
+ {"Right HP Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right HP Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right HP Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right HP Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right HP Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right HP Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right HP Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Left speaker output mixer */
+ {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left SPK Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left SPK Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left SPK Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right speaker output mixer */
+ {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right SPK Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right SPK Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right SPK Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Earpiece/Receiver output mixer */
+ {"Left REC Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left REC Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left REC Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left REC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left REC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left REC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left REC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left REC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left REC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Earpiece/Receiver output mixer */
+ {"Right REC Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right REC Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Right REC Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right REC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right REC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right REC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right REC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right REC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right REC Mixer", "INB2 Switch", "INB2 Input"},
+
+ {"HP Left Out", NULL, "Left HP Mixer"},
+ {"HP Right Out", NULL, "Right HP Mixer"},
+ {"SPK Left Out", NULL, "Left SPK Mixer"},
+ {"SPK Right Out", NULL, "Right SPK Mixer"},
+ {"REC Left Out", NULL, "Left REC Mixer"},
+ {"REC Right Out", NULL, "Right REC Mixer"},
+
+ {"HPL", NULL, "HP Left Out"},
+ {"HPR", NULL, "HP Right Out"},
+ {"SPKL", NULL, "SPK Left Out"},
+ {"SPKR", NULL, "SPK Right Out"},
+ {"RECL", NULL, "REC Left Out"},
+ {"RECR", NULL, "REC Right Out"},
+
+ /* Left ADC input mixer */
+ {"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left ADC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left ADC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left ADC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right ADC input mixer */
+ {"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right ADC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right ADC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right ADC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* inputs */
+ {"ADCL", NULL, "Left ADC Mixer"},
+ {"ADCR", NULL, "Right ADC Mixer"},
+ {"INA1 Input", NULL, "INA1"},
+ {"INA2 Input", NULL, "INA2"},
+ {"INB1 Input", NULL, "INB1"},
+ {"INB2 Input", NULL, "INB2"},
+ {"MIC1 Input", NULL, "MIC1"},
+ {"MIC2 Input", NULL, "MIC2"},
+};
+
+static int max98088_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, max98088_dapm_widgets,
+ ARRAY_SIZE(max98088_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_add_controls(codec, max98088_snd_controls,
+ ARRAY_SIZE(max98088_snd_controls));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+/* codec mclk clock divider coefficients */
+static const struct {
+ u32 rate;
+ u8 sr;
+} rate_table[] = {
+ {8000, 0x10},
+ {11025, 0x20},
+ {16000, 0x30},
+ {22050, 0x40},
+ {24000, 0x50},
+ {32000, 0x60},
+ {44100, 0x70},
+ {48000, 0x80},
+ {88200, 0x90},
+ {96000, 0xA0},
+};
+
+static inline int rate_value(int rate, u8 *value)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+ if (rate_table[i].rate >= rate) {
+ *value = rate_table[i].sr;
+ return 0;
+ }
+ }
+ *value = rate_table[0].sr;
+ return -EINVAL;
+}
+
+static int max98088_dai1_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 max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ unsigned int rate;
+ u8 regval;
+ u16 ni;
+
+ cdata = &max98088->dai[0];
+
+ rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ M98088_DAI_WS, 0);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ M98088_DAI_WS, M98088_DAI_WS);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+ if (rate != cdata->rate) {
+ /* set DAI1 SR1 value for the DSP; FREQ1:0=anyclock */
+ if (rate_value(rate, ®val))
+ return -EINVAL;
+
+ snd_soc_write(codec, M98088_REG_11_DAI1_CLKMODE, regval);
+ cdata->rate = rate;
+ }
+
+ /* Configure NI when operating as master */
+ if (snd_soc_read(codec, M98088_REG_14_DAI1_FORMAT)
+ & M98088_DAI_MAS) {
+ if (max98088->sysclk == 0)
+ return -EINVAL;
+ ni = (u16)ulldiv(65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+ * (unsigned long long int)rate,
+ (unsigned long long int)max98088->sysclk);
+ snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+ (ni >> 8) & 0x7f);
+ snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+ ni & 0xff);
+ }
+
+ /* Update sample rate mode */
+ if (rate < 50000)
+ snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+ M98088_DAI_DHF, 0);
+ else
+ snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+ M98088_DAI_DHF, M98088_DAI_DHF);
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, 0, M98088_SHDNRUN);
+
+ return 0;
+}
+
+static int max98088_dai2_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 max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ unsigned int rate;
+ u8 regval;
+ u16 ni;
+
+ cdata = &max98088->dai[1];
+
+ rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ M98088_DAI_WS, 0);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ M98088_DAI_WS, M98088_DAI_WS);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+ if (rate != cdata->rate) {
+ /* set DAI2 SR2 value for the DSP */
+ if (rate_value(rate, ®val))
+ return -EINVAL;
+
+ snd_soc_write(codec, M98088_REG_19_DAI2_CLKMODE, regval);
+ cdata->rate = rate;
+ }
+
+ /* Configure NI when operating as master */
+ if (snd_soc_read(codec, M98088_REG_1C_DAI2_FORMAT)
+ & M98088_DAI_MAS) {
+ if (max98088->sysclk == 0)
+ return -EINVAL;
+ ni = (u16)ulldiv(65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+ * (unsigned long long int)rate,
+ (unsigned long long int)max98088->sysclk);
+ snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+ (ni >> 8) & 0x7f);
+ snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+ ni & 0xff);
+ }
+
+ /* Update sample rate mode */
+ if (rate < 50000)
+ snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+ M98088_DAI_DHF, 0);
+ else
+ snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+ M98088_DAI_DHF, M98088_DAI_DHF);
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, 0, M98088_SHDNRUN);
+
+ return 0;
+}
+
+static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ /* requested clock frequency is already setup */
+ if (freq == max98088->sysclk)
+ return 0;
+
+ max98088->sysclk = freq; /* remember current sysclk */
+
+ /* setup clocks for slave mode, and using the PLL
+ * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+ * 0x02 (when master clk is 20MHz to 30MHz)..
+ */
+ if ((freq >= 10000000) && (freq < 20000000)) {
+ snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x10);
+ } else if ((freq >= 20000000) && (freq < 30000000)) {
+ snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x20);
+ } else {
+ dev_err(codec->dev, "Invalid master clock frequency\n");
+ return -EINVAL;
+ }
+
+ if (snd_soc_read(codec, M98088_REG_51_PWR_SYS) & M98088_SHDNRUN) {
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+ M98088_SHDNRUN, 0);
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+ 0, M98088_SHDNRUN);
+ }
+
+ dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+ max98088->sysclk = freq;
+ return 0;
+}
+
+static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ u8 reg15val;
+ u8 reg14msk = 0;
+ u8 reg14val = 0;
+
+ cdata = &max98088->dai[0];
+
+ if (fmt != cdata->fmt) {
+ cdata->fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* mask MAS to select slave mode */
+ reg14msk |= M98088_DAI_MAS;
+ /* slave mode PLL */
+ snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+ 0x80);
+ snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+ 0x00);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* set to master mode */
+ reg14val |= M98088_DAI_MAS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ dev_err(codec->dev, "Clock mode unsupported");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ reg14val |= M98088_DAI_DLY;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg14msk |= M98088_DAI_DLY;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ reg14msk |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ reg14msk |= M98088_DAI_BCI;
+ reg14val |= M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg14msk |= M98088_DAI_WCI;
+ reg14val |= M98088_DAI_BCI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ reg14val |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ reg14msk, reg14val);
+
+ reg15val = M98088_DAI_BSEL64;
+ if (max98088->digmic)
+ reg15val |= M98088_DAI_OSR64;
+ snd_soc_write(codec, M98088_REG_15_DAI1_CLOCK, reg15val);
+ }
+
+ return 0;
+}
+
+static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ u8 reg1Cmsk = 0;
+ u8 reg1Cval = 0;
+
+ cdata = &max98088->dai[1];
+
+ if (fmt != cdata->fmt) {
+ cdata->fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* mask MAS to select slave mode */
+ reg1Cmsk |= M98088_DAI_MAS;
+ /* slave mode PLL */
+ snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+ 0x80);
+ snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+ 0x00);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* set to master mode */
+ reg1Cval |= M98088_DAI_MAS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ dev_err(codec->dev, "Clock mode unsupported");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ reg1Cval |= M98088_DAI_DLY;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg1Cmsk |= M98088_DAI_DLY;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ reg1Cmsk |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ reg1Cmsk |= M98088_DAI_BCI;
+ reg1Cval |= M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg1Cmsk |= M98088_DAI_WCI;
+ reg1Cval |= M98088_DAI_BCI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ reg1Cval |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ reg1Cmsk, reg1Cval);
+
+ snd_soc_write(codec, M98088_REG_1D_DAI2_CLOCK,
+ M98088_DAI_BSEL64);
+ }
+
+ return 0;
+}
+
+static void max98088_sync_cache(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ if (!codec->cache_sync)
+ return;
+
+ codec->cache_only = 0;
+
+ /* write back cached values if they're writeable and
+ * different from the hardware default.
+ */
+ for (i = 1; i < ARRAY_SIZE(max98088->reg_cache); i++) {
+ if (!max98088_access[i].writable)
+ continue;
+
+ if (max98088->reg_cache[i] == max98088_reg[i])
+ continue;
+
+ snd_soc_write(codec, i, max98088->reg_cache[i]);
+ }
+
+ codec->cache_sync = 0;
+}
+
+static int max98088_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ max98088_sync_cache(codec);
+ snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+ M98088_MBEN, M98088_MBEN);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+ M98088_MBEN, 0);
+#ifdef CONFIG_REGULATOR
+ codec->cache_sync = 1;
+#endif
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+#define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98088_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98088_dai1_ops = {
+ .set_sysclk = max98088_dai_set_sysclk,
+ .set_fmt = max98088_dai1_set_fmt,
+ .hw_params = max98088_dai1_hw_params,
+};
+
+static struct snd_soc_dai_ops max98088_dai2_ops = {
+ .set_sysclk = max98088_dai_set_sysclk,
+ .set_fmt = max98088_dai2_set_fmt,
+ .hw_params = max98088_dai2_hw_params,
+};
+
+static struct snd_soc_dai_driver max98088_dai[] = {
+{
+ .name = "HiFi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .ops = &max98088_dai1_ops,
+},
+{
+ .name = "Aux",
+ .playback = {
+ .stream_name = "Aux Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .ops = &max98088_dai2_ops,
+}
+};
+
+static void max98088_setup_eq1(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_eq_cfg *coef_set;
+ int best, best_val, save, i, sel, fs;
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[0];
+
+ if (!pdata || !cdata->eq_textcnt)
+ return;
+
+ /* Find the selected configuration with nearest sample rate */
+ fs = cdata->rate;
+ sel = cdata->eq_sel;
+
+ best = 0;
+ best_val = INT_MAX;
+ for (i = 0; i < pdata->eq1_cfgcnt; i++) {
+ if (strcmp(pdata->eq1_cfg[i].name, cdata->eq_texts[sel]) == 0 &&
+ abs(pdata->eq1_cfg[i].rate - fs) < best_val) {
+ best = i;
+ best_val = abs(pdata->eq1_cfg[i].rate - fs);
+ }
+ }
+
+ dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+ pdata->eq1_cfg[best].name,
+ pdata->eq1_cfg[best].rate, fs);
+
+ /* Disable EQ while configuring, and save current on/off state */
+ save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, 0);
+
+ coef_set = &pdata->eq1_cfg[sel];
+
+ m98088_eq_band(codec, 0, 0, coef_set->band1);
+ m98088_eq_band(codec, 0, 1, coef_set->band2);
+ m98088_eq_band(codec, 0, 2, coef_set->band3);
+ m98088_eq_band(codec, 0, 3, coef_set->band4);
+ m98088_eq_band(codec, 0, 4, coef_set->band5);
+
+ /* restore original on/off state */
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, save);
+}
+
+static void max98088_setup_eq2(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_eq_cfg *coef_set;
+ int best, best_val, save, i, sel, fs;
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[1];
+
+ if (!pdata || !cdata->eq_textcnt)
+ return;
+
+ /* Find the selected configuration with nearest sample rate */
+ fs = cdata->rate;
+
+ sel = cdata->eq_sel;
+ best = 0;
+ best_val = INT_MAX;
+ for (i = 0; i < pdata->eq2_cfgcnt; i++) {
+ if (strcmp(pdata->eq2_cfg[i].name, cdata->eq_texts[sel]) == 0 &&
+ abs(pdata->eq2_cfg[i].rate - fs) < best_val) {
+ best = i;
+ best_val = abs(pdata->eq2_cfg[i].rate - fs);
+ }
+ }
+
+ dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+ pdata->eq2_cfg[best].name,
+ pdata->eq2_cfg[best].rate, fs);
+
+ /* Disable EQ while configuring, and save current on/off state */
+ save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN, 0);
+
+ coef_set = &pdata->eq2_cfg[sel];
+
+ m98088_eq_band(codec, 1, 0, coef_set->band1);
+ m98088_eq_band(codec, 1, 1, coef_set->band2);
+ m98088_eq_band(codec, 1, 2, coef_set->band3);
+ m98088_eq_band(codec, 1, 3, coef_set->band4);
+ m98088_eq_band(codec, 1, 4, coef_set->band5);
+
+ /* restore original on/off state */
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN,
+ save);
+}
+
+
+static int max98088_put_eq1_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_cdata *cdata;
+ int sel = ucontrol->value.integer.value[0];
+
+ cdata = &max98088->dai[0];
+
+ if (sel >= pdata->eq1_cfgcnt)
+ return -EINVAL;
+
+ cdata->eq_sel = sel;
+ max98088_setup_eq1(codec);
+ return 0;
+}
+
+static int max98088_put_eq2_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_cdata *cdata;
+ int sel = ucontrol->value.integer.value[0];
+
+ cdata = &max98088->dai[1];
+
+ if (sel >= pdata->eq2_cfgcnt)
+ return -EINVAL;
+
+ cdata->eq_sel = sel;
+ max98088_setup_eq2(codec);
+ return 0;
+}
+
+static int max98088_get_eq1_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[0];
+
+ ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+ return 0;
+}
+
+static int max98088_get_eq2_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[1];
+
+ ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+ return 0;
+}
+
+static void max98088_handle_eq1_pdata(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_cdata *cdata;
+ int ret, i, j;
+
+ struct snd_kcontrol_new eq1control =
+ SOC_ENUM_EXT("EQ1 Mode",
+ max98088->dai[0].eq_enum,
+ max98088_get_eq1_enum,
+ max98088_put_eq1_enum);
+
+ cdata = &max98088->dai[0];
+
+ /* Build an array of texts for the enum API. The number
+ * of texts is likely fewer than the number of configurations
+ * due to multiple sample rates for the same text name. */
+ cdata->eq_textcnt = 0;
+ for (i = 0; i < pdata->eq1_cfgcnt; i++) {
+ for (j = 0; j < cdata->eq_textcnt; j++) {
+ if (strcmp(pdata->eq1_cfg[i].name,
+ cdata->eq_texts[j]) == 0) {
+ break;
+ }
+ }
+
+ if (j != cdata->eq_textcnt)
+ continue;
+
+ /* ...and remember the new version. */
+ cdata->eq_texts[i] = pdata->eq1_cfg[i].name;
+ cdata->eq_textcnt++;
+
+ if (cdata->eq_textcnt >= EQ_CFG_MAX) {
+ dev_err(codec->dev, "Too many EQ config entries\n");
+ cdata->eq_textcnt--;
+ break;
+ }
+ }
+
+ dev_dbg(codec->dev, "Installed %d EQ1 configurations\n",
+ cdata->eq_textcnt);
+
+ /* now point the soc_enum to .texts array items */
+ cdata->eq_enum.texts = cdata->eq_texts;
+ cdata->eq_enum.max = cdata->eq_textcnt;
+
+ ret = snd_soc_add_controls(codec, &eq1control, 1);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static void max98088_handle_eq2_pdata(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_cdata *cdata;
+ int ret, i, j;
+
+ struct snd_kcontrol_new eq2control =
+ SOC_ENUM_EXT("EQ2 Mode",
+ max98088->dai[1].eq_enum,
+ max98088_get_eq2_enum,
+ max98088_put_eq2_enum);
+
+ cdata = &max98088->dai[1];
+
+ /* Build an array of texts for the enum API. The number
+ * of texts is likely fewer than the number of configurations
+ * due to multiple sample rates for the same text name. */
+ cdata->eq_textcnt = 0;
+ for (i = 0; i < pdata->eq2_cfgcnt; i++) {
+ for (j = 0; j < cdata->eq_textcnt; j++) {
+ if (strcmp(pdata->eq2_cfg[i].name,
+ cdata->eq_texts[j]) == 0) {
+ break;
+ }
+ }
+
+ if (j != cdata->eq_textcnt)
+ continue;
+
+ cdata->eq_texts[i] = pdata->eq2_cfg[i].name;
+ cdata->eq_textcnt++;
+
+ if (cdata->eq_textcnt >= EQ_CFG_MAX) {
+ dev_err(codec->dev, "Too many EQ config entries\n");
+ cdata->eq_textcnt--;
+ break;
+ }
+ }
+
+ dev_dbg(codec->dev, "Installed %d EQ2 configurations\n",
+ cdata->eq_textcnt);
+
+ /* now point the soc_enum to .texts array items */
+ cdata->eq_enum.texts = cdata->eq_texts;
+ cdata->eq_enum.max = cdata->eq_textcnt;
+
+ ret = snd_soc_add_controls(codec, &eq2control, 1);
+ if (ret != 0)
+ printk(KERN_ERR "Failed to add EQ control: %d\n", ret);
+}
+
+static void max98088_handle_pdata(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ u8 regval = 0;
+
+ if (!pdata) {
+ dev_dbg(codec->dev, "No platform data\n");
+ return;
+ }
+
+ /* configure mic for analog/digital mic mode */
+ if (pdata->digmic_left_mode)
+ regval |= M98088_DIGMIC_L;
+
+ if (pdata->digmic_right_mode)
+ regval |= M98088_DIGMIC_R;
+
+ max98088->digmic = (regval ? 1 : 0);
+
+ snd_soc_write(codec, M98088_REG_48_CFG_MIC, regval);
+
+ /* configure receiver output */
+ regval = ((pdata->receiver_mode) ? M98088_REC_LINEMODE : 0);
+ snd_soc_update_bits(codec, M98088_REG_2A_MIC_REC_CNTL,
+ M98088_REC_LINEMODE_MASK, regval);
+
+ /* configure equalizers */
+ if (pdata->eq1_cfgcnt)
+ max98088_handle_eq1_pdata(codec);
+
+ if (pdata->eq2_cfgcnt)
+ max98088_handle_eq2_pdata(codec);
+}
+
+#ifdef CONFIG_PM
+static int max98088_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int max98088_resume(struct snd_soc_codec *codec)
+{
+ int i;
+ u8 *cache = codec->reg_cache;
+
+ max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ /* Sync reg_cache with the hardware */
+ for (i = 0; i < M98088_REG_CNT; i++) {
+ if (i == M98088_REG_51_PWR_SYS)
+ continue;
+
+ if (!max98088_access[i].writable)
+ continue;
+
+ max98088_hw_write(codec, i, cache[i]);
+ }
+
+ /* now enter into the resume mode bias level */
+ max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define max98088_suspend NULL
+#define max98088_resume NULL
+#endif
+
+static int max98088_probe(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ int ret = 0;
+
+ codec->cache_sync = 1;
+ memcpy(codec->reg_cache, max98088_reg, sizeof(max98088_reg));
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ /* initalize private data */
+
+ max98088->sysclk = (unsigned)-1;
+
+ cdata = &max98088->dai[0];
+ cdata->rate = (unsigned)-1;
+ cdata->fmt = (unsigned)-1;
+ cdata->eq_textcnt = 0;
+ cdata->eq_sel = 0;
+
+ cdata = &max98088->dai[1];
+ cdata->rate = (unsigned)-1;
+ cdata->fmt = (unsigned)-1;
+ cdata->eq_textcnt = 0;
+ cdata->eq_sel = 0;
+
+ max98088->power_state = 0; /* INA INB power enable state */
+ max98088->ex_mode = 0; /* excursion limiter mode */
+ max98088->digmic = 0; /* 0=analog, 1=digital */
+ max98088->mic1pre = 0;
+ max98088->mic2pre = 0;
+
+ ret = snd_soc_read(codec, M98088_REG_FF_REV_ID);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read device revision: %d\n",
+ ret);
+ goto err_access;
+ }
+ dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+ snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
+
+ /* initialize registers cache to hardware default */
+ max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
+
+ snd_soc_write(codec, M98088_REG_22_MIX_DAC,
+ M98088_DAI1L_TO_DACL|M98088_DAI2L_TO_DACL|
+ M98088_DAI1R_TO_DACR|M98088_DAI2R_TO_DACR);
+
+ snd_soc_write(codec, M98088_REG_4E_BIAS_CNTL, 0xF0);
+ snd_soc_write(codec, M98088_REG_50_DAC_BIAS2, 0x0F);
+
+ snd_soc_write(codec, M98088_REG_16_DAI1_IOCFG,
+ M98088_S1NORMAL|M98088_SDATA);
+
+ snd_soc_write(codec, M98088_REG_1E_DAI2_IOCFG,
+ M98088_S2NORMAL|M98088_SDATA);
+
+ max98088_handle_pdata(codec);
+
+ max98088_add_widgets(codec);
+
+err_access:
+ return ret;
+}
+
+static int max98088_remove(struct snd_soc_codec *codec)
+{
+ if (codec->control_data)
+ max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
+ .probe = max98088_probe,
+ .remove = max98088_remove,
+ .suspend = max98088_suspend,
+ .resume = max98088_resume,
+ .set_bias_level = max98088_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(max98088_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = max98088_reg,
+ .volatile_register = max98088_volatile_register,
+};
+
+static int max98088_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct max98088_priv *max98088;
+ int ret;
+
+ max98088 = kzalloc(sizeof(struct max98088_priv), GFP_KERNEL);
+ if (max98088 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, max98088);
+ max98088->control_data = i2c;
+ max98088->pdata = i2c->dev.platform_data;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_max98088, &max98088_dai[0], 2);
+ if (ret < 0)
+ kfree(max98088);
+ return ret;
+}
+
+static int max98088_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id max98088_i2c_id[] = {
+ { "max98088", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
+
+static struct i2c_driver max98088_i2c_driver = {
+ .driver = {
+ .name = "max98088-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = max98088_i2c_probe,
+ .remove = __devexit_p(max98088_i2c_remove),
+ .id_table = max98088_i2c_id,
+};
+
+static int __init max98088_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&max98088_i2c_driver);
+ if (ret)
+ pr_err("Failed to register max98088 I2C driver: %d\n", ret);
+
+ return ret;
+}
+
+static void __exit max98088_exit(void)
+{
+ i2c_del_driver(&max98088_i2c_driver);
+}
+
+module_init(max98088_init);
+module_exit(max98088_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");
+MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
new file mode 100644
index 0000000..9e9d8da
--- /dev/null
+++ b/sound/soc/codecs/max98088.h
@@ -0,0 +1,190 @@
+/*
+ * max98088.h -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98088_H
+#define _MAX98088_H
+
+/*
+ * MAX98088 Registers Definition
+ */
+#define M98088_REG_00_IRQ_STATUS 0x00
+#define M98088_REG_01_MIC_STATUS 0x01
+#define M98088_REG_02_JACK_STAUS 0x02
+#define M98088_REG_03_BATTERY_VOLTAGE 0x03
+#define M98088_REG_0F_IRQ_ENABLE 0x0F
+#define M98088_REG_10_SYS_CLK 0x10
+#define M98088_REG_11_DAI1_CLKMODE 0x11
+#define M98088_REG_12_DAI1_CLKCFG_HI 0x12
+#define M98088_REG_13_DAI1_CLKCFG_LO 0x13
+#define M98088_REG_14_DAI1_FORMAT 0x14
+#define M98088_REG_15_DAI1_CLOCK 0x15
+#define M98088_REG_16_DAI1_IOCFG 0x16
+#define M98088_REG_17_DAI1_TDM 0x17
+#define M98088_REG_18_DAI1_FILTERS 0x18
+#define M98088_REG_19_DAI2_CLKMODE 0x19
+#define M98088_REG_1A_DAI2_CLKCFG_HI 0x1A
+#define M98088_REG_1B_DAI2_CLKCFG_LO 0x1B
+#define M98088_REG_1C_DAI2_FORMAT 0x1C
+#define M98088_REG_1D_DAI2_CLOCK 0x1D
+#define M98088_REG_1E_DAI2_IOCFG 0x1E
+#define M98088_REG_1F_DAI2_TDM 0x1F
+#define M98088_REG_20_DAI2_FILTERS 0x20
+#define M98088_REG_21_SRC 0x21
+#define M98088_REG_22_MIX_DAC 0x22
+#define M98088_REG_23_MIX_ADC_LEFT 0x23
+#define M98088_REG_24_MIX_ADC_RIGHT 0x24
+#define M98088_REG_25_MIX_HP_LEFT 0x25
+#define M98088_REG_26_MIX_HP_RIGHT 0x26
+#define M98088_REG_27_MIX_HP_CNTL 0x27
+#define M98088_REG_28_MIX_REC_LEFT 0x28
+#define M98088_REG_29_MIX_REC_RIGHT 0x29
+#define M98088_REG_2A_MIC_REC_CNTL 0x2A
+#define M98088_REG_2B_MIX_SPK_LEFT 0x2B
+#define M98088_REG_2C_MIX_SPK_RIGHT 0x2C
+#define M98088_REG_2D_MIX_SPK_CNTL 0x2D
+#define M98088_REG_2E_LVL_SIDETONE 0x2E
+#define M98088_REG_2F_LVL_DAI1_PLAY 0x2F
+#define M98088_REG_30_LVL_DAI1_PLAY_EQ 0x30
+#define M98088_REG_31_LVL_DAI2_PLAY 0x31
+#define M98088_REG_32_LVL_DAI2_PLAY_EQ 0x32
+#define M98088_REG_33_LVL_ADC_L 0x33
+#define M98088_REG_34_LVL_ADC_R 0x34
+#define M98088_REG_35_LVL_MIC1 0x35
+#define M98088_REG_36_LVL_MIC2 0x36
+#define M98088_REG_37_LVL_INA 0x37
+#define M98088_REG_38_LVL_INB 0x38
+#define M98088_REG_39_LVL_HP_L 0x39
+#define M98088_REG_3A_LVL_HP_R 0x3A
+#define M98088_REG_3B_LVL_REC_L 0x3B
+#define M98088_REG_3C_LVL_REC_R 0x3C
+#define M98088_REG_3D_LVL_SPK_L 0x3D
+#define M98088_REG_3E_LVL_SPK_R 0x3E
+#define M98088_REG_3F_MICAGC_CFG 0x3F
+#define M98088_REG_40_MICAGC_THRESH 0x40
+#define M98088_REG_41_SPKDHP 0x41
+#define M98088_REG_42_SPKDHP_THRESH 0x42
+#define M98088_REG_43_SPKALC_COMP 0x43
+#define M98088_REG_44_PWRLMT_CFG 0x44
+#define M98088_REG_45_PWRLMT_TIME 0x45
+#define M98088_REG_46_THDLMT_CFG 0x46
+#define M98088_REG_47_CFG_AUDIO_IN 0x47
+#define M98088_REG_48_CFG_MIC 0x48
+#define M98088_REG_49_CFG_LEVEL 0x49
+#define M98088_REG_4A_CFG_BYPASS 0x4A
+#define M98088_REG_4B_CFG_JACKDET 0x4B
+#define M98088_REG_4C_PWR_EN_IN 0x4C
+#define M98088_REG_4D_PWR_EN_OUT 0x4D
+#define M98088_REG_4E_BIAS_CNTL 0x4E
+#define M98088_REG_4F_DAC_BIAS1 0x4F
+#define M98088_REG_50_DAC_BIAS2 0x50
+#define M98088_REG_51_PWR_SYS 0x51
+#define M98088_REG_52_DAI1_EQ_BASE 0x52
+#define M98088_REG_84_DAI2_EQ_BASE 0x84
+#define M98088_REG_B6_DAI1_BIQUAD_BASE 0xB6
+#define M98088_REG_C0_DAI2_BIQUAD_BASE 0xC0
+#define M98088_REG_FF_REV_ID 0xFF
+
+#define M98088_REG_CNT (0xFF+1)
+
+/* MAX98088 Registers Bit Fields */
+
+/* M98088_REG_14_DAI1_FORMAT, M98088_REG_1C_DAI2_FORMAT */
+ #define M98088_DAI_MAS (1<<7)
+ #define M98088_DAI_WCI (1<<6)
+ #define M98088_DAI_BCI (1<<5)
+ #define M98088_DAI_DLY (1<<4)
+ #define M98088_DAI_TDM (1<<2)
+ #define M98088_DAI_FSW (1<<1)
+ #define M98088_DAI_WS (1<<0)
+
+/* M98088_REG_15_DAI1_CLOCK, M98088_REG_1D_DAI2_CLOCK */
+ #define M98088_DAI_BSEL64 (1<<0)
+ #define M98088_DAI_OSR64 (1<<6)
+
+/* M98088_REG_16_DAI1_IOCFG, M98088_REG_1E_DAI2_IOCFG */
+ #define M98088_S1NORMAL (1<<6)
+ #define M98088_S2NORMAL (2<<6)
+ #define M98088_SDATA (3<<0)
+
+/* M98088_REG_18_DAI1_FILTERS, M98088_REG_20_DAI2_FILTERS */
+ #define M98088_DAI_DHF (1<<3)
+
+/* M98088_REG_22_MIX_DAC */
+ #define M98088_DAI1L_TO_DACL (1<<7)
+ #define M98088_DAI1R_TO_DACL (1<<6)
+ #define M98088_DAI2L_TO_DACL (1<<5)
+ #define M98088_DAI2R_TO_DACL (1<<4)
+ #define M98088_DAI1L_TO_DACR (1<<3)
+ #define M98088_DAI1R_TO_DACR (1<<2)
+ #define M98088_DAI2L_TO_DACR (1<<1)
+ #define M98088_DAI2R_TO_DACR (1<<0)
+
+/* M98088_REG_2A_MIC_REC_CNTL */
+ #define M98088_REC_LINEMODE (1<<7)
+ #define M98088_REC_LINEMODE_MASK (1<<7)
+
+/* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
+ #define M98088_MICPRE_MASK (3<<5)
+ #define M98088_MICPRE_SHIFT 5
+
+/* M98088_REG_3A_LVL_HP_R */
+ #define M98088_HP_MUTE (1<<7)
+
+/* M98088_REG_3C_LVL_REC_R */
+ #define M98088_REC_MUTE (1<<7)
+
+/* M98088_REG_3E_LVL_SPK_R */
+ #define M98088_SP_MUTE (1<<7)
+
+/* M98088_REG_48_CFG_MIC */
+ #define M98088_EXTMIC_MASK (3<<0)
+ #define M98088_DIGMIC_L (1<<5)
+ #define M98088_DIGMIC_R (1<<4)
+
+/* M98088_REG_49_CFG_LEVEL */
+ #define M98088_VSEN (1<<6)
+ #define M98088_ZDEN (1<<5)
+ #define M98088_EQ2EN (1<<1)
+ #define M98088_EQ1EN (1<<0)
+
+/* M98088_REG_4C_PWR_EN_IN */
+ #define M98088_INAEN (1<<7)
+ #define M98088_INBEN (1<<6)
+ #define M98088_MBEN (1<<3)
+ #define M98088_ADLEN (1<<1)
+ #define M98088_ADREN (1<<0)
+
+/* M98088_REG_4D_PWR_EN_OUT */
+ #define M98088_HPLEN (1<<7)
+ #define M98088_HPREN (1<<6)
+ #define M98088_HPEN ((1<<7)|(1<<6))
+ #define M98088_SPLEN (1<<5)
+ #define M98088_SPREN (1<<4)
+ #define M98088_RECEN (1<<3)
+ #define M98088_DALEN (1<<1)
+ #define M98088_DAREN (1<<0)
+
+/* M98088_REG_51_PWR_SYS */
+ #define M98088_SHDNRUN (1<<7)
+ #define M98088_PERFMODE (1<<3)
+ #define M98088_HPPLYBACK (1<<2)
+ #define M98088_PWRSV8K (1<<1)
+ #define M98088_PWRSV (1<<0)
+
+#define M98088_COEFS_PER_BAND 5
+
+#define M98088_BYTE1(w) ((w >> 8) & 0xff)
+#define M98088_BYTE0(w) (w & 0xff)
+
+struct max98088_setup_data {
+ unsigned short i2c_address;
+};
+
+#endif
--
1.6.3.3
6
43
Cem ERGEN wrote:
> fist 3 soundcards of each hub works .. but 4 soundcards of each hub aren't
> work same time
Looks like a bandwidth issue.
You still didn't tell what sample format these devices are using.
Regards,
Clemens
1
0
Re: [alsa-devel] [PATCH 1/7] [RFC] OMAP: MCBSP: hwmod database for 2xxx devices
by Varadarajan, Charulatha 15 Oct '10
by Varadarajan, Charulatha 15 Oct '10
15 Oct '10
> -----Original Message-----
> From: ABRAHAM, KISHON VIJAY
> Sent: Tuesday, October 05, 2010 10:08 PM
> To: linux-omap(a)vger.kernel.org
> Cc: Kamat, Nishant; Varadarajan, Charulatha; ABRAHAM, KISHON
> VIJAY; Datta, Shubhrajyoti; Basak, Partha
> Subject: [PATCH 1/7] [RFC] OMAP: MCBSP: hwmod database for
> 2xxx devices
>
This patch series is targeted to implement mcbsp driver in
hwmod way and to make use of pm_runtime APIs.
This patch series is tested on OMAP3 & 4 and yet to be tested
on OMAP2.
There are few clarifications required so that the next patch series
can be implemented after aligning.
1. Audio layer is making use of mcbsp and it's dma base addresses and
is closely coupled with omap-mcbsp.
This can be handled either by
a. providing an API with which Audio layer can get these addresses.
(or)
b. move the plat-omap/mcbsp.c and mach-omap2/mcbsp.c to sound/soc/omap/
[1]
Option (a) would only be a workaround to handle the situation. As
audio is the only user for mcbsp, option (b) is better. If option(b)
is agreed upon, the same can be addressed on top of the mcbsp hwmod
series.
2. Sidetone feature is available only in OMAP3 (McBSP2&3) which has
different base address and sys configs compared to it's mcbsp port.
Hence the mcbsp is considered as a single device with two hwmods
for McBSP2&3 devices in OMAP3.
3. Autoidle needs to be disabled for sidetone before enabling the sidetone
feature. There was a design proposed by Kishon [2] to add an API in hwmod
to modify the autoidle bit but was not agreed upon. How do we handle this
situation where the device has to disable or enable the autoidle bit at
runtime?
[1] https://patchwork.kernel.org/patch/225582/
[2] https://patchwork.kernel.org/patch/134371/
We would resend the same patch series by including alsa mailing list
(alsa-devel(a)alsa-project.org)
<<snip>>
6
9
[alsa-devel] Need expert's advice - Fast Track Ultra (8R) dropping samples
by Felix Homann 15 Oct '10
by Felix Homann 15 Oct '10
15 Oct '10
Hi,
in that past months I've been trying get the Fast Track Ultra devices
working properly in Alsa. We've had lots of progress, most of the code
has moved to Alsa git and today I've even posted a patch for getting
mixer support for these devices.
Now, I need to get some expert's advice: The devices seem to drop
samples or frames. Here's a report I've got today on the M-Audio forum:
"I've got a subtle problem to report: I think audio playback is dropping
sample frames. To hear the problem, open Audacity at 48 kHz and play
a 10-kHz. sine wave. When I do that I hear a regular clicking sound, about
four clicks a second. I've tried recording the output and if I'm seeing
correctly,
exactly one sample frame in every 13312 (13x1024) is being dropped on
output.
I don't see anything similar on input. When either jack or Pd has both
the input and
the output open, the delay from input to output gradually decreases
until it forces
occasional sync errors. (I haven't tried this with audacity though.)"
(see
http://forums.m-audio.com/showthread.php?714-Not-a-problem.-FastTrack-on-li…)
I could reproduce it on my machines, even at 44.1 kHz. The clicking
sound is very subtle, it goes unnoticed when not listening to pure sines
without attention to clicks.
How can this be sorted out. Any ideas?
Kind regards,
Felix
4
23
15 Oct '10
2S SSP device on Intel MID Platforms
Signed-off-by: Louis LE GALL <louis.le.gall(a)intel.com>
Change-Id: I17052a3b464c5682d2ab17a9b6e0fad30137243f
Signed-off-by: Louis LE GALL <louis.le.gall(a)intel.com>
---
include/linux/intel_mid_i2s_if.h | 280 ++++++
sound/pci/Kconfig | 18 +
sound/pci/Makefile | 4 +-
sound/pci/intel_mid_i2s/Makefile | 18 +
sound/pci/intel_mid_i2s/intel_mid_i2s.c | 1428 +++++++++++++++++++++++++++=
++++
sound/pci/intel_mid_i2s/intel_mid_i2s.h | 500 +++++++++++
6 files changed, 2247 insertions(+), 1 deletions(-)
create mode 100644 include/linux/intel_mid_i2s_if.h
create mode 100644 sound/pci/intel_mid_i2s/Makefile
create mode 100644 sound/pci/intel_mid_i2s/intel_mid_i2s.c
create mode 100644 sound/pci/intel_mid_i2s/intel_mid_i2s.h
diff --git a/include/linux/intel_mid_i2s_if.h b/include/linux/intel_mid_i2s=
_if.h
new file mode 100644
index 0000000..1563577
--- /dev/null
+++ b/include/linux/intel_mid_i2s_if.h
@@ -0,0 +1,280 @@
+/*
+ * <Driver for I2S protocol on SSP (Moorestown and Medfield hardware)>
+ * Copyright (c) 2010, Intel Corporation.
+ * Louis LE GALL <louis.le.gall intel.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License =
for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License alon=
g with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MID_I2S_EXTERNAL_H_
+#define MID_I2S_EXTERNAL_H_
+
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/intel_mid_dma.h>
+
+#include <linux/interrupt.h>
+
+/*
+ * Structures Definition
+ */
+
+
+/*
+ * SSCR0 settings
+ */
+enum mrst_ssp_mode {
+ SSP_IN_NORMAL_MODE =3D 0x0,
+ SSP_IN_NETWORK_MODE
+};
+
+enum mrst_ssp_rx_fifo_over_run_int_mask {
+ SSP_RX_FIFO_OVER_INT_ENABLE =3D 0x0,
+ SSP_RX_FIFO_OVER_INT_DISABLE
+};
+
+enum mrst_ssp_tx_fifo_under_run_int_mask {
+ SSP_TX_FIFO_UNDER_INT_ENABLE =3D 0x0,
+ SSP_TX_FIFO_UNDER_INT_DISABLE
+};
+
+enum mrst_ssp_frame_format {
+ MOTOROLA_SPI_FORMAT =3D 0x0,
+ TI_SSP_FORMAT,
+ MICROWIRE_FORMAT,
+ PSP_FORMAT
+
+};
+
+enum mrst_ssp_master_mode_clock_selection {
+ SSP_ONCHIP_CLOCK =3D 0x0,
+ SSP_NETWORK_CLOCK,
+ SSP_EXTERNAL_CLOCK,
+ SSP_ONCHIP_AUDIO_CLOCK,
+ SSP_MASTER_CLOCK_UNDEFINED =3D 0xFF
+};
+
+/*
+ * SSCR1 settings
+ */
+enum mrst_ssp_txd_tristate_last_phase {
+ TXD_TRISTATE_LAST_PHASE_OFF =3D 0x0,
+ TXD_TRISTATE_LAST_PHASE_ON
+};
+
+enum mrst_ssp_txd_tristate_enable {
+ TXD_TRISTATE_OFF =3D 0x0,
+ TXD_TRISTATE_ON
+};
+
+enum mrst_ssp_slave_sspclk_free_running {
+ SLAVE_SSPCLK_ON_ALWAYS =3D 0x0,
+ SLAVE_SSPCLK_ON_DURING_TRANSFER_ONLY
+};
+
+enum mrst_ssp_sspsclk_direction {
+ SSPSCLK_MASTER_MODE =3D 0x0,
+ SSPSCLK_SLAVE_MODE
+};
+
+enum mrst_ssp_sspsfrm_direction {
+ SSPSFRM_MASTER_MODE =3D 0x0,
+ SSPSFRM_SLAVE_MODE
+};
+
+enum mrst_ssp_rx_without_tx {
+ RX_AND_TX_MODE =3D 0x0,
+ RX_WITHOUT_TX_MODE
+};
+
+enum mrst_trailing_byte_mode {
+ SSP_TRAILING_BYTE_HDL_BY_IA =3D 0x0,
+ SSP_TRAILING_BYTE_HDL_BY_DMA
+};
+
+enum mrst_ssp_tx_dma_status {
+ SSP_TX_DMA_MASK =3D 0x0,
+ SSP_TX_DMA_ENABLE
+};
+
+enum mrst_ssp_rx_dma_status {
+ SSP_RX_DMA_MASK =3D 0x0,
+ SSP_RX_DMA_ENABLE
+};
+
+enum mrst_ssp_rx_timeout_int_status {
+ SSP_RX_TIMEOUT_INT_DISABLE =3D 0x0,
+ SSP_RX_TIMEOUT_INT_ENABLE
+};
+
+enum mrst_ssp_trailing_byte_int_status {
+ SSP_TRAILING_BYTE_INT_DISABLE =3D 0x0,
+ SSP_TRAILING_BYTE_INT_ENABLE
+};
+
+enum mrst_ssp_loopback_mode_status {
+ SSP_LOOPBACK_OFF =3D 0x0,
+ SSP_LOOPBACK_ON
+};
+
+
+/*
+ * SSPSP settings: for PSP Format ONLY!!!!!!!!
+ */
+
+enum mrst_ssp_frame_sync_relative_timing_bit {
+ NEXT_FRMS_ASS_AFTER_END_OF_T4 =3D 0x0,
+ NEXT_FRMS_ASS_WITH_LSB_PREVIOUS_FRM
+};
+
+enum mrst_ssp_frame_sync_polarity_bit {
+ SSP_FRMS_ACTIVE_LOW =3D 0x0,
+ SSP_FRMS_ACTIVE_HIGH
+};
+
+enum mrst_ssp_end_of_transfer_data_state {
+ SSP_END_DATA_TRANSFER_STATE_LOW =3D 0x0,
+ SSP_END_DATA_TRANSFER_STATE_PEVIOUS_BIT
+};
+
+enum mrst_ssp_clk_mode {
+ SSP_CLK_MODE_0 =3D 0x0,
+ SSP_CLK_MODE_1,
+ SSP_CLK_MODE_2,
+ SSP_CLK_MODE_3
+};
+
+
+/*
+ * list of differents types of SSP, value depends of adid entry of
+ * capability ID of the PCI
+ */
+
+/*
+ *
+ * The PCI header associated to SSP devices now includes a configuration
+ * register. It provides information to a driver which is probed for the
+ * SSP, specifying in which way the SSP is supposed to be used. Here is
+ * the format of this byte register:
+ *
+ * bits 2..0: Mode
+ * 000=3D0x0 : Invalid, the register should be ignored
+ * 001=3D0x1 : SSP to be used as SPI controller
+ * 010=3D0x2: SSP to be used in I2S/ISS mode
+ * other: Reserved
+ *
+ * bits 5..3: Configuration
+ * In I2S/ISS mode:
+ * 000=3D0x0: Invalid
+ * 001=3D0x1: Bluetooth
+ * 010=3D0x2: Modem
+ * other: Reserved
+ * In SPI mode:
+ * Value is the SPI bus number connected to the SSP.
+ * To be used for registration to the Linux SPI
+ * framework.
+ * bit 6: SPI slave
+ * Relevant in SPI mode only. If set, indicates the SPI clock
+ * is not provided by the SSP: SPI slave mode.
+ *
+ * bit 7: Reserved (0)
+ *
+ * This configuration register is implemented in the adid field of the
+ * Vendor Specific PCI capability associated to the SSP.
+ *
+ */
+
+#define PCI_ADID_SSP_MODE_SPI (1)
+#define PCI_ADID_SSP_MODE_I2S (2)
+
+#define PCI_ADID_SSP_CONF_BT_FM (1<<3)
+#define PCI_ADID_SSP_CONF_MODEM (2<<3)
+
+
+#define PCI_CAP_ADID_I2S_BT_FM ((PCI_ADID_SSP_CONF_BT_FM) | (PCI_ADID_SSP=
_MODE_I2S))
+#define PCI_CAP_ADID_I2S_MODEM ((PCI_ADID_SSP_CONF_MODEM) | (PCI_ADID_SSP=
_MODE_I2S))
+
+enum intel_mid_i2s_ssp_usage {
+ SSP_USAGE_UNASSIGNED =3D 0x00,
+ SSP_USAGE_BLUETOOTH_FM =3D 0x01,
+ SSP_USAGE_MODEM =3D 0x02
+};
+
+/*
+ * Structure used to configure the SSP Port
+ * Please note that only the PSP format and the DMA transfer are suppo=
rted
+ */
+
+struct intel_mid_i2s_settings {
+ enum mrst_ssp_mode mode;
+ enum mrst_ssp_rx_fifo_over_run_int_mask rx_fifo_interrupt;
+ enum mrst_ssp_tx_fifo_under_run_int_mask tx_fifo_interrupt;
+ enum mrst_ssp_frame_format frame_format;
+ enum mrst_ssp_master_mode_clock_selection master_mode_clk_selectio=
n; /* for Master Mode Only */
+ u8 frame_rate_divider_contr=
ol;
+ u16 master_mode_serial_clock=
_rate; /* for Master Mode Only */
+ u16 data_size;
+
+ enum mrst_ssp_txd_tristate_last_phase tx_tristate_phase;
+ enum mrst_ssp_txd_tristate_enable tx_tristate_enable;
+ enum mrst_ssp_slave_sspclk_free_running slave_clk_free_running_s=
tatus;
+ enum mrst_ssp_sspsclk_direction sspslclk_direction;
+ enum mrst_ssp_sspsfrm_direction sspsfrm_direction;
+ enum mrst_ssp_rx_without_tx ssp_duplex_mode;
+ enum mrst_trailing_byte_mode ssp_trailing_byte_mode;
+ enum mrst_ssp_tx_dma_status ssp_tx_dma;
+ enum mrst_ssp_rx_dma_status ssp_rx_dma;
+ enum mrst_ssp_rx_timeout_int_status ssp_rx_timeout_interrupt=
_status;
+ enum mrst_ssp_trailing_byte_int_status ssp_trailing_byte_interr=
upt_status;
+ enum mrst_ssp_loopback_mode_status ssp_loopback_mode_status;
+ u8 ssp_rx_fifo_threshold;
+ u8 ssp_tx_fifo_threshold;
+
+
+ enum mrst_ssp_frame_sync_relative_timing_bit ssp_frmsync_timing_bi=
t;
+ enum mrst_ssp_frame_sync_polarity_bit ssp_frmsync_pol_bit;
+ enum mrst_ssp_end_of_transfer_data_state ssp_end_transfer_state;
+ enum mrst_ssp_clk_mode ssp_serial_clk_mode;
+ u8 ssp_psp_T1;
+ u8 ssp_psp_T2;
+ u8 ssp_psp_T4; /* DMYSTOP=
*/
+ u8 ssp_psp_T5; /* SFRMDLY=
*/
+ u8 ssp_psp_T6; /* SFRMWDT=
H */
+
+ u8 ssp_active_tx_slots_map;
+ u8 ssp_active_rx_slots_map;
+};
+
+/*
+ * Provided Interface
+ */
+
+
+struct intel_mid_i2s_hdl *intel_mid_i2s_open(enum intel_mid_i2s_ssp_usage =
usage, const struct intel_mid_i2s_settings *ps_settings);
+void intel_mid_i2s_close(struct intel_mid_i2s_hdl *handle);
+
+int intel_mid_i2s_rd_req(struct intel_mid_i2s_hdl *handle, u32 *dst, size_=
t len, void *param);
+int intel_mid_i2s_wr_req(struct intel_mid_i2s_hdl *handle, u32 *src, size_=
t len, void *param);
+int intel_mid_i2s_enable_ssp(struct intel_mid_i2s_hdl *handle);
+
+
+int intel_mid_i2s_set_wr_cb(struct intel_mid_i2s_hdl *handle, int (*write_=
callback)(void *param));
+int intel_mid_i2s_set_rd_cb(struct intel_mid_i2s_hdl *handle, int (*read_c=
allback)(void *param));
+
+
+int intel_mid_i2s_get_tx_fifo_level(struct intel_mid_i2s_hdl *handle);
+int intel_mid_i2s_get_rx_fifo_level(struct intel_mid_i2s_hdl *handle);
+int intel_mid_i2s_flush(struct intel_mid_i2s_hdl *handle);
+
+#endif /*MID_I2S_EXTERNAL_H_*/
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 12e3465..0b0a524 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -853,4 +853,22 @@ config SND_YMFPCI
To compile this driver as a module, choose M here: the module
will be called snd-ymfpci.
+config SND_INTEL_MID_I2S
+ tristate "Intel mid I2S hardware driver"
+ depends on EXPERIMENTAL && PCI && INTEL_MID_DMAC
+ default n
+ help
+ Say Y here if you want to build low level driver to support
+ sending/receving I2S audio samples on Intel MID SSP device.
+ This interface is mostly used on Intel MID platforms and provide
+ the low level interface for some upper layer drivers such as
+ Alsa SoC, char device interfaces... depending of peripheral conne=
cted.
+ PCI Header should have ADID field set to I2S BT_FM or
+ I2S MODEM to be used by this driver (so it know connected periphe=
ral).
+ Note this is a prototype driver and support for continuous
+ flow is still working-in-progress.
+ This driver can also be built as a module. If so, the module
+ will be called intel_mid_i2s.ko
+ If unsure, say N here.
+
endif # SND_PCI
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index 9cf4348..46613a2 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -78,4 +78,6 @@ obj-$(CONFIG_SND) +=3D \
rme9652/ \
trident/ \
ymfpci/ \
- vx222/
+ vx222/ \
+ intel_mid_i2s/
+
diff --git a/sound/pci/intel_mid_i2s/Makefile b/sound/pci/intel_mid_i2s/Mak=
efile
new file mode 100644
index 0000000..bebac1c
--- /dev/null
+++ b/sound/pci/intel_mid_i2s/Makefile
@@ -0,0 +1,18 @@
+# SSP audio driver
+# Copyright (c) 2010, Intel Corporation.
+
+# 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.
+
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+
+# You should have received a copy of the GNU General Public License along =
with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+obj-$(CONFIG_SND_INTEL_MID_I2S) +=3D intel_mid_i2s.o
+
diff --git a/sound/pci/intel_mid_i2s/intel_mid_i2s.c b/sound/pci/intel_mid_=
i2s/intel_mid_i2s.c
new file mode 100644
index 0000000..572abde
--- /dev/null
+++ b/sound/pci/intel_mid_i2s/intel_mid_i2s.c
@@ -0,0 +1,1428 @@
+/*
+ * <Driver for I2S protocol on SSP (Moorestown and Medfield hardware)>
+ * Copyright (c) 2010, Intel Corporation.
+ * Louis LE GALL <louis.le.gall intel.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without evenp the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License =
for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License alon=
g with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/pci_regs.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <linux/device.h>
+
+#include <linux/intel_mid_i2s_if.h>
+#include "intel_mid_i2s.h"
+
+MODULE_AUTHOR("Louis LE GALL <louis.le.gall intel.com>");
+MODULE_DESCRIPTION("Intel MID I2S/PCM SSP Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
+
+
+/*
+ * structures for pci probing
+ */
+static const struct dev_pm_ops intel_mid_i2s_pm_ops =3D {
+ .runtime_suspend =3D intel_mid_i2s_runtime_suspend,
+ .runtime_resume =3D intel_mid_i2s_runtime_resume,
+};
+static DEFINE_PCI_DEVICE_TABLE(pci_ids) =3D {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, MFLD_SSP1_DEVICE_ID) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, MFLD_SSP0_DEVICE_ID) },
+ { 0, }, /* terminate list */
+};
+static struct pci_driver intel_mid_i2s_driver =3D {
+ .driver =3D {
+ .pm =3D &intel_mid_i2s_pm_ops,
+ },
+ .name =3D DRIVER_NAME,
+ .id_table =3D pci_ids,
+ .probe =3D intel_mid_i2s_probe,
+ .remove =3D __devexit_p(intel_mid_i2s_remove),
+#ifdef CONFIG_PM
+ .suspend =3D intel_mid_i2s_driver_suspend,
+ .resume =3D intel_mid_i2s_driver_resume,
+#endif
+};
+
+
+/*
+ * POWER MANAGEMENT FUNCTIONS
+ */
+
+#ifdef CONFIG_PM
+/**
+ * intel_mid_i2s_driver_suspend - driver power management suspend activity
+ * @device_ptr : pointer of the device to resume
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+static int intel_mid_i2s_driver_suspend(struct pci_dev *dev, pm_message_t=
state)
+{
+ struct intel_mid_i2s_hdl *drv_data =3D pci_get_drvdata(dev);
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return 0;
+ dev_dbg(&drv_data->pdev->dev, "SUSPEND SSP ID %d\n", drv_data->pdev=
->device);
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, PCI_D3hot);
+ return 0;
+}
+
+/**
+ * intel_mid_i2s_driver_resume - driver power management suspend activity
+ * @device_ptr : pointer of the device to resume
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+static int intel_mid_i2s_driver_resume(struct pci_dev *dev)
+{
+ int err;
+ int ret =3D 0;
+ struct intel_mid_i2s_hdl *drv_data =3D pci_get_drvdata(dev);
+
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ dev_dbg(&drv_data->pdev->dev, "RESUME SSP ID %d\n", drv_data->pdev-=
>device);
+
+ err =3D pci_enable_device(dev);
+ if (err)
+ dev_err(&drv_data->pdev->dev, "Unable to re-enable device, =
trying to continue.\n");
+ dev_dbg(&drv_data->pdev->dev, "resuming\n");
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+ ret =3D pci_enable_device(dev);
+ if (ret)
+ dev_err(&drv_data->pdev->dev, "I2S: device can't be enabled=
");
+ dev_dbg(&drv_data->pdev->dev, "resumed in D3\n");
+ return ret;
+}
+
+/**
+ * intel_mid_i2s_runtime_suspend - runtime power management suspend activi=
ty
+ * @device_ptr : pointer of the device to resume
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+static int intel_mid_i2s_runtime_suspend(struct device *device_ptr)
+{
+ struct pci_dev *pdev;
+ struct intel_mid_i2s_hdl *drv_data;
+ void __iomem *reg;
+
+ pdev =3D to_pci_dev(device_ptr);
+ WARN(!pdev, "Pci dev=3DNULL\n");
+ if (!pdev)
+ return -EFAULT;
+ drv_data =3D (struct intel_mid_i2s_hdl *) pci_get_drvdata(pdev);
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ if (test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_err(device_ptr, "Trying to suspend a device that is ope=
ned\n");
+ return -ENODEV;
+ }
+ reg =3D drv_data->ioaddr;
+ dev_dbg(&drv_data->pdev->dev, "Suspend of SSP requested !!\n");
+ return intel_mid_i2s_driver_suspend(to_pci_dev(device_ptr), PMSG_SU=
SPEND);
+}
+#endif
+
+/**
+ * intel_mid_i2s_runtime_resume - runtime power management resume activity
+ * @device_ptr : pointer of the device to resume
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+static int intel_mid_i2s_runtime_resume(struct device *device_ptr)
+{
+ struct pci_dev *pdev;
+ struct intel_mid_i2s_hdl *drv_data;
+ pdev =3D to_pci_dev(device_ptr);
+ WARN(!pdev, "Pci dev=3DNULL\n");
+ if (!pdev)
+ return -EFAULT;
+ drv_data =3D (struct intel_mid_i2s_hdl *) pci_get_drvdata(pdev);
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ dev_dbg(&drv_data->pdev->dev, "RT RESUME SSP ID\n");
+ return intel_mid_i2s_driver_resume(to_pci_dev(device_ptr));
+}
+
+/*
+ * INTERFACE FUNCTIONS
+ */
+
+/**
+ * intel_mid_i2s_flush - This is the I2S flush request
+ * @drv_data : pointer on private i2s driver data (by i2s_open function)
+ *
+ * It will flush the TX FIFO
+ * WARNING: this function is used in a Burst Mode context where it is call=
ed
+ * between Bursts i.e. when there is no FMSYNC, no transfer ongoing at
+ * that time
+ * If you need a flush while SSP configured in I2S is BUSY and FMSYNC are
+ * generated, you have to write another function
+ * (loop on BUSY bit and do not limit the flush to at most 16 samples)
+ *
+ * Output parameters
+ * int : number of samples flushed
+ */
+int intel_mid_i2s_flush(struct intel_mid_i2s_hdl *drv_data)
+{
+ u32 sssr, data;
+ u32 num =3D 0;
+ void __iomem *reg;
+
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return 0;
+ reg =3D drv_data->ioaddr;
+ sssr =3D read_SSSR(reg);
+ dev_dbg(&drv_data->pdev->dev, "in flush sssr=3D0x%08X\n", sssr);
+ /*
+ * Flush "by hand" was generating spurious DMA SERV REQUEST
+ * from SSP to DMA =3D> then buggy retrieval of data for next dma_r=
eq
+ * Disable: RX Service Request from RX fifo to DMA
+ * as we will flush by hand
+ */
+ clear_SSCR1_reg(reg, RSRE);
+ /* i2s_flush is called in between 2 bursts
+ * =3D> no FMSYNC at that time (i.e. SSP not busy)
+ * =3D> at most 16 samples in the FIFO */
+ while ((read_SSSR(reg) & (SSSR_RNE_MASK<<SSSR_RNE_SHIFT))
+ && (num < FIFO_SIZE)) {
+ data =3D read_SSDR(reg);
+ num++;
+ dev_warn(&drv_data->pdev->dev, "flush(%u)=3D%u\n", num, dat=
a);
+ }
+ /* Enable: RX Service Request from RX fifo to DMA
+ * as flush by hand is done
+ */
+ set_SSCR1_reg(reg, RSRE);
+ sssr =3D read_SSSR(reg);
+ dev_dbg(&drv_data->pdev->dev, "out flush sssr=3D0x%08X\n", sssr);
+ return num;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_flush);
+
+/**
+ * intel_mid_i2s_get_rx_fifo_level - returns I2S rx fifo level
+ * @drv_data : pointer on private i2s driver data (by i2s_open function)
+ *
+ * Output parameters
+ * int : Number of samples currently in the RX FIFO (negative =3D err=
or)
+ */
+int intel_mid_i2s_get_rx_fifo_level(struct intel_mid_i2s_hdl *drv_data)
+{
+ u32 sssr;
+ u32 rne, rfl;
+ void __iomem *reg;
+
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ reg =3D drv_data->ioaddr;
+ sssr =3D read_SSSR(reg);
+ rfl =3D GET_SSSR_val(sssr, RFL);
+ rne =3D GET_SSSR_val(sssr, RNE);
+ if (!rne)
+ return 0;
+ else
+ return rfl+1;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_get_rx_fifo_level);
+
+/**
+ * intel_mid_i2s_get_tx_fifo_level - returns I2S tx fifo level
+ * @drv_data : pointer on private i2s driver data (by i2s_open function)
+ *
+ * Output parameters
+ * int : number of samples currently in the TX FIFO (negative =3D err=
or)
+ */
+int intel_mid_i2s_get_tx_fifo_level(struct intel_mid_i2s_hdl *drv_data)
+{
+ u32 sssr;
+ u32 tnf, tfl;
+ void __iomem *reg;
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ reg =3D drv_data->ioaddr;
+ sssr =3D read_SSSR(reg);
+ tfl =3D GET_SSSR_val(sssr, TFL);
+ tnf =3D GET_SSSR_val(sssr, TFN);
+ if (!tnf)
+ return 16;
+ else
+ return tfl;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_get_tx_fifo_level);
+
+/**
+ * intel_mid_i2s_set_rd_cb - set the callback function after read is done
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open function)
+ * @read_callback : pointer of callback function
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+int intel_mid_i2s_set_rd_cb(struct intel_mid_i2s_hdl *drv_data, int (*read=
_callback)(void *param))
+{
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ mutex_lock(&drv_data->mutex);
+ if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "set WR CB I2S_PORT NOT_OPEN=
ED");
+ mutex_unlock(&drv_data->mutex);
+ return -EPERM;
+ }
+ /* Do not change read parameters in the middle of a READ request */
+ if (test_bit(I2S_PORT_READ_BUSY, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "CB reject I2S_PORT_READ_BUS=
Y");
+ mutex_unlock(&drv_data->mutex);
+ return -EBUSY;
+ }
+ drv_data->read_callback =3D read_callback;
+ drv_data->read_len =3D 0;
+ mutex_unlock(&drv_data->mutex);
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_set_rd_cb);
+
+/**
+ * intel_mid_i2s_set_wr_cb - set the callback function after write is done
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open functio=
n)
+ * @write_callback : pointer of callback function
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+int intel_mid_i2s_set_wr_cb(struct intel_mid_i2s_hdl *drv_data, int (*writ=
e_callback)(void *param))
+{
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ mutex_lock(&drv_data->mutex);
+ if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_warn(&drv_data->pdev->dev, "set WR CB I2S_PORT NOT_OPEN=
ED");
+ mutex_unlock(&drv_data->mutex);
+ return -EPERM;
+ }
+ /* Do not change write parameters in the middle of a WRITE request =
*/
+ if (test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags)) {
+ dev_warn(&drv_data->pdev->dev, "CB reject I2S_PORT_WRITE_BU=
SY");
+ mutex_unlock(&drv_data->mutex);
+ return -EBUSY;
+ }
+ drv_data->write_callback =3D write_callback;
+ drv_data->write_len =3D 0;
+ mutex_unlock(&drv_data->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_set_wr_cb);
+
+/**
+ * intel_mid_i2s_enable_ssp() : start the ssp right after the read/write r=
eq
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open function)
+ *
+ * This enable the read/write to be started synchronously
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+int intel_mid_i2s_enable_ssp(struct intel_mid_i2s_hdl *drv_data)
+{
+ void __iomem *reg =3D drv_data->ioaddr;
+ set_SSCR0_reg(reg, SSE);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_enable_ssp);
+
+/**
+ * intel_mid_i2s_rd_req - request a read from i2s peripheral
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open function)
+ * @dst : destination buffer where the read sample should be put
+ * @len : number of sample to be read (160 samples only right now)
+ * @param : private context parameter to give back to read callback
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+int intel_mid_i2s_rd_req(struct intel_mid_i2s_hdl *drv_data, u32 *destinat=
ion, size_t len, void *param)
+{
+ struct dma_async_tx_descriptor *rxdesc =3D NULL;
+ struct dma_chan *rxchan =3D drv_data->rxchan;
+ enum dma_ctrl_flags flag;
+ dma_addr_t ssdr_addr;
+ dma_addr_t dst;
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ mutex_lock(&drv_data->mutex);
+ if (!rxchan) {
+ dev_WARN(&(drv_data->pdev->dev), "rd_req FAILED no rxchan\n=
");
+ mutex_unlock(&drv_data->mutex);
+ return -EINVAL;
+ }
+ if (!len) {
+ dev_WARN(&drv_data->pdev->dev, "rd req invalid len=3D0");
+ mutex_unlock(&drv_data->mutex);
+ return -EINVAL;
+ }
+ if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "RD reject I2S_PORT NOT_OPEN=
ED");
+ mutex_unlock(&drv_data->mutex);
+ return -EPERM;
+ }
+ if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "RD reject I2S_PORT CLOSING"=
);
+ mutex_unlock(&drv_data->mutex);
+ return -EPIPE;
+ }
+
+ dev_dbg(&drv_data->pdev->dev, "I2S_READ() dst=3D%p, len=3D%d, drv_d=
ata=3D%p", destination, len, drv_data);
+ dst =3D dma_map_single(NULL, destination, len, DMA_FROM_DEVICE);
+ if (!dst) {
+ dev_WARN(&drv_data->pdev->dev, "can't map DMA address %p", =
destination);
+ mutex_unlock(&drv_data->mutex);
+ return -ENOMEM;
+ }
+
+ drv_data->read_dst =3D dst;
+ drv_data->read_len =3D len;
+ /* get Data Read/Write address */
+ ssdr_addr =3D (drv_data->paddr + OFFSET_SSDR);
+ set_SSCR1_reg((drv_data->ioaddr), RSRE);
+ change_SSCR0_reg((drv_data->ioaddr), RIM,
+ ((drv_data->current_settings).rx_fifo_interrupt));
+ flag =3D DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ /* Start the RX dma transfer */
+ rxdesc =3D rxchan->device->device_prep_dma_memcpy(
+ rxchan, /* DMA Channel */
+ dst, /* DAR */
+ ssdr_addr, /* SAR */
+ len, /* Data Length */
+ flag); /* Flag */
+ if (!rxdesc) {
+ dev_WARN(&drv_data->pdev->dev, "can not prep dma memcpy");
+ mutex_unlock(&drv_data->mutex);
+ return -EFAULT;
+ }
+ /* Only 1 READ at a time allowed. do it at end to avoid clear&wakeu=
p*/
+ if (test_and_set_bit(I2S_PORT_READ_BUSY, &drv_data->flags)) {
+ dma_unmap_single(NULL, dst, len, DMA_FROM_DEVICE);
+ dev_WARN(&drv_data->pdev->dev, "RD reject I2S_PORT READ_BUS=
Y");
+ mutex_unlock(&drv_data->mutex);
+ return -EBUSY;
+ }
+ dev_dbg(&(drv_data->pdev->dev), "RD dma tx submit\n");
+ rxdesc->callback =3D i2s_read_done;
+ drv_data->read_param =3D param;
+ rxdesc->callback_param =3D drv_data;
+ rxdesc->tx_submit(rxdesc);
+ mutex_unlock(&drv_data->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_rd_req);
+
+/**
+ * intel_mid_i2s_wr_req - request a write to i2s peripheral
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open function)
+ * @src : source buffer where the samples to wrote should be get
+ * @len : number of sample to be read (160 samples only right now)
+ * @param : private context parameter to give back to write callback
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+int intel_mid_i2s_wr_req(struct intel_mid_i2s_hdl *drv_data, u32 *source, =
size_t len, void *param)
+{
+ dma_addr_t ssdr_addr;
+ struct dma_async_tx_descriptor *txdesc =3D NULL;
+ struct dma_chan *txchan =3D drv_data->txchan;
+ enum dma_ctrl_flags flag;
+ dma_addr_t src;
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ mutex_lock(&drv_data->mutex);
+ if (!txchan) {
+ dev_WARN(&(drv_data->pdev->dev), "wr_req but no txchan\n");
+ mutex_unlock(&drv_data->mutex);
+ return -EINVAL;
+ }
+ if (!len) {
+ dev_WARN(&drv_data->pdev->dev, "invalid len 0");
+ mutex_unlock(&drv_data->mutex);
+ return -EINVAL;
+ }
+ if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "WR reject I2S_PORT NOT_OPEN=
ED");
+ mutex_unlock(&drv_data->mutex);
+ return -EPERM;
+ }
+ if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "WR reject I2S_PORT CLOSING"=
);
+ mutex_unlock(&drv_data->mutex);
+ return -EPIPE;
+ }
+
+ dev_dbg(&drv_data->pdev->dev, "I2S_WRITE() src=3D%p, len=3D%d, drv_=
data=3D%p", source, len, drv_data);
+
+ src =3D dma_map_single(NULL, source, len, DMA_TO_DEVICE);
+ if (!src) {
+ dev_WARN(&drv_data->pdev->dev, "can't map DMA address %p", =
source);
+ mutex_unlock(&drv_data->mutex);
+ return -EFAULT;
+ }
+ drv_data->write_src =3D src;
+ drv_data->write_len =3D len;
+ /* get Data Read/Write address */
+ ssdr_addr =3D (dma_addr_t)(u32)(drv_data->paddr + OFFSET_SSDR);
+ set_SSCR1_reg((drv_data->ioaddr), TSRE);
+ change_SSCR0_reg((drv_data->ioaddr), TIM,
+ ((drv_data->current_settings).tx_fifo_interrupt));
+ flag =3D DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ txdesc =3D txchan->device->device_prep_dma_memcpy(
+ txchan, /* DMA Channel */
+ ssdr_addr, /* DAR */
+ src, /* SAR */
+ len, /* Data Length */
+ flag); /* Flag */
+ if (!txdesc) {
+ dev_WARN(&(drv_data->pdev->dev),
+ "wr_req dma memcpy FAILED(src=3D%08x,len=3D%d,txcha=
n=3D%p)\n",
+ src, len, txchan);
+ mutex_unlock(&drv_data->mutex);
+ return -1;
+ }
+ dev_dbg(&(drv_data->pdev->dev), "WR dma tx summit\n");
+ /* Only 1 WRITE at a time allowed */
+ if (test_and_set_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags)) {
+ dma_unmap_single(NULL, src, len, DMA_TO_DEVICE);
+ dev_WARN(&drv_data->pdev->dev, "WR reject I2S_PORT WRITE_BU=
SY");
+ mutex_unlock(&drv_data->mutex);
+ return -EBUSY;
+ }
+ txdesc->callback =3D i2s_write_done;
+ drv_data->write_param =3D param;
+ txdesc->callback_param =3D drv_data;
+ txdesc->tx_submit(txdesc);
+ dev_dbg(&(drv_data->pdev->dev), "wr dma req programmed\n");
+ mutex_unlock(&drv_data->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_wr_req);
+
+/**
+ * intel_mid_i2s_open - reserve and start a SSP depending of it's usage
+ * @usage : select which ssp i2s you need by giving usage (BT,MODEM...)
+ * @ps_settings : hardware settings to configure the SSP module
+ *
+ * May sleep (driver_find_device) : no lock permitted when called.
+ *
+ * Output parameters
+ * handle : handle of the selected SSP, or NULL if not found
+ */
+struct intel_mid_i2s_hdl *intel_mid_i2s_open(enum intel_mid_i2s_ssp_usage =
usage,
+ const struct intel_mid_i2s_settings *ps_settings)
+{
+ struct pci_dev *pdev;
+ struct intel_mid_i2s_hdl *drv_data =3D NULL;
+ struct device *found_device =3D NULL;
+ pr_debug("%s : open called,searching for device with usage=3D%x !\n=
", DRIVER_NAME, usage);
+ found_device =3D driver_find_device(&(intel_mid_i2s_driver.driver),=
NULL, &usage, check_device);
+ if (!found_device) {
+ pr_debug("%s : open can not found with usage=3D0x%02X\n", D=
RIVER_NAME, (int)usage);
+ return NULL;
+ }
+ pdev =3D to_pci_dev(found_device);
+ drv_data =3D pci_get_drvdata(pdev);
+
+ if (!drv_data) {
+ dev_err(found_device, "no drv_data in open pdev=3D%p\n", pd=
ev);
+ put_device(found_device);
+ return NULL;
+ }
+ mutex_lock(&drv_data->mutex);
+ dev_dbg(found_device, "Open found pdevice=3D0x%p\n", pdev);
+ /* pm_runtime */
+ pm_runtime_get_sync(&drv_data->pdev->dev);
+ /* dmac1 is already set during probe */
+ if (i2s_dma_start(drv_data) !=3D 0) {
+ dev_err(found_device, "Can not start DMA\n");
+ goto open_error;
+ }
+ /* if we restart after stop without suspend, we start ssp faster */
+ drv_data->current_settings =3D *ps_settings;
+ set_ssp_i2s_hw(drv_data, ps_settings);
+
+ drv_data->mask_sr =3D ((SSSR_BCE_MASK << SSSR_BCE_SHIFT) |
+ (SSSR_EOC_MASK << SSSR_EOC_SHIFT) |
+ (SSSR_ROR_MASK << SSSR_ROR_SHIFT) |
+ (SSSR_TUR_MASK << SSSR_TUR_SHIFT) |
+ (SSSR_TINT_MASK << SSSR_TINT_SHIFT) |
+ (SSSR_PINT_MASK << SSSR_PINT_SHIFT));
+ if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) {
+ dev_err(&drv_data->pdev->dev, "Opening a closing I2S!");
+ goto open_error;
+ }
+ /* there is no need to "wake up" as we can not close an opening i2s=
*/
+ clear_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags);
+ clear_bit(I2S_PORT_READ_BUSY, &drv_data->flags);
+ mutex_unlock(&drv_data->mutex);
+ return drv_data;
+
+open_error:
+ put_device(found_device);
+ mutex_unlock(&drv_data->mutex);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_open);
+
+/**
+ * intel_mid_i2s_close - release and stop the SSP
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open function)
+ *
+ * WARNING: This is not -yet- allowed to call close from a read/write call=
back !
+ *
+ * Output parameters
+ * none
+ */
+void intel_mid_i2s_close(struct intel_mid_i2s_hdl *drv_data)
+{
+ void __iomem *reg;
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return;
+ mutex_lock(&drv_data->mutex);
+ if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_err(&drv_data->pdev->dev, "not opened but closing?");
+ mutex_unlock(&drv_data->mutex);
+ return;
+ }
+ /* to be modified to wait_event_interruptible_timeout */
+ set_bit(I2S_PORT_CLOSING, &drv_data->flags);
+ dev_dbg(&drv_data->pdev->dev, "Status bit pending write=3D%d read=
=3D%d\n",
+ test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags),
+ test_bit(I2S_PORT_READ_BUSY, &drv_data->flags));
+ if (test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags) ||
+ test_bit(I2S_PORT_READ_BUSY, &drv_data->flags)) {
+ dev_dbg(&drv_data->pdev->dev, "Pending callback in close...=
\n");
+ }
+
+ /* waiting below. To be replaced when "DMA_TERMINATE_ALL" fix avail=
able */
+ wait_event(drv_data->wq_chan_closing,
+ ((!test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags)) &&
+ (!test_bit(I2S_PORT_READ_BUSY, &drv_data->flags))));
+ /* release DMA Channel.. */
+ i2s_dma_stop(drv_data);
+ reg =3D drv_data->ioaddr;
+ dev_dbg(&drv_data->pdev->dev, "Stopping the SSP\n");
+ i2s_ssp_stop(drv_data);
+ put_device(&drv_data->pdev->dev);
+ write_SSCR0(0, reg);
+ /* pm runtime */
+ pm_runtime_put(&drv_data->pdev->dev);
+ dev_dbg(&(drv_data->pdev->dev), "SSP Stopped.\n");
+ clear_bit(I2S_PORT_CLOSING, &drv_data->flags);
+ clear_bit(I2S_PORT_OPENED, &drv_data->flags);
+ mutex_unlock(&drv_data->mutex);
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_close);
+/*
+ * INTERNAL FUNCTIONS
+ */
+
+/**
+ * check_device - return if the device is the usage we want (usage =3D*da=
ta)
+ * @device_ptr : pointer on device struct
+ * @data : pointer pointer on usage we are looking for
+ *
+ * this is called for each device by find_device() from intel_mid_i2s_open=
()
+ * Info : when found, the flag of driver is set to I2S_PORT_OPENED
+ *
+ * Output parameters
+ * integer : return 0 means not the device or already started. go next
+ * return !=3D 0 means stop the search and return this device
+ */
+static int
+check_device(struct device *device_ptr, void *data)
+{
+ struct pci_dev *pdev;
+ struct intel_mid_i2s_hdl *drv_data;
+ enum intel_mid_i2s_ssp_usage usage;
+ enum intel_mid_i2s_ssp_usage usage_to_find;
+
+ pdev =3D to_pci_dev(device_ptr);
+ WARN(!pdev, "Pci device=3DNULL\n");
+ if (!pdev)
+ return 0;
+ drv_data =3D (struct intel_mid_i2s_hdl *) pci_get_drvdata(pdev);
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return 0;
+ dev_dbg(&(pdev->dev), "Check device pci_dev ptr =3D 0X%p\n", pdev);
+ usage_to_find =3D *((enum intel_mid_i2s_ssp_usage *) data);
+ usage =3D drv_data->usage;
+
+ /* Can be done in one "if" but separated in purpose : take care of
+ * test_and_set_bit that need to be done AFTER the check on usage.
+ */
+ if (usage =3D=3D usage_to_find) {
+ if (!test_and_set_bit(I2S_PORT_OPENED, &drv_data->flags))
+ return 1; /* Already opened, do not use this resul=
t */
+ };
+ return 0; /* not usage we look for, or already opened */
+}
+
+/**
+ * i2s_read_done - callback from the _dma tasklet_ after read
+ * @arg : void pointer to that should be driver data (context)
+ *
+ * Output parameters
+ * none
+ */
+static void i2s_read_done(void *arg)
+{
+ int status =3D 0;
+
+ struct intel_mid_i2s_hdl *drv_data =3D arg;
+ void *param_complete;
+ void __iomem *reg ;
+
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return;
+ mutex_lock(&drv_data->mutex);
+ if (!test_bit(I2S_PORT_READ_BUSY, &drv_data->flags))
+ dev_WARN(&drv_data->pdev->dev, "spurious read dma complete"=
);
+
+ dma_unmap_single(NULL, drv_data->read_dst,
+ drv_data->read_len, DMA_FROM_DEVICE);
+ drv_data->read_len =3D 0;
+ reg =3D drv_data->ioaddr;
+ /* Rx fifo overrun Interrupt */
+ change_SSCR0_reg(reg, RIM, SSP_RX_FIFO_OVER_INT_DISABLE);
+ param_complete =3D drv_data->read_param;
+ /* Do not change order sequence:
+ * READ_BUSY clear, then test PORT_CLOSING
+ * wakeup for close() function
+ */
+ clear_bit(I2S_PORT_READ_BUSY, &drv_data->flags);
+ wake_up(&drv_data->wq_chan_closing);
+ if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) {
+ dev_dbg(&drv_data->pdev->dev, "read done waking up close");
+ mutex_unlock(&drv_data->mutex);
+ return;
+ }
+ mutex_unlock(&drv_data->mutex);
+ if (drv_data->read_callback !=3D NULL)
+ status =3D drv_data->read_callback(param_complete);
+ else
+ dev_warn(&drv_data->pdev->dev, "RD done but not callback se=
t");
+
+}
+
+/**
+ * i2s_write_done() : callback from the _dma tasklet_ after write
+ * @arg : void pointer to that should be driver data (context)
+ *
+ * Output parameters
+ * none
+ */
+static void i2s_write_done(void *arg)
+{
+ int status =3D 0;
+ void *param_complete;
+ struct intel_mid_i2s_hdl *drv_data =3D arg;
+ void __iomem *reg ;
+
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return;
+ mutex_lock(&drv_data->mutex);
+ if (!test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags))
+ dev_warn(&drv_data->pdev->dev, "spurious write dma complete=
");
+ dma_unmap_single(NULL, drv_data->read_dst,
+ drv_data->read_len, DMA_TO_DEVICE);
+ drv_data->read_len =3D 0;
+ reg =3D drv_data->ioaddr;
+ change_SSCR0_reg(reg, TIM, SSP_TX_FIFO_UNDER_INT_DISABLE);
+ dev_dbg(&(drv_data->pdev->dev), "DMA channel disable..\n");
+ param_complete =3D drv_data->write_param;
+ /* Do not change order sequence:
+ * WRITE_BUSY clear, then test PORT_CLOSING
+ * wakeup for close() function
+ */
+ clear_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags);
+ wake_up(&drv_data->wq_chan_closing);
+ if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) {
+ mutex_unlock(&drv_data->mutex);
+ dev_dbg(&drv_data->pdev->dev, "write done waking up close");
+ return;
+ }
+ mutex_unlock(&drv_data->mutex);
+ if (drv_data->write_callback !=3D NULL)
+ status =3D drv_data->write_callback(param_complete);
+ else
+ dev_warn(&drv_data->pdev->dev, "WR done but no callback set=
");
+}
+
+static bool chan_filter(struct dma_chan *chan, void *param)
+{
+ struct intel_mid_i2s_hdl *drv_data =3D (struct intel_mid_i2s_hdl *)=
param;
+ bool ret =3D false;
+
+ if (!drv_data->dmac1)
+ goto out;
+ if (chan->device->dev =3D=3D &drv_data->dmac1->dev)
+ ret =3D true;
+out:
+ return ret;
+}
+
+/**
+ * i2s_dma_start - prepare and reserve dma channels
+ * @arg : intel_mid_i2s_hdl pointer to that should be driver data (context)
+ *
+ * "ssp open" context and dmac1 should already be filled in drv_data
+ *
+ * Output parameters
+ * int : should be zero, else it means error code
+ */
+static int i2s_dma_start(struct intel_mid_i2s_hdl *drv_data)
+{
+ struct intel_mid_dma_slave *rxs, *txs;
+ dma_cap_mask_t mask;
+ int retval =3D 0;
+ struct pci_dev *l_pdev;
+
+ dev_dbg(&drv_data->pdev->dev, "DMAC1 start\n");
+ drv_data->txchan =3D NULL;
+ drv_data->rxchan =3D NULL;
+ l_pdev =3D drv_data->pdev;
+ /* 1. init rx channel */
+ rxs =3D &drv_data->dmas_rx;
+ rxs->dirn =3D DMA_FROM_DEVICE;
+ rxs->hs_mode =3D LNW_DMA_HW_HS;
+ rxs->cfg_mode =3D LNW_DMA_PER_TO_MEM;
+ rxs->src_width =3D LNW_DMA_WIDTH_16BIT;
+ rxs->dst_width =3D LNW_DMA_WIDTH_32BIT;
+ rxs->src_msize =3D LNW_DMA_MSIZE_8;
+ rxs->dst_msize =3D LNW_DMA_MSIZE_8;
+ rxs->device_instance =3D drv_data->device_instance;
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_MEMCPY, mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ drv_data->rxchan =3D dma_request_channel(mask, chan_filter, drv_dat=
a);
+ if (!drv_data->rxchan) {
+ dev_err(&(drv_data->pdev->dev),
+ "Could not get Rx channel\n");
+ retval =3D -2;
+ goto err_exit;
+ }
+ drv_data->rxchan->private =3D rxs;
+ /* 2. init tx channel */
+ txs =3D &drv_data->dmas_tx;
+ txs->dirn =3D DMA_TO_DEVICE;
+ txs->hs_mode =3D LNW_DMA_HW_HS;
+ txs->cfg_mode =3D LNW_DMA_MEM_TO_PER;
+ txs->src_width =3D LNW_DMA_WIDTH_32BIT;
+ txs->dst_width =3D LNW_DMA_WIDTH_16BIT;
+ txs->src_msize =3D LNW_DMA_MSIZE_8;
+ txs->dst_msize =3D LNW_DMA_MSIZE_8;
+ txs->device_instance =3D drv_data->device_instance;
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_MEMCPY, mask);
+ drv_data->txchan =3D dma_request_channel(mask, chan_filter, drv_dat=
a);
+ if (!drv_data->txchan) {
+ dev_err(&(drv_data->pdev->dev),
+ "Could not get Tx channel\n");
+ retval =3D -3;
+ goto free_rxchan;
+ }
+ drv_data->txchan->private =3D txs;
+ return retval;
+free_rxchan:
+ dma_release_channel(drv_data->rxchan);
+err_exit:
+ return retval;
+}
+
+/**
+ * i2s_dma_stop - release dma channels
+ * @arg : struct intel_mid_i2s_hdl pointer to that should be driver data (=
context)
+ *
+ * called by intel_mid_i2s_close() context
+ *
+ * Output parameters
+ * none
+ */
+static void i2s_dma_stop(struct intel_mid_i2s_hdl *drv_data)
+{
+ dev_dbg(&drv_data->pdev->dev, "DMAC1 stop\n");
+ dma_release_channel(drv_data->txchan);
+ dma_release_channel(drv_data->rxchan);
+}
+
+static void i2s_ssp_stop(struct intel_mid_i2s_hdl *drv_data)
+{
+ void __iomem *reg =3D drv_data->ioaddr;
+ dev_dbg(&drv_data->pdev->dev, "Stop SSP\n");
+ clear_SSCR0_reg(reg, SSE);
+}
+
+static void ssp1_dump_registers(struct intel_mid_i2s_hdl *drv_data)
+{
+ u32 irq_status;
+ void __iomem *reg =3D drv_data->ioaddr;
+ struct device *ddbg =3D &(drv_data->pdev->dev);
+ u32 status;
+ irq_status =3D read_SSSR(reg);
+ dev_dbg(ddbg, "dump SSSR=3D0x%08X\n", irq_status);
+ status =3D read_SSCR0(reg);
+ dev_dbg(ddbg, "dump SSCR0=3D0x%08X\n", status);
+ status =3D read_SSCR1(reg);
+ dev_dbg(ddbg, "dump SSCR1=3D0x%08X\n", status);
+ status =3D read_SSPSP(reg);
+ dev_dbg(ddbg, "dump SSPSP=3D0x%08X\n", status);
+ status =3D read_SSTSA(reg);
+ dev_dbg(ddbg, "dump SSTSA=3D0x%08X\n", status);
+ status =3D read_SSRSA(reg);
+ dev_dbg(ddbg, "dump SSRSA=3D0x%08X\n", status);
+ status =3D read_SSTO(reg);
+ dev_dbg(ddbg, "dump SSTO=3D0x%08X\n", status);
+ status =3D read_SSITR(reg);
+ dev_dbg(ddbg, "dump SSITR=3D0x%08X\n", status);
+ status =3D read_SSTSS(reg);
+ dev_dbg(ddbg, "dump SSTSS=3D0x%08X\n", status);
+ status =3D read_SSACD(reg);
+ dev_dbg(ddbg, "dump SSACD=3D0x%08X\n", status);
+}
+
+/**
+ * i2s_int(): function that handles the SSP Interrupts (errors)
+ * @irq : IRQ Number
+ * @dev_id : structure that contains driver information
+ *
+ * This interrupts do nothing but warnings in case there is some problems
+ * in I2S connection (underruns, overruns...). This may be reported by add=
ing a
+ * new interface to the driver, but not yet requested by "users" of this d=
river
+ *
+ * Output parameters
+ * NA
+ */
+static irqreturn_t i2s_int(int irq, void *dev_id)
+{
+ struct intel_mid_i2s_hdl *drv_data =3D dev_id;
+ void __iomem *reg;
+ u32 irq_status =3D 0;
+ u32 mask_status =3D 0;
+ struct device *ddbg =3D &(drv_data->pdev->dev);
+ reg =3D drv_data->ioaddr;
+ irq_status =3D read_SSSR(reg);
+
+ if (!(irq_status & (drv_data->mask_sr))) {
+ return IRQ_NONE;
+ } else {
+ /* may be improved by using a tasklet to send the error
+ * (underrun,...) to client by using callback
+ */
+ if (irq_status & (SSSR_ROR_MASK << SSSR_ROR_SHIFT)) {
+ dev_warn(ddbg,
+ "ssp_int RX FIFO OVER RUN SSSR=3D0x%08X\n",
+ irq_status);
+ mask_status |=3D (SSSR_ROR_MASK << SSSR_ROR_SHIFT);
+
+ }
+ if (irq_status & (SSSR_TUR_MASK << SSSR_TUR_SHIFT)) {
+ dev_warn(ddbg,
+ "ssp_int TX FIFO UNDER RUN SSSR=3D0x%08X\n",
+ irq_status);
+ mask_status |=3D (SSSR_TUR_MASK << SSSR_TUR_SHIFT);
+
+ }
+ if (irq_status & (SSSR_TINT_MASK << SSSR_TINT_SHIFT)) {
+ dev_warn(ddbg,
+ "ssp_int RX TIME OUT SSSR=3D0x%08X\n",
+ irq_status);
+ mask_status |=3D (SSSR_TINT_MASK << SSSR_TINT_SHIFT=
);
+
+ }
+ if (irq_status & (SSSR_PINT_MASK << SSSR_PINT_SHIFT)) {
+ dev_warn(ddbg,
+ "ssp_int TRAILING BYTE SSSR=3D0x%08X\n",
+ irq_status);
+ mask_status |=3D (SSSR_PINT_MASK << SSSR_PINT_SHIFT=
);
+ }
+ if (irq_status & (SSSR_EOC_MASK << SSSR_EOC_SHIFT)) {
+ dev_warn(ddbg,
+ "ssp_int END OF CHAIN SSSR=3D0x%08X\n",
+ irq_status);
+ mask_status |=3D (SSSR_EOC_MASK << SSSR_EOC_SHIFT);
+ }
+ /* clear sticky bits */
+ write_SSSR((irq_status & mask_status), reg);
+ }
+ return IRQ_HANDLED;
+}
+
+/**
+ * calculate_sspsp_psp - separate function that calculate sspsp register
+ * @ps_settings : pointer of the settings struct
+ *
+ * this function is to simplify/clarify set_ssp_i2s_hw function
+ *
+ *
+ * Output parameters
+ * u32 : calculated SSPSP register
+ */
+u32 calculate_sspsp_psp(const struct intel_mid_i2s_settings *ps_settings)
+{
+ u32 sspsp;
+ sspsp =3D SSPSP_reg(FSRT, ps_settings->ssp_frmsync_timing_bit)
+ |SSPSP_reg(ETDS, ps_settings->ssp_end_transfer_state)
+ |SSPSP_reg(SCMODE, ps_settings->ssp_serial_clk_mode)
+ |SSPSP_reg(DMYSTOP, ps_settings->ssp_psp_T4)
+ |SSPSP_reg(SFRMDLY, ps_settings->ssp_psp_T5)
+ |SSPSP_reg(SFRMWDTH, ps_settings->ssp_psp_T6)
+ |SSPSP_reg(SFRMP, ps_settings->ssp_frmsync_pol_bit);
+ return sspsp;
+}
+
+/*
+ * calculate_sscr0_psp: separate function that calculate sscr0 register
+ * @ps_settings : pointer of the settings struct
+ *
+ * this function is to simplify/clarify set_ssp_i2s_hw function
+ *
+ * Output parameters
+ * u32 : calculated SSCR0 register
+ */
+u32 calculate_sscr0_psp(const struct intel_mid_i2s_settings *ps_settings)
+{
+ u16 l_ssp_data_size =3D ps_settings->data_size;
+ u32 sscr0;
+ if (l_ssp_data_size > 16) {
+ sscr0 =3D SSCR0_reg(DSS, SSCR0_DataSize(l_ssp_data_size -=
16))
+ | SSCR0_reg(EDSS, 1);
+ } else {
+ sscr0 =3D SSCR0_reg(DSS, SSCR0_DataSize(l_ssp_data_size))
+ | SSCR0_reg(EDSS, 0);
+ }
+/*
+Can be replaced by code below :
+sscr0 =3D SSCR0_reg(DSS, (l_ssp_data_size - 1) & 0x0F)
+| SSCR0_reg(EDSS, ((l_ssp_data_size - 1) & 0x10) >> 8);
+*/
+ sscr0 |=3D SSCR0_reg(MOD, ps_settings->mode)
+ |SSCR0_reg(FRF, ps_settings->frame_format)
+ |SSCR0_reg(RIM, SSP_RX_FIFO_OVER_INT_DISABLE)
+ |SSCR0_reg(TIM, SSP_TX_FIFO_UNDER_INT_DISABLE);
+ return sscr0;
+}
+
+/**
+ * calculate_sscr1_psp - separate function that calculate sscr1 register
+ * @ps_settings : pointer of the settings struct
+ *
+ * this function is to simplify/clarify set_ssp_i2s_hw function
+ *
+ * Output parameters
+ * u32 : calculated SSCR1 register
+ */
+u32 calculate_sscr1_psp(const struct intel_mid_i2s_settings *ps_settings)
+{
+ u32 sscr1;
+ sscr1 =3D SSCR1_reg(SFRMDIR, ps_settings->sspsfrm_direction)
+ |SSCR1_reg(SCLKDIR, ps_settings->sspslclk_direction)
+ |SSCR1_reg(TTELP, ps_settings->tx_tristate_phase)
+ |SSCR1_reg(TTE, ps_settings->tx_tristate_enable)
+ |SSCR1_reg(TRAIL, ps_settings->ssp_trailing_byte_mode)
+ |SSCR1_reg(TINTE, ps_settings->ssp_rx_timeout_interru=
pt_status)
+ |SSCR1_reg(PINTE, ps_settings->ssp_trailing_byte_inte=
rrupt_status)
+ |SSCR1_reg(LBM, ps_settings->ssp_loopback_mode_status)
+ |SSCR1_reg(RWOT, ps_settings->ssp_duplex_mode)
+ |SSCR1_reg(RFT, SSCR1_RxTresh(ps_settings->ssp_rx_fifo_thre=
shold))
+ |SSCR1_reg(TFT, SSCR1_TxTresh(ps_settings->ssp_tx_fifo_thre=
shold));
+ return sscr1;
+}
+
+/**
+ * set_ssp_i2s_hw - configure the SSP driver according to the ps_settings
+ * @drv_data : structure that contains all details about the SSP Driver
+ * @ps_settings : structure that contains SSP Hardware settings
+ *
+ * it also store ps_settings the drv_data
+ *
+ * Output parameters
+ * NA
+ */
+static void set_ssp_i2s_hw(struct intel_mid_i2s_hdl *drv_data,
+ const struct intel_mid_i2s_settings *ps_settings)
+{
+ u32 sscr0 =3D 0;
+ u32 sscr1 =3D 0;
+ u32 sstsa =3D 0;
+ u32 ssrsa =3D 0;
+ u32 sspsp =3D 0;
+ u32 sssr =3D 0;
+ /* Get the SSP Settings */
+ u16 l_ssp_clk_frm_mode =3D 0xFF;
+ void __iomem *reg =3D drv_data->ioaddr;
+ struct device *ddbg =3D &(drv_data->pdev->dev);
+ dev_dbg(ddbg,
+ "setup SSP I2S PCM1 configuration\n");
+ if ((ps_settings->sspsfrm_direction =3D=3D SSPSFRM_MASTER_MODE)
+ && (ps_settings->sspslclk_direction =3D=3D SSPSCLK_MASTER_MODE))=
{
+ l_ssp_clk_frm_mode =3D SSP_IN_MASTER_MODE;
+ } else if ((ps_settings->sspsfrm_direction =3D=3D SSPSFRM_SLAVE_MOD=
E)
+ && (ps_settings->sspslclk_direction =3D=3D SSPSCLK_SLAVE_MODE)) {
+ l_ssp_clk_frm_mode =3D SSP_IN_SLAVE_MODE;
+ } else {
+ dev_err(ddbg, "Unsupported I2S PCM1 configuration\n");
+ goto leave;
+ }
+ dev_dbg(ddbg, "SSPSFRM_DIRECTION:%d:\n",
+ ps_settings->sspsfrm_direction);
+ dev_dbg(ddbg, "SSPSCLK_DIRECTION:%d:\n",
+ ps_settings->sspslclk_direction);
+ if (ps_settings->frame_format !=3D PSP_FORMAT) {
+ dev_err(ddbg, "UNSUPPORTED FRAME FORMAT:%d:\n", ps_settings=
->frame_format);
+ goto leave;
+ }
+ if ((ps_settings->ssp_tx_dma !=3D SSP_TX_DMA_ENABLE)
+ || (ps_settings->ssp_rx_dma !=3D SSP_RX_DMA_ENABLE)) {
+ dev_err(ddbg, "ONLY DMA MODE IS SUPPORTED");
+ goto leave;
+ }
+ /*********** DMA Transfer Mode ***********/
+ dev_dbg(ddbg, "FORMAT :%d:\n", ps_settings->frame_format);
+ sscr0 =3D calculate_sscr0_psp(ps_settings);
+ dev_dbg(ddbg, " sscr0 :0x%08X\n", sscr0);
+ sscr1 =3D calculate_sscr1_psp(ps_settings);
+ dev_dbg(ddbg, " sscr1 :0x%08X\n", sscr1);
+ if (ps_settings->mode =3D=3D SSP_IN_NETWORK_MODE) {
+ dev_dbg(ddbg, "MODE :%d:\n", ps_settings->mode);
+ sscr0 |=3D SSCR0_reg(FRDC, SSCR0_SlotsPerFrm(ps_settings->f=
rame_rate_divider_control));
+ dev_dbg(ddbg, "sscr0 :0x%08X\n", sscr0);
+ sspsp =3D calculate_sspsp_psp(ps_settings);
+ dev_dbg(ddbg, "sspsp :0x%08X\n", sspsp);
+ /* set the active TX time slot (bitmap) */
+ sstsa =3D SSTSA_reg(TTSA, ps_settings->ssp_active_tx_slots_=
map);
+ /* set the active RX time slot (bitmap) */
+ ssrsa =3D SSRSA_reg(RTSA, ps_settings->ssp_active_rx_slots_=
map);
+ if (l_ssp_clk_frm_mode =3D=3D SSP_IN_MASTER_MODE) {
+ switch (ps_settings->master_mode_clk_selection) {
+ case SSP_ONCHIP_CLOCK:
+ break;
+ case SSP_NETWORK_CLOCK:
+ sscr0 |=3D SSCR0_reg(NCS, 1);
+ break;
+ case SSP_EXTERNAL_CLOCK:
+ sscr0 |=3D SSCR0_reg(ECS, 1);
+ break;
+ case SSP_ONCHIP_AUDIO_CLOCK:
+ sscr0 |=3D SSCR0_reg(ACS, 1);
+ break;
+ default:
+ dev_err(ddbg, "Master Mode clk selection UN=
KNOWN");
+ break;
+ }
+ sspsp |=3D SSPSP_reg(STRTDLY, ps_settings->ssp_psp_=
T1)
+ |SSPSP_reg(DMYSTRT, ps_settings->ssp_psp_T2=
);
+ } else { /* Set the Slave Clock Free Running Status =
*/
+ sscr1 |=3D SSCR1_reg(SCFR, ps_settings->slave_clk_f=
ree_running_status);
+ }
+ } else { /* SSP_IN_NORMAL_MODE */
+ dev_err(ddbg, "UNSUPPORTED MODE");
+ goto leave;
+ }
+
+ /* Clear status */
+ sssr =3D (SSSR_BCE_MASK << SSSR_BCE_SHIFT)
+ | (SSSR_TUR_MASK << SSSR_TUR_SHIFT)
+ | (SSSR_TINT_MASK << SSSR_TINT_SHIFT)
+ | (SSSR_PINT_MASK << SSSR_PINT_SHIFT)
+ | (SSSR_ROR_MASK << SSSR_ROR_SHIFT);
+ /* disable SSP */
+ clear_SSCR0_reg(reg, SSE);
+ dev_dbg(ddbg, "WRITE SSCR0 DISABLE\n");
+ /* Clear status */
+ write_SSSR(sssr, reg);
+ dev_dbg(ddbg, "WRITE SSSR: 0x%08X\n", sssr);
+ write_SSCR0(sscr0, reg);
+ dev_dbg(ddbg, "WRITE SSCR0\n");
+ /* first set CR1 without interrupt and service enables */
+ write_SSCR1(sscr1, reg);
+ write_SSPSP(sspsp, reg);
+ write_SSTSA(sstsa, reg);
+ write_SSRSA(ssrsa, reg);
+ /* set the time out for the reception */
+ write_SSTO(0, reg);
+ ssp1_dump_registers(drv_data);
+leave:
+ return;
+}
+
+static int
+intel_mid_i2s_find_usage(struct pci_dev *pdev,
+ struct intel_mid_i2s_hdl *drv_data,
+ enum intel_mid_i2s_ssp_usage *usage)
+{
+ int pos;
+ u8 adid;
+ int status =3D 0;
+
+ *usage =3D SSP_USAGE_UNASSIGNED;
+ pos =3D pci_find_capability(pdev, PCI_CAP_ID_VNDR);
+ dev_info((&pdev->dev),
+ "Probe/find capability (VNDR %d pos=3D0x%x)\n",
+ PCI_CAP_ID_VNDR, pos);
+ if (pos > 0) {
+ pos +=3D PCI_CAP_OFFSET_ADID;
+ pci_read_config_byte(pdev, pos, &adid);
+ dev_info(&(pdev->dev), "Vendor capability adid =3D 0x%x\n",=
adid);
+ if (adid =3D=3D PCI_CAP_ADID_I2S_BT_FM)
+ *usage =3D SSP_USAGE_BLUETOOTH_FM;
+ else if (adid =3D=3D PCI_CAP_ADID_I2S_MODEM)
+ *usage =3D SSP_USAGE_MODEM;
+ else
+ *usage =3D SSP_USAGE_UNASSIGNED;
+ }
+ /* If there is no capability, check with old PCI_ID */
+#ifdef BYPASS_ADID
+ if (*usage =3D=3D SSP_USAGE_UNASSIGNED) {
+ dev_warn(&(pdev->dev), "Vendor capability not present/inval=
id\n");
+ switch (pdev->device) {
+ case MFLD_SSP1_DEVICE_ID:
+ *usage =3D SSP_USAGE_BLUETOOTH_FM;
+ break;
+ case MFLD_SSP0_DEVICE_ID:
+ *usage =3D SSP_USAGE_MODEM;
+ break;
+ }
+ }
+#endif
+ if (*usage =3D=3D SSP_USAGE_UNASSIGNED) {
+ dev_info((&pdev->dev),
+ "No probe for I2S PCI-ID: %04x:%04x, ADID(0x%x)=3D0=
x%x\n",
+ pdev->vendor, pdev->device, pos, adid);
+ status =3D -ENODEV;
+ goto err_find_usage;
+ }
+ dev_dbg(&(pdev->dev),
+ "Detected PCI SSP (ID: %04x:%04x) usage =3D%x\n",
+ pdev->vendor, pdev->device, *usage);
+ dev_dbg(&(pdev->dev),
+ " found PCI SSP controller(ID: %04x:%04x)\n",
+ pdev->vendor, pdev->device);
+ /* Init the driver data structure fields*/
+ switch (pdev->device) {
+ case MFLD_SSP1_DEVICE_ID:
+ drv_data->device_instance =3D DMA1C_DEVICE_INSTANCE_SSP1;
+ break;
+ case MFLD_SSP0_DEVICE_ID:
+ drv_data->device_instance =3D DMA1C_DEVICE_INSTANCE_SSP0;
+ break;
+ default:
+ dev_err(&(pdev->dev),
+ "Can not determine dma device instance (PCI ID:%04x=
)\n",
+ pdev->device);
+ status =3D -ENODEV;
+ goto err_find_usage;
+ }
+ status =3D pci_enable_device(pdev);
+ if (status)
+ dev_err((&pdev->dev), "Can not enable device.Err=3D%d\n", s=
tatus);
+err_find_usage:
+ return status;
+}
+
+/**
+ * intel_mid_i2s_probe - probing function for the pci selected
+ * @pdev : pci_dev pointer that is probed
+ * @ent : pci_device_id
+ *
+ * Output parameters
+ * NA
+ */
+static int intel_mid_i2s_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct intel_mid_i2s_hdl *drv_data;
+ int status =3D 0;
+ enum intel_mid_i2s_ssp_usage usage;
+
+ drv_data =3D kzalloc(sizeof(struct intel_mid_i2s_hdl), GFP_KERNEL);
+ dev_dbg(&(pdev->dev), "%s Probe, drv_data =3D%p\n", DRIVER_NAME, dr=
v_data);
+ if (!drv_data) {
+ dev_err((&pdev->dev), "Can't alloc driver data in probe\n");
+ status =3D -ENOMEM;
+ goto leave;
+ }
+ dev_info((&pdev->dev), "Detected PCI SSP (ID: %04x:%04x)\n", pdev->=
vendor, pdev->device);
+ status =3D intel_mid_i2s_find_usage(pdev, drv_data, &usage);
+ if (status)
+ goto err_i2s_probe0;
+ mutex_init(&drv_data->mutex);
+ drv_data->pdev =3D pdev;
+ drv_data->usage =3D usage;
+ /*
+ * Get basic io resource and map it for SSP1 [BAR=3D0]
+ */
+ if ((pdev->device =3D=3D MFLD_SSP1_DEVICE_ID) ||
+ (pdev->device =3D=3D MFLD_SSP0_DEVICE_ID)) {
+ drv_data->paddr =3D pci_resource_start(pdev, MRST_SSP_BAR);
+ drv_data->iolen =3D pci_resource_len(pdev, MRST_SSP_BAR);
+ status =3D pci_request_region(pdev, MRST_SSP_BAR, dev_name(=
&pdev->dev));
+ /* map bus memory into CPU space */
+ drv_data->ioaddr =3D pci_ioremap_bar(pdev, MRST_SSP_BAR);
+ } else {
+ dev_err(&pdev->dev,
+ "Don't know which BAR to usefor this SSP PCDID=3D%x=
\n",
+ pdev->device);
+ status =3D -ENODEV;
+ goto err_i2s_probe1;
+ }
+ dev_dbg(&(pdev->dev), "paddr =3D : %x\n", drv_data->paddr);
+ dev_dbg(&(pdev->dev), "iolen =3D : %d\n", drv_data->iolen);
+ if (status) {
+ dev_err((&pdev->dev), "Can't request region. err=3D%d\n", s=
tatus);
+ goto err_i2s_probe1;
+ }
+ if (!drv_data->ioaddr) {
+ dev_err((&pdev->dev), "ioremap_nocache error\n");
+ status =3D -ENOMEM;
+ goto err_i2s_probe2;
+ }
+ dev_dbg(&(pdev->dev), "ioaddr =3D : %p\n", drv_data->ioaddr);
+ /* prepare for DMA channel allocation */
+ /* get the pci_dev structure pointer */
+ /* Check the SSP, if SSP3, then another DMA is used (GPDMA..) */
+ if ((pdev->device =3D=3D MFLD_SSP1_DEVICE_ID) ||
+ (pdev->device =3D=3D MFLD_SSP0_DEVICE_ID)) {
+ drv_data->dmac1 =3D pci_get_device(PCI_VENDOR_ID_INTEL,
+ MFLD_LPE_DMA_DEVICE_ID,
+ NULL);
+ } else {
+ dev_err(&pdev->dev,
+ "Don't know dma device ID for this SSP PCDID=3D%x\n=
",
+ pdev->device);
+ goto err_i2s_probe3;
+ }
+ /* in case the stop dma have to wait for end of callbacks */
+ /* This will be removed when TERMINATE_ALL available in DMA */
+ init_waitqueue_head(&drv_data->wq_chan_closing);
+ if (!drv_data->dmac1) {
+ dev_err(&(drv_data->pdev->dev), "Can't find DMAC1, dma init=
failed\n");
+ status =3D -ENODEV;
+ goto err_i2s_probe3;
+ }
+ /* increment ref count of pci device structure already done by */
+ /* pci_get_device. will do a pci_dev_put when exiting the module */
+ pci_set_drvdata(pdev, drv_data);
+ /* set SSP FrameSync and CLK direction in INPUT mode in order
+ * to avoid disturbing peripherals
+ */
+ write_SSCR1((SSCR1_SFRMDIR_MASK<<SSCR1_SFRMDIR_SHIFT)
+ | (SSCR1_SCLKDIR_MASK<<SSCR1_SCLKDIR_SHIFT),
+ drv_data->ioaddr);
+ /* Attach to IRQ */
+ drv_data->irq =3D pdev->irq;
+ dev_dbg(&(pdev->dev), "attaching to IRQ: %04x\n", pdev->irq);
+ status =3D request_irq(drv_data->irq, i2s_int, IRQF_SHARED, "i2s ss=
p", drv_data);
+ if (status < 0) {
+ dev_err(&pdev->dev, "can not get IRQ. status err=3D%d\n", s=
tatus);
+ goto err_i2s_probe3;
+ }
+ pm_runtime_enable(&(drv_data->pdev->dev));
+ goto leave;
+err_i2s_probe3:
+ iounmap(drv_data->ioaddr);
+err_i2s_probe2:
+ pci_release_region(pdev, MRST_SSP_BAR);
+err_i2s_probe1:
+ pci_disable_device(pdev);
+err_i2s_probe0:
+ kfree(drv_data);
+leave:
+ return status;
+}
+
+static void __devexit intel_mid_i2s_remove(struct pci_dev *pdev)
+{
+ struct intel_mid_i2s_hdl *drv_data;
+
+ drv_data =3D pci_get_drvdata(pdev);
+ if (!drv_data) {
+ dev_err(&pdev->dev, "no drv_data in pci device to remove!\n=
");
+ goto leave;
+ }
+ if (test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_warn(&pdev->dev, "Not closed before removing pci_dev!\n=
");
+ intel_mid_i2s_close(drv_data);
+ }
+ pci_set_drvdata(pdev, NULL);
+ /* Stop DMA is already done during close() */
+ pci_dev_put(drv_data->dmac1);
+ /* Disable the SSP at the peripheral and SOC level */
+ write_SSCR0(0, drv_data->ioaddr);
+ free_irq(drv_data->irq, drv_data);
+ iounmap(drv_data->ioaddr);
+ pci_release_region(pdev, MRST_SSP_BAR);
+ pci_release_region(pdev, MRST_LPE_BAR);
+ pci_disable_device(pdev);
+ kfree(drv_data);
+leave:
+ return;
+}
+
+/**
+ * intel_mid_i2s_init - register pci driver
+ *
+ */
+static int __init intel_mid_i2s_init(void)
+{
+ return pci_register_driver(&intel_mid_i2s_driver);
+}
+
+static void __exit intel_mid_i2s_exit(void)
+{
+ pci_unregister_driver(&intel_mid_i2s_driver);
+}
+
+
+module_init(intel_mid_i2s_init);
+module_exit(intel_mid_i2s_exit);
+
+
+
diff --git a/sound/pci/intel_mid_i2s/intel_mid_i2s.h b/sound/pci/intel_mid_=
i2s/intel_mid_i2s.h
new file mode 100644
index 0000000..ef29ce7
--- /dev/null
+++ b/sound/pci/intel_mid_i2s/intel_mid_i2s.h
@@ -0,0 +1,500 @@
+/*
+ * <Driver for I2S protocol on SSP (Moorestown and Medfield hardware)>
+ * Copyright (c) 2010, Intel Corporation.
+ * Louis LE GALL <louis.le.gall intel.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License =
for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License alon=
g with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define DRIVER_NAME "I2S SSP Driver"
+/*
+ * Defines
+ */
+#define MFLD_SSP1_DEVICE_ID 0x0825 /* FOR MFLD */
+#define MRST_SSP0_DEVICE_ID 0x0815 /* FOR MRST */
+#define MFLD_SSP0_DEVICE_ID 0x0832 /* FOR MFLD */
+
+#define MRST_LPE_DMA_DEVICE_ID 0x0814
+#define MFLD_LPE_DMA_DEVICE_ID 0x0830
+
+/* SSP1 PCI device Base Address Register */
+#define MRST_SSP_BAR 0
+#define MRST_LPE_BAR 1
+#define DMA1C_DEVICE_INSTANCE_SSP0 0
+#define DMA1C_DEVICE_INSTANCE_SSP1 1
+#define OFFSET_SSCR0 0x00
+#define OFFSET_SSCR1 0x04
+#define OFFSET_SSSR 0x08
+#define OFFSET_SSITR 0x0c
+#define OFFSET_SSDR 0x10
+#define OFFSET_SSTO 0x28
+#define OFFSET_SSPSP 0x2c
+#define OFFSET_SSTSA 0x30 /* SSP Tx Timeslot Active */
+#define OFFSET_SSRSA 0x34 /* SSP Rx Timeslot Active */
+/* SST register map */
+#define OFFSET_LPE_CSR 0x00
+#define OFFSET_LPE_PISR 0x08
+#define OFFSET_LPE_PIMR 0x10
+#define OFFSET_LPE_ISRX 0x18
+#define OFFSET_LPE_IMRX 0x28
+#define OFFSET_LPE_IPCX 0x38 /* IPC IA-SST */
+#define OFFSET_LPE_IPCD 0x40 /* IPC SST-IA */
+#define OFFSET_LPE_ISRD 0x20 /* dummy register f=
or*/
+ /* shim workaround */
+#define OFFSET_LPE_SHIM_SIZE 0X44
+
+#define SSP_IN_MASTER_MODE 0x0
+#define SSP_IN_SLAVE_MODE 0x1
+
+/*
+ * Macros
+ */
+#define DEFINE_SSP_REG(reg, off) \
+static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
+static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)=
); }
+DEFINE_SSP_REG(SSCR0, 0x00)
+DEFINE_SSP_REG(SSCR1, 0x04)
+DEFINE_SSP_REG(SSSR, 0x08)
+DEFINE_SSP_REG(SSITR, 0x0c)
+DEFINE_SSP_REG(SSDR, 0x10)
+DEFINE_SSP_REG(SSTO, 0x28)
+DEFINE_SSP_REG(SSPSP, 0x2c)
+DEFINE_SSP_REG(SSTSA, 0x30)
+DEFINE_SSP_REG(SSRSA, 0x34)
+DEFINE_SSP_REG(SSTSS, 0x38)
+DEFINE_SSP_REG(SSACD, 0x3C)
+DEFINE_SSP_REG(I2CCTRL, 0x00);
+DEFINE_SSP_REG(I2CDATA, 0x04);
+/*
+ * Langwell SSP serial port register definitions
+ */
+#define SSCR0_DSS_MASK 0x0F /* Data Size Select [4..16] */
+#define SSCR0_DSS_SHIFT 0
+#define SSCR0_FRF_MASK 0x03 /* FRame Format */
+#define SSCR0_FRF_SHIFT 4
+#define SSCR0_ECS_MASK 0x01 /* External clock select */
+#define SSCR0_ECS_SHIFT 6
+#define SSCR0_SSE_MASK 0x01 /* Synchronous Serial Port Enable */
+#define SSCR0_SSE_SHIFT 7
+#define SSCR0_SCR_MASK 0xFFF /* Not implemented */
+#define SSCR0_SCR_SHIFT 8
+#define SSCR0_EDSS_MASK 0x1 /* Extended data size select */
+#define SSCR0_EDSS_SHIFT 20
+#define SSCR0_NCS_MASK 0x1 /* Network clock select */
+#define SSCR0_NCS_SHIFT 21
+#define SSCR0_RIM_MASK 0x1 /* Receive FIFO overrrun int mask */
+#define SSCR0_RIM_SHIFT 22
+#define SSCR0_TIM_MASK 0x1 /* Transmit FIFO underrun int mask */
+#define SSCR0_TIM_SHIFT 23
+#define SSCR0_FRDC_MASK 0x7 /* Frame Rate Divider Control */
+#define SSCR0_FRDC_SHIFT 24
+#define SSCR0_ACS_MASK 0x1 /* Audio clock select */
+#define SSCR0_ACS_SHIFT 30
+#define SSCR0_MOD_MASK 0x1 /* Mode (normal or network) */
+#define SSCR0_MOD_SHIFT 31
+
+#define SSCR0_DataSize(x) ((x) - 1) /* Data Size Select [4..16]=
*/
+#define SSCR0_SlotsPerFrm(x) ((x) - 1) /* Time slots per frame */
+#define SSCR0_SerClkDiv(x) ((x) - 1) /* Divisor [1..4096],... */
+ /*...not implemented on Langwell */
+#define SSCR1_TTELP_MASK 0x1 /* TXD Tristate Enable on Last Phas=
e */
+#define SSCR1_TTELP_SHIFT 31
+#define SSCR1_TTE_MASK 0x1 /* TXD Tristate Enable */
+#define SSCR1_TTE_SHIFT 30
+#define SSCR1_EBCEI_MASK 0x1 /* Enable Bit Count Error Interrupt=
*/
+#define SSCR1_EBCEI_SHIFT 29
+#define SSCR1_SCFR_MASK 0x1 /* Slave Clock Running */
+#define SSCR1_SCFR_SHIFT 28
+#define SSCR1_ECRA_MASK 0x1 /* Enable Clock Request A */
+#define SSCR1_ECRA_SHIFT 27
+#define SSCR1_ECRB_MASK 0x1 /* Enable Clock Request B */
+#define SSCR1_ECRB_SHIFT 26
+#define SSCR1_SCLKDIR_MASK 0x1 /* SSPCLK Direction */
+#define SSCR1_SCLKDIR_SHIFT 25
+#define SSCR1_SFRMDIR_MASK 0x1 /* SSPFRM Direction */
+#define SSCR1_SFRMDIR_SHIFT 24
+#define SSCR1_RWOT_MASK 0x1 /* Receive without Transmit */
+#define SSCR1_RWOT_SHIFT 23
+#define SSCR1_TRAIL_MASK 0x1 /* Trailing Byte */
+#define SSCR1_TRAIL_SHIFT 22
+#define SSCR1_TSRE_MASK 0x1 /* DMA Transmit Service Request Ena=
ble*/
+#define SSCR1_TSRE_SHIFT 21
+#define SSCR1_RSRE_MASK 0x1 /* DMA Receive Service Request Enab=
le */
+#define SSCR1_RSRE_SHIFT 20
+#define SSCR1_TINTE_MASK 0x1 /* Receiver Time-out Interrupt Enab=
le */
+#define SSCR1_TINTE_SHIFT 19
+#define SSCR1_PINTE_MASK 0x1 /* Periph. Trailing Byte Int. Enabl=
e */
+#define SSCR1_PINTE_SHIFT 18
+#define SSCR1_IFS_MASK 0x1 /* Invert Frame Signal */
+#define SSCR1_IFS_SHIFT 16
+#define SSCR1_STFR_MASK 0x1 /* Select FIFO for EFWR: test mode =
*/
+#define SSCR1_STFR_SHIFT 15
+#define SSCR1_EFWR_MASK 0x1 /* Enable FIFO Write/Read: test mod=
e */
+#define SSCR1_EFWR_SHIFT 14
+#define SSCR1_RFT_MASK 0xF /* Receive FIFO Trigger Threshold */
+#define SSCR1_RFT_SHIFT 10
+#define SSCR1_TFT_MASK 0xF /* Transmit FIFO Trigger Threshold =
*/
+#define SSCR1_TFT_SHIFT 6
+#define SSCR1_MWDS_MASK 0x1 /* Microwire Transmit Data Size */
+#define SSCR1_MWDS_SHIFT 5
+#define SSCR1_SPH_MASK 0x1 /* Motorola SPI SSPSCLK phase setti=
ng */
+#define SSCR1_SPH_SHIFT 4
+#define SSCR1_SPO_MASK 0x1 /* Motorola SPI SSPSCLK polarity */
+#define SSCR1_SPO_SHIFT 3
+#define SSCR1_LBM_MASK 0x1 /* Loopback mode: test mode */
+#define SSCR1_LBM_SHIFT 2
+#define SSCR1_TIE_MASK 0x1 /* Transmit FIFO Interrupt Enable */
+#define SSCR1_TIE_SHIFT 1
+#define SSCR1_RIE_MASK 0x1 /* Receive FIFO Interrupt Enable */
+#define SSCR1_RIE_SHIFT 0
+
+#define SSCR1_RxTresh(x) ((x) - 1) /* level [1..16] */
+#define SSCR1_TxTresh(x) ((x) - 1) /* level [1..16] */
+
+#define SSPSP_FSRT_MASK 0x1 /* Frame Sync Relative Timing Bit */
+#define SSPSP_FSRT_SHIFT 25
+#define SSPSP_DMYSTOP_MASK 0x3 /* Dummy Stop in Number of SSPSCLKs=
:T4*/
+#define SSPSP_DMYSTOP_SHIFT 23
+#define SSPSP_SFRMWDTH_MASK 0x3F /* Serial Frame width : T6 */
+#define SSPSP_SFRMWDTH_SHIFT 16
+#define SSPSP_SFRMDLY_MASK 0x7F /* Serial Fr. Delay in 1/2SSPSCLKs:=
T5 */
+#define SSPSP_SFRMDLY_SHIFT 9
+#define SSPSP_DMYSTRT_MASK 0x3 /* Dummy Start in Number of SSPSCLK=
s..*/
+#define SSPSP_DMYSTRT_SHIFT 7 /*...after STRTDLY, T2 (master mode onl=
y) */
+#define SSPSP_STRTDLY_MASK 0x7 /* Start Delay, T1 (master mode onl=
y) */
+#define SSPSP_STRTDLY_SHIFT 4
+#define SSPSP_ETDS_MASK 0x1 /* End of Transfer Data State */
+#define SSPSP_ETDS_SHIFT 3
+#define SSPSP_SFRMP_MASK 0x1 /* Serial Frame Polarity */
+#define SSPSP_SFRMP_SHIFT 2
+#define SSPSP_SCMODE_MASK 0x3 /* Serial bit-rate Clock Mode */
+#define SSPSP_SCMODE_SHIFT 0
+
+#define SSTSA_TTSA_MASK 0xFF
+#define SSTSA_TTSA_SHIFT 0
+
+#define SSRSA_RTSA_MASK 0xFF
+#define SSRSA_RTSA_SHIFT 0
+
+#define SSSR_BCE_MASK 0x1 /* Bit Count Error: Read/Write 1 to Clear */
+#define SSSR_BCE_SHIFT 23
+#define SSSR_CSS_MASK 0x1 /* Clock Synchronization Status */
+#define SSSR_CSS_SHIFT 22
+#define SSSR_TUR_MASK 0x1 /* Transmit FIFO UnderRun: Rd/Wr 1 to Clear=
*/
+#define SSSR_TUR_SHIFT 21
+#define SSSR_EOC_MASK 0x1 /* End Of Chain: Read/Write 1 to Clear */
+#define SSSR_EOC_SHIFT 20
+#define SSSR_TINT_MASK 0x1 /* Receiver Time-out Interrupt:... */
+#define SSSR_TINT_SHIFT 19 /* ...Read/Write 1 to Clear */
+#define SSSR_PINT_MASK 0x1 /* Peripheral Trailing Byte Interrupt:... */
+#define SSSR_PINT_SHIFT 18 /* ...Read/Write 1 to Clear */
+#define SSSR_RFL_MASK 0xF /* Receive FIFO Level */
+#define SSSR_RFL_SHIFT 12
+#define SSSR_TFL_MASK 0xF /* Transmit FIFO Level */
+#define SSSR_TFL_SHIFT 8
+#define SSSR_ROR_MASK 0x1 /* Receive FIFO Overrun: Read/Write 1 to Cl=
ear*/
+#define SSSR_ROR_SHIFT 7
+#define SSSR_RFS_MASK 0x1 /* Receive FIFO Service Request */
+#define SSSR_RFS_SHIFT 6
+#define SSSR_TFS_MASK 0x1 /* Transmit FIFO Service Request */
+#define SSSR_TFS_SHIFT 5
+#define SSSR_BSY_MASK 0x1 /* SSP Busy */
+#define SSSR_BSY_SHIFT 4
+#define SSSR_RNE_MASK 0x1 /* Receive FIFO not empty */
+#define SSSR_RNE_SHIFT 3
+#define SSSR_TFN_MASK 0x1 /* Transmit FIFO not Full */
+#define SSSR_TFN_SHIFT 2
+
+
+#define SSP_OFF 0
+#define SSP_ON 1
+
+/* bit I2S_PORT_OPENED lock for open/close
+ * bit I2S_PORT_READ_BUSY lock for read requests (serialized)
+ * bit I2S_PORT_WRITE_BUSY lock for write requests (serialized)
+ * bit I2S_PORT_CLOSING means close on going, waiting for pending callback=
s.
+ */
+
+enum i2s_flags {
+ I2S_PORT_OPENED,
+ I2S_PORT_WRITE_BUSY,
+ I2S_PORT_READ_BUSY,
+ I2S_PORT_CLOSING
+};
+
+#define FIFO_SIZE 16
+/*
+ * Structures Definition
+ */
+
+/**
+ * struct intel_mid_i2s_data - context struct to keep SSP I2S data
+ * @pdev: pci dev pointer corresponding to context
+ * @paddr:
+ * @ioaddr:
+ * @iolen:
+ * @irq:
+ * @clear_sr:
+ * @mask_sr:
+ * @dmac1:
+ * @dmas_tx: dma slave structure for transmit
+ * @dmas_rx: dma slave structure for receive
+ * @txchan: Dma channel for transmit
+ * @rxchan: Dma channel for receive
+ *
+ * @read_done:
+ * @read_dst:
+ * @read_len:
+ *
+ * @write_done:
+ * @write_src:
+ * @write_len:
+ *
+ * @mutex: a mutex to make sure we have once-at-time critical functions.
+ *
+ * Longer description
+ */
+
+/* Locking rules:
+ *
+ * All the fields, not listed below, are set during probe, and then read o=
nly
+ * So they do not require locking
+ *
+ * The fields that require locking are related to the I2S read and write
+ * requests.
+ *
+ * We allow only 1 read at a time, and 1 write at a time.
+ * We allow read in parallel of write but use separate variables.
+ * We allow only 1 user per SSP/I2S port.
+ * Typically this user will be a dedicated PulseAudio RT thread communicat=
ing
+ * with cmt-speech driver which in turns communicates with intel_mid_ssp
+ * driver.
+ * PCM mixing is done before access to kernel drivers;typically within
+ * PulseAudio or after; typically within the modem.
+ * So no concurrent users, per I2S channel, to this driver are allowed
+ * The read & write are triggered from a USER context
+ * The read & write callbacks are called from a BH context
+ * You should have not callback pending before calling close, close will w=
ait
+ * for remaining callback calls.
+ * It is not allowed to call close function from read/write callback threa=
ds.
+ *
+ * Locking is handled via drv_data->flags & atomic bitwise operations
+ *
+ * I2S0 is dedicated for PCM transfer to/from the modem module
+ * I2S1 is dedicated for PCM transfer to/from the Bluetooth or FM module
+ *
+ * read_done:
+ * read_len:
+ * read_dst:
+ *
+ * write_done:
+ * write_src:
+ * write_len:
+ *
+ * mutex: a mutex to make sure we have once-at-time critical functions.
+ * once-at-a-time actions functions are:
+ * -intel_mid_i2s_open
+ * -intel_mid_i2s_close
+ * -intel_mid_i2s_rd_req
+ * -intel_mid_i2s_wr_req
+ * -intel_mid_i2s_set_rd_cb
+ * -intel_mid_i2s_set_wr_cb
+ * These functions should not be called during a lock() neither in interru=
pt.
+ */
+
+struct intel_mid_i2s_hdl {
+ /* Driver model hookup */
+ struct pci_dev *pdev;
+ /* register addresses */
+ dma_addr_t paddr;
+ void __iomem *ioaddr;
+ u32 iolen;
+ int irq;
+
+ /* SSP masks */
+ u32 clear_sr;
+ u32 mask_sr;
+
+ /* SSP Configuration */
+ /* DMA info */
+ struct pci_dev *dmac1;
+ wait_queue_head_t wq_chan_closing;
+
+ struct intel_mid_dma_slave dmas_tx;
+ struct intel_mid_dma_slave dmas_rx;
+ struct dma_chan *txchan;
+ struct dma_chan *rxchan;
+
+ unsigned int device_instance;
+ /* Call back functions */
+ int (*read_callback)(void *param);
+ dma_addr_t read_dst;
+ size_t read_len; /* read_len > 0 <=3D> read_dma_running */
+ void *read_param; /* context param for callback */
+ int (*write_callback)(void *param);
+ dma_addr_t write_src;
+ size_t write_len; /* write_len > 0 <=3D> read_dma_running */
+ void *write_param; /* context param for callback */
+
+ unsigned long flags;
+ struct mutex mutex;
+ enum intel_mid_i2s_ssp_usage usage;
+
+ struct intel_mid_i2s_settings current_settings;
+
+};
+
+static void i2s_read_done(void *arg);
+static void i2s_write_done(void *arg);
+static bool chan_filter(struct dma_chan *chan, void *param);
+static void i2s_dma_stop(struct intel_mid_i2s_hdl *drv_data);
+static int i2s_dma_start(struct intel_mid_i2s_hdl *drv_data);
+static void ssp1_dump_registers(struct intel_mid_i2s_hdl *);
+static irqreturn_t i2s_int(int irq, void *dev_id);
+static void set_ssp_i2s_hw(struct intel_mid_i2s_hdl *drv_data,
+ const struct intel_mid_i2s_settings *ps_settings);
+static int check_device(struct device *device_ptr, void *data);
+static int intel_mid_i2s_runtime_resume(struct device *device_ptr);
+static int intel_mid_i2s_runtime_suspend(struct device *device_ptr);
+static int intel_mid_i2s_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static void intel_mid_i2s_remove(struct pci_dev *pdev);
+static void i2s_ssp_stop(struct intel_mid_i2s_hdl *drv_data);
+/*static int bt_pcm_dma_init(struct intel_mid_i2s_hdl *drv_data);*/
+
+
+#ifdef CONFIG_PM
+static int intel_mid_i2s_driver_suspend(struct pci_dev *dev,
+ pm_message_t state);
+static int intel_mid_i2s_driver_resume(struct pci_dev *dev);
+#endif
+
+/*
+ * These define will clarify source code when accessing SSCRx registers
+ */
+
+#define SSCR0_reg(regbit, value) \
+ (((value) & SSCR0_##regbit##_MASK) << SSCR0_##regbit##_SHIFT)
+
+#define SSCR1_reg(regbit, value) \
+ (((value) & SSCR1_##regbit##_MASK) << SSCR1_##regbit##_SHIFT)
+
+#define SSPSP_reg(regbit, value) \
+ (((value) & SSPSP_##regbit##_MASK) << SSPSP_##regbit##_SHIFT)
+
+#define SSRSA_reg(regbit, value) \
+ (((value) & SSRSA_##regbit##_MASK) << SSRSA_##regbit##_SHIFT)
+#define SSTSA_reg(regbit, value) \
+ (((value) & SSTSA_##regbit##_MASK) << SSTSA_##regbit##_SHIFT)
+
+
+#define change_SSCR0_reg(reg_pointer, regbit, value) \
+ write_SSCR0((read_SSCR0(reg_pointer) \
+ & (~((SSCR0_##regbit##_MASK << SSCR0_##regbit##_SHIFT)))) \
+ | (((value) & SSCR0_##regbit##_MASK) << SSCR0_##regbit##_SHIFT), \
+ reg_pointer);
+
+#define set_SSCR0_reg(reg_pointer, regbit) \
+ write_SSCR0(read_SSCR0(reg_pointer) \
+ | (SSCR0_##regbit##_MASK << SSCR0_##regbit##_SHIFT), \
+ reg_pointer);
+
+#define clear_SSCR0_reg(reg_pointer, regbit) \
+ write_SSCR0((read_SSCR0(reg_pointer) \
+ & (~((SSCR0_##regbit##_MASK << SSCR0_##regbit##_SHIFT)))), \
+ reg_pointer);
+
+#define change_SSCR1_reg(reg_pointer, regbit, value) \
+ write_SSCR1((read_SSCR1(reg_pointer) \
+ & (~((SSCR1_##regbit##_MASK << SSCR1_##regbit##_SHIFT)))) \
+ | (((value) & SSCR1_##regbit##_MASK) << SSCR1_##regbit##_SHIFT), \
+ reg_pointer);
+
+#define set_SSCR1_reg(reg_pointer, regbit) \
+ write_SSCR1(read_SSCR1(reg_pointer) \
+ | (SSCR1_##regbit##_MASK << SSCR1_##regbit##_SHIFT), \
+ reg_pointer);
+
+#define clear_SSCR1_reg(reg_pointer, regbit) \
+ write_SSCR1((read_SSCR1(reg_pointer) \
+ & (~((SSCR1_##regbit##_MASK << SSCR1_##regbit##_SHIFT)))), \
+ reg_pointer);
+
+/* RX FIFO level */
+#define GET_SSSR_val(x, regb) \
+ ((x & (SSSR_##regb##_MASK<<SSSR_##regb##_SHIFT))>>SSSR_##regb##_SHI=
FT)
+
+
+/*
+ * SSP hardware can be configured as I2S, PCM, SPI...
+ * In order to allow flexibility without modifying the software driver, the
+ * PCI header uses the configuration register 'adid':
+ *
+ * The PCI header associated to SSP devices includes a configuration regis=
ter.
+ * It provides information to a driver which is probed for the SSP, specif=
ying
+ * in which way the SSP is supposed to be used.
+ * Here is the format of this configuration register (8 bits):
+ *
+ * bits 2..0: Mode
+ * 000: Invalid, the register should be ignored
+ * 001: SSP to be used as SPI controller
+ * 010: SSP to be used in I2S/ISS mode
+ * other: Reserved
+ *
+ * bits 5..3: Configuration
+ * In I2S/ISS mode:
+ * 000: Invalid
+ * 001: Bluetooth
+ * 010: Modem
+ * other: Reserved
+ * In SPI mode:
+ * Value is the SPI bus number connected to the SSP.
+ * To be used for registration to the Linux SPI
+ * framework.
+ *
+ * bit 6: SPI slave
+ * Relevant in SPI mode only. If set, indicates the SPI clock
+ * is not provided by the SSP: SPI slave mode.
+ *
+ * bit 7: Reserved (0)
+ *
+ * This configuration register is implemented in the adid field of the
+ * Vendor Specific PCI capability associated to the SSP. The format of
+ * this capability is:
+ *
+ * uint8_t capId; < Capability ID (vendor-specific)
+ * uint8_t nextCap; < Next Item Ptr
+ * uint8_t length; < Size of this capability (7)
+ * uint8_t version; < Version of this capability (1)
+ * uint8_t lss; < Logical subsystem info
+ * Bit 7 =3D PMU (0 =3D NC, 1 =3D =
SC)
+ * Bits 6:0 =3D LSS ID
+ * uint8_t apmc; < Additional PM capabilities
+ * Bit 7 =3D Rsvd
+ * Bit 6 =3D Wake capable
+ * Bit 5 =3D D3 support
+ * Bit 4 =3D D2 support
+ * Bit 3 =3D D1 support
+ * Bit 2 =3D D0i3 support
+ * Bit 1 =3D D0i2 support
+ * Bit 0 =3D D0i1 support
+ * uint8_t adid; < Additional device ID (dev-specific)
+ * uint8_t rsvd; < Reserved for future use
+ *
+ * The capability data are in the PCI configuration space and the
+ * adid field can be modified using BMP tool.
+ */
+/* ADDID =3D Additional Device ID */
+#define PCI_CAP_OFFSET_ADID 6
+
+
--
1.6.6.1
---------------------------------------------------------------------
Intel Corporation SAS (French simplified joint stock company)
Registered headquarters: "Les Montalets"- 2, rue de Paris,=20
92196 Meudon Cedex, France
Registration Number: 302 456 199 R.C.S. NANTERRE
Capital: 4,572,000 Euros
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
--_002_2A84145621092446B6659B8A0F28E26F46FE77084Airsmsx501gerc_
Content-Type: application/octet-stream;
name="0001-New-low-level-driver-Intel_mid_i2s-provide-support-alsa.patch"
Content-Description: 0001-New-low-level-driver-Intel_mid_i2s-provide-support-alsa.patch
Content-Disposition: attachment; filename=
"0001-New-low-level-driver-Intel_mid_i2s-provide-support-alsa.patch";
size=77099; creation-date="Fri, 15 Oct 2010 16:02:59 GMT";
modification-date="Fri, 15 Oct 2010 14:45:31 GMT"
Content-Transfer-Encoding: base64
RnJvbSAxNmRhM2ViZmZhZDAyNmU0NGQ3NDUzOGI3NzczYTUxMDQ0MjU0OTIwIE1vbiBTZXAgMTcg
MDA6MDA6MDAgMjAwMQpGcm9tOiBMb3VpcyBMRSBHQUxMIDxsb3Vpcy5sZS5nYWxsQGludGVsLmNv
bT4KRGF0ZTogRnJpLCAxNSBPY3QgMjAxMCAxNTozMDo0OSArMDIwMApTdWJqZWN0OiBbUEFUQ0hd
IE5ldyBsb3cgbGV2ZWwgZHJpdmVyICJJbnRlbF9taWRfaTJzIiBwcm92aWRlIHN1cHBvcnQgZm9y
IEkyUyBTU1AgZGV2aWNlIG9uIEludGVsIE1JRCBQbGF0Zm9ybXMKIFNpZ25lZC1vZmYtYnk6IExv
dWlzIExFIEdBTEwgPGxvdWlzLmxlLmdhbGxAaW50ZWwuY29tPgoKQ2hhbmdlLUlkOiBJMTcwNTJh
M2I0NjRjNTY4MmQyYWIxN2E5YjZlMGZhZDMwMTM3MjQzZgoKU2lnbmVkLW9mZi1ieTogTG91aXMg
TEUgR0FMTCA8bG91aXMubGUuZ2FsbEBpbnRlbC5jb20+Ci0tLQogaW5jbHVkZS9saW51eC9pbnRl
bF9taWRfaTJzX2lmLmggICAgICAgIHwgIDI4MCArKysrKysKIHNvdW5kL3BjaS9LY29uZmlnICAg
ICAgICAgICAgICAgICAgICAgICB8ICAgMTggKwogc291bmQvcGNpL01ha2VmaWxlICAgICAgICAg
ICAgICAgICAgICAgIHwgICAgNCArLQogc291bmQvcGNpL2ludGVsX21pZF9pMnMvTWFrZWZpbGUg
ICAgICAgIHwgICAxOCArCiBzb3VuZC9wY2kvaW50ZWxfbWlkX2kycy9pbnRlbF9taWRfaTJzLmMg
fCAxNDI4ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIHNvdW5kL3BjaS9pbnRlbF9t
aWRfaTJzL2ludGVsX21pZF9pMnMuaCB8ICA1MDAgKysrKysrKysrKysKIDYgZmlsZXMgY2hhbmdl
ZCwgMjI0NyBpbnNlcnRpb25zKCspLCAxIGRlbGV0aW9ucygtKQogY3JlYXRlIG1vZGUgMTAwNjQ0
IGluY2x1ZGUvbGludXgvaW50ZWxfbWlkX2kyc19pZi5oCiBjcmVhdGUgbW9kZSAxMDA2NDQgc291
bmQvcGNpL2ludGVsX21pZF9pMnMvTWFrZWZpbGUKIGNyZWF0ZSBtb2RlIDEwMDY0NCBzb3VuZC9w
Y2kvaW50ZWxfbWlkX2kycy9pbnRlbF9taWRfaTJzLmMKIGNyZWF0ZSBtb2RlIDEwMDY0NCBzb3Vu
ZC9wY2kvaW50ZWxfbWlkX2kycy9pbnRlbF9taWRfaTJzLmgKCmRpZmYgLS1naXQgYS9pbmNsdWRl
L2xpbnV4L2ludGVsX21pZF9pMnNfaWYuaCBiL2luY2x1ZGUvbGludXgvaW50ZWxfbWlkX2kyc19p
Zi5oCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAuLjE1NjM1NzcKLS0tIC9kZXYv
bnVsbAorKysgYi9pbmNsdWRlL2xpbnV4L2ludGVsX21pZF9pMnNfaWYuaApAQCAtMCwwICsxLDI4
MCBAQAorLyoKKyAgKiA8RHJpdmVyIGZvciBJMlMgcHJvdG9jb2wgb24gU1NQIChNb29yZXN0b3du
IGFuZCBNZWRmaWVsZCBoYXJkd2FyZSk+CisgICogQ29weXJpZ2h0IChjKSAyMDEwLCBJbnRlbCBD
b3Jwb3JhdGlvbi4KKyAgKiBMb3VpcyBMRSBHQUxMIDxsb3Vpcy5sZS5nYWxsIGludGVsLmNvbT4K
KyAgKgorICAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJp
YnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0CisgICogdW5kZXIgdGhlIHRlcm1zIGFuZCBjb25kaXRp
b25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSwKKyAgKiB2ZXJzaW9uIDIsIGFz
IHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLgorICAqCisgICogVGhp
cyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIGl0IHdpbGwgYmUgdXNlZnVsLCBi
dXQgV0lUSE9VVAorICAqIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdh
cnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWSBvcgorICAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxB
UiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IKKyAgKiBt
b3JlIGRldGFpbHMuCisgICoKKyAgKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9m
IHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoCisgICogdGhpcyBwcm9n
cmFtOyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIEluYy4s
CisgICogNTEgRnJhbmtsaW4gU3QgLSBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAwMjExMC0xMzAx
IFVTQS4KKyAgKi8KKworI2lmbmRlZiBNSURfSTJTX0VYVEVSTkFMX0hfCisjZGVmaW5lIE1JRF9J
MlNfRVhURVJOQUxfSF8KKworI2luY2x1ZGUgPGxpbnV4L3BjaS5oPgorI2luY2x1ZGUgPGxpbnV4
L2RtYS1tYXBwaW5nLmg+CisjaW5jbHVkZSA8bGludXgvaW50ZWxfbWlkX2RtYS5oPgorCisjaW5j
bHVkZSA8bGludXgvaW50ZXJydXB0Lmg+CisKKy8qCisgKglTdHJ1Y3R1cmVzIERlZmluaXRpb24K
KyAqLworCisKKy8qCisgKglTU0NSMCBzZXR0aW5ncworICovCitlbnVtIG1yc3Rfc3NwX21vZGUg
eworCVNTUF9JTl9OT1JNQUxfTU9ERSA9IDB4MCwKKwlTU1BfSU5fTkVUV09SS19NT0RFCit9Owor
CitlbnVtIG1yc3Rfc3NwX3J4X2ZpZm9fb3Zlcl9ydW5faW50X21hc2sgeworCVNTUF9SWF9GSUZP
X09WRVJfSU5UX0VOQUJMRSA9IDB4MCwKKwlTU1BfUlhfRklGT19PVkVSX0lOVF9ESVNBQkxFCit9
OworCitlbnVtIG1yc3Rfc3NwX3R4X2ZpZm9fdW5kZXJfcnVuX2ludF9tYXNrIHsKKwlTU1BfVFhf
RklGT19VTkRFUl9JTlRfRU5BQkxFID0gMHgwLAorCVNTUF9UWF9GSUZPX1VOREVSX0lOVF9ESVNB
QkxFCit9OworCitlbnVtIG1yc3Rfc3NwX2ZyYW1lX2Zvcm1hdCB7CisJTU9UT1JPTEFfU1BJX0ZP
Uk1BVCA9IDB4MCwKKwlUSV9TU1BfRk9STUFULAorCU1JQ1JPV0lSRV9GT1JNQVQsCisJUFNQX0ZP
Uk1BVAorCit9OworCitlbnVtIG1yc3Rfc3NwX21hc3Rlcl9tb2RlX2Nsb2NrX3NlbGVjdGlvbiB7
CisJU1NQX09OQ0hJUF9DTE9DSyA9IDB4MCwKKwlTU1BfTkVUV09SS19DTE9DSywKKwlTU1BfRVhU
RVJOQUxfQ0xPQ0ssCisJU1NQX09OQ0hJUF9BVURJT19DTE9DSywKKwlTU1BfTUFTVEVSX0NMT0NL
X1VOREVGSU5FRCA9IDB4RkYKK307CisKKy8qCisgKglTU0NSMSBzZXR0aW5ncworICovCitlbnVt
IG1yc3Rfc3NwX3R4ZF90cmlzdGF0ZV9sYXN0X3BoYXNlIHsKKwlUWERfVFJJU1RBVEVfTEFTVF9Q
SEFTRV9PRkYgPSAgMHgwLAorCVRYRF9UUklTVEFURV9MQVNUX1BIQVNFX09OCit9OworCitlbnVt
IG1yc3Rfc3NwX3R4ZF90cmlzdGF0ZV9lbmFibGUgeworCVRYRF9UUklTVEFURV9PRkYgPSAgMHgw
LAorCVRYRF9UUklTVEFURV9PTgorfTsKKworZW51bSBtcnN0X3NzcF9zbGF2ZV9zc3BjbGtfZnJl
ZV9ydW5uaW5nIHsKKwlTTEFWRV9TU1BDTEtfT05fQUxXQVlTID0gIDB4MCwKKwlTTEFWRV9TU1BD
TEtfT05fRFVSSU5HX1RSQU5TRkVSX09OTFkKK307CisKK2VudW0gbXJzdF9zc3Bfc3Nwc2Nsa19k
aXJlY3Rpb24geworCVNTUFNDTEtfTUFTVEVSX01PREUgPSAweDAsCisJU1NQU0NMS19TTEFWRV9N
T0RFCit9OworCitlbnVtIG1yc3Rfc3NwX3NzcHNmcm1fZGlyZWN0aW9uIHsKKwlTU1BTRlJNX01B
U1RFUl9NT0RFID0gMHgwLAorCVNTUFNGUk1fU0xBVkVfTU9ERQorfTsKKworZW51bSBtcnN0X3Nz
cF9yeF93aXRob3V0X3R4IHsKKwlSWF9BTkRfVFhfTU9ERSA9IDB4MCwKKwlSWF9XSVRIT1VUX1RY
X01PREUKK307CisKK2VudW0gbXJzdF90cmFpbGluZ19ieXRlX21vZGUgeworCVNTUF9UUkFJTElO
R19CWVRFX0hETF9CWV9JQSA9IDB4MCwKKwlTU1BfVFJBSUxJTkdfQllURV9IRExfQllfRE1BCit9
OworCitlbnVtIG1yc3Rfc3NwX3R4X2RtYV9zdGF0dXMgeworCVNTUF9UWF9ETUFfTUFTSyA9IDB4
MCwKKwlTU1BfVFhfRE1BX0VOQUJMRQorfTsKKworZW51bSBtcnN0X3NzcF9yeF9kbWFfc3RhdHVz
IHsKKwlTU1BfUlhfRE1BX01BU0sgPSAweDAsCisJU1NQX1JYX0RNQV9FTkFCTEUKK307CisKK2Vu
dW0gbXJzdF9zc3BfcnhfdGltZW91dF9pbnRfc3RhdHVzIHsKKwlTU1BfUlhfVElNRU9VVF9JTlRf
RElTQUJMRSA9IDB4MCwKKwlTU1BfUlhfVElNRU9VVF9JTlRfRU5BQkxFCit9OworCitlbnVtIG1y
c3Rfc3NwX3RyYWlsaW5nX2J5dGVfaW50X3N0YXR1cyB7CisJU1NQX1RSQUlMSU5HX0JZVEVfSU5U
X0RJU0FCTEUgPSAweDAsCisJU1NQX1RSQUlMSU5HX0JZVEVfSU5UX0VOQUJMRQorfTsKKworZW51
bSBtcnN0X3NzcF9sb29wYmFja19tb2RlX3N0YXR1cyB7CisJU1NQX0xPT1BCQUNLX09GRiA9IDB4
MCwKKwlTU1BfTE9PUEJBQ0tfT04KK307CisKKworLyoKKyAqCVNTUFNQIHNldHRpbmdzOiBmb3Ig
UFNQIEZvcm1hdCBPTkxZISEhISEhISEKKyAqLworCitlbnVtIG1yc3Rfc3NwX2ZyYW1lX3N5bmNf
cmVsYXRpdmVfdGltaW5nX2JpdCB7CisJTkVYVF9GUk1TX0FTU19BRlRFUl9FTkRfT0ZfVDQgPSAg
MHgwLAorCU5FWFRfRlJNU19BU1NfV0lUSF9MU0JfUFJFVklPVVNfRlJNCit9OworCitlbnVtIG1y
c3Rfc3NwX2ZyYW1lX3N5bmNfcG9sYXJpdHlfYml0IHsKKwlTU1BfRlJNU19BQ1RJVkVfTE9XID0g
IDB4MCwKKwlTU1BfRlJNU19BQ1RJVkVfSElHSAorfTsKKworZW51bSBtcnN0X3NzcF9lbmRfb2Zf
dHJhbnNmZXJfZGF0YV9zdGF0ZSB7CisJU1NQX0VORF9EQVRBX1RSQU5TRkVSX1NUQVRFX0xPVyA9
IDB4MCwKKwlTU1BfRU5EX0RBVEFfVFJBTlNGRVJfU1RBVEVfUEVWSU9VU19CSVQKK307CisKK2Vu
dW0gbXJzdF9zc3BfY2xrX21vZGUgeworCVNTUF9DTEtfTU9ERV8wID0gMHgwLAorCVNTUF9DTEtf
TU9ERV8xLAorCVNTUF9DTEtfTU9ERV8yLAorCVNTUF9DTEtfTU9ERV8zCit9OworCisKKy8qCisg
KglsaXN0IG9mIGRpZmZlcmVudHMgdHlwZXMgb2YgU1NQLCB2YWx1ZSBkZXBlbmRzIG9mIGFkaWQg
ZW50cnkgb2YKKyAqCWNhcGFiaWxpdHkgSUQgb2YgdGhlIFBDSQorICovCisKKy8qCisgKgorICog
VGhlIFBDSSBoZWFkZXIgYXNzb2NpYXRlZCB0byBTU1AgZGV2aWNlcyBub3cgaW5jbHVkZXMgYSBj
b25maWd1cmF0aW9uCisgKiByZWdpc3Rlci4gSXQgcHJvdmlkZXMgaW5mb3JtYXRpb24gdG8gYSBk
cml2ZXIgd2hpY2ggaXMgcHJvYmVkIGZvciB0aGUKKyAqIFNTUCwgc3BlY2lmeWluZyBpbiB3aGlj
aCB3YXkgdGhlIFNTUCBpcyBzdXBwb3NlZCB0byBiZSB1c2VkLiBIZXJlIGlzCisgKiB0aGUgZm9y
bWF0IG9mIHRoaXMgYnl0ZSByZWdpc3RlcjoKKyAqCisgKgliaXRzIDIuLjA6IE1vZGUKKyAqCQkw
MDA9MHgwIDogSW52YWxpZCwgdGhlIHJlZ2lzdGVyIHNob3VsZCBiZSBpZ25vcmVkCisgKgkJMDAx
PTB4MSA6IFNTUCB0byBiZSB1c2VkIGFzIFNQSSBjb250cm9sbGVyCisgKgkJMDEwPTB4MjogU1NQ
IHRvIGJlIHVzZWQgaW4gSTJTL0lTUyBtb2RlCisgKgkJb3RoZXI6IFJlc2VydmVkCisgKgorICoJ
Yml0cyA1Li4zOiBDb25maWd1cmF0aW9uCisgKglJbiBJMlMvSVNTIG1vZGU6CisgKgkJMDAwPTB4
MDogSW52YWxpZAorICoJCTAwMT0weDE6IEJsdWV0b290aAorICoJCTAxMD0weDI6IE1vZGVtCisg
KgkJb3RoZXI6IFJlc2VydmVkCisgKglJbiBTUEkgbW9kZToKKyAqCQlWYWx1ZSBpcyB0aGUgU1BJ
IGJ1cyBudW1iZXIgY29ubmVjdGVkIHRvIHRoZSBTU1AuCisgKgkJVG8gYmUgdXNlZCBmb3IgcmVn
aXN0cmF0aW9uIHRvIHRoZSBMaW51eCBTUEkKKyAqCQlmcmFtZXdvcmsuCisgKgliaXQgNjogU1BJ
IHNsYXZlCisgKglSZWxldmFudCBpbiBTUEkgbW9kZSBvbmx5LiBJZiBzZXQsIGluZGljYXRlcyB0
aGUgU1BJIGNsb2NrCisgKglpcyBub3QgcHJvdmlkZWQgYnkgdGhlIFNTUDogU1BJIHNsYXZlIG1v
ZGUuCisgKgorICoJYml0IDc6IFJlc2VydmVkICgwKQorICoKKyAqIFRoaXMgY29uZmlndXJhdGlv
biByZWdpc3RlciBpcyBpbXBsZW1lbnRlZCBpbiB0aGUgYWRpZCBmaWVsZCBvZiB0aGUKKyAqIFZl
bmRvciBTcGVjaWZpYyBQQ0kgY2FwYWJpbGl0eSBhc3NvY2lhdGVkIHRvIHRoZSBTU1AuCisgKgor
ICovCisKKyNkZWZpbmUgUENJX0FESURfU1NQX01PREVfU1BJICAoMSkKKyNkZWZpbmUgUENJX0FE
SURfU1NQX01PREVfSTJTICAoMikKKworI2RlZmluZSBQQ0lfQURJRF9TU1BfQ09ORl9CVF9GTSAg
KDE8PDMpCisjZGVmaW5lIFBDSV9BRElEX1NTUF9DT05GX01PREVNICAoMjw8MykKKworCisjZGVm
aW5lIFBDSV9DQVBfQURJRF9JMlNfQlRfRk0gICgoUENJX0FESURfU1NQX0NPTkZfQlRfRk0pIHwg
KFBDSV9BRElEX1NTUF9NT0RFX0kyUykpCisjZGVmaW5lIFBDSV9DQVBfQURJRF9JMlNfTU9ERU0g
ICgoUENJX0FESURfU1NQX0NPTkZfTU9ERU0pIHwgKFBDSV9BRElEX1NTUF9NT0RFX0kyUykpCisK
K2VudW0gaW50ZWxfbWlkX2kyc19zc3BfdXNhZ2UgeworCVNTUF9VU0FHRV9VTkFTU0lHTkVEID0g
MHgwMCwKKwlTU1BfVVNBR0VfQkxVRVRPT1RIX0ZNID0gMHgwMSwKKwlTU1BfVVNBR0VfTU9ERU0g
PSAweDAyCit9OworCisvKgorICoJU3RydWN0dXJlIHVzZWQgdG8gY29uZmlndXJlIHRoZSBTU1Ag
UG9ydAorICoJUGxlYXNlIG5vdGUgdGhhdCBvbmx5IHRoZSBQU1AgZm9ybWF0IGFuZCB0aGUgRE1B
IHRyYW5zZmVyIGFyZSBzdXBwb3J0ZWQKKyAqLworCitzdHJ1Y3QgaW50ZWxfbWlkX2kyc19zZXR0
aW5ncyB7CisJZW51bSBtcnN0X3NzcF9tb2RlICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGU7
CisJZW51bSBtcnN0X3NzcF9yeF9maWZvX292ZXJfcnVuX2ludF9tYXNrICAgIHJ4X2ZpZm9faW50
ZXJydXB0OworCWVudW0gbXJzdF9zc3BfdHhfZmlmb191bmRlcl9ydW5faW50X21hc2sgICB0eF9m
aWZvX2ludGVycnVwdDsKKwllbnVtIG1yc3Rfc3NwX2ZyYW1lX2Zvcm1hdCAgICAgICAgICAgICAg
ICAgZnJhbWVfZm9ybWF0OworCWVudW0gbXJzdF9zc3BfbWFzdGVyX21vZGVfY2xvY2tfc2VsZWN0
aW9uICBtYXN0ZXJfbW9kZV9jbGtfc2VsZWN0aW9uOyAgICAgICAgICAgICAgLyogZm9yIE1hc3Rl
ciBNb2RlIE9ubHkgKi8KKwl1OCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgZnJhbWVfcmF0ZV9kaXZpZGVyX2NvbnRyb2w7CisJdTE2ICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIG1hc3Rlcl9tb2RlX3NlcmlhbF9jbG9ja19yYXRlOyAgICAgICAg
ICAvKiBmb3IgTWFzdGVyIE1vZGUgT25seSAqLworCXUxNiAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICBkYXRhX3NpemU7CisKKwllbnVtIG1yc3Rfc3NwX3R4ZF90cmlzdGF0
ZV9sYXN0X3BoYXNlICAgICAgdHhfdHJpc3RhdGVfcGhhc2U7CisJZW51bSBtcnN0X3NzcF90eGRf
dHJpc3RhdGVfZW5hYmxlICAgICAgICAgIHR4X3RyaXN0YXRlX2VuYWJsZTsKKwllbnVtIG1yc3Rf
c3NwX3NsYXZlX3NzcGNsa19mcmVlX3J1bm5pbmcgICAgc2xhdmVfY2xrX2ZyZWVfcnVubmluZ19z
dGF0dXM7CisJZW51bSBtcnN0X3NzcF9zc3BzY2xrX2RpcmVjdGlvbiAgICAgICAgICAgIHNzcHNs
Y2xrX2RpcmVjdGlvbjsKKwllbnVtIG1yc3Rfc3NwX3NzcHNmcm1fZGlyZWN0aW9uICAgICAgICAg
ICAgc3Nwc2ZybV9kaXJlY3Rpb247CisJZW51bSBtcnN0X3NzcF9yeF93aXRob3V0X3R4ICAgICAg
ICAgICAgICAgIHNzcF9kdXBsZXhfbW9kZTsKKwllbnVtIG1yc3RfdHJhaWxpbmdfYnl0ZV9tb2Rl
ICAgICAgICAgICAgICAgc3NwX3RyYWlsaW5nX2J5dGVfbW9kZTsKKwllbnVtIG1yc3Rfc3NwX3R4
X2RtYV9zdGF0dXMgICAgICAgICAgICAgICAgc3NwX3R4X2RtYTsKKwllbnVtIG1yc3Rfc3NwX3J4
X2RtYV9zdGF0dXMgICAgICAgICAgICAgICAgc3NwX3J4X2RtYTsKKwllbnVtIG1yc3Rfc3NwX3J4
X3RpbWVvdXRfaW50X3N0YXR1cyAgICAgICAgc3NwX3J4X3RpbWVvdXRfaW50ZXJydXB0X3N0YXR1
czsKKwllbnVtIG1yc3Rfc3NwX3RyYWlsaW5nX2J5dGVfaW50X3N0YXR1cyAgICAgc3NwX3RyYWls
aW5nX2J5dGVfaW50ZXJydXB0X3N0YXR1czsKKwllbnVtIG1yc3Rfc3NwX2xvb3BiYWNrX21vZGVf
c3RhdHVzICAgICAgICAgc3NwX2xvb3BiYWNrX21vZGVfc3RhdHVzOworCXU4ICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzc3BfcnhfZmlmb190aHJlc2hvbGQ7CisJdTgg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcF90eF9maWZvX3RocmVz
aG9sZDsKKworCisJZW51bSBtcnN0X3NzcF9mcmFtZV9zeW5jX3JlbGF0aXZlX3RpbWluZ19iaXQg
IHNzcF9mcm1zeW5jX3RpbWluZ19iaXQ7CisJZW51bSBtcnN0X3NzcF9mcmFtZV9zeW5jX3BvbGFy
aXR5X2JpdCAgICAgIHNzcF9mcm1zeW5jX3BvbF9iaXQ7CisJZW51bSBtcnN0X3NzcF9lbmRfb2Zf
dHJhbnNmZXJfZGF0YV9zdGF0ZSAgIHNzcF9lbmRfdHJhbnNmZXJfc3RhdGU7CisJZW51bSBtcnN0
X3NzcF9jbGtfbW9kZSAgICAgICAgICAgICAgICAgICAgIHNzcF9zZXJpYWxfY2xrX21vZGU7CisJ
dTggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcF9wc3BfVDE7CisJ
dTggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcF9wc3BfVDI7CisJ
dTggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcF9wc3BfVDQ7ICAg
LyogRE1ZU1RPUCAqLworCXU4ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBzc3BfcHNwX1Q1OyAgIC8qIFNGUk1ETFkgKi8KKwl1OCAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgc3NwX3BzcF9UNjsgICAvKiBTRlJNV0RUSCAqLworCisJdTggICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcF9hY3RpdmVfdHhfc2xvdHNf
bWFwOworCXU4ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzc3BfYWN0
aXZlX3J4X3Nsb3RzX21hcDsKK307CisKKy8qCisgKglQcm92aWRlZCBJbnRlcmZhY2UKKyAqLwor
CisKK3N0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqaW50ZWxfbWlkX2kyc19vcGVuKGVudW0gaW50
ZWxfbWlkX2kyc19zc3BfdXNhZ2UgdXNhZ2UsIGNvbnN0IHN0cnVjdCBpbnRlbF9taWRfaTJzX3Nl
dHRpbmdzICpwc19zZXR0aW5ncyk7Cit2b2lkICBpbnRlbF9taWRfaTJzX2Nsb3NlKHN0cnVjdCBp
bnRlbF9taWRfaTJzX2hkbCAqaGFuZGxlKTsKKworaW50IGludGVsX21pZF9pMnNfcmRfcmVxKHN0
cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqaGFuZGxlLCB1MzIgKmRzdCwgc2l6ZV90IGxlbiwgdm9p
ZCAqcGFyYW0pOworaW50IGludGVsX21pZF9pMnNfd3JfcmVxKHN0cnVjdCBpbnRlbF9taWRfaTJz
X2hkbCAqaGFuZGxlLCB1MzIgKnNyYywgc2l6ZV90IGxlbiwgdm9pZCAqcGFyYW0pOworaW50IGlu
dGVsX21pZF9pMnNfZW5hYmxlX3NzcChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmhhbmRsZSk7
CisKKworaW50IGludGVsX21pZF9pMnNfc2V0X3dyX2NiKHN0cnVjdCBpbnRlbF9taWRfaTJzX2hk
bCAqaGFuZGxlLCBpbnQgKCp3cml0ZV9jYWxsYmFjaykodm9pZCAqcGFyYW0pKTsKK2ludCBpbnRl
bF9taWRfaTJzX3NldF9yZF9jYihzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmhhbmRsZSwgaW50
ICgqcmVhZF9jYWxsYmFjaykodm9pZCAqcGFyYW0pKTsKKworCitpbnQgaW50ZWxfbWlkX2kyc19n
ZXRfdHhfZmlmb19sZXZlbChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmhhbmRsZSk7CitpbnQg
aW50ZWxfbWlkX2kyc19nZXRfcnhfZmlmb19sZXZlbChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmhhbmRsZSk7CitpbnQgaW50ZWxfbWlkX2kyc19mbHVzaChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19o
ZGwgKmhhbmRsZSk7CisKKyNlbmRpZiAvKk1JRF9JMlNfRVhURVJOQUxfSF8qLwpkaWZmIC0tZ2l0
IGEvc291bmQvcGNpL0tjb25maWcgYi9zb3VuZC9wY2kvS2NvbmZpZwppbmRleCAxMmUzNDY1Li4w
YjBhNTI0IDEwMDY0NAotLS0gYS9zb3VuZC9wY2kvS2NvbmZpZworKysgYi9zb3VuZC9wY2kvS2Nv
bmZpZwpAQCAtODUzLDQgKzg1MywyMiBAQCBjb25maWcgU05EX1lNRlBDSQogCSAgVG8gY29tcGls
ZSB0aGlzIGRyaXZlciBhcyBhIG1vZHVsZSwgY2hvb3NlIE0gaGVyZTogdGhlIG1vZHVsZQogCSAg
d2lsbCBiZSBjYWxsZWQgc25kLXltZnBjaS4KIAorY29uZmlnIFNORF9JTlRFTF9NSURfSTJTCisJ
dHJpc3RhdGUgIkludGVsIG1pZCBJMlMgaGFyZHdhcmUgZHJpdmVyIgorCWRlcGVuZHMgb24gRVhQ
RVJJTUVOVEFMICYmIFBDSSAmJiBJTlRFTF9NSURfRE1BQworCWRlZmF1bHQgbgorCWhlbHAKKwkg
IFNheSBZIGhlcmUgaWYgeW91IHdhbnQgdG8gYnVpbGQgbG93IGxldmVsIGRyaXZlciB0byBzdXBw
b3J0CisJICBzZW5kaW5nL3JlY2V2aW5nIEkyUyBhdWRpbyBzYW1wbGVzIG9uIEludGVsIE1JRCBT
U1AgZGV2aWNlLgorCSAgVGhpcyBpbnRlcmZhY2UgaXMgbW9zdGx5IHVzZWQgb24gSW50ZWwgTUlE
IHBsYXRmb3JtcyBhbmQgcHJvdmlkZQorCSAgdGhlIGxvdyBsZXZlbCBpbnRlcmZhY2UgZm9yIHNv
bWUgdXBwZXIgbGF5ZXIgZHJpdmVycyBzdWNoIGFzCisJICBBbHNhIFNvQywgY2hhciBkZXZpY2Ug
aW50ZXJmYWNlcy4uLiBkZXBlbmRpbmcgb2YgcGVyaXBoZXJhbCBjb25uZWN0ZWQuCisJICBQQ0kg
SGVhZGVyIHNob3VsZCBoYXZlIEFESUQgZmllbGQgc2V0IHRvIEkyUyBCVF9GTSBvciAKKwkgIEky
UyBNT0RFTSB0byBiZSB1c2VkIGJ5IHRoaXMgZHJpdmVyIChzbyBpdCBrbm93IGNvbm5lY3RlZCBw
ZXJpcGhlcmFsKS4KKwkgIE5vdGUgdGhpcyBpcyBhIHByb3RvdHlwZSBkcml2ZXIgYW5kIHN1cHBv
cnQgZm9yIGNvbnRpbnVvdXMKKwkgIGZsb3cgaXMgc3RpbGwgd29ya2luZy1pbi1wcm9ncmVzcy4K
KwkgIFRoaXMgZHJpdmVyIGNhbiBhbHNvIGJlIGJ1aWx0IGFzIGEgbW9kdWxlLiBJZiBzbywgdGhl
IG1vZHVsZQorCSAgd2lsbCBiZSBjYWxsZWQgaW50ZWxfbWlkX2kycy5rbworCSAgSWYgdW5zdXJl
LCBzYXkgTiBoZXJlLgorCiBlbmRpZgkjIFNORF9QQ0kKZGlmZiAtLWdpdCBhL3NvdW5kL3BjaS9N
YWtlZmlsZSBiL3NvdW5kL3BjaS9NYWtlZmlsZQppbmRleCA5Y2Y0MzQ4Li40NjYxM2EyIDEwMDY0
NAotLS0gYS9zb3VuZC9wY2kvTWFrZWZpbGUKKysrIGIvc291bmQvcGNpL01ha2VmaWxlCkBAIC03
OCw0ICs3OCw2IEBAIG9iai0kKENPTkZJR19TTkQpICs9IFwKIAlybWU5NjUyLyBcCiAJdHJpZGVu
dC8gXAogCXltZnBjaS8gXAotCXZ4MjIyLworCXZ4MjIyLyBcCisJaW50ZWxfbWlkX2kycy8KKwpk
aWZmIC0tZ2l0IGEvc291bmQvcGNpL2ludGVsX21pZF9pMnMvTWFrZWZpbGUgYi9zb3VuZC9wY2kv
aW50ZWxfbWlkX2kycy9NYWtlZmlsZQpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAw
Li5iZWJhYzFjCi0tLSAvZGV2L251bGwKKysrIGIvc291bmQvcGNpL2ludGVsX21pZF9pMnMvTWFr
ZWZpbGUKQEAgLTAsMCArMSwxOCBAQAorIyBTU1AgYXVkaW8gZHJpdmVyCisjIENvcHlyaWdodCAo
YykgMjAxMCwgSW50ZWwgQ29ycG9yYXRpb24uCisKKyMgVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29m
dHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXQKKyMgdW5kZXIg
dGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5z
ZSwKKyMgdmVyc2lvbiAyLCBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRh
dGlvbi4KKworIyBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgaXQgd2ls
bCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUCisjIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRo
ZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWSBvcgorIyBGSVRORVNTIEZPUiBB
IFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2Ug
Zm9yCisjIG1vcmUgZGV0YWlscy4KKworIyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5
IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoCisjIHRoaXMgcHJv
Z3JhbTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBJbmMu
LAorIyA1MSBGcmFua2xpbiBTdCAtIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BIDAyMTEwLTEzMDEg
VVNBLgorCitvYmotJChDT05GSUdfU05EX0lOVEVMX01JRF9JMlMpICAgICs9ICBpbnRlbF9taWRf
aTJzLm8KKwpkaWZmIC0tZ2l0IGEvc291bmQvcGNpL2ludGVsX21pZF9pMnMvaW50ZWxfbWlkX2ky
cy5jIGIvc291bmQvcGNpL2ludGVsX21pZF9pMnMvaW50ZWxfbWlkX2kycy5jCm5ldyBmaWxlIG1v
ZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAuLjU3MmFiZGUKLS0tIC9kZXYvbnVsbAorKysgYi9zb3Vu
ZC9wY2kvaW50ZWxfbWlkX2kycy9pbnRlbF9taWRfaTJzLmMKQEAgLTAsMCArMSwxNDI4IEBACisv
KgorICAqIDxEcml2ZXIgZm9yIEkyUyBwcm90b2NvbCBvbiBTU1AgKE1vb3Jlc3Rvd24gYW5kIE1l
ZGZpZWxkIGhhcmR3YXJlKT4KKyAgKiBDb3B5cmlnaHQgKGMpIDIwMTAsIEludGVsIENvcnBvcmF0
aW9uLgorICAqIExvdWlzIExFIEdBTEwgPGxvdWlzLmxlLmdhbGwgaW50ZWwuY29tPgorICAqCisg
ICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0
IGFuZC9vciBtb2RpZnkgaXQKKyAgKiB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2Yg
dGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLAorICAqIHZlcnNpb24gMiwgYXMgcHVibGlz
aGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24uCisgICoKKyAgKiBUaGlzIHByb2dy
YW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRI
T1VUCisgICogQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW5wIHRoZSBpbXBsaWVkIHdhcnJhbnR5
IG9mIE1FUkNIQU5UQUJJTElUWSBvcgorICAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQ
T1NFLiAgU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IKKyAgKiBtb3JlIGRl
dGFpbHMuCisgICoKKyAgKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBH
TlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoCisgICogdGhpcyBwcm9ncmFtOyBp
ZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIEluYy4sCisgICog
NTEgRnJhbmtsaW4gU3QgLSBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAwMjExMC0xMzAxIFVTQS4K
KyAgKi8KKyNpbmNsdWRlIDxsaW51eC9wY2kuaD4KKyNpbmNsdWRlIDxsaW51eC9kbWEtbWFwcGlu
Zy5oPgorI2luY2x1ZGUgPGxpbnV4L2ludGVycnVwdC5oPgorI2luY2x1ZGUgPGxpbnV4L3BtX3J1
bnRpbWUuaD4KKyNpbmNsdWRlIDxsaW51eC9wY2lfcmVncy5oPgorI2luY2x1ZGUgPGxpbnV4L3dh
aXQuaD4KKyNpbmNsdWRlIDxsaW51eC9pbnRlcnJ1cHQuaD4KKyNpbmNsdWRlIDxsaW51eC9zY2hl
ZC5oPgorCisjaW5jbHVkZSA8bGludXgvZGV2aWNlLmg+CisKKyNpbmNsdWRlIDxsaW51eC9pbnRl
bF9taWRfaTJzX2lmLmg+CisjaW5jbHVkZSAiaW50ZWxfbWlkX2kycy5oIgorCitNT0RVTEVfQVVU
SE9SKCJMb3VpcyBMRSBHQUxMIDxsb3Vpcy5sZS5nYWxsIGludGVsLmNvbT4iKTsKK01PRFVMRV9E
RVNDUklQVElPTigiSW50ZWwgTUlEIEkyUy9QQ00gU1NQIERyaXZlciIpOworTU9EVUxFX0xJQ0VO
U0UoIkdQTCIpOworTU9EVUxFX1ZFUlNJT04oIjEuMC4wIik7CisKKworLyoKKyAqIHN0cnVjdHVy
ZXMgZm9yIHBjaSBwcm9iaW5nCisgKi8KK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZGV2X3BtX29wcyBp
bnRlbF9taWRfaTJzX3BtX29wcyA9IHsKKwkucnVudGltZV9zdXNwZW5kID0gaW50ZWxfbWlkX2ky
c19ydW50aW1lX3N1c3BlbmQsCisJLnJ1bnRpbWVfcmVzdW1lID0gaW50ZWxfbWlkX2kyc19ydW50
aW1lX3Jlc3VtZSwKK307CitzdGF0aWMgREVGSU5FX1BDSV9ERVZJQ0VfVEFCTEUocGNpX2lkcykg
PSB7CisJeyBQQ0lfREVWSUNFKFBDSV9WRU5ET1JfSURfSU5URUwsIE1GTERfU1NQMV9ERVZJQ0Vf
SUQpIH0sCisJeyBQQ0lfREVWSUNFKFBDSV9WRU5ET1JfSURfSU5URUwsIE1GTERfU1NQMF9ERVZJ
Q0VfSUQpIH0sCisJeyAwLCB9LCAvKiB0ZXJtaW5hdGUgbGlzdCAqLworfTsKK3N0YXRpYyBzdHJ1
Y3QgcGNpX2RyaXZlciBpbnRlbF9taWRfaTJzX2RyaXZlciA9IHsKKwkuZHJpdmVyID0geworCQku
cG0gPSAmaW50ZWxfbWlkX2kyc19wbV9vcHMsCisJfSwKKwkubmFtZSA9IERSSVZFUl9OQU1FLAor
CS5pZF90YWJsZSA9IHBjaV9pZHMsCisJLnByb2JlID0gaW50ZWxfbWlkX2kyc19wcm9iZSwKKwku
cmVtb3ZlID0gX19kZXZleGl0X3AoaW50ZWxfbWlkX2kyc19yZW1vdmUpLAorI2lmZGVmIENPTkZJ
R19QTQorCS5zdXNwZW5kID0gaW50ZWxfbWlkX2kyc19kcml2ZXJfc3VzcGVuZCwKKwkucmVzdW1l
ID0gaW50ZWxfbWlkX2kyc19kcml2ZXJfcmVzdW1lLAorI2VuZGlmCit9OworCisKKy8qCisgKiBQ
T1dFUiBNQU5BR0VNRU5UIEZVTkNUSU9OUworICovCisKKyNpZmRlZiBDT05GSUdfUE0KKy8qKgor
ICogaW50ZWxfbWlkX2kyc19kcml2ZXJfc3VzcGVuZCAtIGRyaXZlciBwb3dlciBtYW5hZ2VtZW50
IHN1c3BlbmQgYWN0aXZpdHkKKyAqIEBkZXZpY2VfcHRyIDogcG9pbnRlciBvZiB0aGUgZGV2aWNl
IHRvIHJlc3VtZQorICoKKyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIGVycm9yIDogMCBt
ZWFucyBubyBlcnJvcgorICovCitzdGF0aWMgaW50ICBpbnRlbF9taWRfaTJzX2RyaXZlcl9zdXNw
ZW5kKHN0cnVjdCBwY2lfZGV2ICpkZXYsIHBtX21lc3NhZ2VfdCBzdGF0ZSkKK3sKKwlzdHJ1Y3Qg
aW50ZWxfbWlkX2kyc19oZGwgKmRydl9kYXRhID0gcGNpX2dldF9kcnZkYXRhKGRldik7CisJV0FS
TighZHJ2X2RhdGEsICJEcml2ZXIgZGF0YT1OVUxMXG4iKTsKKwlpZiAoIWRydl9kYXRhKQorCQly
ZXR1cm4gMDsKKwlkZXZfZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiU1VTUEVORCBTU1AgSUQg
JWRcbiIsIGRydl9kYXRhLT5wZGV2LT5kZXZpY2UpOworCXBjaV9zYXZlX3N0YXRlKGRldik7CisJ
cGNpX2Rpc2FibGVfZGV2aWNlKGRldik7CisJcGNpX3NldF9wb3dlcl9zdGF0ZShkZXYsIFBDSV9E
M2hvdCk7CisJcmV0dXJuIDA7Cit9CisKKy8qKgorICogaW50ZWxfbWlkX2kyc19kcml2ZXJfcmVz
dW1lIC0gZHJpdmVyIHBvd2VyIG1hbmFnZW1lbnQgc3VzcGVuZCBhY3Rpdml0eQorICogQGRldmlj
ZV9wdHIgOiBwb2ludGVyIG9mIHRoZSBkZXZpY2UgdG8gcmVzdW1lCisgKgorICogT3V0cHV0IHBh
cmFtZXRlcnMKKyAqICAgICAgZXJyb3IgOiAwIG1lYW5zIG5vIGVycm9yCisgKi8KK3N0YXRpYyBp
bnQgaW50ZWxfbWlkX2kyc19kcml2ZXJfcmVzdW1lKHN0cnVjdCBwY2lfZGV2ICpkZXYpCit7CisJ
aW50IGVycjsKKwlpbnQgcmV0ID0gMDsKKwlzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmRydl9k
YXRhID0gcGNpX2dldF9kcnZkYXRhKGRldik7CisKKwlXQVJOKCFkcnZfZGF0YSwgIkRyaXZlciBk
YXRhPU5VTExcbiIpOworCWlmICghZHJ2X2RhdGEpCisJCXJldHVybiAtRUZBVUxUOworCWRldl9k
YmcoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJSRVNVTUUgU1NQIElEICVkXG4iLCBkcnZfZGF0YS0+
cGRldi0+ZGV2aWNlKTsKKworCWVyciA9IHBjaV9lbmFibGVfZGV2aWNlKGRldik7CisJaWYgKGVy
cikKKwkJZGV2X2VycigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIlVuYWJsZSB0byByZS1lbmFibGUg
ZGV2aWNlLCB0cnlpbmcgdG8gY29udGludWUuXG4iKTsKKwlkZXZfZGJnKCZkcnZfZGF0YS0+cGRl
di0+ZGV2LCAicmVzdW1pbmdcbiIpOworCXBjaV9zZXRfcG93ZXJfc3RhdGUoZGV2LCBQQ0lfRDAp
OworCXBjaV9yZXN0b3JlX3N0YXRlKGRldik7CisJcmV0ID0gcGNpX2VuYWJsZV9kZXZpY2UoZGV2
KTsKKwlpZiAocmV0KQorCQlkZXZfZXJyKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiSTJTOiBkZXZp
Y2UgY2FuJ3QgYmUgZW5hYmxlZCIpOworCWRldl9kYmcoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJy
ZXN1bWVkIGluIEQzXG4iKTsKKwlyZXR1cm4gcmV0OworfQorCisvKioKKyAqIGludGVsX21pZF9p
MnNfcnVudGltZV9zdXNwZW5kIC0gcnVudGltZSBwb3dlciBtYW5hZ2VtZW50IHN1c3BlbmQgYWN0
aXZpdHkKKyAqIEBkZXZpY2VfcHRyIDogcG9pbnRlciBvZiB0aGUgZGV2aWNlIHRvIHJlc3VtZQor
ICoKKyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIGVycm9yIDogMCBtZWFucyBubyBlcnJv
cgorICovCitzdGF0aWMgaW50IGludGVsX21pZF9pMnNfcnVudGltZV9zdXNwZW5kKHN0cnVjdCBk
ZXZpY2UgKmRldmljZV9wdHIpCit7CisJc3RydWN0IHBjaV9kZXYgKnBkZXY7CisJc3RydWN0IGlu
dGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YTsKKwl2b2lkIF9faW9tZW0gKnJlZzsKKworCXBkZXYg
PSB0b19wY2lfZGV2KGRldmljZV9wdHIpOworCVdBUk4oIXBkZXYsICJQY2kgZGV2PU5VTExcbiIp
OworCWlmICghcGRldikKKwkJcmV0dXJuIC1FRkFVTFQ7CisJZHJ2X2RhdGEgPSAoc3RydWN0IGlu
dGVsX21pZF9pMnNfaGRsICopIHBjaV9nZXRfZHJ2ZGF0YShwZGV2KTsKKwlXQVJOKCFkcnZfZGF0
YSwgIkRyaXZlciBkYXRhPU5VTExcbiIpOworCWlmICghZHJ2X2RhdGEpCisJCXJldHVybiAtRUZB
VUxUOworCWlmICh0ZXN0X2JpdChJMlNfUE9SVF9PUEVORUQsICZkcnZfZGF0YS0+ZmxhZ3MpKSB7
CisJCWRldl9lcnIoZGV2aWNlX3B0ciwgIlRyeWluZyB0byBzdXNwZW5kIGEgZGV2aWNlIHRoYXQg
aXMgb3BlbmVkXG4iKTsKKwkJcmV0dXJuIC1FTk9ERVY7CisJfQorCXJlZyA9IGRydl9kYXRhLT5p
b2FkZHI7CisJZGV2X2RiZygmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIlN1c3BlbmQgb2YgU1NQIHJl
cXVlc3RlZCAhIVxuIik7CisJcmV0dXJuIGludGVsX21pZF9pMnNfZHJpdmVyX3N1c3BlbmQodG9f
cGNpX2RldihkZXZpY2VfcHRyKSwgUE1TR19TVVNQRU5EKTsKK30KKyNlbmRpZgorCisvKioKKyAq
IGludGVsX21pZF9pMnNfcnVudGltZV9yZXN1bWUgLSBydW50aW1lIHBvd2VyIG1hbmFnZW1lbnQg
cmVzdW1lIGFjdGl2aXR5CisgKiBAZGV2aWNlX3B0ciA6IHBvaW50ZXIgb2YgdGhlIGRldmljZSB0
byByZXN1bWUKKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICBlcnJvciA6IDAgbWVh
bnMgbm8gZXJyb3IKKyAqLworc3RhdGljIGludCBpbnRlbF9taWRfaTJzX3J1bnRpbWVfcmVzdW1l
KHN0cnVjdCBkZXZpY2UgKmRldmljZV9wdHIpCit7CisJc3RydWN0IHBjaV9kZXYgKnBkZXY7CisJ
c3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YTsKKwlwZGV2ID0gdG9fcGNpX2Rldihk
ZXZpY2VfcHRyKTsKKwlXQVJOKCFwZGV2LCAiUGNpIGRldj1OVUxMXG4iKTsKKwlpZiAoIXBkZXYp
CisJCXJldHVybiAtRUZBVUxUOworCWRydl9kYXRhID0gKHN0cnVjdCBpbnRlbF9taWRfaTJzX2hk
bCAqKSBwY2lfZ2V0X2RydmRhdGEocGRldik7CisJV0FSTighZHJ2X2RhdGEsICJEcml2ZXIgZGF0
YT1OVUxMXG4iKTsKKwlpZiAoIWRydl9kYXRhKQorCQlyZXR1cm4gLUVGQVVMVDsKKwlkZXZfZGJn
KCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiUlQgUkVTVU1FIFNTUCBJRFxuIik7CisJcmV0dXJuIGlu
dGVsX21pZF9pMnNfZHJpdmVyX3Jlc3VtZSh0b19wY2lfZGV2KGRldmljZV9wdHIpKTsKK30KKwor
LyoKKyAqIElOVEVSRkFDRSBGVU5DVElPTlMKKyAqLworCisvKioKKyAqIGludGVsX21pZF9pMnNf
Zmx1c2ggLSBUaGlzIGlzIHRoZSBJMlMgZmx1c2ggcmVxdWVzdAorICogQGRydl9kYXRhIDogcG9p
bnRlciBvbiBwcml2YXRlIGkycyBkcml2ZXIgZGF0YSAoYnkgaTJzX29wZW4gZnVuY3Rpb24pCisg
KgorICogSXQgd2lsbCBmbHVzaCB0aGUgVFggRklGTworICogV0FSTklORzogdGhpcyBmdW5jdGlv
biBpcyB1c2VkIGluIGEgQnVyc3QgTW9kZSBjb250ZXh0IHdoZXJlIGl0IGlzIGNhbGxlZAorICog
YmV0d2VlbiBCdXJzdHMgaS5lLiB3aGVuIHRoZXJlIGlzIG5vIEZNU1lOQywgbm8gdHJhbnNmZXIg
b25nb2luZyBhdAorICogdGhhdCB0aW1lCisgKiBJZiB5b3UgbmVlZCBhIGZsdXNoIHdoaWxlIFNT
UCBjb25maWd1cmVkIGluIEkyUyBpcyBCVVNZIGFuZCBGTVNZTkMgYXJlCisgKiBnZW5lcmF0ZWQs
IHlvdSBoYXZlIHRvIHdyaXRlIGFub3RoZXIgZnVuY3Rpb24KKyAqIChsb29wIG9uIEJVU1kgYml0
IGFuZCBkbyBub3QgbGltaXQgdGhlIGZsdXNoIHRvIGF0IG1vc3QgMTYgc2FtcGxlcykKKyAqCisg
KiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICBpbnQgOiBudW1iZXIgb2Ygc2FtcGxlcyBmbHVz
aGVkCisgKi8KK2ludCBpbnRlbF9taWRfaTJzX2ZsdXNoKHN0cnVjdCBpbnRlbF9taWRfaTJzX2hk
bCAqZHJ2X2RhdGEpCit7CisJdTMyIHNzc3IsIGRhdGE7CisJdTMyIG51bSA9IDA7CisJdm9pZCBf
X2lvbWVtICpyZWc7CisKKwlXQVJOKCFkcnZfZGF0YSwgIkRyaXZlciBkYXRhPU5VTExcbiIpOwor
CWlmICghZHJ2X2RhdGEpCisJCXJldHVybiAwOworCXJlZyA9IGRydl9kYXRhLT5pb2FkZHI7CisJ
c3NzciA9IHJlYWRfU1NTUihyZWcpOworCWRldl9kYmcoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJp
biBmbHVzaCBzc3NyPTB4JTA4WFxuIiwgc3Nzcik7CisJLyoKKwkgKiBGbHVzaCAiYnkgaGFuZCIg
d2FzIGdlbmVyYXRpbmcgc3B1cmlvdXMgRE1BIFNFUlYgUkVRVUVTVAorCSAqIGZyb20gU1NQIHRv
IERNQSA9PiB0aGVuIGJ1Z2d5IHJldHJpZXZhbCBvZiBkYXRhIGZvciBuZXh0IGRtYV9yZXEKKwkg
KiBEaXNhYmxlOiBSWCBTZXJ2aWNlIFJlcXVlc3QgZnJvbSBSWCBmaWZvIHRvIERNQQorCSAqIGFz
IHdlIHdpbGwgZmx1c2ggYnkgaGFuZAorCSAqLworCWNsZWFyX1NTQ1IxX3JlZyhyZWcsIFJTUkUp
OworCS8qIGkyc19mbHVzaCBpcyBjYWxsZWQgaW4gYmV0d2VlbiAyIGJ1cnN0cworCSAqID0+IG5v
IEZNU1lOQyBhdCB0aGF0IHRpbWUgKGkuZS4gU1NQIG5vdCBidXN5KQorCSAqID0+IGF0IG1vc3Qg
MTYgc2FtcGxlcyBpbiB0aGUgRklGTyAqLworCXdoaWxlICgocmVhZF9TU1NSKHJlZykgJiAoU1NT
Ul9STkVfTUFTSzw8U1NTUl9STkVfU0hJRlQpKQorCQkJJiYgKG51bSA8IEZJRk9fU0laRSkpIHsK
KwkJZGF0YSA9IHJlYWRfU1NEUihyZWcpOworCQludW0rKzsKKwkJZGV2X3dhcm4oJmRydl9kYXRh
LT5wZGV2LT5kZXYsICJmbHVzaCgldSk9JXVcbiIsIG51bSwgZGF0YSk7CisJfQorCS8qIEVuYWJs
ZTogUlggU2VydmljZSBSZXF1ZXN0IGZyb20gUlggZmlmbyB0byBETUEKKwkgKiBhcyBmbHVzaCBi
eSBoYW5kIGlzIGRvbmUKKwkgKi8KKwlzZXRfU1NDUjFfcmVnKHJlZywgUlNSRSk7CisJc3NzciA9
IHJlYWRfU1NTUihyZWcpOworCWRldl9kYmcoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJvdXQgZmx1
c2ggc3Nzcj0weCUwOFhcbiIsIHNzc3IpOworCXJldHVybiBudW07Cit9CitFWFBPUlRfU1lNQk9M
X0dQTChpbnRlbF9taWRfaTJzX2ZsdXNoKTsKKworLyoqCisgKiBpbnRlbF9taWRfaTJzX2dldF9y
eF9maWZvX2xldmVsIC0gcmV0dXJucyBJMlMgcnggZmlmbyBsZXZlbAorICogQGRydl9kYXRhIDog
cG9pbnRlciBvbiBwcml2YXRlIGkycyBkcml2ZXIgZGF0YSAoYnkgaTJzX29wZW4gZnVuY3Rpb24p
CisgKgorICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgaW50IDogTnVtYmVyIG9mIHNhbXBs
ZXMgY3VycmVudGx5IGluIHRoZSBSWCBGSUZPIChuZWdhdGl2ZSA9IGVycm9yKQorICovCitpbnQg
aW50ZWxfbWlkX2kyc19nZXRfcnhfZmlmb19sZXZlbChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmRydl9kYXRhKQoreworCXUzMiBzc3NyOworCXUzMiBybmUsIHJmbDsKKwl2b2lkIF9faW9tZW0g
KnJlZzsKKworCVdBUk4oIWRydl9kYXRhLCAiRHJpdmVyIGRhdGE9TlVMTFxuIik7CisJaWYgKCFk
cnZfZGF0YSkKKwkJcmV0dXJuIC1FRkFVTFQ7CisJcmVnID0gZHJ2X2RhdGEtPmlvYWRkcjsKKwlz
c3NyID0gcmVhZF9TU1NSKHJlZyk7CisJcmZsID0gR0VUX1NTU1JfdmFsKHNzc3IsIFJGTCk7CisJ
cm5lID0gR0VUX1NTU1JfdmFsKHNzc3IsIFJORSk7CisJaWYgKCFybmUpCisJCXJldHVybiAwOwor
CWVsc2UKKwkJcmV0dXJuIHJmbCsxOworfQorRVhQT1JUX1NZTUJPTF9HUEwoaW50ZWxfbWlkX2ky
c19nZXRfcnhfZmlmb19sZXZlbCk7CisKKy8qKgorICogaW50ZWxfbWlkX2kyc19nZXRfdHhfZmlm
b19sZXZlbCAtIHJldHVybnMgSTJTIHR4IGZpZm8gbGV2ZWwKKyAqIEBkcnZfZGF0YSA6IHBvaW50
ZXIgb24gcHJpdmF0ZSBpMnMgZHJpdmVyIGRhdGEgKGJ5IGkyc19vcGVuIGZ1bmN0aW9uKQorICoK
KyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIGludCA6IG51bWJlciBvZiBzYW1wbGVzIGN1
cnJlbnRseSBpbiB0aGUgVFggRklGTyAobmVnYXRpdmUgPSBlcnJvcikKKyAqLworaW50IGludGVs
X21pZF9pMnNfZ2V0X3R4X2ZpZm9fbGV2ZWwoc3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZf
ZGF0YSkKK3sKKwl1MzIgc3NzcjsKKwl1MzIgdG5mLCB0Zmw7CisJdm9pZCBfX2lvbWVtICpyZWc7
CisJV0FSTighZHJ2X2RhdGEsICJEcml2ZXIgZGF0YT1OVUxMXG4iKTsKKwlpZiAoIWRydl9kYXRh
KQorCQlyZXR1cm4gLUVGQVVMVDsKKwlyZWcgPSBkcnZfZGF0YS0+aW9hZGRyOworCXNzc3IgPSBy
ZWFkX1NTU1IocmVnKTsKKwl0ZmwgPSBHRVRfU1NTUl92YWwoc3NzciwgVEZMKTsKKwl0bmYgPSBH
RVRfU1NTUl92YWwoc3NzciwgVEZOKTsKKwlpZiAoIXRuZikKKwkJcmV0dXJuIDE2OworCWVsc2UK
KwkJcmV0dXJuIHRmbDsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKGludGVsX21pZF9pMnNfZ2V0X3R4
X2ZpZm9fbGV2ZWwpOworCisvKioKKyAqIGludGVsX21pZF9pMnNfc2V0X3JkX2NiIC0gc2V0IHRo
ZSBjYWxsYmFjayBmdW5jdGlvbiBhZnRlciByZWFkIGlzIGRvbmUKKyAqIEBkcnZfZGF0YSA6IGhh
bmRsZSBvZiBjb3JyZXNwb25kaW5nIHNzcCBpMnMgKGdpdmVuIGJ5IGkyc19vcGVuIGZ1bmN0aW9u
KQorICogQHJlYWRfY2FsbGJhY2sgOiBwb2ludGVyIG9mIGNhbGxiYWNrIGZ1bmN0aW9uCisgKgor
ICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgZXJyb3IgOiAwIG1lYW5zIG5vIGVycm9yCisg
Ki8KK2ludCBpbnRlbF9taWRfaTJzX3NldF9yZF9jYihzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmRydl9kYXRhLCBpbnQgKCpyZWFkX2NhbGxiYWNrKSh2b2lkICpwYXJhbSkpCit7CisJV0FSTigh
ZHJ2X2RhdGEsICJEcml2ZXIgZGF0YT1OVUxMXG4iKTsKKwlpZiAoIWRydl9kYXRhKQorCQlyZXR1
cm4gLUVGQVVMVDsKKwltdXRleF9sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCWlmICghdGVzdF9i
aXQoSTJTX1BPUlRfT1BFTkVELCAmZHJ2X2RhdGEtPmZsYWdzKSkgeworCQlkZXZfV0FSTigmZHJ2
X2RhdGEtPnBkZXYtPmRldiwgInNldCBXUiBDQiBJMlNfUE9SVCBOT1RfT1BFTkVEIik7CisJCW11
dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKKwkJcmV0dXJuIC1FUEVSTTsKKwl9CisJLyog
RG8gbm90IGNoYW5nZSByZWFkIHBhcmFtZXRlcnMgaW4gdGhlIG1pZGRsZSBvZiBhIFJFQUQgcmVx
dWVzdCAqLworCWlmICh0ZXN0X2JpdChJMlNfUE9SVF9SRUFEX0JVU1ksICZkcnZfZGF0YS0+Zmxh
Z3MpKSB7CisJCWRldl9XQVJOKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiQ0IgcmVqZWN0IEkyU19Q
T1JUX1JFQURfQlVTWSIpOworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJCXJl
dHVybiAtRUJVU1k7CisJfQorCWRydl9kYXRhLT5yZWFkX2NhbGxiYWNrID0gcmVhZF9jYWxsYmFj
azsKKwlkcnZfZGF0YS0+cmVhZF9sZW4gPSAwOworCW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11
dGV4KTsKKwlyZXR1cm4gMDsKKworfQorRVhQT1JUX1NZTUJPTF9HUEwoaW50ZWxfbWlkX2kyc19z
ZXRfcmRfY2IpOworCisvKioKKyAqIGludGVsX21pZF9pMnNfc2V0X3dyX2NiIC0gc2V0IHRoZSBj
YWxsYmFjayBmdW5jdGlvbiBhZnRlciB3cml0ZSBpcyBkb25lCisgKiBAZHJ2X2RhdGEgOiBoYW5k
bGUgb2YgY29ycmVzcG9uZGluZyBzc3AgaTJzIChnaXZlbiBieSBpMnNfb3BlbiAgZnVuY3Rpb24p
CisgKiBAd3JpdGVfY2FsbGJhY2sgOiBwb2ludGVyIG9mIGNhbGxiYWNrIGZ1bmN0aW9uCisgKgor
ICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgZXJyb3IgOiAwIG1lYW5zIG5vIGVycm9yCisg
Ki8KK2ludCBpbnRlbF9taWRfaTJzX3NldF93cl9jYihzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmRydl9kYXRhLCBpbnQgKCp3cml0ZV9jYWxsYmFjaykodm9pZCAqcGFyYW0pKQoreworCVdBUk4o
IWRydl9kYXRhLCAiRHJpdmVyIGRhdGE9TlVMTFxuIik7CisJaWYgKCFkcnZfZGF0YSkKKwkJcmV0
dXJuIC1FRkFVTFQ7CisJbXV0ZXhfbG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKKwlpZiAoIXRlc3Rf
Yml0KEkyU19QT1JUX09QRU5FRCwgJmRydl9kYXRhLT5mbGFncykpIHsKKwkJZGV2X3dhcm4oJmRy
dl9kYXRhLT5wZGV2LT5kZXYsICJzZXQgV1IgQ0IgSTJTX1BPUlQgTk9UX09QRU5FRCIpOworCQlt
dXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJCXJldHVybiAtRVBFUk07CisJfQorCS8q
IERvIG5vdCBjaGFuZ2Ugd3JpdGUgcGFyYW1ldGVycyBpbiB0aGUgbWlkZGxlIG9mIGEgV1JJVEUg
cmVxdWVzdCAqLworCWlmICh0ZXN0X2JpdChJMlNfUE9SVF9XUklURV9CVVNZLCAmZHJ2X2RhdGEt
PmZsYWdzKSkgeworCQlkZXZfd2FybigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIkNCIHJlamVjdCBJ
MlNfUE9SVF9XUklURV9CVVNZIik7CisJCW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4KTsK
KwkJcmV0dXJuIC1FQlVTWTsKKwl9CisJZHJ2X2RhdGEtPndyaXRlX2NhbGxiYWNrID0gd3JpdGVf
Y2FsbGJhY2s7CisJZHJ2X2RhdGEtPndyaXRlX2xlbiA9IDA7CisJbXV0ZXhfdW5sb2NrKCZkcnZf
ZGF0YS0+bXV0ZXgpOworCXJldHVybiAwOworfQorRVhQT1JUX1NZTUJPTF9HUEwoaW50ZWxfbWlk
X2kyc19zZXRfd3JfY2IpOworCisvKioKKyAqIGludGVsX21pZF9pMnNfZW5hYmxlX3NzcCgpIDog
c3RhcnQgdGhlIHNzcCByaWdodCBhZnRlciB0aGUgcmVhZC93cml0ZSByZXEKKyAqIEBkcnZfZGF0
YSA6IGhhbmRsZSBvZiBjb3JyZXNwb25kaW5nIHNzcCBpMnMgKGdpdmVuIGJ5IGkyc19vcGVuIGZ1
bmN0aW9uKQorICoKKyAqIFRoaXMgZW5hYmxlIHRoZSByZWFkL3dyaXRlIHRvIGJlIHN0YXJ0ZWQg
c3luY2hyb25vdXNseQorICoKKyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIGVycm9yIDog
MCBtZWFucyBubyBlcnJvcgorICovCitpbnQgaW50ZWxfbWlkX2kyc19lbmFibGVfc3NwKHN0cnVj
dCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEpCit7CisJdm9pZCBfX2lvbWVtICpyZWcgPSBk
cnZfZGF0YS0+aW9hZGRyOworCXNldF9TU0NSMF9yZWcocmVnLCBTU0UpOworCXJldHVybiAwOwor
fQorRVhQT1JUX1NZTUJPTF9HUEwoaW50ZWxfbWlkX2kyc19lbmFibGVfc3NwKTsKKworLyoqCisg
KiBpbnRlbF9taWRfaTJzX3JkX3JlcSAtIHJlcXVlc3QgYSByZWFkIGZyb20gaTJzIHBlcmlwaGVy
YWwKKyAqIEBkcnZfZGF0YSA6IGhhbmRsZSBvZiBjb3JyZXNwb25kaW5nIHNzcCBpMnMgKGdpdmVu
IGJ5IGkyc19vcGVuIGZ1bmN0aW9uKQorICogQGRzdCA6IGRlc3RpbmF0aW9uIGJ1ZmZlciB3aGVy
ZSB0aGUgcmVhZCBzYW1wbGUgc2hvdWxkIGJlIHB1dAorICogQGxlbiA6IG51bWJlciBvZiBzYW1w
bGUgdG8gYmUgcmVhZCAoMTYwIHNhbXBsZXMgb25seSByaWdodCBub3cpCisgKiBAcGFyYW0gOiBw
cml2YXRlIGNvbnRleHQgcGFyYW1ldGVyIHRvIGdpdmUgYmFjayB0byByZWFkIGNhbGxiYWNrCisg
KgorICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgZXJyb3IgOiAwIG1lYW5zIG5vIGVycm9y
CisgKi8KK2ludCBpbnRlbF9taWRfaTJzX3JkX3JlcShzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmRydl9kYXRhLCB1MzIgKmRlc3RpbmF0aW9uLCBzaXplX3QgbGVuLCB2b2lkICpwYXJhbSkKK3sK
KwlzdHJ1Y3QgZG1hX2FzeW5jX3R4X2Rlc2NyaXB0b3IgKnJ4ZGVzYyA9IE5VTEw7CisJc3RydWN0
IGRtYV9jaGFuICpyeGNoYW4gPSBkcnZfZGF0YS0+cnhjaGFuOworCWVudW0gZG1hX2N0cmxfZmxh
Z3MgZmxhZzsKKwlkbWFfYWRkcl90IHNzZHJfYWRkcjsKKwlkbWFfYWRkcl90IGRzdDsKKwlXQVJO
KCFkcnZfZGF0YSwgIkRyaXZlciBkYXRhPU5VTExcbiIpOworCWlmICghZHJ2X2RhdGEpCisJCXJl
dHVybiAtRUZBVUxUOworCW11dGV4X2xvY2soJmRydl9kYXRhLT5tdXRleCk7CisJaWYgKCFyeGNo
YW4pIHsKKwkJZGV2X1dBUk4oJihkcnZfZGF0YS0+cGRldi0+ZGV2KSwgInJkX3JlcSBGQUlMRUQg
bm8gcnhjaGFuXG4iKTsKKwkJbXV0ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCQlyZXR1
cm4gLUVJTlZBTDsKKwl9CisJaWYgKCFsZW4pIHsKKwkJZGV2X1dBUk4oJmRydl9kYXRhLT5wZGV2
LT5kZXYsICJyZCByZXEgaW52YWxpZCBsZW49MCIpOworCQltdXRleF91bmxvY2soJmRydl9kYXRh
LT5tdXRleCk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKwlpZiAoIXRlc3RfYml0KEkyU19QT1JU
X09QRU5FRCwgJmRydl9kYXRhLT5mbGFncykpIHsKKwkJZGV2X1dBUk4oJmRydl9kYXRhLT5wZGV2
LT5kZXYsICJSRCByZWplY3QgSTJTX1BPUlQgTk9UX09QRU5FRCIpOworCQltdXRleF91bmxvY2so
JmRydl9kYXRhLT5tdXRleCk7CisJCXJldHVybiAtRVBFUk07CisJfQorCWlmICh0ZXN0X2JpdChJ
MlNfUE9SVF9DTE9TSU5HLCAmZHJ2X2RhdGEtPmZsYWdzKSkgeworCQlkZXZfV0FSTigmZHJ2X2Rh
dGEtPnBkZXYtPmRldiwgIlJEIHJlamVjdCBJMlNfUE9SVCBDTE9TSU5HIik7CisJCW11dGV4X3Vu
bG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKKwkJcmV0dXJuIC1FUElQRTsKKwl9CisKKwlkZXZfZGJn
KCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiSTJTX1JFQUQoKSBkc3Q9JXAsIGxlbj0lZCwgZHJ2X2Rh
dGE9JXAiLAlkZXN0aW5hdGlvbiwgbGVuLCBkcnZfZGF0YSk7CisJZHN0ID0gZG1hX21hcF9zaW5n
bGUoTlVMTCwgZGVzdGluYXRpb24sIGxlbiwgRE1BX0ZST01fREVWSUNFKTsKKwlpZiAoIWRzdCkg
eworCQlkZXZfV0FSTigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgImNhbid0IG1hcCBETUEgYWRkcmVz
cyAlcCIsIGRlc3RpbmF0aW9uKTsKKwkJbXV0ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOwor
CQlyZXR1cm4gLUVOT01FTTsKKwl9CisKKwlkcnZfZGF0YS0+cmVhZF9kc3QgPSBkc3Q7CisJZHJ2
X2RhdGEtPnJlYWRfbGVuID0gbGVuOworCS8qIGdldCBEYXRhIFJlYWQvV3JpdGUgYWRkcmVzcyAq
LworCXNzZHJfYWRkciA9IChkcnZfZGF0YS0+cGFkZHIgKyBPRkZTRVRfU1NEUik7CisJc2V0X1NT
Q1IxX3JlZygoZHJ2X2RhdGEtPmlvYWRkciksIFJTUkUpOworCWNoYW5nZV9TU0NSMF9yZWcoKGRy
dl9kYXRhLT5pb2FkZHIpLCBSSU0sCisJCQkgKChkcnZfZGF0YS0+Y3VycmVudF9zZXR0aW5ncyku
cnhfZmlmb19pbnRlcnJ1cHQpKTsKKwlmbGFnID0gRE1BX1BSRVBfSU5URVJSVVBUIHwgRE1BX0NU
UkxfQUNLOworCS8qIFN0YXJ0IHRoZSBSWCBkbWEgdHJhbnNmZXIgKi8KKwlyeGRlc2MgPSByeGNo
YW4tPmRldmljZS0+ZGV2aWNlX3ByZXBfZG1hX21lbWNweSgKKwkJCXJ4Y2hhbiwJCS8qIERNQSBD
aGFubmVsICovCisJCQlkc3QsCQkvKiBEQVIgKi8KKwkJCXNzZHJfYWRkciwJLyogU0FSICovCisJ
CQlsZW4sCQkvKiBEYXRhIExlbmd0aCAqLworCQkJZmxhZyk7CQkvKiBGbGFnICovCisJaWYgKCFy
eGRlc2MpIHsKKwkJZGV2X1dBUk4oJmRydl9kYXRhLT5wZGV2LT5kZXYsICJjYW4gbm90IHByZXAg
ZG1hIG1lbWNweSIpOworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJCXJldHVy
biAtRUZBVUxUOworCX0KKwkvKiBPbmx5IDEgUkVBRCBhdCBhIHRpbWUgYWxsb3dlZC4gZG8gaXQg
YXQgZW5kIHRvIGF2b2lkIGNsZWFyJndha2V1cCovCisJaWYgKHRlc3RfYW5kX3NldF9iaXQoSTJT
X1BPUlRfUkVBRF9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKSkgeworCQlkbWFfdW5tYXBfc2luZ2xl
KE5VTEwsIGRzdCwgbGVuLCBETUFfRlJPTV9ERVZJQ0UpOworCQlkZXZfV0FSTigmZHJ2X2RhdGEt
PnBkZXYtPmRldiwgIlJEIHJlamVjdCBJMlNfUE9SVCBSRUFEX0JVU1kiKTsKKwkJbXV0ZXhfdW5s
b2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCQlyZXR1cm4gLUVCVVNZOworCX0KKwlkZXZfZGJnKCYo
ZHJ2X2RhdGEtPnBkZXYtPmRldiksICJSRCBkbWEgdHggc3VibWl0XG4iKTsKKwlyeGRlc2MtPmNh
bGxiYWNrID0gaTJzX3JlYWRfZG9uZTsKKwlkcnZfZGF0YS0+cmVhZF9wYXJhbSA9IHBhcmFtOwor
CXJ4ZGVzYy0+Y2FsbGJhY2tfcGFyYW0gPSBkcnZfZGF0YTsKKwlyeGRlc2MtPnR4X3N1Ym1pdChy
eGRlc2MpOworCW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKKwlyZXR1cm4gMDsKK30K
K0VYUE9SVF9TWU1CT0xfR1BMKGludGVsX21pZF9pMnNfcmRfcmVxKTsKKworLyoqCisgKiBpbnRl
bF9taWRfaTJzX3dyX3JlcSAtIHJlcXVlc3QgYSB3cml0ZSB0byBpMnMgcGVyaXBoZXJhbAorICog
QGRydl9kYXRhIDogaGFuZGxlIG9mIGNvcnJlc3BvbmRpbmcgc3NwIGkycyAoZ2l2ZW4gYnkgaTJz
X29wZW4gZnVuY3Rpb24pCisgKiBAc3JjIDogc291cmNlIGJ1ZmZlciB3aGVyZSB0aGUgc2FtcGxl
cyB0byB3cm90ZSBzaG91bGQgYmUgZ2V0CisgKiBAbGVuIDogbnVtYmVyIG9mIHNhbXBsZSB0byBi
ZSByZWFkICgxNjAgc2FtcGxlcyBvbmx5IHJpZ2h0IG5vdykKKyAqIEBwYXJhbSA6IHByaXZhdGUg
Y29udGV4dCBwYXJhbWV0ZXIgdG8gZ2l2ZSBiYWNrIHRvIHdyaXRlIGNhbGxiYWNrCisgKgorICog
T3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgZXJyb3IgOiAwIG1lYW5zIG5vIGVycm9yCisgKi8K
K2ludCBpbnRlbF9taWRfaTJzX3dyX3JlcShzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmRydl9k
YXRhLCB1MzIgKnNvdXJjZSwgc2l6ZV90IGxlbiwgdm9pZCAqcGFyYW0pCit7CisJZG1hX2FkZHJf
dCBzc2RyX2FkZHI7CisJc3RydWN0IGRtYV9hc3luY190eF9kZXNjcmlwdG9yICp0eGRlc2MgPSBO
VUxMOworCXN0cnVjdCBkbWFfY2hhbiAqdHhjaGFuID0gZHJ2X2RhdGEtPnR4Y2hhbjsKKwllbnVt
IGRtYV9jdHJsX2ZsYWdzIGZsYWc7CisJZG1hX2FkZHJfdCBzcmM7CisJV0FSTighZHJ2X2RhdGEs
ICJEcml2ZXIgZGF0YT1OVUxMXG4iKTsKKwlpZiAoIWRydl9kYXRhKQorCQlyZXR1cm4gLUVGQVVM
VDsKKwltdXRleF9sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCWlmICghdHhjaGFuKSB7CisJCWRl
dl9XQVJOKCYoZHJ2X2RhdGEtPnBkZXYtPmRldiksICJ3cl9yZXEgYnV0IG5vIHR4Y2hhblxuIik7
CisJCW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJ
fQorCWlmICghbGVuKSB7CisJCWRldl9XQVJOKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiaW52YWxp
ZCBsZW4gMCIpOworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJCXJldHVybiAt
RUlOVkFMOworCX0KKwlpZiAoIXRlc3RfYml0KEkyU19QT1JUX09QRU5FRCwgJmRydl9kYXRhLT5m
bGFncykpIHsKKwkJZGV2X1dBUk4oJmRydl9kYXRhLT5wZGV2LT5kZXYsICJXUiByZWplY3QgSTJT
X1BPUlQgTk9UX09QRU5FRCIpOworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJ
CXJldHVybiAtRVBFUk07CisJfQorCWlmICh0ZXN0X2JpdChJMlNfUE9SVF9DTE9TSU5HLCAmZHJ2
X2RhdGEtPmZsYWdzKSkgeworCQlkZXZfV0FSTigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIldSIHJl
amVjdCBJMlNfUE9SVCBDTE9TSU5HIik7CisJCW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4
KTsKKwkJcmV0dXJuIC1FUElQRTsKKwl9CisKKwlkZXZfZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2
LCAiSTJTX1dSSVRFKCkgc3JjPSVwLCBsZW49JWQsIGRydl9kYXRhPSVwIiwgc291cmNlLCBsZW4s
IGRydl9kYXRhKTsKKworCXNyYyA9IGRtYV9tYXBfc2luZ2xlKE5VTEwsIHNvdXJjZSwgbGVuLCBE
TUFfVE9fREVWSUNFKTsKKwlpZiAoIXNyYykgeworCQlkZXZfV0FSTigmZHJ2X2RhdGEtPnBkZXYt
PmRldiwgImNhbid0IG1hcCBETUEgYWRkcmVzcyAlcCIsIHNvdXJjZSk7CisJCW11dGV4X3VubG9j
aygmZHJ2X2RhdGEtPm11dGV4KTsKKwkJcmV0dXJuIC1FRkFVTFQ7CisJfQorCWRydl9kYXRhLT53
cml0ZV9zcmMgPSBzcmM7CisJZHJ2X2RhdGEtPndyaXRlX2xlbiA9IGxlbjsKKwkvKiBnZXQgRGF0
YSBSZWFkL1dyaXRlIGFkZHJlc3MgKi8KKwlzc2RyX2FkZHIgPSAoZG1hX2FkZHJfdCkodTMyKShk
cnZfZGF0YS0+cGFkZHIgKyBPRkZTRVRfU1NEUik7CisJc2V0X1NTQ1IxX3JlZygoZHJ2X2RhdGEt
PmlvYWRkciksIFRTUkUpOworCWNoYW5nZV9TU0NSMF9yZWcoKGRydl9kYXRhLT5pb2FkZHIpLCBU
SU0sCisJCQkgKChkcnZfZGF0YS0+Y3VycmVudF9zZXR0aW5ncykudHhfZmlmb19pbnRlcnJ1cHQp
KTsKKwlmbGFnID0gRE1BX1BSRVBfSU5URVJSVVBUIHwgRE1BX0NUUkxfQUNLOworCXR4ZGVzYyA9
IHR4Y2hhbi0+ZGV2aWNlLT5kZXZpY2VfcHJlcF9kbWFfbWVtY3B5KAorCQkJdHhjaGFuLAkJLyog
RE1BIENoYW5uZWwgKi8KKwkJCXNzZHJfYWRkciwJLyogREFSICovCisJCQlzcmMsCQkvKiBTQVIg
Ki8KKwkJCWxlbiwJCS8qIERhdGEgTGVuZ3RoICovCisJCQlmbGFnKTsJCS8qIEZsYWcgKi8KKwlp
ZiAoIXR4ZGVzYykgeworCQlkZXZfV0FSTigmKGRydl9kYXRhLT5wZGV2LT5kZXYpLAorCQkJIndy
X3JlcSBkbWEgbWVtY3B5IEZBSUxFRChzcmM9JTA4eCxsZW49JWQsdHhjaGFuPSVwKVxuIiwKKwkJ
CXNyYywgbGVuLCB0eGNoYW4pOworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJ
CXJldHVybiAtMTsKKwl9CisJZGV2X2RiZygmKGRydl9kYXRhLT5wZGV2LT5kZXYpLCAiV1IgZG1h
IHR4IHN1bW1pdFxuIik7CisJLyogT25seSAxIFdSSVRFIGF0IGEgdGltZSBhbGxvd2VkICovCisJ
aWYgKHRlc3RfYW5kX3NldF9iaXQoSTJTX1BPUlRfV1JJVEVfQlVTWSwgJmRydl9kYXRhLT5mbGFn
cykpIHsKKwkJZG1hX3VubWFwX3NpbmdsZShOVUxMLCBzcmMsIGxlbiwgRE1BX1RPX0RFVklDRSk7
CisJCWRldl9XQVJOKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiV1IgcmVqZWN0IEkyU19QT1JUIFdS
SVRFX0JVU1kiKTsKKwkJbXV0ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCQlyZXR1cm4g
LUVCVVNZOworCX0KKwl0eGRlc2MtPmNhbGxiYWNrID0gaTJzX3dyaXRlX2RvbmU7CisJZHJ2X2Rh
dGEtPndyaXRlX3BhcmFtID0gcGFyYW07CisJdHhkZXNjLT5jYWxsYmFja19wYXJhbSA9IGRydl9k
YXRhOworCXR4ZGVzYy0+dHhfc3VibWl0KHR4ZGVzYyk7CisJZGV2X2RiZygmKGRydl9kYXRhLT5w
ZGV2LT5kZXYpLCAid3IgZG1hIHJlcSBwcm9ncmFtbWVkXG4iKTsKKwltdXRleF91bmxvY2soJmRy
dl9kYXRhLT5tdXRleCk7CisJcmV0dXJuIDA7Cit9CitFWFBPUlRfU1lNQk9MX0dQTChpbnRlbF9t
aWRfaTJzX3dyX3JlcSk7CisKKy8qKgorICogaW50ZWxfbWlkX2kyc19vcGVuIC0gcmVzZXJ2ZSBh
bmQgc3RhcnQgYSBTU1AgZGVwZW5kaW5nIG9mIGl0J3MgdXNhZ2UKKyAqIEB1c2FnZSA6IHNlbGVj
dCB3aGljaCBzc3AgaTJzIHlvdSBuZWVkIGJ5IGdpdmluZyB1c2FnZSAoQlQsTU9ERU0uLi4pCisg
KiBAcHNfc2V0dGluZ3MgOiBoYXJkd2FyZSBzZXR0aW5ncyB0byBjb25maWd1cmUgdGhlIFNTUCBt
b2R1bGUKKyAqCisgKiBNYXkgc2xlZXAgKGRyaXZlcl9maW5kX2RldmljZSkgOiBubyBsb2NrIHBl
cm1pdHRlZCB3aGVuIGNhbGxlZC4KKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICBo
YW5kbGUgOiBoYW5kbGUgb2YgdGhlIHNlbGVjdGVkIFNTUCwgb3IgTlVMTCBpZiBub3QgZm91bmQK
KyAqLworc3RydWN0IGludGVsX21pZF9pMnNfaGRsICppbnRlbF9taWRfaTJzX29wZW4oZW51bSBp
bnRlbF9taWRfaTJzX3NzcF91c2FnZSB1c2FnZSwKKwkJCSBjb25zdCBzdHJ1Y3QgaW50ZWxfbWlk
X2kyc19zZXR0aW5ncyAqcHNfc2V0dGluZ3MpCit7CisJc3RydWN0IHBjaV9kZXYgKnBkZXY7CisJ
c3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YSA9IE5VTEw7CisJc3RydWN0IGRldmlj
ZSAqZm91bmRfZGV2aWNlID0gTlVMTDsKKwlwcl9kZWJ1ZygiJXMgOiBvcGVuIGNhbGxlZCxzZWFy
Y2hpbmcgZm9yIGRldmljZSB3aXRoIHVzYWdlPSV4ICFcbiIsIERSSVZFUl9OQU1FLCB1c2FnZSk7
CisJZm91bmRfZGV2aWNlID0gZHJpdmVyX2ZpbmRfZGV2aWNlKCYoaW50ZWxfbWlkX2kyc19kcml2
ZXIuZHJpdmVyKSwgTlVMTCwgJnVzYWdlLCBjaGVja19kZXZpY2UpOworCWlmICghZm91bmRfZGV2
aWNlKSB7CisJCXByX2RlYnVnKCIlcyA6IG9wZW4gY2FuIG5vdCBmb3VuZCB3aXRoIHVzYWdlPTB4
JTAyWFxuIiwgRFJJVkVSX05BTUUsIChpbnQpdXNhZ2UpOworCQlyZXR1cm4gTlVMTDsKKwl9CisJ
cGRldiA9IHRvX3BjaV9kZXYoZm91bmRfZGV2aWNlKTsKKwlkcnZfZGF0YSA9IHBjaV9nZXRfZHJ2
ZGF0YShwZGV2KTsKKworCWlmICghZHJ2X2RhdGEpIHsKKwkJZGV2X2Vycihmb3VuZF9kZXZpY2Us
ICJubyBkcnZfZGF0YSBpbiBvcGVuIHBkZXY9JXBcbiIsIHBkZXYpOworCQlwdXRfZGV2aWNlKGZv
dW5kX2RldmljZSk7CisJCXJldHVybiBOVUxMOworCX0KKwltdXRleF9sb2NrKCZkcnZfZGF0YS0+
bXV0ZXgpOworCWRldl9kYmcoZm91bmRfZGV2aWNlLCAiT3BlbiBmb3VuZCBwZGV2aWNlPTB4JXBc
biIsIHBkZXYpOworCS8qIHBtX3J1bnRpbWUgKi8KKwlwbV9ydW50aW1lX2dldF9zeW5jKCZkcnZf
ZGF0YS0+cGRldi0+ZGV2KTsKKwkvKiBkbWFjMSBpcyBhbHJlYWR5IHNldCBkdXJpbmcgcHJvYmUg
Ki8KKwlpZiAoaTJzX2RtYV9zdGFydChkcnZfZGF0YSkgIT0gMCkgeworCQlkZXZfZXJyKGZvdW5k
X2RldmljZSwgIkNhbiBub3Qgc3RhcnQgRE1BXG4iKTsKKwkJZ290byBvcGVuX2Vycm9yOworCX0K
KwkvKiBpZiB3ZSByZXN0YXJ0IGFmdGVyIHN0b3Agd2l0aG91dCBzdXNwZW5kLCB3ZSBzdGFydCBz
c3AgZmFzdGVyICovCisJZHJ2X2RhdGEtPmN1cnJlbnRfc2V0dGluZ3MgPSAqcHNfc2V0dGluZ3M7
CisJc2V0X3NzcF9pMnNfaHcoZHJ2X2RhdGEsIHBzX3NldHRpbmdzKTsKKworCWRydl9kYXRhLT5t
YXNrX3NyID0gKChTU1NSX0JDRV9NQVNLIDw8IFNTU1JfQkNFX1NISUZUKSB8CisJCQkoU1NTUl9F
T0NfTUFTSyA8PCBTU1NSX0VPQ19TSElGVCkgfAorCQkJKFNTU1JfUk9SX01BU0sgPDwgU1NTUl9S
T1JfU0hJRlQpIHwKKwkJCShTU1NSX1RVUl9NQVNLIDw8IFNTU1JfVFVSX1NISUZUKSB8CisJCQko
U1NTUl9USU5UX01BU0sgPDwgU1NTUl9USU5UX1NISUZUKSB8CisJCQkoU1NTUl9QSU5UX01BU0sg
PDwgU1NTUl9QSU5UX1NISUZUKSk7CisJaWYgKHRlc3RfYml0KEkyU19QT1JUX0NMT1NJTkcsICZk
cnZfZGF0YS0+ZmxhZ3MpKSB7CisJCWRldl9lcnIoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJPcGVu
aW5nIGEgY2xvc2luZyBJMlMhIik7CisJCWdvdG8gb3Blbl9lcnJvcjsKKwl9CisJLyogdGhlcmUg
aXMgbm8gbmVlZCB0byAid2FrZSB1cCIgYXMgd2UgY2FuIG5vdCBjbG9zZSBhbiBvcGVuaW5nIGky
cyAqLworCWNsZWFyX2JpdChJMlNfUE9SVF9XUklURV9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKTsK
KwljbGVhcl9iaXQoSTJTX1BPUlRfUkVBRF9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKTsKKwltdXRl
eF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJcmV0dXJuIGRydl9kYXRhOworCitvcGVuX2Vy
cm9yOgorCXB1dF9kZXZpY2UoZm91bmRfZGV2aWNlKTsKKwltdXRleF91bmxvY2soJmRydl9kYXRh
LT5tdXRleCk7CisJcmV0dXJuIE5VTEw7Cit9CitFWFBPUlRfU1lNQk9MX0dQTChpbnRlbF9taWRf
aTJzX29wZW4pOworCisvKioKKyAqIGludGVsX21pZF9pMnNfY2xvc2UgLSByZWxlYXNlIGFuZCBz
dG9wIHRoZSBTU1AKKyAqIEBkcnZfZGF0YSA6IGhhbmRsZSBvZiBjb3JyZXNwb25kaW5nIHNzcCBp
MnMgKGdpdmVuIGJ5IGkyc19vcGVuIGZ1bmN0aW9uKQorICoKKyAqIFdBUk5JTkc6IFRoaXMgaXMg
bm90IC15ZXQtIGFsbG93ZWQgdG8gY2FsbCBjbG9zZSBmcm9tIGEgcmVhZC93cml0ZSBjYWxsYmFj
ayAhCisgKgorICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgbm9uZQorICovCit2b2lkIGlu
dGVsX21pZF9pMnNfY2xvc2Uoc3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YSkKK3sK
Kwl2b2lkIF9faW9tZW0gKnJlZzsKKwlXQVJOKCFkcnZfZGF0YSwgIkRyaXZlciBkYXRhPU5VTExc
biIpOworCWlmICghZHJ2X2RhdGEpCisJCXJldHVybjsKKwltdXRleF9sb2NrKCZkcnZfZGF0YS0+
bXV0ZXgpOworCWlmICghdGVzdF9iaXQoSTJTX1BPUlRfT1BFTkVELCAmZHJ2X2RhdGEtPmZsYWdz
KSkgeworCQlkZXZfZXJyKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAibm90IG9wZW5lZCBidXQgY2xv
c2luZz8iKTsKKwkJbXV0ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCQlyZXR1cm47CisJ
fQorCS8qIHRvIGJlIG1vZGlmaWVkIHRvIHdhaXRfZXZlbnRfaW50ZXJydXB0aWJsZV90aW1lb3V0
ICovCisJc2V0X2JpdChJMlNfUE9SVF9DTE9TSU5HLCAmZHJ2X2RhdGEtPmZsYWdzKTsKKwlkZXZf
ZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiU3RhdHVzIGJpdCBwZW5kaW5nIHdyaXRlPSVkIHJl
YWQ9JWRcbiIsCisJCQl0ZXN0X2JpdChJMlNfUE9SVF9XUklURV9CVVNZLCAmZHJ2X2RhdGEtPmZs
YWdzKSwKKwkJCXRlc3RfYml0KEkyU19QT1JUX1JFQURfQlVTWSwgJmRydl9kYXRhLT5mbGFncykp
OworCWlmICh0ZXN0X2JpdChJMlNfUE9SVF9XUklURV9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKSB8
fAorCSAgICAgdGVzdF9iaXQoSTJTX1BPUlRfUkVBRF9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKSkg
eworCQlkZXZfZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiUGVuZGluZyBjYWxsYmFjayBpbiBj
bG9zZS4uLlxuIik7CisJfQorCisJLyogd2FpdGluZyBiZWxvdy4gVG8gYmUgcmVwbGFjZWQgd2hl
biAiRE1BX1RFUk1JTkFURV9BTEwiIGZpeCBhdmFpbGFibGUgKi8KKwl3YWl0X2V2ZW50KGRydl9k
YXRhLT53cV9jaGFuX2Nsb3NpbmcsCisJCSgoIXRlc3RfYml0KEkyU19QT1JUX1dSSVRFX0JVU1ks
ICZkcnZfZGF0YS0+ZmxhZ3MpKSAmJgorCQkgKCF0ZXN0X2JpdChJMlNfUE9SVF9SRUFEX0JVU1ks
ICAmZHJ2X2RhdGEtPmZsYWdzKSkpKTsKKwkvKiByZWxlYXNlIERNQSBDaGFubmVsLi4gKi8KKwlp
MnNfZG1hX3N0b3AoZHJ2X2RhdGEpOworCXJlZyA9IGRydl9kYXRhLT5pb2FkZHI7CisJZGV2X2Ri
ZygmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIlN0b3BwaW5nIHRoZSBTU1BcbiIpOworCWkyc19zc3Bf
c3RvcChkcnZfZGF0YSk7CisJcHV0X2RldmljZSgmZHJ2X2RhdGEtPnBkZXYtPmRldik7CisJd3Jp
dGVfU1NDUjAoMCwgcmVnKTsKKwkvKiBwbSBydW50aW1lICovCisJcG1fcnVudGltZV9wdXQoJmRy
dl9kYXRhLT5wZGV2LT5kZXYpOworCWRldl9kYmcoJihkcnZfZGF0YS0+cGRldi0+ZGV2KSwgIlNT
UCBTdG9wcGVkLlxuIik7CisJY2xlYXJfYml0KEkyU19QT1JUX0NMT1NJTkcsICZkcnZfZGF0YS0+
ZmxhZ3MpOworCWNsZWFyX2JpdChJMlNfUE9SVF9PUEVORUQsICZkcnZfZGF0YS0+ZmxhZ3MpOwor
CW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKGlu
dGVsX21pZF9pMnNfY2xvc2UpOworLyoKKyAqIElOVEVSTkFMIEZVTkNUSU9OUworICovCisKKy8q
KgorICogY2hlY2tfZGV2aWNlIC0gIHJldHVybiBpZiB0aGUgZGV2aWNlIGlzIHRoZSB1c2FnZSB3
ZSB3YW50ICh1c2FnZSA9KmRhdGEpCisgKiBAZGV2aWNlX3B0ciA6IHBvaW50ZXIgb24gZGV2aWNl
IHN0cnVjdAorICogQGRhdGEgOiBwb2ludGVyIHBvaW50ZXIgb24gdXNhZ2Ugd2UgYXJlIGxvb2tp
bmcgZm9yCisgKgorICogdGhpcyBpcyBjYWxsZWQgZm9yIGVhY2ggZGV2aWNlIGJ5IGZpbmRfZGV2
aWNlKCkgZnJvbSBpbnRlbF9taWRfaTJzX29wZW4oKQorICogSW5mbyA6IHdoZW4gZm91bmQsIHRo
ZSBmbGFnIG9mIGRyaXZlciBpcyBzZXQgdG8gSTJTX1BPUlRfT1BFTkVECisgKgorICogT3V0cHV0
IHBhcmFtZXRlcnMKKyAqICAgICAgaW50ZWdlciA6IHJldHVybiAwIG1lYW5zIG5vdCB0aGUgZGV2
aWNlIG9yIGFscmVhZHkgc3RhcnRlZC4gZ28gbmV4dAorICoJCSAgcmV0dXJuICE9IDAgbWVhbnMg
c3RvcCB0aGUgc2VhcmNoIGFuZCByZXR1cm4gdGhpcyBkZXZpY2UKKyAqLworc3RhdGljIGludAor
Y2hlY2tfZGV2aWNlKHN0cnVjdCBkZXZpY2UgKmRldmljZV9wdHIsIHZvaWQgKmRhdGEpCit7CisJ
c3RydWN0IHBjaV9kZXYgKnBkZXY7CisJc3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0
YTsKKwllbnVtIGludGVsX21pZF9pMnNfc3NwX3VzYWdlIHVzYWdlOworCWVudW0gaW50ZWxfbWlk
X2kyc19zc3BfdXNhZ2UgdXNhZ2VfdG9fZmluZDsKKworCXBkZXYgPSB0b19wY2lfZGV2KGRldmlj
ZV9wdHIpOworCVdBUk4oIXBkZXYsICJQY2kgZGV2aWNlPU5VTExcbiIpOworCWlmICghcGRldikK
KwkJcmV0dXJuIDA7CisJZHJ2X2RhdGEgPSAoc3RydWN0IGludGVsX21pZF9pMnNfaGRsICopIHBj
aV9nZXRfZHJ2ZGF0YShwZGV2KTsKKwlXQVJOKCFkcnZfZGF0YSwgIkRyaXZlciBkYXRhPU5VTExc
biIpOworCWlmICghZHJ2X2RhdGEpCisJCXJldHVybiAwOworCWRldl9kYmcoJihwZGV2LT5kZXYp
LCAiQ2hlY2sgZGV2aWNlIHBjaV9kZXYgcHRyID0gMFglcFxuIiwgcGRldik7CisJdXNhZ2VfdG9f
ZmluZCA9ICooKGVudW0gaW50ZWxfbWlkX2kyc19zc3BfdXNhZ2UgKikgZGF0YSk7CisJdXNhZ2Ug
PSBkcnZfZGF0YS0+dXNhZ2U7CisKKwkvKiBDYW4gYmUgZG9uZSBpbiBvbmUgImlmIiBidXQgc2Vw
YXJhdGVkIGluIHB1cnBvc2UgOiB0YWtlIGNhcmUgb2YKKwkgKiB0ZXN0X2FuZF9zZXRfYml0IHRo
YXQgbmVlZCB0byBiZSBkb25lIEFGVEVSIHRoZSBjaGVjayBvbiB1c2FnZS4KKwkgKi8KKwlpZiAo
dXNhZ2UgPT0gdXNhZ2VfdG9fZmluZCkgeworCQlpZiAoIXRlc3RfYW5kX3NldF9iaXQoSTJTX1BP
UlRfT1BFTkVELCAmZHJ2X2RhdGEtPmZsYWdzKSkKKwkJCXJldHVybiAxOyAgLyogQWxyZWFkeSBv
cGVuZWQsIGRvIG5vdCB1c2UgdGhpcyByZXN1bHQgKi8KKwl9OworCXJldHVybiAwOyAvKiBub3Qg
dXNhZ2Ugd2UgbG9vayBmb3IsIG9yIGFscmVhZHkgb3BlbmVkICovCit9CisKKy8qKgorICogaTJz
X3JlYWRfZG9uZSAtIGNhbGxiYWNrIGZyb20gdGhlIF9kbWEgdGFza2xldF8gYWZ0ZXIgcmVhZAor
ICogQGFyZyA6IHZvaWQgcG9pbnRlciB0byB0aGF0IHNob3VsZCBiZSBkcml2ZXIgZGF0YSAoY29u
dGV4dCkKKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICBub25lCisgKi8KK3N0YXRp
YyB2b2lkIGkyc19yZWFkX2RvbmUodm9pZCAqYXJnKQoreworCWludCBzdGF0dXMgPSAwOworCisJ
c3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YSA9IGFyZzsKKwl2b2lkICpwYXJhbV9j
b21wbGV0ZTsKKwl2b2lkIF9faW9tZW0gKnJlZyA7CisKKwlXQVJOKCFkcnZfZGF0YSwgIkRyaXZl
ciBkYXRhPU5VTExcbiIpOworCWlmICghZHJ2X2RhdGEpCisJCXJldHVybjsKKwltdXRleF9sb2Nr
KCZkcnZfZGF0YS0+bXV0ZXgpOworCWlmICghdGVzdF9iaXQoSTJTX1BPUlRfUkVBRF9CVVNZLCAm
ZHJ2X2RhdGEtPmZsYWdzKSkKKwkJZGV2X1dBUk4oJmRydl9kYXRhLT5wZGV2LT5kZXYsICJzcHVy
aW91cyByZWFkIGRtYSBjb21wbGV0ZSIpOworCisJZG1hX3VubWFwX3NpbmdsZShOVUxMLCBkcnZf
ZGF0YS0+cmVhZF9kc3QsCisJCQkgZHJ2X2RhdGEtPnJlYWRfbGVuLCBETUFfRlJPTV9ERVZJQ0Up
OworCWRydl9kYXRhLT5yZWFkX2xlbiA9IDA7CisJcmVnID0gZHJ2X2RhdGEtPmlvYWRkcjsKKwkv
KiBSeCBmaWZvIG92ZXJydW4gSW50ZXJydXB0ICovCisJY2hhbmdlX1NTQ1IwX3JlZyhyZWcsIFJJ
TSwgU1NQX1JYX0ZJRk9fT1ZFUl9JTlRfRElTQUJMRSk7CisJcGFyYW1fY29tcGxldGUgPSBkcnZf
ZGF0YS0+cmVhZF9wYXJhbTsKKwkvKiBEbyBub3QgY2hhbmdlIG9yZGVyIHNlcXVlbmNlOgorCSAq
IFJFQURfQlVTWSBjbGVhciwgdGhlbiB0ZXN0IFBPUlRfQ0xPU0lORworCSAqIHdha2V1cCBmb3Ig
Y2xvc2UoKSBmdW5jdGlvbgorCSAqLworCWNsZWFyX2JpdChJMlNfUE9SVF9SRUFEX0JVU1ksICZk
cnZfZGF0YS0+ZmxhZ3MpOworCXdha2VfdXAoJmRydl9kYXRhLT53cV9jaGFuX2Nsb3NpbmcpOwor
CWlmICh0ZXN0X2JpdChJMlNfUE9SVF9DTE9TSU5HLCAmZHJ2X2RhdGEtPmZsYWdzKSkgeworCQlk
ZXZfZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAicmVhZCBkb25lIHdha2luZyB1cCBjbG9zZSIp
OworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJCXJldHVybjsKKwl9CisJbXV0
ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCWlmIChkcnZfZGF0YS0+cmVhZF9jYWxsYmFj
ayAhPSBOVUxMKQorCQlzdGF0dXMgPSBkcnZfZGF0YS0+cmVhZF9jYWxsYmFjayhwYXJhbV9jb21w
bGV0ZSk7CisJZWxzZQorCQlkZXZfd2FybigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIlJEIGRvbmUg
YnV0IG5vdCBjYWxsYmFjayBzZXQiKTsKKworfQorCisvKioKKyAqIGkyc193cml0ZV9kb25lKCkg
OiBjYWxsYmFjayBmcm9tIHRoZSBfZG1hIHRhc2tsZXRfIGFmdGVyIHdyaXRlCisgKiBAYXJnIDog
dm9pZCBwb2ludGVyIHRvIHRoYXQgc2hvdWxkIGJlIGRyaXZlciBkYXRhIChjb250ZXh0KQorICoK
KyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIG5vbmUKKyAqLworc3RhdGljIHZvaWQgaTJz
X3dyaXRlX2RvbmUodm9pZCAqYXJnKQoreworCWludCBzdGF0dXMgPSAwOworCXZvaWQgKnBhcmFt
X2NvbXBsZXRlOworCXN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEgPSBhcmc7CisJ
dm9pZCBfX2lvbWVtICpyZWcgOworCisJV0FSTighZHJ2X2RhdGEsICJEcml2ZXIgZGF0YT1OVUxM
XG4iKTsKKwlpZiAoIWRydl9kYXRhKQorCQlyZXR1cm47CisJbXV0ZXhfbG9jaygmZHJ2X2RhdGEt
Pm11dGV4KTsKKwlpZiAoIXRlc3RfYml0KEkyU19QT1JUX1dSSVRFX0JVU1ksICZkcnZfZGF0YS0+
ZmxhZ3MpKQorCQlkZXZfd2FybigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgInNwdXJpb3VzIHdyaXRl
IGRtYSBjb21wbGV0ZSIpOworCWRtYV91bm1hcF9zaW5nbGUoTlVMTCwgZHJ2X2RhdGEtPnJlYWRf
ZHN0LAorCQkJIGRydl9kYXRhLT5yZWFkX2xlbiwgRE1BX1RPX0RFVklDRSk7CisJZHJ2X2RhdGEt
PnJlYWRfbGVuID0gMDsKKwlyZWcgPSBkcnZfZGF0YS0+aW9hZGRyOworCWNoYW5nZV9TU0NSMF9y
ZWcocmVnLCBUSU0sIFNTUF9UWF9GSUZPX1VOREVSX0lOVF9ESVNBQkxFKTsKKwlkZXZfZGJnKCYo
ZHJ2X2RhdGEtPnBkZXYtPmRldiksICJETUEgY2hhbm5lbCBkaXNhYmxlLi5cbiIpOworCXBhcmFt
X2NvbXBsZXRlID0gZHJ2X2RhdGEtPndyaXRlX3BhcmFtOworCS8qIERvIG5vdCBjaGFuZ2Ugb3Jk
ZXIgc2VxdWVuY2U6CisJICogV1JJVEVfQlVTWSBjbGVhciwgdGhlbiB0ZXN0IFBPUlRfQ0xPU0lO
RworCSAqIHdha2V1cCBmb3IgY2xvc2UoKSBmdW5jdGlvbgorCSAqLworCWNsZWFyX2JpdChJMlNf
UE9SVF9XUklURV9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKTsKKwl3YWtlX3VwKCZkcnZfZGF0YS0+
d3FfY2hhbl9jbG9zaW5nKTsKKwlpZiAodGVzdF9iaXQoSTJTX1BPUlRfQ0xPU0lORywgJmRydl9k
YXRhLT5mbGFncykpIHsKKwkJbXV0ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCQlkZXZf
ZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAid3JpdGUgZG9uZSB3YWtpbmcgdXAgY2xvc2UiKTsK
KwkJcmV0dXJuOworCX0KKwltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJaWYgKGRy
dl9kYXRhLT53cml0ZV9jYWxsYmFjayAhPSBOVUxMKQorCQlzdGF0dXMgPSBkcnZfZGF0YS0+d3Jp
dGVfY2FsbGJhY2socGFyYW1fY29tcGxldGUpOworCWVsc2UKKwkJZGV2X3dhcm4oJmRydl9kYXRh
LT5wZGV2LT5kZXYsICJXUiBkb25lIGJ1dCBubyBjYWxsYmFjayBzZXQiKTsKK30KKworc3RhdGlj
IGJvb2wgY2hhbl9maWx0ZXIoc3RydWN0IGRtYV9jaGFuICpjaGFuLCB2b2lkICpwYXJhbSkKK3sK
KwlzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmRydl9kYXRhID0gKHN0cnVjdCBpbnRlbF9taWRf
aTJzX2hkbCAqKXBhcmFtOworCWJvb2wgcmV0ID0gZmFsc2U7CisKKwlpZiAoIWRydl9kYXRhLT5k
bWFjMSkKKwkJZ290byBvdXQ7CisJaWYgKGNoYW4tPmRldmljZS0+ZGV2ID09ICZkcnZfZGF0YS0+
ZG1hYzEtPmRldikKKwkJcmV0ID0gdHJ1ZTsKK291dDoKKwlyZXR1cm4gcmV0OworfQorCisvKioK
KyAqIGkyc19kbWFfc3RhcnQgLSBwcmVwYXJlIGFuZCByZXNlcnZlIGRtYSBjaGFubmVscworICog
QGFyZyA6IGludGVsX21pZF9pMnNfaGRsIHBvaW50ZXIgdG8gdGhhdCBzaG91bGQgYmUgZHJpdmVy
IGRhdGEgKGNvbnRleHQpCisgKgorICogInNzcCBvcGVuIiBjb250ZXh0IGFuZCBkbWFjMSBzaG91
bGQgYWxyZWFkeSBiZSBmaWxsZWQgaW4gZHJ2X2RhdGEKKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVy
cworICogICAgICBpbnQgOiBzaG91bGQgYmUgemVybywgZWxzZSBpdCBtZWFucyBlcnJvciBjb2Rl
CisgKi8KK3N0YXRpYyBpbnQgaTJzX2RtYV9zdGFydChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmRydl9kYXRhKQoreworCXN0cnVjdCBpbnRlbF9taWRfZG1hX3NsYXZlICpyeHMsICp0eHM7CisJ
ZG1hX2NhcF9tYXNrX3QgbWFzazsKKwlpbnQgcmV0dmFsID0gMDsKKwlzdHJ1Y3QgcGNpX2RldiAq
bF9wZGV2OworCisJZGV2X2RiZygmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIkRNQUMxIHN0YXJ0XG4i
KTsKKwlkcnZfZGF0YS0+dHhjaGFuID0gTlVMTDsKKwlkcnZfZGF0YS0+cnhjaGFuID0gTlVMTDsK
KwlsX3BkZXYgPSBkcnZfZGF0YS0+cGRldjsKKwkvKiAxLiBpbml0IHJ4IGNoYW5uZWwgKi8KKwly
eHMgPSAmZHJ2X2RhdGEtPmRtYXNfcng7CisJcnhzLT5kaXJuID0gRE1BX0ZST01fREVWSUNFOwor
CXJ4cy0+aHNfbW9kZSA9IExOV19ETUFfSFdfSFM7CisJcnhzLT5jZmdfbW9kZSA9IExOV19ETUFf
UEVSX1RPX01FTTsKKwlyeHMtPnNyY193aWR0aCA9IExOV19ETUFfV0lEVEhfMTZCSVQ7CisJcnhz
LT5kc3Rfd2lkdGggPSBMTldfRE1BX1dJRFRIXzMyQklUOworCXJ4cy0+c3JjX21zaXplID0gTE5X
X0RNQV9NU0laRV84OworCXJ4cy0+ZHN0X21zaXplID0gTE5XX0RNQV9NU0laRV84OworCXJ4cy0+
ZGV2aWNlX2luc3RhbmNlID0gZHJ2X2RhdGEtPmRldmljZV9pbnN0YW5jZTsKKwlkbWFfY2FwX3pl
cm8obWFzayk7CisJZG1hX2NhcF9zZXQoRE1BX01FTUNQWSwgbWFzayk7CisJZG1hX2NhcF9zZXQo
RE1BX1NMQVZFLCBtYXNrKTsKKwlkcnZfZGF0YS0+cnhjaGFuID0gZG1hX3JlcXVlc3RfY2hhbm5l
bChtYXNrLCBjaGFuX2ZpbHRlciwgZHJ2X2RhdGEpOworCWlmICghZHJ2X2RhdGEtPnJ4Y2hhbikg
eworCQlkZXZfZXJyKCYoZHJ2X2RhdGEtPnBkZXYtPmRldiksCisJCQkiQ291bGQgbm90IGdldCBS
eCBjaGFubmVsXG4iKTsKKwkJcmV0dmFsID0gLTI7CisJCWdvdG8gZXJyX2V4aXQ7CisJfQorCWRy
dl9kYXRhLT5yeGNoYW4tPnByaXZhdGUgPSByeHM7CisJLyogMi4gaW5pdCB0eCBjaGFubmVsICov
CisJdHhzID0gJmRydl9kYXRhLT5kbWFzX3R4OworCXR4cy0+ZGlybiA9IERNQV9UT19ERVZJQ0U7
CisJdHhzLT5oc19tb2RlID0gTE5XX0RNQV9IV19IUzsKKwl0eHMtPmNmZ19tb2RlID0gTE5XX0RN
QV9NRU1fVE9fUEVSOworCXR4cy0+c3JjX3dpZHRoID0gTE5XX0RNQV9XSURUSF8zMkJJVDsKKwl0
eHMtPmRzdF93aWR0aCA9IExOV19ETUFfV0lEVEhfMTZCSVQ7CisJdHhzLT5zcmNfbXNpemUgPSBM
TldfRE1BX01TSVpFXzg7CisJdHhzLT5kc3RfbXNpemUgPSBMTldfRE1BX01TSVpFXzg7CisJdHhz
LT5kZXZpY2VfaW5zdGFuY2UgPSBkcnZfZGF0YS0+ZGV2aWNlX2luc3RhbmNlOworCWRtYV9jYXBf
c2V0KERNQV9TTEFWRSwgbWFzayk7CisJZG1hX2NhcF9zZXQoRE1BX01FTUNQWSwgbWFzayk7CisJ
ZHJ2X2RhdGEtPnR4Y2hhbiA9IGRtYV9yZXF1ZXN0X2NoYW5uZWwobWFzaywgY2hhbl9maWx0ZXIs
IGRydl9kYXRhKTsKKwlpZiAoIWRydl9kYXRhLT50eGNoYW4pIHsKKwkJZGV2X2VycigmKGRydl9k
YXRhLT5wZGV2LT5kZXYpLAorCQkJIkNvdWxkIG5vdCBnZXQgVHggY2hhbm5lbFxuIik7CisJCXJl
dHZhbCA9IC0zOworCQlnb3RvIGZyZWVfcnhjaGFuOworCX0KKwlkcnZfZGF0YS0+dHhjaGFuLT5w
cml2YXRlID0gdHhzOworCXJldHVybiByZXR2YWw7CitmcmVlX3J4Y2hhbjoKKwlkbWFfcmVsZWFz
ZV9jaGFubmVsKGRydl9kYXRhLT5yeGNoYW4pOworZXJyX2V4aXQ6CisJcmV0dXJuIHJldHZhbDsK
K30KKworLyoqCisgKiBpMnNfZG1hX3N0b3AgLSByZWxlYXNlIGRtYSBjaGFubmVscworICogQGFy
ZyA6IHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCBwb2ludGVyIHRvIHRoYXQgc2hvdWxkIGJlIGRy
aXZlciBkYXRhIChjb250ZXh0KQorICoKKyAqIGNhbGxlZCBieSBpbnRlbF9taWRfaTJzX2Nsb3Nl
KCkgY29udGV4dAorICoKKyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIG5vbmUKKyAqLwor
c3RhdGljIHZvaWQgaTJzX2RtYV9zdG9wKHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2Rh
dGEpCit7CisJZGV2X2RiZygmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIkRNQUMxIHN0b3BcbiIpOwor
CWRtYV9yZWxlYXNlX2NoYW5uZWwoZHJ2X2RhdGEtPnR4Y2hhbik7CisJZG1hX3JlbGVhc2VfY2hh
bm5lbChkcnZfZGF0YS0+cnhjaGFuKTsKK30KKworc3RhdGljIHZvaWQgaTJzX3NzcF9zdG9wKHN0
cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEpCit7CisJdm9pZCBfX2lvbWVtICpyZWcg
PSBkcnZfZGF0YS0+aW9hZGRyOworCWRldl9kYmcoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJTdG9w
IFNTUFxuIik7CisJY2xlYXJfU1NDUjBfcmVnKHJlZywgU1NFKTsKK30KKworc3RhdGljIHZvaWQg
c3NwMV9kdW1wX3JlZ2lzdGVycyhzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmRydl9kYXRhKQor
eworCXUzMiBpcnFfc3RhdHVzOworCXZvaWQgX19pb21lbSAqcmVnID0gZHJ2X2RhdGEtPmlvYWRk
cjsKKwlzdHJ1Y3QgZGV2aWNlICpkZGJnID0gJihkcnZfZGF0YS0+cGRldi0+ZGV2KTsKKwl1MzIg
c3RhdHVzOworCWlycV9zdGF0dXMgPSByZWFkX1NTU1IocmVnKTsKKwlkZXZfZGJnKGRkYmcsICJk
dW1wIFNTU1I9MHglMDhYXG4iLCBpcnFfc3RhdHVzKTsKKwlzdGF0dXMgPSByZWFkX1NTQ1IwKHJl
Zyk7CisJZGV2X2RiZyhkZGJnLCAiZHVtcCBTU0NSMD0weCUwOFhcbiIsIHN0YXR1cyk7CisJc3Rh
dHVzID0gcmVhZF9TU0NSMShyZWcpOworCWRldl9kYmcoZGRiZywgImR1bXAgU1NDUjE9MHglMDhY
XG4iLCBzdGF0dXMpOworCXN0YXR1cyA9IHJlYWRfU1NQU1AocmVnKTsKKwlkZXZfZGJnKGRkYmcs
ICJkdW1wIFNTUFNQPTB4JTA4WFxuIiwgc3RhdHVzKTsKKwlzdGF0dXMgPSByZWFkX1NTVFNBKHJl
Zyk7CisJZGV2X2RiZyhkZGJnLCAiZHVtcCBTU1RTQT0weCUwOFhcbiIsIHN0YXR1cyk7CisJc3Rh
dHVzID0gcmVhZF9TU1JTQShyZWcpOworCWRldl9kYmcoZGRiZywgImR1bXAgU1NSU0E9MHglMDhY
XG4iLCBzdGF0dXMpOworCXN0YXR1cyA9IHJlYWRfU1NUTyhyZWcpOworCWRldl9kYmcoZGRiZywg
ImR1bXAgU1NUTz0weCUwOFhcbiIsIHN0YXR1cyk7CisJc3RhdHVzID0gcmVhZF9TU0lUUihyZWcp
OworCWRldl9kYmcoZGRiZywgImR1bXAgU1NJVFI9MHglMDhYXG4iLCBzdGF0dXMpOworCXN0YXR1
cyA9IHJlYWRfU1NUU1MocmVnKTsKKwlkZXZfZGJnKGRkYmcsICJkdW1wIFNTVFNTPTB4JTA4WFxu
Iiwgc3RhdHVzKTsKKwlzdGF0dXMgPSByZWFkX1NTQUNEKHJlZyk7CisJZGV2X2RiZyhkZGJnLCAi
ZHVtcCBTU0FDRD0weCUwOFhcbiIsIHN0YXR1cyk7Cit9CisKKy8qKgorICogaTJzX2ludCgpOiBm
dW5jdGlvbiB0aGF0IGhhbmRsZXMgdGhlIFNTUCBJbnRlcnJ1cHRzIChlcnJvcnMpCisgKiBAaXJx
IDogSVJRIE51bWJlcgorICogQGRldl9pZCA6IHN0cnVjdHVyZSB0aGF0IGNvbnRhaW5zIGRyaXZl
ciBpbmZvcm1hdGlvbgorICoKKyAqIFRoaXMgaW50ZXJydXB0cyBkbyBub3RoaW5nIGJ1dCB3YXJu
aW5ncyBpbiBjYXNlIHRoZXJlIGlzIHNvbWUgcHJvYmxlbXMKKyAqIGluIEkyUyBjb25uZWN0aW9u
ICh1bmRlcnJ1bnMsIG92ZXJydW5zLi4uKS4gVGhpcyBtYXkgYmUgcmVwb3J0ZWQgYnkgYWRkaW5n
IGEKKyAqIG5ldyBpbnRlcmZhY2UgdG8gdGhlIGRyaXZlciwgYnV0IG5vdCB5ZXQgcmVxdWVzdGVk
IGJ5ICJ1c2VycyIgb2YgdGhpcyBkcml2ZXIKKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICog
ICAgICBOQQorICovCitzdGF0aWMgaXJxcmV0dXJuX3QgaTJzX2ludChpbnQgaXJxLCB2b2lkICpk
ZXZfaWQpCit7CisJc3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YSA9IGRldl9pZDsK
Kwl2b2lkIF9faW9tZW0gKnJlZzsKKwl1MzIgaXJxX3N0YXR1cyA9IDA7CisJdTMyIG1hc2tfc3Rh
dHVzID0gMDsKKwlzdHJ1Y3QgZGV2aWNlICpkZGJnID0gJihkcnZfZGF0YS0+cGRldi0+ZGV2KTsK
KwlyZWcgPSBkcnZfZGF0YS0+aW9hZGRyOworCWlycV9zdGF0dXMgPSByZWFkX1NTU1IocmVnKTsK
KworCWlmICghKGlycV9zdGF0dXMgJiAoZHJ2X2RhdGEtPm1hc2tfc3IpKSkgeworCQlyZXR1cm4g
SVJRX05PTkU7CisJfSBlbHNlIHsKKwkJLyogbWF5IGJlIGltcHJvdmVkIGJ5IHVzaW5nIGEgdGFz
a2xldCB0byBzZW5kIHRoZSBlcnJvcgorCQkgKiAodW5kZXJydW4sLi4uKSB0byBjbGllbnQgYnkg
dXNpbmcgY2FsbGJhY2sKKwkJICovCisJCWlmIChpcnFfc3RhdHVzICYgKFNTU1JfUk9SX01BU0sg
PDwgU1NTUl9ST1JfU0hJRlQpKSB7CisJCQlkZXZfd2FybihkZGJnLAorCQkJCSJzc3BfaW50IFJY
IEZJRk8gT1ZFUiBSVU4gU1NTUj0weCUwOFhcbiIsCisJCQkJaXJxX3N0YXR1cyk7CisJCQltYXNr
X3N0YXR1cyB8PSAoU1NTUl9ST1JfTUFTSyA8PCBTU1NSX1JPUl9TSElGVCk7CisKKwkJfQorCQlp
ZiAoaXJxX3N0YXR1cyAmIChTU1NSX1RVUl9NQVNLIDw8IFNTU1JfVFVSX1NISUZUKSkgeworCQkJ
ZGV2X3dhcm4oZGRiZywKKwkJCQkic3NwX2ludCBUWCBGSUZPIFVOREVSIFJVTiBTU1NSPTB4JTA4
WFxuIiwKKwkJCQlpcnFfc3RhdHVzKTsKKwkJCW1hc2tfc3RhdHVzIHw9IChTU1NSX1RVUl9NQVNL
IDw8IFNTU1JfVFVSX1NISUZUKTsKKworCQl9CisJCWlmIChpcnFfc3RhdHVzICYgKFNTU1JfVElO
VF9NQVNLIDw8IFNTU1JfVElOVF9TSElGVCkpIHsKKwkJCWRldl93YXJuKGRkYmcsCisJCQkJInNz
cF9pbnQgUlggVElNRSBPVVQgU1NTUj0weCUwOFhcbiIsCisJCQkJaXJxX3N0YXR1cyk7CisJCQlt
YXNrX3N0YXR1cyB8PSAoU1NTUl9USU5UX01BU0sgPDwgU1NTUl9USU5UX1NISUZUKTsKKworCQl9
CisJCWlmIChpcnFfc3RhdHVzICYgKFNTU1JfUElOVF9NQVNLIDw8IFNTU1JfUElOVF9TSElGVCkp
IHsKKwkJCWRldl93YXJuKGRkYmcsCisJCQkJInNzcF9pbnQgVFJBSUxJTkcgQllURSBTU1NSPTB4
JTA4WFxuIiwKKwkJCQlpcnFfc3RhdHVzKTsKKwkJCW1hc2tfc3RhdHVzIHw9IChTU1NSX1BJTlRf
TUFTSyA8PCBTU1NSX1BJTlRfU0hJRlQpOworCQl9CisJCWlmIChpcnFfc3RhdHVzICYgKFNTU1Jf
RU9DX01BU0sgPDwgU1NTUl9FT0NfU0hJRlQpKSB7CisJCQlkZXZfd2FybihkZGJnLAorCQkJCSJz
c3BfaW50IEVORCBPRiBDSEFJTiBTU1NSPTB4JTA4WFxuIiwKKwkJCQlpcnFfc3RhdHVzKTsKKwkJ
CW1hc2tfc3RhdHVzIHw9IChTU1NSX0VPQ19NQVNLIDw8IFNTU1JfRU9DX1NISUZUKTsKKwkJfQor
CQkvKiBjbGVhciBzdGlja3kgYml0cyAqLworCQl3cml0ZV9TU1NSKChpcnFfc3RhdHVzICYgbWFz
a19zdGF0dXMpLCByZWcpOworCX0KKwlyZXR1cm4gSVJRX0hBTkRMRUQ7Cit9CisKKy8qKgorICog
Y2FsY3VsYXRlX3NzcHNwX3BzcCAtIHNlcGFyYXRlIGZ1bmN0aW9uIHRoYXQgY2FsY3VsYXRlIHNz
cHNwIHJlZ2lzdGVyCisgKiBAcHNfc2V0dGluZ3MgOiBwb2ludGVyIG9mIHRoZSBzZXR0aW5ncyBz
dHJ1Y3QKKyAqCisgKiB0aGlzIGZ1bmN0aW9uIGlzIHRvIHNpbXBsaWZ5L2NsYXJpZnkgc2V0X3Nz
cF9pMnNfaHcgZnVuY3Rpb24KKyAqCisgKgorICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAg
dTMyIDogY2FsY3VsYXRlZCBTU1BTUCByZWdpc3RlcgorICovCit1MzIgY2FsY3VsYXRlX3NzcHNw
X3BzcChjb25zdCBzdHJ1Y3QgaW50ZWxfbWlkX2kyc19zZXR0aW5ncyAqcHNfc2V0dGluZ3MpCit7
CisJdTMyIHNzcHNwOworCXNzcHNwID0gU1NQU1BfcmVnKEZTUlQsCXBzX3NldHRpbmdzLT5zc3Bf
ZnJtc3luY190aW1pbmdfYml0KQorCQl8U1NQU1BfcmVnKEVURFMsCXBzX3NldHRpbmdzLT5zc3Bf
ZW5kX3RyYW5zZmVyX3N0YXRlKQorCQl8U1NQU1BfcmVnKFNDTU9ERSwJcHNfc2V0dGluZ3MtPnNz
cF9zZXJpYWxfY2xrX21vZGUpCisJCXxTU1BTUF9yZWcoRE1ZU1RPUCwJcHNfc2V0dGluZ3MtPnNz
cF9wc3BfVDQpCisJCXxTU1BTUF9yZWcoU0ZSTURMWSwJcHNfc2V0dGluZ3MtPnNzcF9wc3BfVDUp
CisJCXxTU1BTUF9yZWcoU0ZSTVdEVEgsCXBzX3NldHRpbmdzLT5zc3BfcHNwX1Q2KQorCQl8U1NQ
U1BfcmVnKFNGUk1QLAlwc19zZXR0aW5ncy0+c3NwX2ZybXN5bmNfcG9sX2JpdCk7CisJcmV0dXJu
IHNzcHNwOworfQorCisvKgorICogY2FsY3VsYXRlX3NzY3IwX3BzcDogc2VwYXJhdGUgZnVuY3Rp
b24gdGhhdCBjYWxjdWxhdGUgc3NjcjAgcmVnaXN0ZXIKKyAqIEBwc19zZXR0aW5ncyA6IHBvaW50
ZXIgb2YgdGhlIHNldHRpbmdzIHN0cnVjdAorICoKKyAqIHRoaXMgZnVuY3Rpb24gaXMgdG8gc2lt
cGxpZnkvY2xhcmlmeSBzZXRfc3NwX2kyc19odyBmdW5jdGlvbgorICoKKyAqIE91dHB1dCBwYXJh
bWV0ZXJzCisgKiAgICAgIHUzMiA6IGNhbGN1bGF0ZWQgU1NDUjAgcmVnaXN0ZXIKKyAqLwordTMy
IGNhbGN1bGF0ZV9zc2NyMF9wc3AoY29uc3Qgc3RydWN0IGludGVsX21pZF9pMnNfc2V0dGluZ3Mg
KnBzX3NldHRpbmdzKQoreworCXUxNiBsX3NzcF9kYXRhX3NpemUgPSBwc19zZXR0aW5ncy0+ZGF0
YV9zaXplOworCXUzMiBzc2NyMDsKKwlpZiAobF9zc3BfZGF0YV9zaXplID4gMTYpIHsKKwkJc3Nj
cjAgPSAgIFNTQ1IwX3JlZyhEU1MsIFNTQ1IwX0RhdGFTaXplKGxfc3NwX2RhdGFfc2l6ZSAtIDE2
KSkKKwkJCXwgU1NDUjBfcmVnKEVEU1MsIDEpOworCX0gZWxzZSB7CisJCXNzY3IwID0gICBTU0NS
MF9yZWcoRFNTLCBTU0NSMF9EYXRhU2l6ZShsX3NzcF9kYXRhX3NpemUpKQorCQkJfCBTU0NSMF9y
ZWcoRURTUywgMCk7CisJfQorLyoKK0NhbiBiZSByZXBsYWNlZCBieSBjb2RlIGJlbG93IDoKK3Nz
Y3IwID0gU1NDUjBfcmVnKERTUywgKGxfc3NwX2RhdGFfc2l6ZSAtIDEpICYgMHgwRikKK3wgU1ND
UjBfcmVnKEVEU1MsICgobF9zc3BfZGF0YV9zaXplIC0gMSkgJiAweDEwKSA+PiA4KTsKKyovCisJ
c3NjcjAgfD0gU1NDUjBfcmVnKE1PRCwJcHNfc2V0dGluZ3MtPm1vZGUpCisJCXxTU0NSMF9yZWco
RlJGLAlwc19zZXR0aW5ncy0+ZnJhbWVfZm9ybWF0KQorCQl8U1NDUjBfcmVnKFJJTSwJU1NQX1JY
X0ZJRk9fT1ZFUl9JTlRfRElTQUJMRSkKKwkJfFNTQ1IwX3JlZyhUSU0sCVNTUF9UWF9GSUZPX1VO
REVSX0lOVF9ESVNBQkxFKTsKKwlyZXR1cm4gc3NjcjA7Cit9CisKKy8qKgorICogY2FsY3VsYXRl
X3NzY3IxX3BzcCAtIHNlcGFyYXRlIGZ1bmN0aW9uIHRoYXQgY2FsY3VsYXRlIHNzY3IxIHJlZ2lz
dGVyCisgKiBAcHNfc2V0dGluZ3MgOiBwb2ludGVyIG9mIHRoZSBzZXR0aW5ncyBzdHJ1Y3QKKyAq
CisgKiB0aGlzIGZ1bmN0aW9uIGlzIHRvIHNpbXBsaWZ5L2NsYXJpZnkgc2V0X3NzcF9pMnNfaHcg
ZnVuY3Rpb24KKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICB1MzIgOiBjYWxjdWxh
dGVkIFNTQ1IxIHJlZ2lzdGVyCisgKi8KK3UzMiBjYWxjdWxhdGVfc3NjcjFfcHNwKGNvbnN0IHN0
cnVjdCBpbnRlbF9taWRfaTJzX3NldHRpbmdzICpwc19zZXR0aW5ncykKK3sKKwl1MzIgc3NjcjE7
CisJc3NjcjEgPSBTU0NSMV9yZWcoU0ZSTURJUiwJcHNfc2V0dGluZ3MtPnNzcHNmcm1fZGlyZWN0
aW9uKQorCQl8U1NDUjFfcmVnKFNDTEtESVIsCXBzX3NldHRpbmdzLT5zc3BzbGNsa19kaXJlY3Rp
b24pCisJCXxTU0NSMV9yZWcoVFRFTFAsCXBzX3NldHRpbmdzLT50eF90cmlzdGF0ZV9waGFzZSkK
KwkJfFNTQ1IxX3JlZyhUVEUsCXBzX3NldHRpbmdzLT50eF90cmlzdGF0ZV9lbmFibGUpCisJCXxT
U0NSMV9yZWcoVFJBSUwsCXBzX3NldHRpbmdzLT5zc3BfdHJhaWxpbmdfYnl0ZV9tb2RlKQorCQl8
U1NDUjFfcmVnKFRJTlRFLAlwc19zZXR0aW5ncy0+c3NwX3J4X3RpbWVvdXRfaW50ZXJydXB0X3N0
YXR1cykKKwkJfFNTQ1IxX3JlZyhQSU5URSwJcHNfc2V0dGluZ3MtPnNzcF90cmFpbGluZ19ieXRl
X2ludGVycnVwdF9zdGF0dXMpCisJCXxTU0NSMV9yZWcoTEJNLAlwc19zZXR0aW5ncy0+c3NwX2xv
b3BiYWNrX21vZGVfc3RhdHVzKQorCQl8U1NDUjFfcmVnKFJXT1QsCXBzX3NldHRpbmdzLT5zc3Bf
ZHVwbGV4X21vZGUpCisJCXxTU0NSMV9yZWcoUkZULAlTU0NSMV9SeFRyZXNoKHBzX3NldHRpbmdz
LT5zc3BfcnhfZmlmb190aHJlc2hvbGQpKQorCQl8U1NDUjFfcmVnKFRGVCwJU1NDUjFfVHhUcmVz
aChwc19zZXR0aW5ncy0+c3NwX3R4X2ZpZm9fdGhyZXNob2xkKSk7CisJcmV0dXJuIHNzY3IxOwor
fQorCisvKioKKyAqIHNldF9zc3BfaTJzX2h3IC0gY29uZmlndXJlIHRoZSBTU1AgZHJpdmVyIGFj
Y29yZGluZyB0byB0aGUgcHNfc2V0dGluZ3MKKyAqIEBkcnZfZGF0YSA6IHN0cnVjdHVyZSB0aGF0
IGNvbnRhaW5zIGFsbCBkZXRhaWxzIGFib3V0IHRoZSBTU1AgRHJpdmVyCisgKiBAcHNfc2V0dGlu
Z3MgOiBzdHJ1Y3R1cmUgdGhhdCBjb250YWlucyBTU1AgSGFyZHdhcmUgc2V0dGluZ3MKKyAqCisg
KiBpdCBhbHNvIHN0b3JlIHBzX3NldHRpbmdzIHRoZSBkcnZfZGF0YQorICoKKyAqIE91dHB1dCBw
YXJhbWV0ZXJzCisgKiAgICAgIE5BCisgKi8KK3N0YXRpYyB2b2lkIHNldF9zc3BfaTJzX2h3KHN0
cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEsCisJCQljb25zdCBzdHJ1Y3QgaW50ZWxf
bWlkX2kyc19zZXR0aW5ncyAqcHNfc2V0dGluZ3MpCit7CisJdTMyIHNzY3IwID0gMDsKKwl1MzIg
c3NjcjEgPSAwOworCXUzMiBzc3RzYSA9IDA7CisJdTMyIHNzcnNhID0gMDsKKwl1MzIgc3Nwc3Ag
PSAwOworCXUzMiBzc3NyID0gMDsKKwkvKiBHZXQgdGhlIFNTUCBTZXR0aW5ncyAqLworCXUxNiBs
X3NzcF9jbGtfZnJtX21vZGUgPSAweEZGOworCXZvaWQgX19pb21lbSAqcmVnID0gZHJ2X2RhdGEt
PmlvYWRkcjsKKwlzdHJ1Y3QgZGV2aWNlICpkZGJnID0gJihkcnZfZGF0YS0+cGRldi0+ZGV2KTsK
KwlkZXZfZGJnKGRkYmcsCisJCSJzZXR1cCBTU1AgSTJTIFBDTTEgY29uZmlndXJhdGlvblxuIik7
CisJaWYgKChwc19zZXR0aW5ncy0+c3Nwc2ZybV9kaXJlY3Rpb24gPT0gU1NQU0ZSTV9NQVNURVJf
TU9ERSkKKwkgICAmJiAocHNfc2V0dGluZ3MtPnNzcHNsY2xrX2RpcmVjdGlvbiA9PSBTU1BTQ0xL
X01BU1RFUl9NT0RFKSkgeworCQlsX3NzcF9jbGtfZnJtX21vZGUgPSBTU1BfSU5fTUFTVEVSX01P
REU7CisJfSBlbHNlIGlmICgocHNfc2V0dGluZ3MtPnNzcHNmcm1fZGlyZWN0aW9uID09IFNTUFNG
Uk1fU0xBVkVfTU9ERSkKKwkgICAmJiAocHNfc2V0dGluZ3MtPnNzcHNsY2xrX2RpcmVjdGlvbiA9
PSBTU1BTQ0xLX1NMQVZFX01PREUpKSB7CisJCWxfc3NwX2Nsa19mcm1fbW9kZSA9IFNTUF9JTl9T
TEFWRV9NT0RFOworCX0gZWxzZSB7CisJCWRldl9lcnIoZGRiZywgIlVuc3VwcG9ydGVkIEkyUyBQ
Q00xIGNvbmZpZ3VyYXRpb25cbiIpOworCQlnb3RvIGxlYXZlOworCX0KKwlkZXZfZGJnKGRkYmcs
ICJTU1BTRlJNX0RJUkVDVElPTjolZDpcbiIsCisJCXBzX3NldHRpbmdzLT5zc3BzZnJtX2RpcmVj
dGlvbik7CisJZGV2X2RiZyhkZGJnLCAiU1NQU0NMS19ESVJFQ1RJT046JWQ6XG4iLAorCQlwc19z
ZXR0aW5ncy0+c3Nwc2xjbGtfZGlyZWN0aW9uKTsKKwlpZiAocHNfc2V0dGluZ3MtPmZyYW1lX2Zv
cm1hdCAhPSBQU1BfRk9STUFUKSB7CisJCWRldl9lcnIoZGRiZywgIlVOU1VQUE9SVEVEIEZSQU1F
IEZPUk1BVDolZDpcbiIsIHBzX3NldHRpbmdzLT5mcmFtZV9mb3JtYXQpOworCQlnb3RvIGxlYXZl
OworCX0KKwlpZiAoKHBzX3NldHRpbmdzLT5zc3BfdHhfZG1hICE9IFNTUF9UWF9ETUFfRU5BQkxF
KQorCXx8IChwc19zZXR0aW5ncy0+c3NwX3J4X2RtYSAhPSBTU1BfUlhfRE1BX0VOQUJMRSkpIHsK
KwkJZGV2X2VycihkZGJnLCAiT05MWSBETUEgTU9ERSBJUyBTVVBQT1JURUQiKTsKKwkJZ290byBs
ZWF2ZTsKKwl9CisJLyoqKioqKioqKioqIERNQSBUcmFuc2ZlciBNb2RlICoqKioqKioqKioqLwor
CWRldl9kYmcoZGRiZywgIkZPUk1BVCA6JWQ6XG4iLCBwc19zZXR0aW5ncy0+ZnJhbWVfZm9ybWF0
KTsKKwlzc2NyMCA9IGNhbGN1bGF0ZV9zc2NyMF9wc3AocHNfc2V0dGluZ3MpOworCWRldl9kYmco
ZGRiZywgIiBzc2NyMCA6MHglMDhYXG4iLCBzc2NyMCk7CisJc3NjcjEgPSBjYWxjdWxhdGVfc3Nj
cjFfcHNwKHBzX3NldHRpbmdzKTsKKwlkZXZfZGJnKGRkYmcsICIgc3NjcjEgOjB4JTA4WFxuIiwg
c3NjcjEpOworCWlmIChwc19zZXR0aW5ncy0+bW9kZSA9PSBTU1BfSU5fTkVUV09SS19NT0RFKSB7
CisJCWRldl9kYmcoZGRiZywgIk1PREUgOiVkOlxuIiwgcHNfc2V0dGluZ3MtPm1vZGUpOworCQlz
c2NyMCB8PSBTU0NSMF9yZWcoRlJEQywgU1NDUjBfU2xvdHNQZXJGcm0ocHNfc2V0dGluZ3MtPmZy
YW1lX3JhdGVfZGl2aWRlcl9jb250cm9sKSk7CisJCWRldl9kYmcoZGRiZywgInNzY3IwIDoweCUw
OFhcbiIsIHNzY3IwKTsKKwkJc3Nwc3AgPSBjYWxjdWxhdGVfc3Nwc3BfcHNwKHBzX3NldHRpbmdz
KTsKKwkJZGV2X2RiZyhkZGJnLCAic3Nwc3AgOjB4JTA4WFxuIiwgc3Nwc3ApOworCQkvKiBzZXQg
dGhlIGFjdGl2ZSBUWCB0aW1lIHNsb3QgKGJpdG1hcCkgKi8KKwkJc3N0c2EgPSBTU1RTQV9yZWco
VFRTQSwgcHNfc2V0dGluZ3MtPnNzcF9hY3RpdmVfdHhfc2xvdHNfbWFwKTsKKwkJLyogc2V0IHRo
ZSBhY3RpdmUgUlggdGltZSBzbG90IChiaXRtYXApICovCisJCXNzcnNhID0gU1NSU0FfcmVnKFJU
U0EsIHBzX3NldHRpbmdzLT5zc3BfYWN0aXZlX3J4X3Nsb3RzX21hcCk7CisJCWlmIChsX3NzcF9j
bGtfZnJtX21vZGUgPT0gU1NQX0lOX01BU1RFUl9NT0RFKSB7CisJCQlzd2l0Y2ggKHBzX3NldHRp
bmdzLT5tYXN0ZXJfbW9kZV9jbGtfc2VsZWN0aW9uKSB7CisJCQljYXNlIFNTUF9PTkNISVBfQ0xP
Q0s6CisJCQkJYnJlYWs7CisJCQljYXNlIFNTUF9ORVRXT1JLX0NMT0NLOgorCQkJCXNzY3IwIHw9
IFNTQ1IwX3JlZyhOQ1MsIDEpOworCQkJCWJyZWFrOworCQkJY2FzZSBTU1BfRVhURVJOQUxfQ0xP
Q0s6CisJCQkJc3NjcjAgfD0gU1NDUjBfcmVnKEVDUywgMSk7CisJCQkJYnJlYWs7CisJCQljYXNl
IFNTUF9PTkNISVBfQVVESU9fQ0xPQ0s6CisJCQkJc3NjcjAgfD0gU1NDUjBfcmVnKEFDUywgMSk7
CisJCQkJYnJlYWs7CisJCQlkZWZhdWx0OgorCQkJCWRldl9lcnIoZGRiZywgIk1hc3RlciBNb2Rl
IGNsayBzZWxlY3Rpb24gVU5LTk9XTiIpOworCQkJCWJyZWFrOworCQkJfQorCQkJc3Nwc3AgfD0g
U1NQU1BfcmVnKFNUUlRETFksIHBzX3NldHRpbmdzLT5zc3BfcHNwX1QxKQorCQkJCXxTU1BTUF9y
ZWcoRE1ZU1RSVCwgcHNfc2V0dGluZ3MtPnNzcF9wc3BfVDIpOworCQl9IGVsc2UgewkvKiBTZXQg
dGhlIFNsYXZlIENsb2NrIEZyZWUgUnVubmluZyBTdGF0dXMgKi8KKwkJCXNzY3IxIHw9IFNTQ1Ix
X3JlZyhTQ0ZSLCBwc19zZXR0aW5ncy0+c2xhdmVfY2xrX2ZyZWVfcnVubmluZ19zdGF0dXMpOwor
CQl9CisJfSBlbHNlIHsgIC8qIFNTUF9JTl9OT1JNQUxfTU9ERSAqLworCQlkZXZfZXJyKGRkYmcs
ICJVTlNVUFBPUlRFRCBNT0RFIik7CisJCWdvdG8gbGVhdmU7CisJfQorCisJLyogQ2xlYXIgc3Rh
dHVzICovCisJc3NzciA9IChTU1NSX0JDRV9NQVNLIDw8IFNTU1JfQkNFX1NISUZUKQorCSAgICAg
fCAoU1NTUl9UVVJfTUFTSyA8PCBTU1NSX1RVUl9TSElGVCkKKwkgICAgIHwgKFNTU1JfVElOVF9N
QVNLIDw8IFNTU1JfVElOVF9TSElGVCkKKwkgICAgIHwgKFNTU1JfUElOVF9NQVNLIDw8IFNTU1Jf
UElOVF9TSElGVCkKKwkgICAgIHwgKFNTU1JfUk9SX01BU0sgPDwgU1NTUl9ST1JfU0hJRlQpOwor
CS8qIGRpc2FibGUgU1NQICovCisJY2xlYXJfU1NDUjBfcmVnKHJlZywgU1NFKTsKKwlkZXZfZGJn
KGRkYmcsICJXUklURSBTU0NSMCBESVNBQkxFXG4iKTsKKwkvKiBDbGVhciBzdGF0dXMgKi8KKwl3
cml0ZV9TU1NSKHNzc3IsIHJlZyk7CisJZGV2X2RiZyhkZGJnLCAiV1JJVEUgU1NTUjogMHglMDhY
XG4iLCBzc3NyKTsKKwl3cml0ZV9TU0NSMChzc2NyMCwgcmVnKTsKKwlkZXZfZGJnKGRkYmcsICJX
UklURSBTU0NSMFxuIik7CisJLyogZmlyc3Qgc2V0IENSMSB3aXRob3V0IGludGVycnVwdCBhbmQg
c2VydmljZSBlbmFibGVzICovCisJd3JpdGVfU1NDUjEoc3NjcjEsIHJlZyk7CisJd3JpdGVfU1NQ
U1Aoc3Nwc3AsIHJlZyk7CisJd3JpdGVfU1NUU0Eoc3N0c2EsIHJlZyk7CisJd3JpdGVfU1NSU0Eo
c3Nyc2EsIHJlZyk7CisJLyogc2V0IHRoZSB0aW1lIG91dCBmb3IgdGhlIHJlY2VwdGlvbiAqLwor
CXdyaXRlX1NTVE8oMCwgcmVnKTsKKwlzc3AxX2R1bXBfcmVnaXN0ZXJzKGRydl9kYXRhKTsKK2xl
YXZlOgorCXJldHVybjsKK30KKworc3RhdGljIGludAoraW50ZWxfbWlkX2kyc19maW5kX3VzYWdl
KHN0cnVjdCBwY2lfZGV2ICpwZGV2LAorCQkJIHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2
X2RhdGEsCisJCQkgZW51bSBpbnRlbF9taWRfaTJzX3NzcF91c2FnZSAqdXNhZ2UpCit7CisJaW50
IHBvczsKKwl1OCAgYWRpZDsKKwlpbnQgc3RhdHVzID0gMDsKKworCSp1c2FnZSA9IFNTUF9VU0FH
RV9VTkFTU0lHTkVEOworCXBvcyA9IHBjaV9maW5kX2NhcGFiaWxpdHkocGRldiwgUENJX0NBUF9J
RF9WTkRSKTsKKwlkZXZfaW5mbygoJnBkZXYtPmRldiksCisJCSJQcm9iZS9maW5kIGNhcGFiaWxp
dHkgKFZORFIgJWQgcG9zPTB4JXgpXG4iLAorCQlQQ0lfQ0FQX0lEX1ZORFIsIHBvcyk7CisJaWYg
KHBvcyA+IDApIHsKKwkJcG9zICs9IFBDSV9DQVBfT0ZGU0VUX0FESUQ7CisJCXBjaV9yZWFkX2Nv
bmZpZ19ieXRlKHBkZXYsIHBvcywgJmFkaWQpOworCQlkZXZfaW5mbygmKHBkZXYtPmRldiksICJW
ZW5kb3IgY2FwYWJpbGl0eSBhZGlkID0gMHgleFxuIiwgYWRpZCk7CisJCWlmIChhZGlkID09IFBD
SV9DQVBfQURJRF9JMlNfQlRfRk0pCisJCQkqdXNhZ2UJPSBTU1BfVVNBR0VfQkxVRVRPT1RIX0ZN
OworCQllbHNlIGlmIChhZGlkID09IFBDSV9DQVBfQURJRF9JMlNfTU9ERU0pCisJCQkqdXNhZ2UJ
PSBTU1BfVVNBR0VfTU9ERU07CisJCWVsc2UKKwkJCSp1c2FnZQk9IFNTUF9VU0FHRV9VTkFTU0lH
TkVEOworCX0KKwkvKiBJZiB0aGVyZSBpcyBubyBjYXBhYmlsaXR5LCBjaGVjayB3aXRoIG9sZCBQ
Q0lfSUQgKi8KKyNpZmRlZiBCWVBBU1NfQURJRAorCWlmICgqdXNhZ2UgPT0gU1NQX1VTQUdFX1VO
QVNTSUdORUQpIHsKKwkJZGV2X3dhcm4oJihwZGV2LT5kZXYpLCAiVmVuZG9yIGNhcGFiaWxpdHkg
bm90IHByZXNlbnQvaW52YWxpZFxuIik7CisJCXN3aXRjaCAocGRldi0+ZGV2aWNlKSB7CisJCWNh
c2UgTUZMRF9TU1AxX0RFVklDRV9JRDoKKwkJCSp1c2FnZQk9IFNTUF9VU0FHRV9CTFVFVE9PVEhf
Rk07CisJCQlicmVhazsKKwkJY2FzZSBNRkxEX1NTUDBfREVWSUNFX0lEOgorCQkJKnVzYWdlCT0g
U1NQX1VTQUdFX01PREVNOworCQkJYnJlYWs7CisJCX0KKwl9CisjZW5kaWYKKwlpZiAoKnVzYWdl
ID09IFNTUF9VU0FHRV9VTkFTU0lHTkVEKSB7CisJCWRldl9pbmZvKCgmcGRldi0+ZGV2KSwKKwkJ
CSJObyBwcm9iZSBmb3IgSTJTIFBDSS1JRDogJTA0eDolMDR4LCBBRElEKDB4JXgpPTB4JXhcbiIs
CisJCQlwZGV2LT52ZW5kb3IsIHBkZXYtPmRldmljZSwgcG9zLCBhZGlkKTsKKwkJc3RhdHVzID0g
LUVOT0RFVjsKKwkJZ290byBlcnJfZmluZF91c2FnZTsKKwl9CisJZGV2X2RiZygmKHBkZXYtPmRl
diksCisJCSJEZXRlY3RlZCBQQ0kgU1NQIChJRDogJTA0eDolMDR4KSB1c2FnZSA9JXhcbiIsCisJ
CXBkZXYtPnZlbmRvciwgcGRldi0+ZGV2aWNlLCAqdXNhZ2UpOworCWRldl9kYmcoJihwZGV2LT5k
ZXYpLAorCQkiIGZvdW5kIFBDSSBTU1AgY29udHJvbGxlcihJRDogJTA0eDolMDR4KVxuIiwKKwkJ
cGRldi0+dmVuZG9yLCBwZGV2LT5kZXZpY2UpOworCS8qIEluaXQgdGhlIGRyaXZlciBkYXRhIHN0
cnVjdHVyZSBmaWVsZHMqLworCXN3aXRjaCAocGRldi0+ZGV2aWNlKSB7CisJY2FzZSBNRkxEX1NT
UDFfREVWSUNFX0lEOgorCQlkcnZfZGF0YS0+ZGV2aWNlX2luc3RhbmNlID0gRE1BMUNfREVWSUNF
X0lOU1RBTkNFX1NTUDE7CisJCWJyZWFrOworCWNhc2UgTUZMRF9TU1AwX0RFVklDRV9JRDoKKwkJ
ZHJ2X2RhdGEtPmRldmljZV9pbnN0YW5jZSA9IERNQTFDX0RFVklDRV9JTlNUQU5DRV9TU1AwOwor
CQlicmVhazsKKwlkZWZhdWx0OgorCQlkZXZfZXJyKCYocGRldi0+ZGV2KSwKKwkJCSJDYW4gbm90
IGRldGVybWluZSBkbWEgZGV2aWNlIGluc3RhbmNlIChQQ0kgSUQ6JTA0eClcbiIsCisJCQlwZGV2
LT5kZXZpY2UpOworCQlzdGF0dXMgPSAtRU5PREVWOworCQlnb3RvIGVycl9maW5kX3VzYWdlOwor
CX0KKwlzdGF0dXMgPSBwY2lfZW5hYmxlX2RldmljZShwZGV2KTsKKwlpZiAoc3RhdHVzKQorCQlk
ZXZfZXJyKCgmcGRldi0+ZGV2KSwgIkNhbiBub3QgZW5hYmxlIGRldmljZS5FcnI9JWRcbiIsIHN0
YXR1cyk7CitlcnJfZmluZF91c2FnZToKKwlyZXR1cm4gc3RhdHVzOworfQorCisvKioKKyAqIGlu
dGVsX21pZF9pMnNfcHJvYmUgLSBwcm9iaW5nIGZ1bmN0aW9uIGZvciB0aGUgcGNpIHNlbGVjdGVk
CisgKiBAcGRldiA6IHBjaV9kZXYgcG9pbnRlciB0aGF0IGlzIHByb2JlZAorICogQGVudCA6IHBj
aV9kZXZpY2VfaWQKKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICBOQQorICovCitz
dGF0aWMgaW50IGludGVsX21pZF9pMnNfcHJvYmUoc3RydWN0IHBjaV9kZXYgKnBkZXYsCisJCQkJ
Y29uc3Qgc3RydWN0IHBjaV9kZXZpY2VfaWQgKmVudCkKK3sKKwlzdHJ1Y3QgaW50ZWxfbWlkX2ky
c19oZGwgKmRydl9kYXRhOworCWludCBzdGF0dXMgPSAwOworCWVudW0gaW50ZWxfbWlkX2kyc19z
c3BfdXNhZ2UgdXNhZ2U7CisKKwlkcnZfZGF0YSA9IGt6YWxsb2Moc2l6ZW9mKHN0cnVjdCBpbnRl
bF9taWRfaTJzX2hkbCksIEdGUF9LRVJORUwpOworCWRldl9kYmcoJihwZGV2LT5kZXYpLCAiJXMg
UHJvYmUsIGRydl9kYXRhID0lcFxuIiwgRFJJVkVSX05BTUUsIGRydl9kYXRhKTsKKwlpZiAoIWRy
dl9kYXRhKSB7CisJCWRldl9lcnIoKCZwZGV2LT5kZXYpLCAiQ2FuJ3QgYWxsb2MgZHJpdmVyIGRh
dGEgaW4gcHJvYmVcbiIpOworCQlzdGF0dXMgPSAtRU5PTUVNOworCQlnb3RvIGxlYXZlOworCX0K
KwlkZXZfaW5mbygoJnBkZXYtPmRldiksICJEZXRlY3RlZCBQQ0kgU1NQIChJRDogJTA0eDolMDR4
KVxuIiwgcGRldi0+dmVuZG9yLCBwZGV2LT5kZXZpY2UpOworCXN0YXR1cyA9IGludGVsX21pZF9p
MnNfZmluZF91c2FnZShwZGV2LCBkcnZfZGF0YSwgJnVzYWdlKTsKKwlpZiAoc3RhdHVzKQorCQln
b3RvIGVycl9pMnNfcHJvYmUwOworCW11dGV4X2luaXQoJmRydl9kYXRhLT5tdXRleCk7CisJZHJ2
X2RhdGEtPnBkZXYgPSBwZGV2OworCWRydl9kYXRhLT51c2FnZSA9IHVzYWdlOworCS8qCisJICog
R2V0IGJhc2ljIGlvIHJlc291cmNlIGFuZCBtYXAgaXQgZm9yIFNTUDEgW0JBUj0wXQorCSAqLwor
CWlmICgocGRldi0+ZGV2aWNlID09IE1GTERfU1NQMV9ERVZJQ0VfSUQpIHx8CisJICAgIChwZGV2
LT5kZXZpY2UgPT0gTUZMRF9TU1AwX0RFVklDRV9JRCkpIHsKKwkJZHJ2X2RhdGEtPnBhZGRyID0g
cGNpX3Jlc291cmNlX3N0YXJ0KHBkZXYsIE1SU1RfU1NQX0JBUik7CisJCWRydl9kYXRhLT5pb2xl
biA9IHBjaV9yZXNvdXJjZV9sZW4ocGRldiwgTVJTVF9TU1BfQkFSKTsKKwkJc3RhdHVzID0gcGNp
X3JlcXVlc3RfcmVnaW9uKHBkZXYsIE1SU1RfU1NQX0JBUiwgZGV2X25hbWUoJnBkZXYtPmRldikp
OworCQkvKiBtYXAgYnVzIG1lbW9yeSBpbnRvIENQVSBzcGFjZSAqLworCQlkcnZfZGF0YS0+aW9h
ZGRyID0gcGNpX2lvcmVtYXBfYmFyKHBkZXYsIE1SU1RfU1NQX0JBUik7CisJfSBlbHNlIHsKKwkJ
ZGV2X2VycigmcGRldi0+ZGV2LAorCQkJIkRvbid0IGtub3cgd2hpY2ggQkFSIHRvIHVzZWZvciB0
aGlzIFNTUCBQQ0RJRD0leFxuIiwKKwkJCXBkZXYtPmRldmljZSk7CisJCXN0YXR1cyA9IC1FTk9E
RVY7CisJCWdvdG8gZXJyX2kyc19wcm9iZTE7CisJfQorCWRldl9kYmcoJihwZGV2LT5kZXYpLCAi
cGFkZHIgPSA6ICV4XG4iLCBkcnZfZGF0YS0+cGFkZHIpOworCWRldl9kYmcoJihwZGV2LT5kZXYp
LCAiaW9sZW4gPSA6ICVkXG4iLCBkcnZfZGF0YS0+aW9sZW4pOworCWlmIChzdGF0dXMpIHsKKwkJ
ZGV2X2VycigoJnBkZXYtPmRldiksICJDYW4ndCByZXF1ZXN0IHJlZ2lvbi4gZXJyPSVkXG4iLCBz
dGF0dXMpOworCQlnb3RvIGVycl9pMnNfcHJvYmUxOworCX0KKwlpZiAoIWRydl9kYXRhLT5pb2Fk
ZHIpIHsKKwkJZGV2X2VycigoJnBkZXYtPmRldiksICJpb3JlbWFwX25vY2FjaGUgZXJyb3JcbiIp
OworCQlzdGF0dXMgPSAtRU5PTUVNOworCQlnb3RvIGVycl9pMnNfcHJvYmUyOworCX0KKwlkZXZf
ZGJnKCYocGRldi0+ZGV2KSwgImlvYWRkciA9IDogJXBcbiIsIGRydl9kYXRhLT5pb2FkZHIpOwor
CS8qIHByZXBhcmUgZm9yIERNQSBjaGFubmVsIGFsbG9jYXRpb24gKi8KKwkvKiBnZXQgdGhlIHBj
aV9kZXYgc3RydWN0dXJlIHBvaW50ZXIgKi8KKwkvKiBDaGVjayB0aGUgU1NQLCBpZiBTU1AzLCB0
aGVuIGFub3RoZXIgRE1BIGlzIHVzZWQgKEdQRE1BLi4pICovCisJaWYgKChwZGV2LT5kZXZpY2Ug
PT0gTUZMRF9TU1AxX0RFVklDRV9JRCkgfHwKKwkgICAgKHBkZXYtPmRldmljZSA9PSBNRkxEX1NT
UDBfREVWSUNFX0lEKSkgeworCQlkcnZfZGF0YS0+ZG1hYzEgPSBwY2lfZ2V0X2RldmljZShQQ0lf
VkVORE9SX0lEX0lOVEVMLAorCQkJCQkJIE1GTERfTFBFX0RNQV9ERVZJQ0VfSUQsCisJCQkJCQkg
TlVMTCk7CisJfSBlbHNlIHsKKwkJZGV2X2VycigmcGRldi0+ZGV2LAorCQkJIkRvbid0IGtub3cg
ZG1hIGRldmljZSBJRCBmb3IgdGhpcyBTU1AgUENESUQ9JXhcbiIsCisJCQlwZGV2LT5kZXZpY2Up
OworCQlnb3RvIGVycl9pMnNfcHJvYmUzOworCX0KKwkvKiBpbiBjYXNlIHRoZSBzdG9wIGRtYSBo
YXZlIHRvIHdhaXQgZm9yIGVuZCBvZiBjYWxsYmFja3MgICAqLworCS8qIFRoaXMgd2lsbCBiZSBy
ZW1vdmVkIHdoZW4gVEVSTUlOQVRFX0FMTCBhdmFpbGFibGUgaW4gRE1BICovCisJaW5pdF93YWl0
cXVldWVfaGVhZCgmZHJ2X2RhdGEtPndxX2NoYW5fY2xvc2luZyk7CisJaWYgKCFkcnZfZGF0YS0+
ZG1hYzEpIHsKKwkJZGV2X2VycigmKGRydl9kYXRhLT5wZGV2LT5kZXYpLCAiQ2FuJ3QgZmluZCBE
TUFDMSwgZG1hIGluaXQgZmFpbGVkXG4iKTsKKwkJc3RhdHVzID0gLUVOT0RFVjsKKwkJZ290byBl
cnJfaTJzX3Byb2JlMzsKKwl9CisJLyogaW5jcmVtZW50IHJlZiBjb3VudCBvZiBwY2kgZGV2aWNl
IHN0cnVjdHVyZSBhbHJlYWR5IGRvbmUgYnkgKi8KKwkvKiBwY2lfZ2V0X2RldmljZS4gd2lsbCBk
byBhIHBjaV9kZXZfcHV0IHdoZW4gZXhpdGluZyB0aGUgbW9kdWxlICovCisJcGNpX3NldF9kcnZk
YXRhKHBkZXYsIGRydl9kYXRhKTsKKwkvKiBzZXQgU1NQIEZyYW1lU3luYyBhbmQgQ0xLIGRpcmVj
dGlvbiBpbiBJTlBVVCBtb2RlIGluIG9yZGVyCisJICogdG8gYXZvaWQgZGlzdHVyYmluZyBwZXJp
cGhlcmFscworCSAqLworCXdyaXRlX1NTQ1IxKChTU0NSMV9TRlJNRElSX01BU0s8PFNTQ1IxX1NG
Uk1ESVJfU0hJRlQpCisJCSAgfCAoU1NDUjFfU0NMS0RJUl9NQVNLPDxTU0NSMV9TQ0xLRElSX1NI
SUZUKSwKKwlkcnZfZGF0YS0+aW9hZGRyKTsKKwkvKiBBdHRhY2ggdG8gSVJRICovCisJZHJ2X2Rh
dGEtPmlycSA9IHBkZXYtPmlycTsKKwlkZXZfZGJnKCYocGRldi0+ZGV2KSwgImF0dGFjaGluZyB0
byBJUlE6ICUwNHhcbiIsIHBkZXYtPmlycSk7CisJc3RhdHVzID0gcmVxdWVzdF9pcnEoZHJ2X2Rh
dGEtPmlycSwgaTJzX2ludCwgSVJRRl9TSEFSRUQsICJpMnMgc3NwIiwgZHJ2X2RhdGEpOworCWlm
IChzdGF0dXMgPCAwKQl7CisJCWRldl9lcnIoJnBkZXYtPmRldiwgImNhbiBub3QgZ2V0IElSUS4g
c3RhdHVzIGVycj0lZFxuIiwgc3RhdHVzKTsKKwkJZ290byBlcnJfaTJzX3Byb2JlMzsKKwl9CisJ
cG1fcnVudGltZV9lbmFibGUoJihkcnZfZGF0YS0+cGRldi0+ZGV2KSk7CisJZ290byBsZWF2ZTsK
K2Vycl9pMnNfcHJvYmUzOgorCWlvdW5tYXAoZHJ2X2RhdGEtPmlvYWRkcik7CitlcnJfaTJzX3By
b2JlMjoKKwlwY2lfcmVsZWFzZV9yZWdpb24ocGRldiwgTVJTVF9TU1BfQkFSKTsKK2Vycl9pMnNf
cHJvYmUxOgorCXBjaV9kaXNhYmxlX2RldmljZShwZGV2KTsKK2Vycl9pMnNfcHJvYmUwOgorCWtm
cmVlKGRydl9kYXRhKTsKK2xlYXZlOgorCXJldHVybiBzdGF0dXM7Cit9CisKK3N0YXRpYyB2b2lk
IF9fZGV2ZXhpdCBpbnRlbF9taWRfaTJzX3JlbW92ZShzdHJ1Y3QgcGNpX2RldiAqcGRldikKK3sK
KwlzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmRydl9kYXRhOworCisJZHJ2X2RhdGEgPSBwY2lf
Z2V0X2RydmRhdGEocGRldik7CisJaWYgKCFkcnZfZGF0YSkgeworCQlkZXZfZXJyKCZwZGV2LT5k
ZXYsICJubyBkcnZfZGF0YSBpbiBwY2kgZGV2aWNlIHRvIHJlbW92ZSFcbiIpOworCQlnb3RvIGxl
YXZlOworCX0KKwlpZiAodGVzdF9iaXQoSTJTX1BPUlRfT1BFTkVELCAmZHJ2X2RhdGEtPmZsYWdz
KSkgeworCQlkZXZfd2FybigmcGRldi0+ZGV2LCAiTm90IGNsb3NlZCBiZWZvcmUgcmVtb3Zpbmcg
cGNpX2RldiFcbiIpOworCQlpbnRlbF9taWRfaTJzX2Nsb3NlKGRydl9kYXRhKTsKKwl9CisJcGNp
X3NldF9kcnZkYXRhKHBkZXYsIE5VTEwpOworCS8qIFN0b3AgRE1BIGlzIGFscmVhZHkgZG9uZSBk
dXJpbmcgY2xvc2UoKSAgKi8KKwlwY2lfZGV2X3B1dChkcnZfZGF0YS0+ZG1hYzEpOworCS8qIERp
c2FibGUgdGhlIFNTUCBhdCB0aGUgcGVyaXBoZXJhbCBhbmQgU09DIGxldmVsICovCisJd3JpdGVf
U1NDUjAoMCwgZHJ2X2RhdGEtPmlvYWRkcik7CisJZnJlZV9pcnEoZHJ2X2RhdGEtPmlycSwgZHJ2
X2RhdGEpOworCWlvdW5tYXAoZHJ2X2RhdGEtPmlvYWRkcik7CisJcGNpX3JlbGVhc2VfcmVnaW9u
KHBkZXYsIE1SU1RfU1NQX0JBUik7CisJcGNpX3JlbGVhc2VfcmVnaW9uKHBkZXYsIE1SU1RfTFBF
X0JBUik7CisJcGNpX2Rpc2FibGVfZGV2aWNlKHBkZXYpOworCWtmcmVlKGRydl9kYXRhKTsKK2xl
YXZlOgorCXJldHVybjsKK30KKworLyoqCisgKiBpbnRlbF9taWRfaTJzX2luaXQgLSByZWdpc3Rl
ciBwY2kgZHJpdmVyCisgKgorICovCitzdGF0aWMgaW50IF9faW5pdCBpbnRlbF9taWRfaTJzX2lu
aXQodm9pZCkKK3sKKwlyZXR1cm4gcGNpX3JlZ2lzdGVyX2RyaXZlcigmaW50ZWxfbWlkX2kyc19k
cml2ZXIpOworfQorCitzdGF0aWMgdm9pZCBfX2V4aXQgaW50ZWxfbWlkX2kyc19leGl0KHZvaWQp
Cit7CisJcGNpX3VucmVnaXN0ZXJfZHJpdmVyKCZpbnRlbF9taWRfaTJzX2RyaXZlcik7Cit9CisK
KworbW9kdWxlX2luaXQoaW50ZWxfbWlkX2kyc19pbml0KTsKK21vZHVsZV9leGl0KGludGVsX21p
ZF9pMnNfZXhpdCk7CisKKworCmRpZmYgLS1naXQgYS9zb3VuZC9wY2kvaW50ZWxfbWlkX2kycy9p
bnRlbF9taWRfaTJzLmggYi9zb3VuZC9wY2kvaW50ZWxfbWlkX2kycy9pbnRlbF9taWRfaTJzLmgK
bmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uZWYyOWNlNwotLS0gL2Rldi9udWxs
CisrKyBiL3NvdW5kL3BjaS9pbnRlbF9taWRfaTJzL2ludGVsX21pZF9pMnMuaApAQCAtMCwwICsx
LDUwMCBAQAorLyoKKyAgKiA8RHJpdmVyIGZvciBJMlMgcHJvdG9jb2wgb24gU1NQIChNb29yZXN0
b3duIGFuZCBNZWRmaWVsZCBoYXJkd2FyZSk+CisgICogQ29weXJpZ2h0IChjKSAyMDEwLCBJbnRl
bCBDb3Jwb3JhdGlvbi4KKyAgKiBMb3VpcyBMRSBHQUxMIDxsb3Vpcy5sZS5nYWxsIGludGVsLmNv
bT4KKyAgKgorICAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlz
dHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0CisgICogdW5kZXIgdGhlIHRlcm1zIGFuZCBjb25k
aXRpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSwKKyAgKiB2ZXJzaW9uIDIs
IGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLgorICAqCisgICog
VGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIGl0IHdpbGwgYmUgdXNlZnVs
LCBidXQgV0lUSE9VVAorICAqIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVk
IHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWSBvcgorICAqIEZJVE5FU1MgRk9SIEEgUEFSVElD
VUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IKKyAg
KiBtb3JlIGRldGFpbHMuCisgICoKKyAgKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5
IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoCisgICogdGhpcyBw
cm9ncmFtOyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIElu
Yy4sCisgICogNTEgRnJhbmtsaW4gU3QgLSBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAwMjExMC0x
MzAxIFVTQS4KKyAgKi8KKyNkZWZpbmUgRFJJVkVSX05BTUUgIkkyUyBTU1AgRHJpdmVyIgorLyoK
KyAqIERlZmluZXMKKyAqLworI2RlZmluZSBNRkxEX1NTUDFfREVWSUNFX0lEIDB4MDgyNQkvKiBG
T1IgTUZMRCAqLworI2RlZmluZSBNUlNUX1NTUDBfREVWSUNFX0lEIDB4MDgxNQkvKiBGT1IgTVJT
VCAqLworI2RlZmluZSBNRkxEX1NTUDBfREVWSUNFX0lEIDB4MDgzMgkvKiBGT1IgTUZMRCAqLwor
CisjZGVmaW5lIE1SU1RfTFBFX0RNQV9ERVZJQ0VfSUQgMHgwODE0CisjZGVmaW5lIE1GTERfTFBF
X0RNQV9ERVZJQ0VfSUQgMHgwODMwCisKKy8qIFNTUDEgUENJIGRldmljZSBCYXNlIEFkZHJlc3Mg
UmVnaXN0ZXIgKi8KKyNkZWZpbmUgTVJTVF9TU1BfQkFSCTAKKyNkZWZpbmUgTVJTVF9MUEVfQkFS
CTEKKyNkZWZpbmUgRE1BMUNfREVWSUNFX0lOU1RBTkNFX1NTUDAgMAorI2RlZmluZSBETUExQ19E
RVZJQ0VfSU5TVEFOQ0VfU1NQMSAxCisjZGVmaW5lIE9GRlNFVF9TU0NSMAkweDAwCisjZGVmaW5l
IE9GRlNFVF9TU0NSMQkweDA0CisjZGVmaW5lIE9GRlNFVF9TU1NSCQkweDA4CisjZGVmaW5lIE9G
RlNFVF9TU0lUUgkweDBjCisjZGVmaW5lIE9GRlNFVF9TU0RSCQkweDEwCisjZGVmaW5lIE9GRlNF
VF9TU1RPCQkweDI4CisjZGVmaW5lIE9GRlNFVF9TU1BTUAkweDJjCisjZGVmaW5lIE9GRlNFVF9T
U1RTQQkweDMwCS8qIFNTUCBUeCBUaW1lc2xvdCBBY3RpdmUgKi8KKyNkZWZpbmUgT0ZGU0VUX1NT
UlNBCTB4MzQJLyogU1NQIFJ4IFRpbWVzbG90IEFjdGl2ZSAqLworLyogU1NUIHJlZ2lzdGVyIG1h
cCAqLworI2RlZmluZSBPRkZTRVRfTFBFX0NTUgkJCTB4MDAKKyNkZWZpbmUgT0ZGU0VUX0xQRV9Q
SVNSCQkJMHgwOAorI2RlZmluZSBPRkZTRVRfTFBFX1BJTVIJCQkweDEwCisjZGVmaW5lIE9GRlNF
VF9MUEVfSVNSWAkJCTB4MTgKKyNkZWZpbmUgT0ZGU0VUX0xQRV9JTVJYCQkJMHgyOAorI2RlZmlu
ZSBPRkZTRVRfTFBFX0lQQ1gJCQkweDM4CS8qIElQQyBJQS1TU1QgKi8KKyNkZWZpbmUgT0ZGU0VU
X0xQRV9JUENECQkJMHg0MAkvKiBJUEMgU1NULUlBICovCisjZGVmaW5lIE9GRlNFVF9MUEVfSVNS
RAkJCTB4MjAJLyogZHVtbXkgcmVnaXN0ZXIgZm9yKi8KKwkJCQkJCS8qIHNoaW0gd29ya2Fyb3Vu
ZCAgICovCisjZGVmaW5lIE9GRlNFVF9MUEVfU0hJTV9TSVpFCTBYNDQKKworI2RlZmluZSBTU1Bf
SU5fTUFTVEVSX01PREUJCTB4MAorI2RlZmluZSBTU1BfSU5fU0xBVkVfTU9ERQkJMHgxCisKKy8q
CisgKglNYWNyb3MKKyAqLworI2RlZmluZSBERUZJTkVfU1NQX1JFRyhyZWcsIG9mZikgXAorc3Rh
dGljIGlubGluZSB1MzIgcmVhZF8jI3JlZyh2b2lkICpwKSB7IHJldHVybiBfX3Jhd19yZWFkbChw
ICsgKG9mZikpOyB9IFwKK3N0YXRpYyBpbmxpbmUgdm9pZCB3cml0ZV8jI3JlZyh1MzIgdiwgdm9p
ZCAqcCkgeyBfX3Jhd193cml0ZWwodiwgcCArIChvZmYpKTsgfQorREVGSU5FX1NTUF9SRUcoU1ND
UjAsIDB4MDApCitERUZJTkVfU1NQX1JFRyhTU0NSMSwgMHgwNCkKK0RFRklORV9TU1BfUkVHKFNT
U1IsIDB4MDgpCitERUZJTkVfU1NQX1JFRyhTU0lUUiwgMHgwYykKK0RFRklORV9TU1BfUkVHKFNT
RFIsIDB4MTApCitERUZJTkVfU1NQX1JFRyhTU1RPLCAweDI4KQorREVGSU5FX1NTUF9SRUcoU1NQ
U1AsIDB4MmMpCitERUZJTkVfU1NQX1JFRyhTU1RTQSwgMHgzMCkKK0RFRklORV9TU1BfUkVHKFNT
UlNBLCAweDM0KQorREVGSU5FX1NTUF9SRUcoU1NUU1MsIDB4MzgpCitERUZJTkVfU1NQX1JFRyhT
U0FDRCwgMHgzQykKK0RFRklORV9TU1BfUkVHKEkyQ0NUUkwsIDB4MDApOworREVGSU5FX1NTUF9S
RUcoSTJDREFUQSwgMHgwNCk7CisvKgorICogTGFuZ3dlbGwgU1NQIHNlcmlhbCBwb3J0IHJlZ2lz
dGVyIGRlZmluaXRpb25zCisgKi8KKyNkZWZpbmUgU1NDUjBfRFNTX01BU0sgICAweDBGCS8qIERh
dGEgU2l6ZSBTZWxlY3QgWzQuLjE2XSAqLworI2RlZmluZSBTU0NSMF9EU1NfU0hJRlQgIDAKKyNk
ZWZpbmUgU1NDUjBfRlJGX01BU0sgICAweDAzCS8qIEZSYW1lIEZvcm1hdCAqLworI2RlZmluZSBT
U0NSMF9GUkZfU0hJRlQgIDQKKyNkZWZpbmUgU1NDUjBfRUNTX01BU0sgICAweDAxCS8qIEV4dGVy
bmFsIGNsb2NrIHNlbGVjdCAqLworI2RlZmluZSBTU0NSMF9FQ1NfU0hJRlQgIDYKKyNkZWZpbmUg
U1NDUjBfU1NFX01BU0sgICAweDAxCS8qIFN5bmNocm9ub3VzIFNlcmlhbCBQb3J0IEVuYWJsZSAq
LworI2RlZmluZSBTU0NSMF9TU0VfU0hJRlQgIDcKKyNkZWZpbmUgU1NDUjBfU0NSX01BU0sgICAw
eEZGRgkvKiBOb3QgaW1wbGVtZW50ZWQgKi8KKyNkZWZpbmUgU1NDUjBfU0NSX1NISUZUICA4Cisj
ZGVmaW5lIFNTQ1IwX0VEU1NfTUFTSyAgMHgxCS8qIEV4dGVuZGVkIGRhdGEgc2l6ZSBzZWxlY3Qg
Ki8KKyNkZWZpbmUgU1NDUjBfRURTU19TSElGVCAyMAorI2RlZmluZSBTU0NSMF9OQ1NfTUFTSyAg
IDB4MQkvKiBOZXR3b3JrIGNsb2NrIHNlbGVjdCAqLworI2RlZmluZSBTU0NSMF9OQ1NfU0hJRlQg
IDIxCisjZGVmaW5lIFNTQ1IwX1JJTV9NQVNLICAgMHgxCS8qIFJlY2VpdmUgRklGTyBvdmVycnJ1
biBpbnQgbWFzayAqLworI2RlZmluZSBTU0NSMF9SSU1fU0hJRlQgIDIyCisjZGVmaW5lIFNTQ1Iw
X1RJTV9NQVNLICAgMHgxCS8qIFRyYW5zbWl0IEZJRk8gdW5kZXJydW4gaW50IG1hc2sgKi8KKyNk
ZWZpbmUgU1NDUjBfVElNX1NISUZUICAyMworI2RlZmluZSBTU0NSMF9GUkRDX01BU0sgIDB4Nwkv
KiBGcmFtZSBSYXRlIERpdmlkZXIgQ29udHJvbCAqLworI2RlZmluZSBTU0NSMF9GUkRDX1NISUZU
IDI0CisjZGVmaW5lIFNTQ1IwX0FDU19NQVNLICAgMHgxCS8qIEF1ZGlvIGNsb2NrIHNlbGVjdCAq
LworI2RlZmluZSBTU0NSMF9BQ1NfU0hJRlQgIDMwCisjZGVmaW5lIFNTQ1IwX01PRF9NQVNLICAg
MHgxCS8qIE1vZGUgKG5vcm1hbCBvciBuZXR3b3JrKSAqLworI2RlZmluZSBTU0NSMF9NT0RfU0hJ
RlQgIDMxCisKKyNkZWZpbmUgU1NDUjBfRGF0YVNpemUoeCkgICAgICgoeCkgLSAxKQkvKiBEYXRh
IFNpemUgU2VsZWN0IFs0Li4xNl0gKi8KKyNkZWZpbmUgU1NDUjBfU2xvdHNQZXJGcm0oeCkgICgo
eCkgLSAxKQkvKiBUaW1lIHNsb3RzIHBlciBmcmFtZSAqLworI2RlZmluZSBTU0NSMF9TZXJDbGtE
aXYoeCkgICAgKCh4KSAtIDEpCS8qIERpdmlzb3IgWzEuLjQwOTZdLC4uLiAqLworCQkJCQkgLyou
Li5ub3QgaW1wbGVtZW50ZWQgb24gTGFuZ3dlbGwgKi8KKyNkZWZpbmUgU1NDUjFfVFRFTFBfTUFT
SyAgICAgMHgxCS8qIFRYRCBUcmlzdGF0ZSBFbmFibGUgb24gTGFzdCBQaGFzZSAqLworI2RlZmlu
ZSBTU0NSMV9UVEVMUF9TSElGVCAgICAzMQorI2RlZmluZSBTU0NSMV9UVEVfTUFTSwkgICAgIDB4
MQkvKiBUWEQgVHJpc3RhdGUgRW5hYmxlICovCisjZGVmaW5lIFNTQ1IxX1RURV9TSElGVCAgICAg
IDMwCisjZGVmaW5lIFNTQ1IxX0VCQ0VJX01BU0sgICAgIDB4MQkvKiBFbmFibGUgQml0IENvdW50
IEVycm9yIEludGVycnVwdCAqLworI2RlZmluZSBTU0NSMV9FQkNFSV9TSElGVCAgICAyOQorI2Rl
ZmluZSBTU0NSMV9TQ0ZSX01BU0sgICAgICAweDEJLyogU2xhdmUgQ2xvY2sgUnVubmluZyAqLwor
I2RlZmluZSBTU0NSMV9TQ0ZSX1NISUZUICAgICAyOAorI2RlZmluZSBTU0NSMV9FQ1JBX01BU0sg
ICAgICAweDEJLyogRW5hYmxlIENsb2NrIFJlcXVlc3QgQSAqLworI2RlZmluZSBTU0NSMV9FQ1JB
X1NISUZUICAgICAyNworI2RlZmluZSBTU0NSMV9FQ1JCX01BU0sgICAgICAweDEJLyogRW5hYmxl
IENsb2NrIFJlcXVlc3QgQiAqLworI2RlZmluZSBTU0NSMV9FQ1JCX1NISUZUICAgICAyNgorI2Rl
ZmluZSBTU0NSMV9TQ0xLRElSX01BU0sgICAweDEJLyogU1NQQ0xLIERpcmVjdGlvbiAqLworI2Rl
ZmluZSBTU0NSMV9TQ0xLRElSX1NISUZUICAyNQorI2RlZmluZSBTU0NSMV9TRlJNRElSX01BU0sg
ICAweDEJLyogU1NQRlJNIERpcmVjdGlvbiAqLworI2RlZmluZSBTU0NSMV9TRlJNRElSX1NISUZU
ICAyNAorI2RlZmluZSBTU0NSMV9SV09UX01BU0sgICAgICAweDEJLyogUmVjZWl2ZSB3aXRob3V0
IFRyYW5zbWl0ICovCisjZGVmaW5lIFNTQ1IxX1JXT1RfU0hJRlQgICAgIDIzCisjZGVmaW5lIFNT
Q1IxX1RSQUlMX01BU0sgICAgIDB4MQkvKiBUcmFpbGluZyBCeXRlICovCisjZGVmaW5lIFNTQ1Ix
X1RSQUlMX1NISUZUICAgIDIyCisjZGVmaW5lIFNTQ1IxX1RTUkVfTUFTSyAgICAgIDB4MQkvKiBE
TUEgVHJhbnNtaXQgU2VydmljZSBSZXF1ZXN0IEVuYWJsZSovCisjZGVmaW5lIFNTQ1IxX1RTUkVf
U0hJRlQgICAgIDIxCisjZGVmaW5lIFNTQ1IxX1JTUkVfTUFTSyAgICAgIDB4MQkvKiBETUEgUmVj
ZWl2ZSBTZXJ2aWNlIFJlcXVlc3QgRW5hYmxlICovCisjZGVmaW5lIFNTQ1IxX1JTUkVfU0hJRlQg
ICAgIDIwCisjZGVmaW5lIFNTQ1IxX1RJTlRFX01BU0sgICAgIDB4MQkvKiBSZWNlaXZlciBUaW1l
LW91dCBJbnRlcnJ1cHQgRW5hYmxlICovCisjZGVmaW5lIFNTQ1IxX1RJTlRFX1NISUZUICAgIDE5
CisjZGVmaW5lIFNTQ1IxX1BJTlRFX01BU0sgICAgIDB4MQkvKiBQZXJpcGguIFRyYWlsaW5nIEJ5
dGUgSW50LiBFbmFibGUgKi8KKyNkZWZpbmUgU1NDUjFfUElOVEVfU0hJRlQgICAgMTgKKyNkZWZp
bmUgU1NDUjFfSUZTX01BU0sgICAgICAgMHgxCS8qIEludmVydCBGcmFtZSBTaWduYWwgKi8KKyNk
ZWZpbmUgU1NDUjFfSUZTX1NISUZUICAgICAgMTYKKyNkZWZpbmUgU1NDUjFfU1RGUl9NQVNLICAg
ICAgMHgxCS8qIFNlbGVjdCBGSUZPIGZvciBFRldSOiB0ZXN0IG1vZGUgKi8KKyNkZWZpbmUgU1ND
UjFfU1RGUl9TSElGVCAgICAgMTUKKyNkZWZpbmUgU1NDUjFfRUZXUl9NQVNLICAgICAgMHgxCS8q
IEVuYWJsZSBGSUZPIFdyaXRlL1JlYWQ6IHRlc3QgbW9kZSAqLworI2RlZmluZSBTU0NSMV9FRldS
X1NISUZUICAgICAxNAorI2RlZmluZSBTU0NSMV9SRlRfTUFTSyAgICAgICAweEYJLyogUmVjZWl2
ZSBGSUZPIFRyaWdnZXIgVGhyZXNob2xkICovCisjZGVmaW5lIFNTQ1IxX1JGVF9TSElGVCAgICAg
IDEwCisjZGVmaW5lIFNTQ1IxX1RGVF9NQVNLICAgICAgIDB4RgkvKiBUcmFuc21pdCBGSUZPIFRy
aWdnZXIgVGhyZXNob2xkICovCisjZGVmaW5lIFNTQ1IxX1RGVF9TSElGVCAgICAgIDYKKyNkZWZp
bmUgU1NDUjFfTVdEU19NQVNLICAgICAgMHgxCS8qIE1pY3Jvd2lyZSBUcmFuc21pdCBEYXRhIFNp
emUgKi8KKyNkZWZpbmUgU1NDUjFfTVdEU19TSElGVCAgICAgNQorI2RlZmluZSBTU0NSMV9TUEhf
TUFTSyAgICAgICAweDEJLyogTW90b3JvbGEgU1BJIFNTUFNDTEsgcGhhc2Ugc2V0dGluZyAqLwor
I2RlZmluZSBTU0NSMV9TUEhfU0hJRlQgICAgICA0CisjZGVmaW5lIFNTQ1IxX1NQT19NQVNLICAg
ICAgIDB4MQkvKiBNb3Rvcm9sYSBTUEkgU1NQU0NMSyBwb2xhcml0eSAqLworI2RlZmluZSBTU0NS
MV9TUE9fU0hJRlQgICAgICAzCisjZGVmaW5lIFNTQ1IxX0xCTV9NQVNLICAgICAgIDB4MQkvKiBM
b29wYmFjayBtb2RlOiB0ZXN0IG1vZGUgKi8KKyNkZWZpbmUgU1NDUjFfTEJNX1NISUZUICAgICAg
MgorI2RlZmluZSBTU0NSMV9USUVfTUFTSyAgICAgICAweDEJLyogVHJhbnNtaXQgRklGTyBJbnRl
cnJ1cHQgRW5hYmxlICovCisjZGVmaW5lIFNTQ1IxX1RJRV9TSElGVCAgICAgIDEKKyNkZWZpbmUg
U1NDUjFfUklFX01BU0sgICAgICAgMHgxCS8qIFJlY2VpdmUgRklGTyBJbnRlcnJ1cHQgRW5hYmxl
ICovCisjZGVmaW5lIFNTQ1IxX1JJRV9TSElGVCAgICAgIDAKKworI2RlZmluZSBTU0NSMV9SeFRy
ZXNoKHgpICgoeCkgLSAxKQkvKiBsZXZlbCBbMS4uMTZdICovCisjZGVmaW5lIFNTQ1IxX1R4VHJl
c2goeCkgKCh4KSAtIDEpCS8qIGxldmVsIFsxLi4xNl0gKi8KKworI2RlZmluZSBTU1BTUF9GU1JU
X01BU0sgICAgICAweDEJLyogRnJhbWUgU3luYyBSZWxhdGl2ZSBUaW1pbmcgQml0ICovCisjZGVm
aW5lIFNTUFNQX0ZTUlRfU0hJRlQgICAgIDI1CisjZGVmaW5lIFNTUFNQX0RNWVNUT1BfTUFTSyAg
IDB4MwkvKiBEdW1teSBTdG9wIGluIE51bWJlciBvZiBTU1BTQ0xLczpUNCovCisjZGVmaW5lIFNT
UFNQX0RNWVNUT1BfU0hJRlQgIDIzCisjZGVmaW5lIFNTUFNQX1NGUk1XRFRIX01BU0sgIDB4M0YJ
LyogU2VyaWFsIEZyYW1lIHdpZHRoIDogVDYgKi8KKyNkZWZpbmUgU1NQU1BfU0ZSTVdEVEhfU0hJ
RlQgMTYKKyNkZWZpbmUgU1NQU1BfU0ZSTURMWV9NQVNLICAgMHg3RgkvKiBTZXJpYWwgRnIuIERl
bGF5IGluIDEvMlNTUFNDTEtzOlQ1ICovCisjZGVmaW5lIFNTUFNQX1NGUk1ETFlfU0hJRlQgIDkK
KyNkZWZpbmUgU1NQU1BfRE1ZU1RSVF9NQVNLICAgMHgzCS8qIER1bW15IFN0YXJ0IGluIE51bWJl
ciBvZiBTU1BTQ0xLcy4uKi8KKyNkZWZpbmUgU1NQU1BfRE1ZU1RSVF9TSElGVCAgNwkgICAgLyou
Li5hZnRlciBTVFJURExZLCBUMiAobWFzdGVyIG1vZGUgb25seSkgKi8KKyNkZWZpbmUgU1NQU1Bf
U1RSVERMWV9NQVNLICAgMHg3CS8qIFN0YXJ0IERlbGF5LCBUMSAobWFzdGVyIG1vZGUgb25seSkg
Ki8KKyNkZWZpbmUgU1NQU1BfU1RSVERMWV9TSElGVCAgNAorI2RlZmluZSBTU1BTUF9FVERTX01B
U0sgICAgICAweDEJLyogRW5kIG9mIFRyYW5zZmVyIERhdGEgU3RhdGUgKi8KKyNkZWZpbmUgU1NQ
U1BfRVREU19TSElGVCAgICAgMworI2RlZmluZSBTU1BTUF9TRlJNUF9NQVNLICAgICAweDEJLyog
U2VyaWFsIEZyYW1lIFBvbGFyaXR5ICovCisjZGVmaW5lIFNTUFNQX1NGUk1QX1NISUZUICAgIDIK
KyNkZWZpbmUgU1NQU1BfU0NNT0RFX01BU0sgICAgMHgzCS8qIFNlcmlhbCBiaXQtcmF0ZSBDbG9j
ayBNb2RlICovCisjZGVmaW5lIFNTUFNQX1NDTU9ERV9TSElGVCAgIDAKKworI2RlZmluZSBTU1RT
QV9UVFNBX01BU0sgICAgICAweEZGCisjZGVmaW5lIFNTVFNBX1RUU0FfU0hJRlQgICAgIDAKKwor
I2RlZmluZSBTU1JTQV9SVFNBX01BU0sgICAgICAweEZGCisjZGVmaW5lIFNTUlNBX1JUU0FfU0hJ
RlQgICAgIDAKKworI2RlZmluZSBTU1NSX0JDRV9NQVNLICAgMHgxCS8qIEJpdCBDb3VudCBFcnJv
cjogUmVhZC9Xcml0ZSAxIHRvIENsZWFyICovCisjZGVmaW5lIFNTU1JfQkNFX1NISUZUICAyMwor
I2RlZmluZSBTU1NSX0NTU19NQVNLICAgMHgxCS8qIENsb2NrIFN5bmNocm9uaXphdGlvbiBTdGF0
dXMgKi8KKyNkZWZpbmUgU1NTUl9DU1NfU0hJRlQgIDIyCisjZGVmaW5lIFNTU1JfVFVSX01BU0sg
ICAweDEJLyogVHJhbnNtaXQgRklGTyBVbmRlclJ1bjogUmQvV3IgMSB0byBDbGVhciAqLworI2Rl
ZmluZSBTU1NSX1RVUl9TSElGVCAgMjEKKyNkZWZpbmUgU1NTUl9FT0NfTUFTSyAgIDB4MQkvKiBF
bmQgT2YgQ2hhaW46IFJlYWQvV3JpdGUgMSB0byBDbGVhciAqLworI2RlZmluZSBTU1NSX0VPQ19T
SElGVCAgMjAKKyNkZWZpbmUgU1NTUl9USU5UX01BU0sgIDB4MQkvKiBSZWNlaXZlciBUaW1lLW91
dCBJbnRlcnJ1cHQ6Li4uICovCisjZGVmaW5lIFNTU1JfVElOVF9TSElGVCAxOQkvKiAuLi5SZWFk
L1dyaXRlIDEgdG8gQ2xlYXIgKi8KKyNkZWZpbmUgU1NTUl9QSU5UX01BU0sgIDB4MQkvKiBQZXJp
cGhlcmFsIFRyYWlsaW5nIEJ5dGUgSW50ZXJydXB0Oi4uLiAqLworI2RlZmluZSBTU1NSX1BJTlRf
U0hJRlQgMTgJLyogLi4uUmVhZC9Xcml0ZSAxIHRvIENsZWFyICovCisjZGVmaW5lIFNTU1JfUkZM
X01BU0sgICAweEYJLyogUmVjZWl2ZSBGSUZPIExldmVsICovCisjZGVmaW5lIFNTU1JfUkZMX1NI
SUZUICAxMgorI2RlZmluZSBTU1NSX1RGTF9NQVNLICAgMHhGCS8qIFRyYW5zbWl0IEZJRk8gTGV2
ZWwgKi8KKyNkZWZpbmUgU1NTUl9URkxfU0hJRlQgIDgKKyNkZWZpbmUgU1NTUl9ST1JfTUFTSyAg
IDB4MQkvKiBSZWNlaXZlIEZJRk8gT3ZlcnJ1bjogUmVhZC9Xcml0ZSAxIHRvIENsZWFyKi8KKyNk
ZWZpbmUgU1NTUl9ST1JfU0hJRlQgIDcKKyNkZWZpbmUgU1NTUl9SRlNfTUFTSyAgIDB4MQkvKiBS
ZWNlaXZlIEZJRk8gU2VydmljZSBSZXF1ZXN0ICovCisjZGVmaW5lIFNTU1JfUkZTX1NISUZUICA2
CisjZGVmaW5lIFNTU1JfVEZTX01BU0sgICAweDEJLyogVHJhbnNtaXQgRklGTyBTZXJ2aWNlIFJl
cXVlc3QgKi8KKyNkZWZpbmUgU1NTUl9URlNfU0hJRlQgIDUKKyNkZWZpbmUgU1NTUl9CU1lfTUFT
SyAgIDB4MQkvKiBTU1AgQnVzeSAqLworI2RlZmluZSBTU1NSX0JTWV9TSElGVCAgNAorI2RlZmlu
ZSBTU1NSX1JORV9NQVNLICAgMHgxCS8qIFJlY2VpdmUgRklGTyBub3QgZW1wdHkgKi8KKyNkZWZp
bmUgU1NTUl9STkVfU0hJRlQgIDMKKyNkZWZpbmUgU1NTUl9URk5fTUFTSyAgIDB4MQkvKiBUcmFu
c21pdCBGSUZPIG5vdCBGdWxsICovCisjZGVmaW5lIFNTU1JfVEZOX1NISUZUICAyCisKKworI2Rl
ZmluZSBTU1BfT0ZGIDAKKyNkZWZpbmUgU1NQX09OICAxCisKKy8qIGJpdCBJMlNfUE9SVF9PUEVO
RUQgbG9jayBmb3Igb3Blbi9jbG9zZQorICogYml0IEkyU19QT1JUX1JFQURfQlVTWSBsb2NrIGZv
ciByZWFkIHJlcXVlc3RzIChzZXJpYWxpemVkKQorICogYml0IEkyU19QT1JUX1dSSVRFX0JVU1kg
bG9jayBmb3Igd3JpdGUgcmVxdWVzdHMgKHNlcmlhbGl6ZWQpCisgKiBiaXQgSTJTX1BPUlRfQ0xP
U0lORyBtZWFucyBjbG9zZSBvbiBnb2luZywgd2FpdGluZyBmb3IgcGVuZGluZyBjYWxsYmFja3Mu
CisgKi8KKworZW51bSBpMnNfZmxhZ3MgeworCUkyU19QT1JUX09QRU5FRCwKKwlJMlNfUE9SVF9X
UklURV9CVVNZLAorCUkyU19QT1JUX1JFQURfQlVTWSwKKwlJMlNfUE9SVF9DTE9TSU5HCit9Owor
CisjZGVmaW5lIEZJRk9fU0laRSAxNgorLyoKKyAqCVN0cnVjdHVyZXMgRGVmaW5pdGlvbgorICov
CisKKy8qKgorICogc3RydWN0IGludGVsX21pZF9pMnNfZGF0YSAtIGNvbnRleHQgc3RydWN0IHRv
IGtlZXAgU1NQIEkyUyBkYXRhCisgKiBAcGRldjogcGNpIGRldiBwb2ludGVyIGNvcnJlc3BvbmRp
bmcgdG8gY29udGV4dAorICogQHBhZGRyOgorICogQGlvYWRkcjoKKyAqIEBpb2xlbjoKKyAqIEBp
cnE6CisgKiBAY2xlYXJfc3I6CisgKiBAbWFza19zcjoKKyAqIEBkbWFjMToKKyAqIEBkbWFzX3R4
OiBkbWEgc2xhdmUgc3RydWN0dXJlIGZvciB0cmFuc21pdAorICogQGRtYXNfcng6IGRtYSBzbGF2
ZSBzdHJ1Y3R1cmUgZm9yIHJlY2VpdmUKKyAqIEB0eGNoYW46IERtYSBjaGFubmVsIGZvciB0cmFu
c21pdAorICogQHJ4Y2hhbjogRG1hIGNoYW5uZWwgZm9yIHJlY2VpdmUKKyAqCisgKiBAcmVhZF9k
b25lOgorICogQHJlYWRfZHN0OgorICogQHJlYWRfbGVuOgorICoKKyAqIEB3cml0ZV9kb25lOgor
ICogQHdyaXRlX3NyYzoKKyAqIEB3cml0ZV9sZW46CisgKgorICogQG11dGV4OiAgYSBtdXRleCB0
byBtYWtlIHN1cmUgd2UgaGF2ZSBvbmNlLWF0LXRpbWUgY3JpdGljYWwgZnVuY3Rpb25zLgorICoK
KyAqIExvbmdlciBkZXNjcmlwdGlvbgorICovCisKKy8qIExvY2tpbmcgcnVsZXM6CisgKgorICog
QWxsIHRoZSBmaWVsZHMsIG5vdCBsaXN0ZWQgYmVsb3csIGFyZSBzZXQgZHVyaW5nIHByb2JlLCBh
bmQgdGhlbiByZWFkIG9ubHkKKyAqIFNvIHRoZXkgZG8gbm90IHJlcXVpcmUgbG9ja2luZworICoK
KyAqIFRoZSBmaWVsZHMgdGhhdCByZXF1aXJlIGxvY2tpbmcgYXJlIHJlbGF0ZWQgdG8gdGhlIEky
UyByZWFkIGFuZCB3cml0ZQorICogcmVxdWVzdHMuCisgKgorICogV2UgYWxsb3cgb25seSAxIHJl
YWQgYXQgYSB0aW1lLCBhbmQgMSB3cml0ZSBhdCBhIHRpbWUuCisgKiBXZSBhbGxvdyByZWFkIGlu
IHBhcmFsbGVsIG9mIHdyaXRlIGJ1dCB1c2Ugc2VwYXJhdGUgdmFyaWFibGVzLgorICogV2UgYWxs
b3cgb25seSAxIHVzZXIgcGVyIFNTUC9JMlMgcG9ydC4KKyAqIFR5cGljYWxseSB0aGlzIHVzZXIg
d2lsbCBiZSBhIGRlZGljYXRlZCBQdWxzZUF1ZGlvIFJUIHRocmVhZCBjb21tdW5pY2F0aW5nCisg
KiB3aXRoIGNtdC1zcGVlY2ggZHJpdmVyIHdoaWNoIGluIHR1cm5zIGNvbW11bmljYXRlcyB3aXRo
IGludGVsX21pZF9zc3AKKyAqIGRyaXZlci4KKyAqIFBDTSBtaXhpbmcgaXMgZG9uZSBiZWZvcmUg
YWNjZXNzIHRvIGtlcm5lbCBkcml2ZXJzO3R5cGljYWxseSB3aXRoaW4KKyAqIFB1bHNlQXVkaW8g
b3IgYWZ0ZXI7IHR5cGljYWxseSB3aXRoaW4gdGhlIG1vZGVtLgorICogU28gbm8gY29uY3VycmVu
dCB1c2VycywgcGVyIEkyUyBjaGFubmVsLCB0byB0aGlzIGRyaXZlciBhcmUgYWxsb3dlZAorICog
VGhlIHJlYWQgJiB3cml0ZSBhcmUgdHJpZ2dlcmVkIGZyb20gYSBVU0VSIGNvbnRleHQKKyAqIFRo
ZSByZWFkICYgd3JpdGUgY2FsbGJhY2tzIGFyZSBjYWxsZWQgZnJvbSBhIEJIIGNvbnRleHQKKyAq
IFlvdSBzaG91bGQgaGF2ZSBub3QgY2FsbGJhY2sgcGVuZGluZyBiZWZvcmUgY2FsbGluZyBjbG9z
ZSwgY2xvc2Ugd2lsbCB3YWl0CisgKiBmb3IgcmVtYWluaW5nIGNhbGxiYWNrIGNhbGxzLgorICog
SXQgaXMgbm90IGFsbG93ZWQgdG8gY2FsbCBjbG9zZSBmdW5jdGlvbiBmcm9tIHJlYWQvd3JpdGUg
Y2FsbGJhY2sgdGhyZWFkcy4KKyAqCisgKiBMb2NraW5nIGlzIGhhbmRsZWQgdmlhIGRydl9kYXRh
LT5mbGFncyAmIGF0b21pYyBiaXR3aXNlIG9wZXJhdGlvbnMKKyAqCisgKiBJMlMwIGlzIGRlZGlj
YXRlZCBmb3IgUENNIHRyYW5zZmVyIHRvL2Zyb20gdGhlIG1vZGVtIG1vZHVsZQorICogSTJTMSBp
cyBkZWRpY2F0ZWQgZm9yIFBDTSB0cmFuc2ZlciB0by9mcm9tIHRoZSBCbHVldG9vdGggb3IgRk0g
bW9kdWxlCisgKgorICogcmVhZF9kb25lOgorICogcmVhZF9sZW46CisgKiByZWFkX2RzdDoKKyAq
CisgKiB3cml0ZV9kb25lOgorICogd3JpdGVfc3JjOgorICogd3JpdGVfbGVuOgorICoKKyAqIG11
dGV4OiAgYSBtdXRleCB0byBtYWtlIHN1cmUgd2UgaGF2ZSBvbmNlLWF0LXRpbWUgY3JpdGljYWwg
ZnVuY3Rpb25zLgorICoJCW9uY2UtYXQtYS10aW1lIGFjdGlvbnMgZnVuY3Rpb25zIGFyZToKKyAq
CQkJLWludGVsX21pZF9pMnNfb3BlbgorICoJCQktaW50ZWxfbWlkX2kyc19jbG9zZQorICoJCQkt
aW50ZWxfbWlkX2kyc19yZF9yZXEKKyAqCQkJLWludGVsX21pZF9pMnNfd3JfcmVxCisgKgkJCS1p
bnRlbF9taWRfaTJzX3NldF9yZF9jYgorICoJCQktaW50ZWxfbWlkX2kyc19zZXRfd3JfY2IKKyAq
IFRoZXNlIGZ1bmN0aW9ucyBzaG91bGQgbm90IGJlIGNhbGxlZCBkdXJpbmcgYSBsb2NrKCkgbmVp
dGhlciBpbiBpbnRlcnJ1cHQuCisgKi8KKworc3RydWN0IGludGVsX21pZF9pMnNfaGRsIHsKKwkv
KiBEcml2ZXIgbW9kZWwgaG9va3VwICovCisJc3RydWN0IHBjaV9kZXYgKnBkZXY7CisJLyogcmVn
aXN0ZXIgYWRkcmVzc2VzICovCisJZG1hX2FkZHJfdCBwYWRkcjsKKwl2b2lkIF9faW9tZW0gKmlv
YWRkcjsKKwl1MzIgaW9sZW47CisJaW50IGlycTsKKworCS8qIFNTUCBtYXNrcyAqLworCXUzMiBj
bGVhcl9zcjsKKwl1MzIgbWFza19zcjsKKworCS8qIFNTUCBDb25maWd1cmF0aW9uICovCisJLyog
RE1BIGluZm8gKi8KKwlzdHJ1Y3QgcGNpX2RldiAqZG1hYzE7CisJd2FpdF9xdWV1ZV9oZWFkX3Qg
d3FfY2hhbl9jbG9zaW5nOworCisJc3RydWN0IGludGVsX21pZF9kbWFfc2xhdmUgZG1hc190eDsK
KwlzdHJ1Y3QgaW50ZWxfbWlkX2RtYV9zbGF2ZSBkbWFzX3J4OworCXN0cnVjdCBkbWFfY2hhbiAq
dHhjaGFuOworCXN0cnVjdCBkbWFfY2hhbiAqcnhjaGFuOworCisJdW5zaWduZWQgaW50IGRldmlj
ZV9pbnN0YW5jZTsKKwkvKiBDYWxsIGJhY2sgZnVuY3Rpb25zICovCisJaW50ICgqcmVhZF9jYWxs
YmFjaykodm9pZCAqcGFyYW0pOworCWRtYV9hZGRyX3QgcmVhZF9kc3Q7CisJc2l6ZV90IHJlYWRf
bGVuOyAgICAgLyogcmVhZF9sZW4gPiAwIDw9PiByZWFkX2RtYV9ydW5uaW5nICovCisJdm9pZCAq
cmVhZF9wYXJhbTsJIC8qIGNvbnRleHQgcGFyYW0gZm9yIGNhbGxiYWNrICovCisJaW50ICgqd3Jp
dGVfY2FsbGJhY2spKHZvaWQgKnBhcmFtKTsKKwlkbWFfYWRkcl90IHdyaXRlX3NyYzsKKwlzaXpl
X3Qgd3JpdGVfbGVuOwkvKiB3cml0ZV9sZW4gPiAwIDw9PiByZWFkX2RtYV9ydW5uaW5nICovCisJ
dm9pZCAqd3JpdGVfcGFyYW07CS8qIGNvbnRleHQgcGFyYW0gZm9yIGNhbGxiYWNrICovCisKKwl1
bnNpZ25lZCBsb25nIGZsYWdzOworCXN0cnVjdCBtdXRleCBtdXRleDsKKwllbnVtIGludGVsX21p
ZF9pMnNfc3NwX3VzYWdlIHVzYWdlOworCisJc3RydWN0IGludGVsX21pZF9pMnNfc2V0dGluZ3Mg
Y3VycmVudF9zZXR0aW5nczsKKworfTsKKworc3RhdGljIHZvaWQgaTJzX3JlYWRfZG9uZSh2b2lk
ICphcmcpOworc3RhdGljIHZvaWQgaTJzX3dyaXRlX2RvbmUodm9pZCAqYXJnKTsKK3N0YXRpYyBi
b29sIGNoYW5fZmlsdGVyKHN0cnVjdCBkbWFfY2hhbiAqY2hhbiwgdm9pZCAqcGFyYW0pOworc3Rh
dGljIHZvaWQgaTJzX2RtYV9zdG9wKHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEp
Oworc3RhdGljIGludCBpMnNfZG1hX3N0YXJ0KHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2
X2RhdGEpOworc3RhdGljIHZvaWQgc3NwMV9kdW1wX3JlZ2lzdGVycyhzdHJ1Y3QgaW50ZWxfbWlk
X2kyc19oZGwgKik7CitzdGF0aWMgaXJxcmV0dXJuX3QgaTJzX2ludChpbnQgaXJxLCB2b2lkICpk
ZXZfaWQpOworc3RhdGljIHZvaWQgc2V0X3NzcF9pMnNfaHcoc3RydWN0IGludGVsX21pZF9pMnNf
aGRsICpkcnZfZGF0YSwKKwkJY29uc3Qgc3RydWN0IGludGVsX21pZF9pMnNfc2V0dGluZ3MgKnBz
X3NldHRpbmdzKTsKK3N0YXRpYyBpbnQgY2hlY2tfZGV2aWNlKHN0cnVjdCBkZXZpY2UgKmRldmlj
ZV9wdHIsIHZvaWQgKmRhdGEpOworc3RhdGljIGludCBpbnRlbF9taWRfaTJzX3J1bnRpbWVfcmVz
dW1lKHN0cnVjdCBkZXZpY2UgKmRldmljZV9wdHIpOworc3RhdGljIGludCBpbnRlbF9taWRfaTJz
X3J1bnRpbWVfc3VzcGVuZChzdHJ1Y3QgZGV2aWNlICpkZXZpY2VfcHRyKTsKK3N0YXRpYyBpbnQg
aW50ZWxfbWlkX2kyc19wcm9iZShzdHJ1Y3QgcGNpX2RldiAqcGRldiwKKwkJY29uc3Qgc3RydWN0
IHBjaV9kZXZpY2VfaWQgKmVudCk7CitzdGF0aWMgdm9pZCBpbnRlbF9taWRfaTJzX3JlbW92ZShz
dHJ1Y3QgcGNpX2RldiAqcGRldik7CitzdGF0aWMgdm9pZCBpMnNfc3NwX3N0b3Aoc3RydWN0IGlu
dGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YSk7CisvKnN0YXRpYyBpbnQgYnRfcGNtX2RtYV9pbml0
KHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEpOyovCisKKworI2lmZGVmIENPTkZJ
R19QTQorc3RhdGljIGludCAgaW50ZWxfbWlkX2kyc19kcml2ZXJfc3VzcGVuZChzdHJ1Y3QgcGNp
X2RldiAqZGV2LAorCQkJCQkgIHBtX21lc3NhZ2VfdCBzdGF0ZSk7CitzdGF0aWMgaW50IGludGVs
X21pZF9pMnNfZHJpdmVyX3Jlc3VtZShzdHJ1Y3QgcGNpX2RldiAqZGV2KTsKKyNlbmRpZgorCisv
KgorICogVGhlc2UgZGVmaW5lIHdpbGwgY2xhcmlmeSBzb3VyY2UgY29kZSB3aGVuIGFjY2Vzc2lu
ZyBTU0NSeCByZWdpc3RlcnMKKyAqLworCisjZGVmaW5lIFNTQ1IwX3JlZyhyZWdiaXQsIHZhbHVl
KQkJCQkJXAorCSgoKHZhbHVlKSAmIFNTQ1IwXyMjcmVnYml0IyNfTUFTSykgPDwgU1NDUjBfIyNy
ZWdiaXQjI19TSElGVCkKKworI2RlZmluZSBTU0NSMV9yZWcocmVnYml0LCB2YWx1ZSkJCQkJCVwK
KwkoKCh2YWx1ZSkgJiBTU0NSMV8jI3JlZ2JpdCMjX01BU0spIDw8IFNTQ1IxXyMjcmVnYml0IyNf
U0hJRlQpCisKKyNkZWZpbmUgU1NQU1BfcmVnKHJlZ2JpdCwgdmFsdWUpCQkJCQlcCisJKCgodmFs
dWUpICYgU1NQU1BfIyNyZWdiaXQjI19NQVNLKSA8PCBTU1BTUF8jI3JlZ2JpdCMjX1NISUZUKQor
CisjZGVmaW5lIFNTUlNBX3JlZyhyZWdiaXQsIHZhbHVlKQkJCQkJXAorCSgoKHZhbHVlKSAmIFNT
UlNBXyMjcmVnYml0IyNfTUFTSykgPDwgU1NSU0FfIyNyZWdiaXQjI19TSElGVCkKKyNkZWZpbmUg
U1NUU0FfcmVnKHJlZ2JpdCwgdmFsdWUpCQkJCQlcCisJKCgodmFsdWUpICYgU1NUU0FfIyNyZWdi
aXQjI19NQVNLKSA8PCBTU1RTQV8jI3JlZ2JpdCMjX1NISUZUKQorCisKKyNkZWZpbmUgY2hhbmdl
X1NTQ1IwX3JlZyhyZWdfcG9pbnRlciwgcmVnYml0LCB2YWx1ZSkJCQkgIFwKKwl3cml0ZV9TU0NS
MCgocmVhZF9TU0NSMChyZWdfcG9pbnRlcikJCQkJICBcCisJJiAofigoU1NDUjBfIyNyZWdiaXQj
I19NQVNLIDw8IFNTQ1IwXyMjcmVnYml0IyNfU0hJRlQpKSkpCSAgXAorCXwgKCgodmFsdWUpICYg
U1NDUjBfIyNyZWdiaXQjI19NQVNLKSA8PCBTU0NSMF8jI3JlZ2JpdCMjX1NISUZUKSwgIFwKKwly
ZWdfcG9pbnRlcik7CisKKyNkZWZpbmUgc2V0X1NTQ1IwX3JlZyhyZWdfcG9pbnRlciwgcmVnYml0
KQkJCQkgIFwKKwl3cml0ZV9TU0NSMChyZWFkX1NTQ1IwKHJlZ19wb2ludGVyKQkJCQkgIFwKKwl8
IChTU0NSMF8jI3JlZ2JpdCMjX01BU0sgPDwgU1NDUjBfIyNyZWdiaXQjI19TSElGVCksCQlcCisJ
cmVnX3BvaW50ZXIpOworCisjZGVmaW5lIGNsZWFyX1NTQ1IwX3JlZyhyZWdfcG9pbnRlciwgcmVn
Yml0KQkJCQkgIFwKKwl3cml0ZV9TU0NSMCgocmVhZF9TU0NSMChyZWdfcG9pbnRlcikJCQkJICBc
CisJJiAofigoU1NDUjBfIyNyZWdiaXQjI19NQVNLIDw8IFNTQ1IwXyMjcmVnYml0IyNfU0hJRlQp
KSkpLAkgIFwKKwlyZWdfcG9pbnRlcik7CisKKyNkZWZpbmUgY2hhbmdlX1NTQ1IxX3JlZyhyZWdf
cG9pbnRlciwgcmVnYml0LCB2YWx1ZSkJCQkgIFwKKwl3cml0ZV9TU0NSMSgocmVhZF9TU0NSMShy
ZWdfcG9pbnRlcikJCQkJICBcCisJJiAofigoU1NDUjFfIyNyZWdiaXQjI19NQVNLIDw8IFNTQ1Ix
XyMjcmVnYml0IyNfU0hJRlQpKSkpCSAgXAorCXwgKCgodmFsdWUpICYgU1NDUjFfIyNyZWdiaXQj
I19NQVNLKSA8PCBTU0NSMV8jI3JlZ2JpdCMjX1NISUZUKSwgIFwKKwlyZWdfcG9pbnRlcik7CisK
KyNkZWZpbmUgc2V0X1NTQ1IxX3JlZyhyZWdfcG9pbnRlciwgcmVnYml0KQkJCQkgIFwKKwl3cml0
ZV9TU0NSMShyZWFkX1NTQ1IxKHJlZ19wb2ludGVyKQkJCQkgIFwKKwl8IChTU0NSMV8jI3JlZ2Jp
dCMjX01BU0sgPDwgU1NDUjFfIyNyZWdiaXQjI19TSElGVCksCQkgIFwKKwlyZWdfcG9pbnRlcik7
CisKKyNkZWZpbmUgY2xlYXJfU1NDUjFfcmVnKHJlZ19wb2ludGVyLCByZWdiaXQpCQkJCSAgXAor
CXdyaXRlX1NTQ1IxKChyZWFkX1NTQ1IxKHJlZ19wb2ludGVyKQkJCQkgIFwKKwkmICh+KChTU0NS
MV8jI3JlZ2JpdCMjX01BU0sgPDwgU1NDUjFfIyNyZWdiaXQjI19TSElGVCkpKSksCSAgXAorCXJl
Z19wb2ludGVyKTsKKworLyogUlggRklGTyBsZXZlbCAqLworI2RlZmluZSBHRVRfU1NTUl92YWwo
eCwgcmVnYikJCQkJCQkgIFwKKwkoKHggJiAoU1NTUl8jI3JlZ2IjI19NQVNLPDxTU1NSXyMjcmVn
YiMjX1NISUZUKSk+PlNTU1JfIyNyZWdiIyNfU0hJRlQpCisKKworLyoKKyAqIFNTUCBoYXJkd2Fy
ZSBjYW4gYmUgY29uZmlndXJlZCBhcyBJMlMsIFBDTSwgU1BJLi4uCisgKiBJbiBvcmRlciB0byBh
bGxvdyBmbGV4aWJpbGl0eSB3aXRob3V0IG1vZGlmeWluZyB0aGUgc29mdHdhcmUgZHJpdmVyLCB0
aGUKKyAqIFBDSSBoZWFkZXIgdXNlcyB0aGUgY29uZmlndXJhdGlvbiByZWdpc3RlciAnYWRpZCc6
CisgKgorICogVGhlIFBDSSBoZWFkZXIgYXNzb2NpYXRlZCB0byBTU1AgZGV2aWNlcyBpbmNsdWRl
cyBhIGNvbmZpZ3VyYXRpb24gcmVnaXN0ZXIuCisgKiBJdCBwcm92aWRlcyBpbmZvcm1hdGlvbiB0
byBhIGRyaXZlciB3aGljaCBpcyBwcm9iZWQgZm9yIHRoZSBTU1AsIHNwZWNpZnlpbmcKKyAqIGlu
IHdoaWNoIHdheSB0aGUgU1NQIGlzIHN1cHBvc2VkIHRvIGJlIHVzZWQuCisgKiBIZXJlIGlzIHRo
ZSBmb3JtYXQgb2YgdGhpcyBjb25maWd1cmF0aW9uIHJlZ2lzdGVyICg4IGJpdHMpOgorICoKKyAq
ICAgYml0cyAyLi4wOiBNb2RlCisgKiAgICAgICAwMDA6IEludmFsaWQsIHRoZSByZWdpc3RlciBz
aG91bGQgYmUgaWdub3JlZAorICogICAgICAgMDAxOiBTU1AgdG8gYmUgdXNlZCBhcyBTUEkgY29u
dHJvbGxlcgorICogICAgICAgMDEwOiBTU1AgdG8gYmUgdXNlZCBpbiBJMlMvSVNTIG1vZGUKKyAq
ICAgICAgIG90aGVyOiBSZXNlcnZlZAorICoKKyAqICAgYml0cyA1Li4zOiBDb25maWd1cmF0aW9u
CisgKiAgICAgICBJbiBJMlMvSVNTIG1vZGU6CisgKiAgICAgICAgICAgICAgIDAwMDogSW52YWxp
ZAorICogICAgICAgICAgICAgICAwMDE6IEJsdWV0b290aAorICogICAgICAgICAgICAgICAwMTA6
IE1vZGVtCisgKiAgICAgICAgICAgICAgIG90aGVyOiBSZXNlcnZlZAorICogICAgICAgSW4gU1BJ
IG1vZGU6CisgKiAgICAgICAgICAgICAgIFZhbHVlIGlzIHRoZSBTUEkgYnVzIG51bWJlciBjb25u
ZWN0ZWQgdG8gdGhlIFNTUC4KKyAqICAgICAgICAgICAgICAgVG8gYmUgdXNlZCBmb3IgcmVnaXN0
cmF0aW9uIHRvIHRoZSBMaW51eCBTUEkKKyAqICAgICAgICAgICAgICAgZnJhbWV3b3JrLgorICoK
KyAqICAgYml0IDY6IFNQSSBzbGF2ZQorICogICAgICAgUmVsZXZhbnQgaW4gU1BJIG1vZGUgb25s
eS4gSWYgc2V0LCBpbmRpY2F0ZXMgdGhlIFNQSSBjbG9jaworICogICAgICAgaXMgbm90IHByb3Zp
ZGVkIGJ5IHRoZSBTU1A6IFNQSSBzbGF2ZSBtb2RlLgorICoKKyAqICAgYml0IDc6IFJlc2VydmVk
ICgwKQorICoKKyAqICAgVGhpcyBjb25maWd1cmF0aW9uIHJlZ2lzdGVyIGlzIGltcGxlbWVudGVk
IGluIHRoZSBhZGlkIGZpZWxkIG9mIHRoZQorICogICBWZW5kb3IgU3BlY2lmaWMgUENJIGNhcGFi
aWxpdHkgYXNzb2NpYXRlZCB0byB0aGUgU1NQLiBUaGUgZm9ybWF0IG9mCisgKiAgIHRoaXMgY2Fw
YWJpbGl0eSBpczoKKyAqCisgKiAgIHVpbnQ4X3QgICAgIGNhcElkOyAgICAgICAgICAgICAgPCBD
YXBhYmlsaXR5IElEICh2ZW5kb3Itc3BlY2lmaWMpCisgKiAgIHVpbnQ4X3QgICAgIG5leHRDYXA7
ICAgICAgICAgICAgPCBOZXh0IEl0ZW0gUHRyCisgKiAgIHVpbnQ4X3QgICAgIGxlbmd0aDsgICAg
ICAgICAgICAgPCBTaXplIG9mIHRoaXMgY2FwYWJpbGl0eSAoNykKKyAqICAgdWludDhfdCAgICAg
dmVyc2lvbjsgICAgICAgICAgICA8IFZlcnNpb24gb2YgdGhpcyBjYXBhYmlsaXR5ICgxKQorICog
ICB1aW50OF90ICAgICBsc3M7ICAgICAgICAgICAgICAgIDwgTG9naWNhbCBzdWJzeXN0ZW0gaW5m
bworICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpdCA3ID0gUE1V
ICgwID0gTkMsIDEgPSBTQykKKyAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBCaXRzIDY6MCA9IExTUyBJRAorICogICB1aW50OF90ICAgICBhcG1jOyAgICAgICAgICAg
ICAgIDwgQWRkaXRpb25hbCBQTSBjYXBhYmlsaXRpZXMKKyAqICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICBCaXQgNyA9IFJzdmQKKyAqICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICBCaXQgNiA9IFdha2UgY2FwYWJsZQorICogICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpdCA1ID0gRDMgc3VwcG9ydAorICogICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpdCA0ID0gRDIgc3VwcG9ydAorICog
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpdCAzID0gRDEgc3VwcG9y
dAorICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpdCAyID0gRDBp
MyBzdXBwb3J0CisgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQml0
IDEgPSBEMGkyIHN1cHBvcnQKKyAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBCaXQgMCA9IEQwaTEgc3VwcG9ydAorICogICB1aW50OF90ICAgICBhZGlkOyAgICAgICAg
ICAgICAgIDwgQWRkaXRpb25hbCBkZXZpY2UgSUQgKGRldi1zcGVjaWZpYykKKyAqICAgdWludDhf
dCAgICAgcnN2ZDsgICAgICAgICAgICAgICA8IFJlc2VydmVkIGZvciBmdXR1cmUgdXNlCisgKgor
ICogICBUaGUgY2FwYWJpbGl0eSBkYXRhIGFyZSBpbiB0aGUgUENJIGNvbmZpZ3VyYXRpb24gc3Bh
Y2UgYW5kIHRoZQorICogICBhZGlkIGZpZWxkIGNhbiBiZSBtb2RpZmllZCB1c2luZyBCTVAgdG9v
bC4KKyAqLworLyogQURESUQgPSBBZGRpdGlvbmFsIERldmljZSBJRCAqLworI2RlZmluZSBQQ0lf
Q0FQX09GRlNFVF9BRElEIDYKKworCi0tIAoxLjYuNi4xCgo=
--_002_2A84145621092446B6659B8A0F28E26F46FE77084Airsmsx501gerc_--
1
0
This patch depends on gpiolib support for h1940 latch access,
here's link to patch in ml archive:
http://www.spinics.net/lists/arm-kernel/msg98042.html
I hope Ben will find some time to merge it into his tree
before 2.6.37 merge window :)
Signed-off-by: Vasily Khoruzhick <anarsoul(a)gmail.com>
Tested-by: Arnaud Patard <arnaud.patard(a)rtp-net.org>
---
sound/soc/s3c24xx/Kconfig | 8 +
sound/soc/s3c24xx/Makefile | 2 +
sound/soc/s3c24xx/h1940_uda1380.c | 296 +++++++++++++++++++++++++++++++++++++
3 files changed, 306 insertions(+), 0 deletions(-)
create mode 100644 sound/soc/s3c24xx/h1940_uda1380.c
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 7d8235d..6b50509 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -118,6 +118,14 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
select SND_SOC_TLV320AIC3X
select SND_S3C24XX_SOC_SIMTEC
+config SND_S3C24XX_SOC_H1940_UDA1380
+ tristate "Audio support for the HP iPAQ H1940"
+ depends on SND_S3C24XX_SOC && ARCH_H1940
+ select SND_S3C24XX_SOC_I2S
+ select SND_SOC_UDA1380
+ help
+ This driver provides audio support for HP iPAQ h1940 PDA.
+
config SND_S3C24XX_SOC_RX1950_UDA1380
tristate "Audio support for the HP iPAQ RX1950"
depends on SND_S3C24XX_SOC && MACH_RX1950
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index dd412a9..33a7c68 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -28,6 +28,7 @@ snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
+snd-soc-h1940-uda1380-objs := h1940_uda1380.o
snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
snd-soc-smdk-wm9713-objs := smdk_wm9713.o
snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
@@ -44,6 +45,7 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
obj-$(CONFIG_SND_S3C24XX_SOC_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
+obj-$(CONFIG_SND_S3C24XX_SOC_H1940_UDA1380) += snd-soc-h1940-uda1380.o
obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
diff --git a/sound/soc/s3c24xx/h1940_uda1380.c b/sound/soc/s3c24xx/h1940_uda1380.c
new file mode 100644
index 0000000..77550fa
--- /dev/null
+++ b/sound/soc/s3c24xx/h1940_uda1380.c
@@ -0,0 +1,296 @@
+/*
+ * h1940-uda1380.c -- ALSA Soc Audio Layer
+ *
+ * Copyright (c) 2010 Arnaud Patard <arnaud.patard(a)rtp-net.org>
+ * Copyright (c) 2010 Vasily Khoruzhick <anarsoul(a)gmail.com>
+ *
+ * Based on version from Arnaud Patard <arnaud.patard(a)rtp-net.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/uda1380.h>
+#include <sound/jack.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/h1940-latch.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c-dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda1380.h"
+
+static unsigned int rates[] = {
+ 11025,
+ 22050,
+ 44100,
+};
+
+static struct snd_pcm_hw_constraint_list hw_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static struct snd_soc_jack hp_jack;
+
+static struct snd_soc_jack_pin hp_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1,
+ },
+};
+
+static struct snd_soc_jack_gpio hp_jack_gpios[] = {
+ {
+ .gpio = S3C2410_GPG(4),
+ .name = "hp-gpio",
+ .report = SND_JACK_HEADPHONE,
+ .invert = 1,
+ .debounce_time = 200,
+ },
+};
+
+static int h1940_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.rate_min = hw_rates.list[0];
+ runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
+ runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+
+ return snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &hw_rates);
+}
+
+static int h1940_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int div;
+ int ret;
+ unsigned int rate = params_rate(params);
+
+ switch (rate) {
+ case 11025:
+ case 22050:
+ case 44100:
+ div = s3c24xx_i2s_get_clockrate() / (384 * rate);
+ if (s3c24xx_i2s_get_clockrate() % (384 * rate) > (192 * rate))
+ div++;
+ break;
+ default:
+ printk(KERN_ERR "%s: rate %d is not supported\n",
+ __func__, rate);
+ return -EINVAL;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* select clock source */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, rate,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ /* set MCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+ S3C2410_IISMOD_384FS);
+ if (ret < 0)
+ return ret;
+
+ /* set BCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+ S3C2410_IISMOD_32FS);
+ if (ret < 0)
+ return ret;
+
+ /* set prescaler division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ S3C24XX_PRESCALE(div, div));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops h1940_ops = {
+ .startup = h1940_startup,
+ .hw_params = h1940_hw_params,
+};
+
+static int h1940_spk_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ gpio_set_value(H1940_LATCH_AUDIO_POWER, 1);
+ else
+ gpio_set_value(H1940_LATCH_AUDIO_POWER, 0);
+
+ return 0;
+}
+
+/* h1940 machine dapm widgets */
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", h1940_spk_power),
+};
+
+/* h1940 machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* headphone connected to VOUTLHP, VOUTRHP */
+ {"Headphone Jack", NULL, "VOUTLHP"},
+ {"Headphone Jack", NULL, "VOUTRHP"},
+
+ /* ext speaker connected to VOUTL, VOUTR */
+ {"Speaker", NULL, "VOUTL"},
+ {"Speaker", NULL, "VOUTR"},
+
+ /* mic is connected to VINM */
+ {"VINM", NULL, "Mic Jack"},
+};
+
+static struct platform_device *s3c24xx_snd_device;
+
+static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int err;
+
+ /* Add h1940 specific widgets */
+ err = snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
+ ARRAY_SIZE(uda1380_dapm_widgets));
+ if (err)
+ return err;
+
+ /* Set up h1940 specific audio path audio_mapnects */
+ err = snd_soc_dapm_add_routes(codec, audio_map,
+ ARRAY_SIZE(audio_map));
+ if (err)
+ return err;
+
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ snd_soc_dapm_enable_pin(codec, "Speaker");
+ snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+ snd_soc_dapm_sync(codec);
+
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+ &hp_jack);
+
+ snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
+ hp_jack_pins);
+
+ snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+
+ return 0;
+}
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link h1940_uda1380_dai[] = {
+ {
+ .name = "uda1380",
+ .stream_name = "UDA1380 Duplex",
+ .cpu_dai_name = "s3c24xx-iis",
+ .codec_dai_name = "uda1380-hifi",
+ .init = h1940_uda1380_init,
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "uda1380-codec.0-001a",
+ .ops = &h1940_ops,
+ },
+};
+
+static struct snd_soc_card h1940_asoc = {
+ .name = "h1940",
+ .dai_link = h1940_uda1380_dai,
+ .num_links = ARRAY_SIZE(h1940_uda1380_dai),
+};
+
+static int __init h1940_init(void)
+{
+ int ret;
+
+ if (!machine_is_h1940())
+ return -ENODEV;
+
+ /* configure some gpios */
+ ret = gpio_request(H1940_LATCH_AUDIO_POWER, "speaker-power");
+ if (ret)
+ goto err_out;
+
+ ret = gpio_direction_output(H1940_LATCH_AUDIO_POWER, 0);
+ if (ret)
+ goto err_gpio;
+
+ s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!s3c24xx_snd_device) {
+ ret = -ENOMEM;
+ goto err_gpio;
+ }
+
+ platform_set_drvdata(s3c24xx_snd_device, &h1940_asoc);
+ ret = platform_device_add(s3c24xx_snd_device);
+
+ if (ret)
+ goto err_plat;
+
+ return 0;
+
+err_plat:
+ platform_device_put(s3c24xx_snd_device);
+err_gpio:
+ gpio_free(H1940_LATCH_AUDIO_POWER);
+
+err_out:
+ return ret;
+}
+
+static void __exit h1940_exit(void)
+{
+ platform_device_unregister(s3c24xx_snd_device);
+ snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+ gpio_free(H1940_LATCH_AUDIO_POWER);
+}
+
+module_init(h1940_init);
+module_exit(h1940_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard, Vasily Khoruzhick");
+MODULE_DESCRIPTION("ALSA SoC H1940");
+MODULE_LICENSE("GPL");
--
1.7.2.2
4
20
[alsa-devel] [PATCH] fbdev: sh_mobile_hdmi: fix compilation without SOUND enabled
by Guennadi Liakhovetski 15 Oct '10
by Guennadi Liakhovetski 15 Oct '10
15 Oct '10
At least two more Kconfig options have to be selected to be able to compile
sh_mobile_hdmi.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski(a)gmx.de>
Cc: Kuninori Morimoto <kuninori.morimoto.gx(a)renesas.com>
---
Liam, Mark: since this patch only touches drivers/video, although that's a
central commonly-used file there, the scope of this patch is limited to
the FB_SH_MOBILE_HDMI block, so, this should safe to go via an SH tree,
but, if Paul doesn't mind, it should also be ok to go via sound.
drivers/video/Kconfig | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 43e90b8..935cdc2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1919,6 +1919,8 @@ config FB_SH_MOBILE_HDMI
tristate "SuperH Mobile HDMI controller support"
depends on FB_SH_MOBILE_LCDC
select FB_MODE_HELPERS
+ select SOUND
+ select SND
select SND_SOC
---help---
Driver for the on-chip SH-Mobile HDMI controller.
--
1.7.1
3
2
15 Oct '10
This patch replace magic code with defined name,
and remove unnecessary settings which set default value
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx(a)renesas.com>
---
sound/soc/codecs/ak4642.c | 64 ++++++++++++++++++++++++++++++++------------
1 files changed, 46 insertions(+), 18 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 009068f..90c90b7 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -72,6 +72,12 @@
#define AK4642_CACHEREGNUM 0x25
+/* PW_MGMT1*/
+#define PMVCM (1 << 6) /* VCOM Power Management */
+#define PMMIN (1 << 5) /* MIN Input Power Management */
+#define PMDAC (1 << 2) /* DAC Power Management */
+#define PMADL (1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
+
/* PW_MGMT2 */
#define HPMTN (1 << 6)
#define PMHPL (1 << 5)
@@ -83,6 +89,23 @@
#define PMHP_MASK (PMHPL | PMHPR)
#define PMHP PMHP_MASK
+/* PW_MGMT3 */
+#define PMADR (1 << 0) /* MIC L / ADC R Power Management */
+
+/* SG_SL1 */
+#define MINS (1 << 6) /* Switch from MIN to Speaker */
+#define DACL (1 << 4) /* Switch from DAC to Stereo or Receiver */
+#define PMMP (1 << 2) /* MPWR pin Power Management */
+#define MGAIN0 (1 << 0) /* MIC amp gain*/
+
+/* TIMER */
+#define ZTM(param) ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */
+#define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2))
+
+/* ALC_CTL1 */
+#define ALC (1 << 5) /* ALC Enable */
+#define LMTH0 (1 << 0) /* ALC Limiter / Recovery Level */
+
/* MD_CTL1 */
#define PLL3 (1 << 7)
#define PLL2 (1 << 6)
@@ -100,6 +123,11 @@
#define FS3 (1 << 5)
#define FS_MASK (FS0 | FS1 | FS2 | FS3)
+/* MD_CTL3 */
+#define BST1 (1 << 3)
+
+/* MD_CTL4 */
+#define DACH (1 << 0)
/*
* Playback Volume (table 39)
@@ -216,11 +244,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p97.
*/
- ak4642_write(codec, 0x0f, 0x09);
- ak4642_write(codec, 0x0e, 0x19);
- ak4642_write(codec, 0x09, 0x91);
- ak4642_write(codec, 0x0c, 0x91);
- snd_soc_update_bits(codec, 0x00, 0x64, 0x64);
+ snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
+ snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
+ ak4642_write(codec, L_IVC, 0x91); /* volume */
+ ak4642_write(codec, R_IVC, 0x91); /* volume */
+ snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
+ PMVCM | PMMIN | PMDAC);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN);
} else {
@@ -237,13 +266,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p94.
*/
- ak4642_write(codec, 0x02, 0x05);
- ak4642_write(codec, 0x06, 0x3c);
- ak4642_write(codec, 0x08, 0xe1);
- ak4642_write(codec, 0x0b, 0x00);
- ak4642_write(codec, 0x07, 0x21);
- snd_soc_update_bits(codec, 0x00, 0x41, 0x41);
- ak4642_write(codec, 0x10, 0x01);
+ ak4642_write(codec, SG_SL1, PMMP | MGAIN0);
+ ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
+ ak4642_write(codec, ALC_CTL1, ALC | LMTH0);
+ snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
+ PMVCM | PMADL);
+ snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
}
return 0;
@@ -259,14 +287,14 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
/* stop headphone output */
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0);
- snd_soc_update_bits(codec, 0x00, 0x64, 0x40);
- ak4642_write(codec, 0x0e, 0x11);
- ak4642_write(codec, 0x0f, 0x08);
+ snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0);
+ snd_soc_update_bits(codec, MD_CTL3, BST1, 0);
+ snd_soc_update_bits(codec, MD_CTL4, DACH, 0);
} else {
/* stop stereo input */
- snd_soc_update_bits(codec, 0x00, 0x41, 0x40);
- ak4642_write(codec, 0x10, 0x00);
- ak4642_write(codec, 0x07, 0x01);
+ snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
+ snd_soc_update_bits(codec, PW_MGMT3, PMADR, 0);
+ snd_soc_update_bits(codec, ALC_CTL1, ALC, 0);
}
}
--
1.7.0.4
3
2
Fixup commit 9b1a2566: Remove error loop
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
---
speaker-test/speaker-test.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c
index 458a8d7..3029110 100644
--- a/speaker-test/speaker-test.c
+++ b/speaker-test/speaker-test.c
@@ -993,9 +993,9 @@ int main(int argc, char *argv[]) {
}
- while ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf(_("Playback open error: %d,%s\n"), err,snd_strerror(err));
- sleep(1);
+ exit(EXIT_FAILURE);
}
if ((err = set_hwparams(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
--
1.7.1
--------------070605020506060102030305--
1
0