* Re: [Qemu-devel] [kvm-unit-tests PATCH v4 09/11] arm/arm64: add initial gicv3 support
From: Andrew Jones @ 2016-11-09 15:23 UTC (permalink / raw)
To: Andre Przywara
Cc: kvm, kvmarm, qemu-devel, qemu-arm, peter.maydell, marc.zyngier,
eric.auger, pbonzini, alex.bennee, christoffer.dall
In-Reply-To: <b4fcac1f-2cc5-09c3-0cab-71f5aaa3e7e1@arm.com>
On Wed, Nov 09, 2016 at 02:43:53PM +0000, Andre Przywara wrote:
> Hi,
>
> On 09/11/16 13:08, Andrew Jones wrote:
> > On Wed, Nov 09, 2016 at 12:35:48PM +0000, Andre Przywara wrote:
> > [...]
> >>> diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h
> >>> new file mode 100644
> >>> index 000000000000..03321f8c860f
> >>> --- /dev/null
> >>> +++ b/lib/arm/asm/gic-v3.h
> >>> @@ -0,0 +1,92 @@
> >>> +/*
> >>> + * All GIC* defines are lifted from include/linux/irqchip/arm-gic-v3.h
> >>> + *
> >>> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
> >>> + *
> >>> + * This work is licensed under the terms of the GNU LGPL, version 2.
> >>> + */
> >>> +#ifndef _ASMARM_GIC_V3_H_
> >>> +#define _ASMARM_GIC_V3_H_
> >>> +
> >>> +#ifndef _ASMARM_GIC_H_
> >>> +#error Do not directly include <asm/gic-v3.h>. Include <asm/gic.h>
> >>> +#endif
> >>> +
> >>> +#define GICD_CTLR 0x0000
> >>> +#define GICD_TYPER 0x0004
> >>
> >> So if we share the distributor register definition with GICv2, these
> >> shouldn't be here, but in gic.h.
> >> But this is the right naming scheme we should use (instead of GIC_DIST_xxx).
> >>
> >> Now this gets interesting with your wish to both share the definitions
> >> for the GICv2 and GICv3 distributors, but also stick to the names the
> >> kernel uses (because they differ between the two) ;-)
> >> So now you loose the greppability for either GIC_DIST_CTR or GICD_TYPER,
> >> for instance.
> >
> > Well, we just have the same offset with two names (giving us two
> > symbols to grep). I put them here, vs. asm/gic.h, because the kernel
> > only uses theses symbols for gicv3. Now, nothing stops a unit test
> > from using them with gicv2 tests, though, because unit tests include
> > gic.h, which includes both gic-v2.h and gic-v3.h, and thus it gets
> > both. I know, it's sounding messy... Shouldn't we post some churn to
> > the kernel? :-)
>
> Well, on top of that the distributor registers are slightly different
> (check CTLR and TYPER, for instance). So it's churn plus a stretch, I
> guess Marc won't like that.
>
> So if greppability is important, should we revert to separate
> definitions in separate header files then, like in v3?
> I don't think we actually share _code_ between the two GIC revisions, do we?
>
> > Note, I tried to only add defines to asm/gic.h that are actually
> > shared in the kernel between v2 and v3, e.g. GIC_DIST_ENABLE_SET.
>
> Huh? GICv3 uses GICD_ISENABLER for that register.
drivers/irqchip/irq-gic-common.c:gic_cpu_config uses it, along with
GICD_INT_DEF_PRI_X4 and GIC_DIST_PRI. But I guess those are the only
shared ones duplicated here so far, so I was wrong to say the two
below were the only two not shared.
>
> > Actually, GIC_DIST_CTRL and GIC_DIST_CTR may be the only exceptions
> > we have so far.
>
> Note that it's GIC_DIST_CTLR (L and R swapped), one reason more to dump
> _CTR ;-)
Yeah, I noticed that too, craziness. OK, I won't fight for the
greppability argument too hard. Actually, you'll likely be the
one doing the grepping when you go fix the driver :-) If you'd
prefer we only use one set of defines (the better, modern ones),
then for v5 that's what I'll do.
>
> >>
> >>> +#define GICD_IGROUPR 0x0080
> >>> +
> >>> +#define GICD_CTLR_RWP (1U << 31)
> >>> +#define GICD_CTLR_ARE_NS (1U << 4)
> >>> +#define GICD_CTLR_ENABLE_G1A (1U << 1)
> >>> +#define GICD_CTLR_ENABLE_G1 (1U << 0)
> >>> +
> >>> +#define GICR_TYPER 0x0008
> >>> +#define GICR_IGROUPR0 GICD_IGROUPR
> >>> +#define GICR_TYPER_LAST (1U << 4)
> >>> +
> >>> +
> >>> +#include <asm/arch_gicv3.h>
> >>> +
> >>> +#ifndef __ASSEMBLY__
> >>> +#include <asm/setup.h>
> >>> +#include <asm/smp.h>
> >>> +#include <asm/processor.h>
> >>> +#include <asm/io.h>
> >>> +
> >>> +struct gicv3_data {
> >>> + void *dist_base;
> >>> + void *redist_base[NR_CPUS];
> >>> + unsigned int irq_nr;
> >>> +};
> >>> +extern struct gicv3_data gicv3_data;
> >>> +
> >>> +#define gicv3_dist_base() (gicv3_data.dist_base)
> >>> +#define gicv3_redist_base() (gicv3_data.redist_base[smp_processor_id()])
> >>> +#define gicv3_sgi_base() (gicv3_data.redist_base[smp_processor_id()] + SZ_64K)
> >>> +
> >>> +extern int gicv3_init(void);
> >>> +extern void gicv3_enable_defaults(void);
> >>> +
> >>> +static inline void gicv3_do_wait_for_rwp(void *base)
> >>> +{
> >>> + int count = 100000; /* 1s */
> >>> +
> >>> + while (readl(base + GICD_CTLR) & GICD_CTLR_RWP) {
> >>> + if (!--count) {
> >>> + printf("GICv3: RWP timeout!\n");
> >>> + abort();
> >>> + }
> >>> + cpu_relax();
> >>> + udelay(10);
> >>> + };
> >>> +}
> >>> +
> >>> +static inline void gicv3_dist_wait_for_rwp(void)
> >>> +{
> >>> + gicv3_do_wait_for_rwp(gicv3_dist_base());
> >>> +}
> >>> +
> >>> +static inline void gicv3_redist_wait_for_rwp(void)
> >>> +{
> >>> + gicv3_do_wait_for_rwp(gicv3_redist_base());
> >>> +}
> >>> +
> >>> +static inline u32 mpidr_compress(u64 mpidr)
> >>> +{
> >>> + u64 compressed = mpidr & MPIDR_HWID_BITMASK;
> >>> +
> >>> + compressed = (((compressed >> 32) & 0xff) << 24) | compressed;
> >>> + return compressed;
> >>> +}
> >>> +
> >>> +static inline u64 mpidr_uncompress(u32 compressed)
> >>> +{
> >>> + u64 mpidr = ((u64)compressed >> 24) << 32;
> >>> +
> >>> + mpidr |= compressed & MPIDR_HWID_BITMASK;
> >>> + return mpidr;
> >>> +}
> >>> +
> >>> +#endif /* !__ASSEMBLY__ */
> >>> +#endif /* _ASMARM_GIC_V3_H_ */
> >>> diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
> >>> index 328e078a9ae1..4897bc592cdd 100644
> >>> --- a/lib/arm/asm/gic.h
> >>> +++ b/lib/arm/asm/gic.h
> >>> @@ -7,6 +7,7 @@
> >>> #define _ASMARM_GIC_H_
> >>>
> >>> #include <asm/gic-v2.h>
> >>> +#include <asm/gic-v3.h>
> >>>
> >>> #define GIC_CPU_CTRL 0x00
> >>> #define GIC_CPU_PRIMASK 0x04
> >>> diff --git a/lib/arm/gic.c b/lib/arm/gic.c
> >>> index 91d78c9a0cc2..af58a11ea13e 100644
> >>> --- a/lib/arm/gic.c
> >>> +++ b/lib/arm/gic.c
> >>> @@ -8,9 +8,11 @@
> >>> #include <asm/io.h>
> >>>
> >>> struct gicv2_data gicv2_data;
> >>> +struct gicv3_data gicv3_data;
> >>>
> >>> /*
> >>> * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
> >>> + * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
> >>> */
> >>> static bool
> >>> gic_get_dt_bases(const char *compatible, void **base1, void **base2)
> >>> @@ -48,10 +50,18 @@ int gicv2_init(void)
> >>> &gicv2_data.dist_base, &gicv2_data.cpu_base);
> >>> }
> >>>
> >>> +int gicv3_init(void)
> >>> +{
> >>> + return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base,
> >>> + &gicv3_data.redist_base[0]);
> >>> +}
> >>> +
> >>> int gic_init(void)
> >>> {
> >>> if (gicv2_init())
> >>> return 2;
> >>> + else if (gicv3_init())
> >>> + return 3;
> >>> return 0;
> >>> }
> >>>
> >>> @@ -73,3 +83,49 @@ void gicv2_enable_defaults(void)
> >>> writel(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK);
> >>> writel(GICC_ENABLE, cpu_base + GIC_CPU_CTRL);
> >>> }
> >>> +
> >>> +void gicv3_set_redist_base(void)
> >>> +{
> >>> + u32 aff = mpidr_compress(get_mpidr());
> >>> + void *ptr = gicv3_data.redist_base[0];
> >>> + u64 typer;
> >>> +
> >>> + do {
> >>> + typer = gicv3_read_typer(ptr + GICR_TYPER);
> >>> + if ((typer >> 32) == aff) {
> >>> + gicv3_redist_base() = ptr;
> >>> + return;
> >>> + }
> >>> + ptr += SZ_64K * 2; /* skip RD_base and SGI_base */
> >>> + } while (!(typer & GICR_TYPER_LAST));
> >>> + assert(0);
> >>> +}
> >>> +
> >>> +void gicv3_enable_defaults(void)
> >>> +{
> >>> + void *dist = gicv3_dist_base();
> >>> + void *sgi_base;
> >>> + unsigned int i;
> >>> +
> >>> + gicv3_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
> >>> + if (gicv3_data.irq_nr > 1020)
> >>> + gicv3_data.irq_nr = 1020;
> >>> +
> >>> + writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
> >>> + dist + GICD_CTLR);
> >>> + gicv3_dist_wait_for_rwp();
> >>> +
> >>> + if (!gicv3_redist_base())
> >>> + gicv3_set_redist_base();
> >>> + sgi_base = gicv3_sgi_base();
> >>> +
> >>> + writel(~0, sgi_base + GICR_IGROUPR0);
> >>
> >> This is mixing redist setup with distributor setup. Is it that what you
> >> meant with:
> >> " - simplify enable by not caring if we reinit the distributor [drew]"?
> >
> > Yes, but, TBH, I wasn't sure I could get away with it. I tested and it
> > worked, and I figured you'd yell at me if I was wrong :-)
> >
> >>
> >> Also if you set the group for the SGIs, you should set it for SPIs as
> >> well (like the kernel does). This was done in v3 of the series.
> >
> > OK, I was also simplifying by removing everything and then adding stuff
> > back until it worked :-) I can certainly add this back for completeness
> > though.
>
> So you did need IGROUP0?
At least with TCG, yes. When I removed it and quick tested on my x86
notebook the gic test hung. I didn't try to debug, I just added stuff
until it worked...
>
> Actually the VGIC implements a single security state, where those
> registers are supposed to be RAZ/WI, if I get the spec correctly.
> And KVM implements them as RAO/WI, both for GICR_IGROUPR0 and GICD_IGROUPRn.
> But the kernel sets both of them up (because it drives real hardware),
> so I'd trust Marc's wisdom more here ;-)
> If we don't need this GROUPR setup for proper functionality, we could
> move it from the generic setup into an actual test.
As I need GICR_IGROUP0, I'll bring GICD_IGROUPRn back too.
>
> >> What about you finish the per-CPU setup first, then bail out with:
> >>
> >> if (smp_processor_id() != 0)
> >> return;
> >>
> >> and then do the distributor setup (only on the first core).
> >
> > Sure, if it's necessary. I actually like not having to worry about
> > a particular core or a particular order/number of times this enable
> > gets called. Does it hurt to just do it each time?
>
> Shouldn't really, so we could let it stay in there until someone
> complains ...
Thanks,
drew
^ permalink raw reply
* Re: [PATCH 4/6 v7] sched: propagate load during synchronous attach/detach
From: Vincent Guittot @ 2016-11-09 15:23 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Ingo Molnar, linux-kernel, Dietmar Eggemann, Yuyang Du,
Morten Rasmussen, Paul Turner, Ben Segall, Wanpeng Li
In-Reply-To: <20161109150319.GR3117@twins.programming.kicks-ass.net>
On 9 November 2016 at 16:03, Peter Zijlstra <peterz@infradead.org> wrote:
> On Tue, Nov 08, 2016 at 10:53:45AM +0100, Vincent Guittot wrote:
>> When a task moves from/to a cfs_rq, we set a flag which is then used to
>> propagate the change at parent level (sched_entity and cfs_rq) during
>> next update. If the cfs_rq is throttled, the flag will stay pending until
>> the cfs_rq is unthrottled.
>>
>> For propagating the utilization, we copy the utilization of group cfs_rq to
>> the sched_entity.
>>
>> For propagating the load, we have to take into account the load of the
>> whole task group in order to evaluate the load of the sched_entity.
>> Similarly to what was done before the rewrite of PELT, we add a correction
>> factor in case the task group's load is greater than its share so it will
>> contribute the same load of a task of equal weight.
>>
>> Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
>> ---
>
>
> I did the below on top, that basically moves code about a bit to reduce
> some #ifdef and kills a few comments that I thought were of the:
>
> i++; /* increment by one */
>
> quality.
OK. The changes look fine to me
>
[snip]
>
^ permalink raw reply
* Applied "ASoC: Add support for CS42L42 codec" to the asoc tree
From: Mark Brown @ 2016-11-09 14:59 UTC (permalink / raw)
To: James Schulman; +Cc: alsa-devel, Mark Brown
The patch
ASoC: Add support for CS42L42 codec
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 2c394ca79604b404fe60218670ab301ecb758b34 Mon Sep 17 00:00:00 2001
From: James Schulman <james.schulman@cirrus.com>
Date: Mon, 7 Nov 2016 14:38:37 -0600
Subject: [PATCH] ASoC: Add support for CS42L42 codec
Add support for Cirrus Logic CS42L42 codec. SoundWire support
is not enabled. Features support for I2C control and I2S audio.
Signed-off-by: James Schulman <james.schulman@cirrus.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
include/dt-bindings/sound/cs42l42.h | 73 ++
sound/soc/codecs/Kconfig | 5 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/cs42l42.c | 1987 +++++++++++++++++++++++++++++++++++
sound/soc/codecs/cs42l42.h | 776 ++++++++++++++
5 files changed, 2843 insertions(+)
create mode 100644 include/dt-bindings/sound/cs42l42.h
create mode 100644 sound/soc/codecs/cs42l42.c
create mode 100644 sound/soc/codecs/cs42l42.h
diff --git a/include/dt-bindings/sound/cs42l42.h b/include/dt-bindings/sound/cs42l42.h
new file mode 100644
index 000000000000..399a123aed58
--- /dev/null
+++ b/include/dt-bindings/sound/cs42l42.h
@@ -0,0 +1,73 @@
+/*
+ * cs42l42.h -- CS42L42 ALSA SoC audio driver DT bindings header
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: James Schulman <james.schulman@cirrus.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ * Author: Michael White <michael.white@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __DT_CS42L42_H
+#define __DT_CS42L42_H
+
+/* HPOUT Load Capacity */
+#define CS42L42_HPOUT_LOAD_1NF 0
+#define CS42L42_HPOUT_LOAD_10NF 1
+
+/* HPOUT Clamp to GND Overide */
+#define CS42L42_HPOUT_CLAMP_EN 0
+#define CS42L42_HPOUT_CLAMP_DIS 1
+
+/* Tip Sense Inversion */
+#define CS42L42_TS_INV_DIS 0
+#define CS42L42_TS_INV_EN 1
+
+/* Tip Sense Debounce */
+#define CS42L42_TS_DBNCE_0 0
+#define CS42L42_TS_DBNCE_125 1
+#define CS42L42_TS_DBNCE_250 2
+#define CS42L42_TS_DBNCE_500 3
+#define CS42L42_TS_DBNCE_750 4
+#define CS42L42_TS_DBNCE_1000 5
+#define CS42L42_TS_DBNCE_1250 6
+#define CS42L42_TS_DBNCE_1500 7
+
+/* Button Press Software Debounce Times */
+#define CS42L42_BTN_DET_INIT_DBNCE_MIN 0
+#define CS42L42_BTN_DET_INIT_DBNCE_DEFAULT 100
+#define CS42L42_BTN_DET_INIT_DBNCE_MAX 200
+
+#define CS42L42_BTN_DET_EVENT_DBNCE_MIN 0
+#define CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT 10
+#define CS42L42_BTN_DET_EVENT_DBNCE_MAX 20
+
+/* Button Detect Level Sensitivities */
+#define CS42L42_NUM_BIASES 4
+
+#define CS42L42_HS_DET_LEVEL_15 0x0F
+#define CS42L42_HS_DET_LEVEL_8 0x08
+#define CS42L42_HS_DET_LEVEL_4 0x04
+#define CS42L42_HS_DET_LEVEL_1 0x01
+
+#define CS42L42_HS_DET_LEVEL_MIN 0
+#define CS42L42_HS_DET_LEVEL_MAX 0x3F
+
+/* HS Bias Ramp Rate */
+
+#define CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL 0
+#define CS42L42_HSBIAS_RAMP_FAST 1
+#define CS42L42_HSBIAS_RAMP_SLOW 2
+#define CS42L42_HSBIAS_RAMP_SLOWEST 3
+
+#define CS42L42_HSBIAS_RAMP_TIME0 10
+#define CS42L42_HSBIAS_RAMP_TIME1 40
+#define CS42L42_HSBIAS_RAMP_TIME2 90
+#define CS42L42_HSBIAS_RAMP_TIME3 170
+
+#endif /* __DT_CS42L42_H */
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index bf2f26dddfab..2aa709a0e87a 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -49,6 +49,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS35L32 if I2C
select SND_SOC_CS35L33 if I2C
select SND_SOC_CS35L34 if I2C
+ select SND_SOC_CS42L42 if I2C
select SND_SOC_CS42L51_I2C if I2C
select SND_SOC_CS42L52 if I2C && INPUT
select SND_SOC_CS42L56 if I2C && INPUT
@@ -404,6 +405,10 @@ config SND_SOC_CS35L34
tristate "Cirrus Logic CS35L34 CODEC"
depends on I2C
+config SND_SOC_CS42L42
+ tristate "Cirrus Logic CS42L42 CODEC"
+ depends on I2C
+
config SND_SOC_CS42L51
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 3f0cd9047f09..4bcafc345248 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -39,6 +39,7 @@ snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs35l32-objs := cs35l32.o
snd-soc-cs35l33-objs := cs35l33.o
snd-soc-cs35l34-objs := cs35l34.o
+snd-soc-cs42l42-objs := cs42l42.o
snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
snd-soc-cs42l52-objs := cs42l52.o
@@ -265,6 +266,7 @@ obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o
obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o
obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o
+obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
new file mode 100644
index 000000000000..f3c10f5d68c8
--- /dev/null
+++ b/sound/soc/codecs/cs42l42.c
@@ -0,0 +1,1987 @@
+/*
+ * cs42l42.c -- CS42L42 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: James Schulman <james.schulman@cirrus.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ * Author: Michael White <michael.white@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_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 <dt-bindings/sound/cs42l42.h>
+
+#include "cs42l42.h"
+
+static const struct reg_default cs42l42_reg_defaults[] = {
+ { CS42L42_FRZ_CTL, 0x00 },
+ { CS42L42_SRC_CTL, 0x10 },
+ { CS42L42_MCLK_STATUS, 0x02 },
+ { CS42L42_MCLK_CTL, 0x02 },
+ { CS42L42_SFTRAMP_RATE, 0xA4 },
+ { CS42L42_I2C_DEBOUNCE, 0x88 },
+ { CS42L42_I2C_STRETCH, 0x03 },
+ { CS42L42_I2C_TIMEOUT, 0xB7 },
+ { CS42L42_PWR_CTL1, 0xFF },
+ { CS42L42_PWR_CTL2, 0x84 },
+ { CS42L42_PWR_CTL3, 0x20 },
+ { CS42L42_RSENSE_CTL1, 0x40 },
+ { CS42L42_RSENSE_CTL2, 0x00 },
+ { CS42L42_OSC_SWITCH, 0x00 },
+ { CS42L42_OSC_SWITCH_STATUS, 0x05 },
+ { CS42L42_RSENSE_CTL3, 0x1B },
+ { CS42L42_TSENSE_CTL, 0x1B },
+ { CS42L42_TSRS_INT_DISABLE, 0x00 },
+ { CS42L42_TRSENSE_STATUS, 0x00 },
+ { CS42L42_HSDET_CTL1, 0x77 },
+ { CS42L42_HSDET_CTL2, 0x00 },
+ { CS42L42_HS_SWITCH_CTL, 0xF3 },
+ { CS42L42_HS_DET_STATUS, 0x00 },
+ { CS42L42_HS_CLAMP_DISABLE, 0x00 },
+ { CS42L42_MCLK_SRC_SEL, 0x00 },
+ { CS42L42_SPDIF_CLK_CFG, 0x00 },
+ { CS42L42_FSYNC_PW_LOWER, 0x00 },
+ { CS42L42_FSYNC_PW_UPPER, 0x00 },
+ { CS42L42_FSYNC_P_LOWER, 0xF9 },
+ { CS42L42_FSYNC_P_UPPER, 0x00 },
+ { CS42L42_ASP_CLK_CFG, 0x00 },
+ { CS42L42_ASP_FRM_CFG, 0x10 },
+ { CS42L42_FS_RATE_EN, 0x00 },
+ { CS42L42_IN_ASRC_CLK, 0x00 },
+ { CS42L42_OUT_ASRC_CLK, 0x00 },
+ { CS42L42_PLL_DIV_CFG1, 0x00 },
+ { CS42L42_ADC_OVFL_STATUS, 0x00 },
+ { CS42L42_MIXER_STATUS, 0x00 },
+ { CS42L42_SRC_STATUS, 0x00 },
+ { CS42L42_ASP_RX_STATUS, 0x00 },
+ { CS42L42_ASP_TX_STATUS, 0x00 },
+ { CS42L42_CODEC_STATUS, 0x00 },
+ { CS42L42_DET_INT_STATUS1, 0x00 },
+ { CS42L42_DET_INT_STATUS2, 0x00 },
+ { CS42L42_SRCPL_INT_STATUS, 0x00 },
+ { CS42L42_VPMON_STATUS, 0x00 },
+ { CS42L42_PLL_LOCK_STATUS, 0x00 },
+ { CS42L42_TSRS_PLUG_STATUS, 0x00 },
+ { CS42L42_ADC_OVFL_INT_MASK, 0x01 },
+ { CS42L42_MIXER_INT_MASK, 0x0F },
+ { CS42L42_SRC_INT_MASK, 0x0F },
+ { CS42L42_ASP_RX_INT_MASK, 0x1F },
+ { CS42L42_ASP_TX_INT_MASK, 0x0F },
+ { CS42L42_CODEC_INT_MASK, 0x03 },
+ { CS42L42_SRCPL_INT_MASK, 0xFF },
+ { CS42L42_VPMON_INT_MASK, 0x01 },
+ { CS42L42_PLL_LOCK_INT_MASK, 0x01 },
+ { CS42L42_TSRS_PLUG_INT_MASK, 0x0F },
+ { CS42L42_PLL_CTL1, 0x00 },
+ { CS42L42_PLL_DIV_FRAC0, 0x00 },
+ { CS42L42_PLL_DIV_FRAC1, 0x00 },
+ { CS42L42_PLL_DIV_FRAC2, 0x00 },
+ { CS42L42_PLL_DIV_INT, 0x40 },
+ { CS42L42_PLL_CTL3, 0x10 },
+ { CS42L42_PLL_CAL_RATIO, 0x80 },
+ { CS42L42_PLL_CTL4, 0x03 },
+ { CS42L42_LOAD_DET_RCSTAT, 0x00 },
+ { CS42L42_LOAD_DET_DONE, 0x00 },
+ { CS42L42_LOAD_DET_EN, 0x00 },
+ { CS42L42_HSBIAS_SC_AUTOCTL, 0x03 },
+ { CS42L42_WAKE_CTL, 0xC0 },
+ { CS42L42_ADC_DISABLE_MUTE, 0x00 },
+ { CS42L42_TIPSENSE_CTL, 0x02 },
+ { CS42L42_MISC_DET_CTL, 0x03 },
+ { CS42L42_MIC_DET_CTL1, 0x1F },
+ { CS42L42_MIC_DET_CTL2, 0x2F },
+ { CS42L42_DET_STATUS1, 0x00 },
+ { CS42L42_DET_STATUS2, 0x00 },
+ { CS42L42_DET_INT1_MASK, 0xE0 },
+ { CS42L42_DET_INT2_MASK, 0xFF },
+ { CS42L42_HS_BIAS_CTL, 0xC2 },
+ { CS42L42_ADC_CTL, 0x00 },
+ { CS42L42_ADC_VOLUME, 0x00 },
+ { CS42L42_ADC_WNF_HPF_CTL, 0x71 },
+ { CS42L42_DAC_CTL1, 0x00 },
+ { CS42L42_DAC_CTL2, 0x02 },
+ { CS42L42_HP_CTL, 0x0D },
+ { CS42L42_CLASSH_CTL, 0x07 },
+ { CS42L42_MIXER_CHA_VOL, 0x3F },
+ { CS42L42_MIXER_ADC_VOL, 0x3F },
+ { CS42L42_MIXER_CHB_VOL, 0x3F },
+ { CS42L42_EQ_COEF_IN0, 0x22 },
+ { CS42L42_EQ_COEF_IN1, 0x00 },
+ { CS42L42_EQ_COEF_IN2, 0x00 },
+ { CS42L42_EQ_COEF_IN3, 0x00 },
+ { CS42L42_EQ_COEF_RW, 0x00 },
+ { CS42L42_EQ_COEF_OUT0, 0x00 },
+ { CS42L42_EQ_COEF_OUT1, 0x00 },
+ { CS42L42_EQ_COEF_OUT2, 0x00 },
+ { CS42L42_EQ_COEF_OUT3, 0x00 },
+ { CS42L42_EQ_INIT_STAT, 0x00 },
+ { CS42L42_EQ_START_FILT, 0x00 },
+ { CS42L42_EQ_MUTE_CTL, 0x00 },
+ { CS42L42_SP_RX_CH_SEL, 0x04 },
+ { CS42L42_SP_RX_ISOC_CTL, 0x04 },
+ { CS42L42_SP_RX_FS, 0x8C },
+ { CS42l42_SPDIF_CH_SEL, 0x0E },
+ { CS42L42_SP_TX_ISOC_CTL, 0x04 },
+ { CS42L42_SP_TX_FS, 0xCC },
+ { CS42L42_SPDIF_SW_CTL1, 0x3F },
+ { CS42L42_SRC_SDIN_FS, 0x40 },
+ { CS42L42_SRC_SDOUT_FS, 0x40 },
+ { CS42L42_SPDIF_CTL1, 0x01 },
+ { CS42L42_SPDIF_CTL2, 0x00 },
+ { CS42L42_SPDIF_CTL3, 0x00 },
+ { CS42L42_SPDIF_CTL4, 0x42 },
+ { CS42L42_ASP_TX_SZ_EN, 0x00 },
+ { CS42L42_ASP_TX_CH_EN, 0x00 },
+ { CS42L42_ASP_TX_CH_AP_RES, 0x0F },
+ { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
+ { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
+ { CS42L42_ASP_TX_HIZ_DLY_CFG, 0x00 },
+ { CS42L42_ASP_TX_CH2_BIT_MSB, 0x00 },
+ { CS42L42_ASP_TX_CH2_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_EN, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI1_CH1_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI1_CH1_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI1_CH1_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI1_CH2_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI1_CH2_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 },
+ { CS42L42_SUB_REVID, 0x03 },
+};
+
+static bool cs42l42_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L42_PAGE_REGISTER:
+ case CS42L42_DEVID_AB:
+ case CS42L42_DEVID_CD:
+ case CS42L42_DEVID_E:
+ case CS42L42_FABID:
+ case CS42L42_REVID:
+ case CS42L42_FRZ_CTL:
+ case CS42L42_SRC_CTL:
+ case CS42L42_MCLK_STATUS:
+ case CS42L42_MCLK_CTL:
+ case CS42L42_SFTRAMP_RATE:
+ case CS42L42_I2C_DEBOUNCE:
+ case CS42L42_I2C_STRETCH:
+ case CS42L42_I2C_TIMEOUT:
+ case CS42L42_PWR_CTL1:
+ case CS42L42_PWR_CTL2:
+ case CS42L42_PWR_CTL3:
+ case CS42L42_RSENSE_CTL1:
+ case CS42L42_RSENSE_CTL2:
+ case CS42L42_OSC_SWITCH:
+ case CS42L42_OSC_SWITCH_STATUS:
+ case CS42L42_RSENSE_CTL3:
+ case CS42L42_TSENSE_CTL:
+ case CS42L42_TSRS_INT_DISABLE:
+ case CS42L42_TRSENSE_STATUS:
+ case CS42L42_HSDET_CTL1:
+ case CS42L42_HSDET_CTL2:
+ case CS42L42_HS_SWITCH_CTL:
+ case CS42L42_HS_DET_STATUS:
+ case CS42L42_HS_CLAMP_DISABLE:
+ case CS42L42_MCLK_SRC_SEL:
+ case CS42L42_SPDIF_CLK_CFG:
+ case CS42L42_FSYNC_PW_LOWER:
+ case CS42L42_FSYNC_PW_UPPER:
+ case CS42L42_FSYNC_P_LOWER:
+ case CS42L42_FSYNC_P_UPPER:
+ case CS42L42_ASP_CLK_CFG:
+ case CS42L42_ASP_FRM_CFG:
+ case CS42L42_FS_RATE_EN:
+ case CS42L42_IN_ASRC_CLK:
+ case CS42L42_OUT_ASRC_CLK:
+ case CS42L42_PLL_DIV_CFG1:
+ case CS42L42_ADC_OVFL_STATUS:
+ case CS42L42_MIXER_STATUS:
+ case CS42L42_SRC_STATUS:
+ case CS42L42_ASP_RX_STATUS:
+ case CS42L42_ASP_TX_STATUS:
+ case CS42L42_CODEC_STATUS:
+ case CS42L42_DET_INT_STATUS1:
+ case CS42L42_DET_INT_STATUS2:
+ case CS42L42_SRCPL_INT_STATUS:
+ case CS42L42_VPMON_STATUS:
+ case CS42L42_PLL_LOCK_STATUS:
+ case CS42L42_TSRS_PLUG_STATUS:
+ case CS42L42_ADC_OVFL_INT_MASK:
+ case CS42L42_MIXER_INT_MASK:
+ case CS42L42_SRC_INT_MASK:
+ case CS42L42_ASP_RX_INT_MASK:
+ case CS42L42_ASP_TX_INT_MASK:
+ case CS42L42_CODEC_INT_MASK:
+ case CS42L42_SRCPL_INT_MASK:
+ case CS42L42_VPMON_INT_MASK:
+ case CS42L42_PLL_LOCK_INT_MASK:
+ case CS42L42_TSRS_PLUG_INT_MASK:
+ case CS42L42_PLL_CTL1:
+ case CS42L42_PLL_DIV_FRAC0:
+ case CS42L42_PLL_DIV_FRAC1:
+ case CS42L42_PLL_DIV_FRAC2:
+ case CS42L42_PLL_DIV_INT:
+ case CS42L42_PLL_CTL3:
+ case CS42L42_PLL_CAL_RATIO:
+ case CS42L42_PLL_CTL4:
+ case CS42L42_LOAD_DET_RCSTAT:
+ case CS42L42_LOAD_DET_DONE:
+ case CS42L42_LOAD_DET_EN:
+ case CS42L42_HSBIAS_SC_AUTOCTL:
+ case CS42L42_WAKE_CTL:
+ case CS42L42_ADC_DISABLE_MUTE:
+ case CS42L42_TIPSENSE_CTL:
+ case CS42L42_MISC_DET_CTL:
+ case CS42L42_MIC_DET_CTL1:
+ case CS42L42_MIC_DET_CTL2:
+ case CS42L42_DET_STATUS1:
+ case CS42L42_DET_STATUS2:
+ case CS42L42_DET_INT1_MASK:
+ case CS42L42_DET_INT2_MASK:
+ case CS42L42_HS_BIAS_CTL:
+ case CS42L42_ADC_CTL:
+ case CS42L42_ADC_VOLUME:
+ case CS42L42_ADC_WNF_HPF_CTL:
+ case CS42L42_DAC_CTL1:
+ case CS42L42_DAC_CTL2:
+ case CS42L42_HP_CTL:
+ case CS42L42_CLASSH_CTL:
+ case CS42L42_MIXER_CHA_VOL:
+ case CS42L42_MIXER_ADC_VOL:
+ case CS42L42_MIXER_CHB_VOL:
+ case CS42L42_EQ_COEF_IN0:
+ case CS42L42_EQ_COEF_IN1:
+ case CS42L42_EQ_COEF_IN2:
+ case CS42L42_EQ_COEF_IN3:
+ case CS42L42_EQ_COEF_RW:
+ case CS42L42_EQ_COEF_OUT0:
+ case CS42L42_EQ_COEF_OUT1:
+ case CS42L42_EQ_COEF_OUT2:
+ case CS42L42_EQ_COEF_OUT3:
+ case CS42L42_EQ_INIT_STAT:
+ case CS42L42_EQ_START_FILT:
+ case CS42L42_EQ_MUTE_CTL:
+ case CS42L42_SP_RX_CH_SEL:
+ case CS42L42_SP_RX_ISOC_CTL:
+ case CS42L42_SP_RX_FS:
+ case CS42l42_SPDIF_CH_SEL:
+ case CS42L42_SP_TX_ISOC_CTL:
+ case CS42L42_SP_TX_FS:
+ case CS42L42_SPDIF_SW_CTL1:
+ case CS42L42_SRC_SDIN_FS:
+ case CS42L42_SRC_SDOUT_FS:
+ case CS42L42_SPDIF_CTL1:
+ case CS42L42_SPDIF_CTL2:
+ case CS42L42_SPDIF_CTL3:
+ case CS42L42_SPDIF_CTL4:
+ case CS42L42_ASP_TX_SZ_EN:
+ case CS42L42_ASP_TX_CH_EN:
+ case CS42L42_ASP_TX_CH_AP_RES:
+ case CS42L42_ASP_TX_CH1_BIT_MSB:
+ case CS42L42_ASP_TX_CH1_BIT_LSB:
+ case CS42L42_ASP_TX_HIZ_DLY_CFG:
+ case CS42L42_ASP_TX_CH2_BIT_MSB:
+ case CS42L42_ASP_TX_CH2_BIT_LSB:
+ case CS42L42_ASP_RX_DAI0_EN:
+ case CS42L42_ASP_RX_DAI0_CH1_AP_RES:
+ case CS42L42_ASP_RX_DAI0_CH1_BIT_MSB:
+ case CS42L42_ASP_RX_DAI0_CH1_BIT_LSB:
+ case CS42L42_ASP_RX_DAI0_CH2_AP_RES:
+ case CS42L42_ASP_RX_DAI0_CH2_BIT_MSB:
+ case CS42L42_ASP_RX_DAI0_CH2_BIT_LSB:
+ case CS42L42_ASP_RX_DAI0_CH3_AP_RES:
+ case CS42L42_ASP_RX_DAI0_CH3_BIT_MSB:
+ case CS42L42_ASP_RX_DAI0_CH3_BIT_LSB:
+ case CS42L42_ASP_RX_DAI0_CH4_AP_RES:
+ case CS42L42_ASP_RX_DAI0_CH4_BIT_MSB:
+ case CS42L42_ASP_RX_DAI0_CH4_BIT_LSB:
+ case CS42L42_ASP_RX_DAI1_CH1_AP_RES:
+ case CS42L42_ASP_RX_DAI1_CH1_BIT_MSB:
+ case CS42L42_ASP_RX_DAI1_CH1_BIT_LSB:
+ case CS42L42_ASP_RX_DAI1_CH2_AP_RES:
+ case CS42L42_ASP_RX_DAI1_CH2_BIT_MSB:
+ case CS42L42_ASP_RX_DAI1_CH2_BIT_LSB:
+ case CS42L42_SUB_REVID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L42_DEVID_AB:
+ case CS42L42_DEVID_CD:
+ case CS42L42_DEVID_E:
+ case CS42L42_MCLK_STATUS:
+ case CS42L42_TRSENSE_STATUS:
+ case CS42L42_HS_DET_STATUS:
+ case CS42L42_ADC_OVFL_STATUS:
+ case CS42L42_MIXER_STATUS:
+ case CS42L42_SRC_STATUS:
+ case CS42L42_ASP_RX_STATUS:
+ case CS42L42_ASP_TX_STATUS:
+ case CS42L42_CODEC_STATUS:
+ case CS42L42_DET_INT_STATUS1:
+ case CS42L42_DET_INT_STATUS2:
+ case CS42L42_SRCPL_INT_STATUS:
+ case CS42L42_VPMON_STATUS:
+ case CS42L42_PLL_LOCK_STATUS:
+ case CS42L42_TSRS_PLUG_STATUS:
+ case CS42L42_LOAD_DET_RCSTAT:
+ case CS42L42_LOAD_DET_DONE:
+ case CS42L42_DET_STATUS1:
+ case CS42L42_DET_STATUS2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_range_cfg cs42l42_page_range = {
+ .name = "Pages",
+ .range_min = 0,
+ .range_max = CS42L42_MAX_REGISTER,
+ .selector_reg = CS42L42_PAGE_REGISTER,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 256,
+};
+
+static const struct regmap_config cs42l42_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .readable_reg = cs42l42_readable_register,
+ .volatile_reg = cs42l42_volatile_register,
+
+ .ranges = &cs42l42_page_range,
+ .num_ranges = 1,
+
+ .max_register = CS42L42_MAX_REGISTER,
+ .reg_defaults = cs42l42_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs42l42_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false);
+static DECLARE_TLV_DB_SCALE(mixer_tlv, -6200, 100, false);
+
+static const char * const cs42l42_hpf_freq_text[] = {
+ "1.86Hz", "120Hz", "235Hz", "466Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l42_hpf_freq_enum, CS42L42_ADC_WNF_HPF_CTL,
+ CS42L42_ADC_HPF_CF_SHIFT,
+ cs42l42_hpf_freq_text);
+
+static const char * const cs42l42_wnf3_freq_text[] = {
+ "160Hz", "180Hz", "200Hz", "220Hz",
+ "240Hz", "260Hz", "280Hz", "300Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l42_wnf3_freq_enum, CS42L42_ADC_WNF_HPF_CTL,
+ CS42L42_ADC_WNF_CF_SHIFT,
+ cs42l42_wnf3_freq_text);
+
+static const char * const cs42l42_wnf05_freq_text[] = {
+ "280Hz", "315Hz", "350Hz", "385Hz",
+ "420Hz", "455Hz", "490Hz", "525Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l42_wnf05_freq_enum, CS42L42_ADC_WNF_HPF_CTL,
+ CS42L42_ADC_WNF_CF_SHIFT,
+ cs42l42_wnf05_freq_text);
+
+static const struct snd_kcontrol_new cs42l42_snd_controls[] = {
+ /* ADC Volume and Filter Controls */
+ SOC_SINGLE("ADC Notch Switch", CS42L42_ADC_CTL,
+ CS42L42_ADC_NOTCH_DIS_SHIFT, true, false),
+ SOC_SINGLE("ADC Weak Force Switch", CS42L42_ADC_CTL,
+ CS42L42_ADC_FORCE_WEAK_VCM_SHIFT, true, false),
+ SOC_SINGLE("ADC Invert Switch", CS42L42_ADC_CTL,
+ CS42L42_ADC_INV_SHIFT, true, false),
+ SOC_SINGLE("ADC Boost Switch", CS42L42_ADC_CTL,
+ CS42L42_ADC_DIG_BOOST_SHIFT, true, false),
+ SOC_SINGLE_SX_TLV("ADC Volume", CS42L42_ADC_VOLUME,
+ CS42L42_ADC_VOL_SHIFT, 0xA0, 0x6C, adc_tlv),
+ SOC_SINGLE("ADC WNF Switch", CS42L42_ADC_WNF_HPF_CTL,
+ CS42L42_ADC_WNF_EN_SHIFT, true, false),
+ SOC_SINGLE("ADC HPF Switch", CS42L42_ADC_WNF_HPF_CTL,
+ CS42L42_ADC_HPF_EN_SHIFT, true, false),
+ SOC_ENUM("HPF Corner Freq", cs42l42_hpf_freq_enum),
+ SOC_ENUM("WNF 3dB Freq", cs42l42_wnf3_freq_enum),
+ SOC_ENUM("WNF 05dB Freq", cs42l42_wnf05_freq_enum),
+
+ /* DAC Volume and Filter Controls */
+ SOC_SINGLE("DACA Invert Switch", CS42L42_DAC_CTL1,
+ CS42L42_DACA_INV_SHIFT, true, false),
+ SOC_SINGLE("DACB Invert Switch", CS42L42_DAC_CTL1,
+ CS42L42_DACB_INV_SHIFT, true, false),
+ SOC_SINGLE("DAC HPF Switch", CS42L42_DAC_CTL2,
+ CS42L42_DAC_HPF_EN_SHIFT, true, false),
+ SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL,
+ CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT,
+ 0x3e, 1, mixer_tlv)
+};
+
+static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ if (event & SND_SOC_DAPM_POST_PMU) {
+ /* Enable the channels */
+ snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN,
+ CS42L42_ASP_RX0_CH_EN_MASK,
+ (CS42L42_ASP_RX0_CH1_EN |
+ CS42L42_ASP_RX0_CH2_EN) <<
+ CS42L42_ASP_RX0_CH_EN_SHIFT);
+
+ /* Power up */
+ snd_soc_update_bits(codec, CS42L42_PWR_CTL1,
+ CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
+ CS42L42_HP_PDN_MASK, 0);
+ } else if (event & SND_SOC_DAPM_PRE_PMD) {
+ /* Disable the channels */
+ snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN,
+ CS42L42_ASP_RX0_CH_EN_MASK, 0);
+
+ /* Power down */
+ snd_soc_update_bits(codec, CS42L42_PWR_CTL1,
+ CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
+ CS42L42_HP_PDN_MASK,
+ CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
+ CS42L42_HP_PDN_MASK);
+ } else {
+ dev_err(codec->dev, "Invalid event 0x%x\n", event);
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("HP"),
+ SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, CS42L42_ASP_CLK_CFG,
+ CS42L42_ASP_SCLK_EN_SHIFT, false),
+ SND_SOC_DAPM_OUT_DRV_E("HPDRV", SND_SOC_NOPM, 0,
+ 0, NULL, 0, cs42l42_hpdrv_evt,
+ SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD)
+};
+
+static const struct snd_soc_dapm_route cs42l42_audio_map[] = {
+ {"SDIN", NULL, "Playback"},
+ {"HPDRV", NULL, "SDIN"},
+ {"HP", NULL, "HPDRV"}
+};
+
+static int cs42l42_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+ regcache_cache_only(cs42l42->regmap, false);
+ regcache_sync(cs42l42->regmap);
+ ret = regulator_bulk_enable(
+ ARRAY_SIZE(cs42l42->supplies),
+ cs42l42->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to enable regulators: %d\n",
+ ret);
+ return ret;
+ }
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+
+ regcache_cache_only(cs42l42->regmap, true);
+ regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
+ cs42l42->supplies);
+ break;
+ }
+
+ return 0;
+}
+
+static int cs42l42_codec_probe(struct snd_soc_codec *codec)
+{
+ struct cs42l42_private *cs42l42 =
+ (struct cs42l42_private *)snd_soc_codec_get_drvdata(codec);
+
+ cs42l42->codec = codec;
+
+ return 0;
+}
+
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l42 = {
+ .probe = cs42l42_codec_probe,
+ .set_bias_level = cs42l42_set_bias_level,
+ .ignore_pmdown_time = true,
+
+ .component_driver = {
+ .dapm_widgets = cs42l42_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets),
+ .dapm_routes = cs42l42_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cs42l42_audio_map),
+
+ .controls = cs42l42_snd_controls,
+ .num_controls = ARRAY_SIZE(cs42l42_snd_controls),
+ },
+};
+
+struct cs42l42_pll_params {
+ u32 sclk;
+ u8 mclk_div;
+ u8 mclk_src_sel;
+ u8 sclk_prediv;
+ u8 pll_div_int;
+ u32 pll_div_frac;
+ u8 pll_mode;
+ u8 pll_divout;
+ u32 mclk_int;
+ u8 pll_cal_ratio;
+};
+
+/*
+ * Common PLL Settings for given SCLK
+ * Table 4-5 from the Datasheet
+ */
+static const struct cs42l42_pll_params pll_ratio_table[] = {
+ { 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125 },
+ { 2822400, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 },
+ { 3000000, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 },
+ { 3072000, 0, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 },
+ { 4000000, 0, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96 },
+ { 4096000, 0, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94 },
+ { 5644800, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 },
+ { 6000000, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 },
+ { 6144000, 0, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 },
+ { 11289600, 0, 0, 0, 0, 0, 0, 0, 11289600, 0 },
+ { 12000000, 0, 0, 0, 0, 0, 0, 0, 12000000, 0 },
+ { 12288000, 0, 0, 0, 0, 0, 0, 0, 12288000, 0 },
+ { 22579200, 1, 0, 0, 0, 0, 0, 0, 22579200, 0 },
+ { 24000000, 1, 0, 0, 0, 0, 0, 0, 24000000, 0 },
+ { 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0 }
+};
+
+static int cs42l42_pll_config(struct snd_soc_codec *codec)
+{
+ struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+ int i;
+ u32 fsync;
+
+ for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+ if (pll_ratio_table[i].sclk == cs42l42->sclk) {
+ /* Configure the internal sample rate */
+ snd_soc_update_bits(codec, CS42L42_MCLK_CTL,
+ CS42L42_INTERNAL_FS_MASK,
+ ((pll_ratio_table[i].mclk_int !=
+ 12000000) &&
+ (pll_ratio_table[i].mclk_int !=
+ 24000000)) <<
+ CS42L42_INTERNAL_FS_SHIFT);
+ /* Set the MCLK src (PLL or SCLK) and the divide
+ * ratio
+ */
+ snd_soc_update_bits(codec, CS42L42_MCLK_SRC_SEL,
+ CS42L42_MCLK_SRC_SEL_MASK |
+ CS42L42_MCLKDIV_MASK,
+ (pll_ratio_table[i].mclk_src_sel
+ << CS42L42_MCLK_SRC_SEL_SHIFT) |
+ (pll_ratio_table[i].mclk_div <<
+ CS42L42_MCLKDIV_SHIFT));
+ /* Set up the LRCLK */
+ fsync = cs42l42->sclk / cs42l42->srate;
+ if (((fsync * cs42l42->srate) != cs42l42->sclk)
+ || ((fsync % 2) != 0)) {
+ dev_err(codec->dev,
+ "Unsupported sclk %d/sample rate %d\n",
+ cs42l42->sclk,
+ cs42l42->srate);
+ return -EINVAL;
+ }
+ /* Set the LRCLK period */
+ snd_soc_update_bits(codec,
+ CS42L42_FSYNC_P_LOWER,
+ CS42L42_FSYNC_PERIOD_MASK,
+ CS42L42_FRAC0_VAL(fsync - 1) <<
+ CS42L42_FSYNC_PERIOD_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_FSYNC_P_UPPER,
+ CS42L42_FSYNC_PERIOD_MASK,
+ CS42L42_FRAC1_VAL(fsync - 1) <<
+ CS42L42_FSYNC_PERIOD_SHIFT);
+ /* Set the LRCLK to 50% duty cycle */
+ fsync = fsync / 2;
+ snd_soc_update_bits(codec,
+ CS42L42_FSYNC_PW_LOWER,
+ CS42L42_FSYNC_PULSE_WIDTH_MASK,
+ CS42L42_FRAC0_VAL(fsync - 1) <<
+ CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_FSYNC_PW_UPPER,
+ CS42L42_FSYNC_PULSE_WIDTH_MASK,
+ CS42L42_FRAC1_VAL(fsync - 1) <<
+ CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_ASP_FRM_CFG,
+ CS42L42_ASP_5050_MASK,
+ CS42L42_ASP_5050_MASK);
+ /* Set the frame delay to 1.0 SCLK clocks */
+ snd_soc_update_bits(codec, CS42L42_ASP_FRM_CFG,
+ CS42L42_ASP_FSD_MASK,
+ CS42L42_ASP_FSD_1_0 <<
+ CS42L42_ASP_FSD_SHIFT);
+ /* Set the sample rates (96k or lower) */
+ snd_soc_update_bits(codec, CS42L42_FS_RATE_EN,
+ CS42L42_FS_EN_MASK,
+ (CS42L42_FS_EN_IASRC_96K |
+ CS42L42_FS_EN_OASRC_96K) <<
+ CS42L42_FS_EN_SHIFT);
+ /* Set the input/output internal MCLK clock ~12 MHz */
+ snd_soc_update_bits(codec, CS42L42_IN_ASRC_CLK,
+ CS42L42_CLK_IASRC_SEL_MASK,
+ CS42L42_CLK_IASRC_SEL_12 <<
+ CS42L42_CLK_IASRC_SEL_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_OUT_ASRC_CLK,
+ CS42L42_CLK_OASRC_SEL_MASK,
+ CS42L42_CLK_OASRC_SEL_12 <<
+ CS42L42_CLK_OASRC_SEL_SHIFT);
+ /* channel 1 on low LRCLK, 32 bit */
+ snd_soc_update_bits(codec,
+ CS42L42_ASP_RX_DAI0_CH1_AP_RES,
+ CS42L42_ASP_RX_CH_AP_MASK |
+ CS42L42_ASP_RX_CH_RES_MASK,
+ (CS42L42_ASP_RX_CH_AP_LOW <<
+ CS42L42_ASP_RX_CH_AP_SHIFT) |
+ (CS42L42_ASP_RX_CH_RES_32 <<
+ CS42L42_ASP_RX_CH_RES_SHIFT));
+ /* Channel 2 on high LRCLK, 32 bit */
+ snd_soc_update_bits(codec,
+ CS42L42_ASP_RX_DAI0_CH2_AP_RES,
+ CS42L42_ASP_RX_CH_AP_MASK |
+ CS42L42_ASP_RX_CH_RES_MASK,
+ (CS42L42_ASP_RX_CH_AP_HI <<
+ CS42L42_ASP_RX_CH_AP_SHIFT) |
+ (CS42L42_ASP_RX_CH_RES_32 <<
+ CS42L42_ASP_RX_CH_RES_SHIFT));
+ if (pll_ratio_table[i].mclk_src_sel == 0) {
+ /* Pass the clock straight through */
+ snd_soc_update_bits(codec,
+ CS42L42_PLL_CTL1,
+ CS42L42_PLL_START_MASK, 0);
+ } else {
+ /* Configure PLL per table 4-5 */
+ snd_soc_update_bits(codec,
+ CS42L42_PLL_DIV_CFG1,
+ CS42L42_SCLK_PREDIV_MASK,
+ pll_ratio_table[i].sclk_prediv
+ << CS42L42_SCLK_PREDIV_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_PLL_DIV_INT,
+ CS42L42_PLL_DIV_INT_MASK,
+ pll_ratio_table[i].pll_div_int
+ << CS42L42_PLL_DIV_INT_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_PLL_DIV_FRAC0,
+ CS42L42_PLL_DIV_FRAC_MASK,
+ CS42L42_FRAC0_VAL(
+ pll_ratio_table[i].pll_div_frac)
+ << CS42L42_PLL_DIV_FRAC_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_PLL_DIV_FRAC1,
+ CS42L42_PLL_DIV_FRAC_MASK,
+ CS42L42_FRAC1_VAL(
+ pll_ratio_table[i].pll_div_frac)
+ << CS42L42_PLL_DIV_FRAC_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_PLL_DIV_FRAC2,
+ CS42L42_PLL_DIV_FRAC_MASK,
+ CS42L42_FRAC2_VAL(
+ pll_ratio_table[i].pll_div_frac)
+ << CS42L42_PLL_DIV_FRAC_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_PLL_CTL4,
+ CS42L42_PLL_MODE_MASK,
+ pll_ratio_table[i].pll_mode
+ << CS42L42_PLL_MODE_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_PLL_CTL3,
+ CS42L42_PLL_DIVOUT_MASK,
+ pll_ratio_table[i].pll_divout
+ << CS42L42_PLL_DIVOUT_SHIFT);
+ snd_soc_update_bits(codec,
+ CS42L42_PLL_CAL_RATIO,
+ CS42L42_PLL_CAL_RATIO_MASK,
+ pll_ratio_table[i].pll_cal_ratio
+ << CS42L42_PLL_CAL_RATIO_SHIFT);
+ }
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u32 asp_cfg_val = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFM:
+ asp_cfg_val |= CS42L42_ASP_MASTER_MODE <<
+ CS42L42_ASP_MODE_SHIFT;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ asp_cfg_val |= CS42L42_ASP_SLAVE_MODE <<
+ CS42L42_ASP_MODE_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Bitclock/frame inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ asp_cfg_val |= CS42L42_ASP_POL_INV <<
+ CS42L42_ASP_LCPOL_IN_SHIFT;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ asp_cfg_val |= CS42L42_ASP_POL_INV <<
+ CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ asp_cfg_val |= CS42L42_ASP_POL_INV <<
+ CS42L42_ASP_LCPOL_IN_SHIFT;
+ asp_cfg_val |= CS42L42_ASP_POL_INV <<
+ CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
+ break;
+ }
+
+ snd_soc_update_bits(codec, CS42L42_ASP_CLK_CFG,
+ CS42L42_ASP_MODE_MASK |
+ CS42L42_ASP_SCPOL_IN_DAC_MASK |
+ CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val);
+
+ return 0;
+}
+
+static int cs42l42_pcm_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 cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+ int retval;
+
+ cs42l42->srate = params_rate(params);
+ cs42l42->swidth = params_width(params);
+
+ retval = cs42l42_pll_config(codec);
+
+ return retval;
+}
+
+static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+
+ cs42l42->sclk = freq;
+
+ return 0;
+}
+
+static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned int regval;
+ u8 fullScaleVol;
+
+ if (mute) {
+ /* Mark SCLK as not present to turn on the internal
+ * oscillator.
+ */
+ snd_soc_update_bits(codec, CS42L42_OSC_SWITCH,
+ CS42L42_SCLK_PRESENT_MASK, 0);
+
+ snd_soc_update_bits(codec, CS42L42_PLL_CTL1,
+ CS42L42_PLL_START_MASK,
+ 0 << CS42L42_PLL_START_SHIFT);
+
+ /* Mute the headphone */
+ snd_soc_update_bits(codec, CS42L42_HP_CTL,
+ CS42L42_HP_ANA_AMUTE_MASK |
+ CS42L42_HP_ANA_BMUTE_MASK,
+ CS42L42_HP_ANA_AMUTE_MASK |
+ CS42L42_HP_ANA_BMUTE_MASK);
+ } else {
+ snd_soc_update_bits(codec, CS42L42_PLL_CTL1,
+ CS42L42_PLL_START_MASK,
+ 1 << CS42L42_PLL_START_SHIFT);
+ /* Read the headphone load */
+ regval = snd_soc_read(codec, CS42L42_LOAD_DET_RCSTAT);
+ if (((regval & CS42L42_RLA_STAT_MASK) >>
+ CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) {
+ fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK;
+ } else {
+ fullScaleVol = 0;
+ }
+
+ /* Un-mute the headphone, set the full scale volume flag */
+ snd_soc_update_bits(codec, CS42L42_HP_CTL,
+ CS42L42_HP_ANA_AMUTE_MASK |
+ CS42L42_HP_ANA_BMUTE_MASK |
+ CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol);
+
+ /* Mark SCLK as present, turn off internal oscillator */
+ snd_soc_update_bits(codec, CS42L42_OSC_SWITCH,
+ CS42L42_SCLK_PRESENT_MASK,
+ CS42L42_SCLK_PRESENT_MASK);
+ }
+
+ return 0;
+}
+
+#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static struct snd_soc_dai_ops cs42l42_ops = {
+ .hw_params = cs42l42_pcm_hw_params,
+ .set_fmt = cs42l42_set_dai_fmt,
+ .set_sysclk = cs42l42_set_sysclk,
+ .digital_mute = cs42l42_digital_mute
+};
+
+static struct snd_soc_dai_driver cs42l42_dai = {
+ .name = "cs42l42",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = CS42L42_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = CS42L42_FORMATS,
+ },
+ .ops = &cs42l42_ops,
+};
+
+static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+ unsigned int hs_det_status;
+ unsigned int int_status;
+
+ /* Mask the auto detect interrupt */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_CODEC_INT_MASK,
+ CS42L42_PDN_DONE_MASK |
+ CS42L42_HSDET_AUTO_DONE_MASK,
+ (1 << CS42L42_PDN_DONE_SHIFT) |
+ (1 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+
+ /* Set hs detect to automatic, disabled mode */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_HSDET_CTL2,
+ CS42L42_HSDET_CTRL_MASK |
+ CS42L42_HSDET_SET_MASK |
+ CS42L42_HSBIAS_REF_MASK |
+ CS42L42_HSDET_AUTO_TIME_MASK,
+ (2 << CS42L42_HSDET_CTRL_SHIFT) |
+ (2 << CS42L42_HSDET_SET_SHIFT) |
+ (0 << CS42L42_HSBIAS_REF_SHIFT) |
+ (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+
+ /* Read and save the hs detection result */
+ regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status);
+
+ cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >>
+ CS42L42_HSDET_TYPE_SHIFT;
+
+ /* Set up button detection */
+ if ((cs42l42->hs_type == CS42L42_PLUG_CTIA) ||
+ (cs42l42->hs_type == CS42L42_PLUG_OMTP)) {
+ /* Set auto HS bias settings to default */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_HSBIAS_SC_AUTOCTL,
+ CS42L42_HSBIAS_SENSE_EN_MASK |
+ CS42L42_AUTO_HSBIAS_HIZ_MASK |
+ CS42L42_TIP_SENSE_EN_MASK |
+ CS42L42_HSBIAS_SENSE_TRIP_MASK,
+ (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+ (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+ (0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+ (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+ /* Set up hs detect level sensitivity */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_MIC_DET_CTL1,
+ CS42L42_LATCH_TO_VP_MASK |
+ CS42L42_EVENT_STAT_SEL_MASK |
+ CS42L42_HS_DET_LEVEL_MASK,
+ (1 << CS42L42_LATCH_TO_VP_SHIFT) |
+ (0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+ (cs42l42->bias_thresholds[0] <<
+ CS42L42_HS_DET_LEVEL_SHIFT));
+
+ /* Set auto HS bias settings to default */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_HSBIAS_SC_AUTOCTL,
+ CS42L42_HSBIAS_SENSE_EN_MASK |
+ CS42L42_AUTO_HSBIAS_HIZ_MASK |
+ CS42L42_TIP_SENSE_EN_MASK |
+ CS42L42_HSBIAS_SENSE_TRIP_MASK,
+ (1 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+ (1 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+ (0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+ (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+ /* Turn on level detect circuitry */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_MISC_DET_CTL,
+ CS42L42_DETECT_MODE_MASK |
+ CS42L42_HSBIAS_CTL_MASK |
+ CS42L42_PDN_MIC_LVL_DET_MASK,
+ (0 << CS42L42_DETECT_MODE_SHIFT) |
+ (3 << CS42L42_HSBIAS_CTL_SHIFT) |
+ (0 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+ msleep(cs42l42->btn_det_init_dbnce);
+
+ /* Clear any button interrupts before unmasking them */
+ regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2,
+ &int_status);
+
+ /* Unmask button detect interrupts */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_DET_INT2_MASK,
+ CS42L42_M_DETECT_TF_MASK |
+ CS42L42_M_DETECT_FT_MASK |
+ CS42L42_M_HSBIAS_HIZ_MASK |
+ CS42L42_M_SHORT_RLS_MASK |
+ CS42L42_M_SHORT_DET_MASK,
+ (0 << CS42L42_M_DETECT_TF_SHIFT) |
+ (0 << CS42L42_M_DETECT_FT_SHIFT) |
+ (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+ (1 << CS42L42_M_SHORT_RLS_SHIFT) |
+ (1 << CS42L42_M_SHORT_DET_SHIFT));
+ } else {
+ /* Make sure button detect and HS bias circuits are off */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_MISC_DET_CTL,
+ CS42L42_DETECT_MODE_MASK |
+ CS42L42_HSBIAS_CTL_MASK |
+ CS42L42_PDN_MIC_LVL_DET_MASK,
+ (0 << CS42L42_DETECT_MODE_SHIFT) |
+ (1 << CS42L42_HSBIAS_CTL_SHIFT) |
+ (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+ }
+
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_DAC_CTL2,
+ CS42L42_HPOUT_PULLDOWN_MASK |
+ CS42L42_HPOUT_LOAD_MASK |
+ CS42L42_HPOUT_CLAMP_MASK |
+ CS42L42_DAC_HPF_EN_MASK |
+ CS42L42_DAC_MON_EN_MASK,
+ (0 << CS42L42_HPOUT_PULLDOWN_SHIFT) |
+ (0 << CS42L42_HPOUT_LOAD_SHIFT) |
+ (0 << CS42L42_HPOUT_CLAMP_SHIFT) |
+ (1 << CS42L42_DAC_HPF_EN_SHIFT) |
+ (0 << CS42L42_DAC_MON_EN_SHIFT));
+
+ /* Unmask tip sense interrupts */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_TSRS_PLUG_INT_MASK,
+ CS42L42_RS_PLUG_MASK |
+ CS42L42_RS_UNPLUG_MASK |
+ CS42L42_TS_PLUG_MASK |
+ CS42L42_TS_UNPLUG_MASK,
+ (1 << CS42L42_RS_PLUG_SHIFT) |
+ (1 << CS42L42_RS_UNPLUG_SHIFT) |
+ (0 << CS42L42_TS_PLUG_SHIFT) |
+ (0 << CS42L42_TS_UNPLUG_SHIFT));
+}
+
+static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+ /* Mask tip sense interrupts */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_TSRS_PLUG_INT_MASK,
+ CS42L42_RS_PLUG_MASK |
+ CS42L42_RS_UNPLUG_MASK |
+ CS42L42_TS_PLUG_MASK |
+ CS42L42_TS_UNPLUG_MASK,
+ (1 << CS42L42_RS_PLUG_SHIFT) |
+ (1 << CS42L42_RS_UNPLUG_SHIFT) |
+ (1 << CS42L42_TS_PLUG_SHIFT) |
+ (1 << CS42L42_TS_UNPLUG_SHIFT));
+
+ /* Make sure button detect and HS bias circuits are off */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_MISC_DET_CTL,
+ CS42L42_DETECT_MODE_MASK |
+ CS42L42_HSBIAS_CTL_MASK |
+ CS42L42_PDN_MIC_LVL_DET_MASK,
+ (0 << CS42L42_DETECT_MODE_SHIFT) |
+ (1 << CS42L42_HSBIAS_CTL_SHIFT) |
+ (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+ /* Set auto HS bias settings to default */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_HSBIAS_SC_AUTOCTL,
+ CS42L42_HSBIAS_SENSE_EN_MASK |
+ CS42L42_AUTO_HSBIAS_HIZ_MASK |
+ CS42L42_TIP_SENSE_EN_MASK |
+ CS42L42_HSBIAS_SENSE_TRIP_MASK,
+ (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+ (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+ (0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+ (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+ /* Set hs detect to manual, disabled mode */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_HSDET_CTL2,
+ CS42L42_HSDET_CTRL_MASK |
+ CS42L42_HSDET_SET_MASK |
+ CS42L42_HSBIAS_REF_MASK |
+ CS42L42_HSDET_AUTO_TIME_MASK,
+ (0 << CS42L42_HSDET_CTRL_SHIFT) |
+ (2 << CS42L42_HSDET_SET_SHIFT) |
+ (0 << CS42L42_HSBIAS_REF_SHIFT) |
+ (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_DAC_CTL2,
+ CS42L42_HPOUT_PULLDOWN_MASK |
+ CS42L42_HPOUT_LOAD_MASK |
+ CS42L42_HPOUT_CLAMP_MASK |
+ CS42L42_DAC_HPF_EN_MASK |
+ CS42L42_DAC_MON_EN_MASK,
+ (8 << CS42L42_HPOUT_PULLDOWN_SHIFT) |
+ (0 << CS42L42_HPOUT_LOAD_SHIFT) |
+ (1 << CS42L42_HPOUT_CLAMP_SHIFT) |
+ (1 << CS42L42_DAC_HPF_EN_SHIFT) |
+ (1 << CS42L42_DAC_MON_EN_SHIFT));
+
+ /* Power up HS bias to 2.7V */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_MISC_DET_CTL,
+ CS42L42_DETECT_MODE_MASK |
+ CS42L42_HSBIAS_CTL_MASK |
+ CS42L42_PDN_MIC_LVL_DET_MASK,
+ (0 << CS42L42_DETECT_MODE_SHIFT) |
+ (3 << CS42L42_HSBIAS_CTL_SHIFT) |
+ (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+ /* Wait for HS bias to ramp up */
+ msleep(cs42l42->hs_bias_ramp_time);
+
+ /* Unmask auto detect interrupt */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_CODEC_INT_MASK,
+ CS42L42_PDN_DONE_MASK |
+ CS42L42_HSDET_AUTO_DONE_MASK,
+ (1 << CS42L42_PDN_DONE_SHIFT) |
+ (0 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+
+ /* Set hs detect to automatic, enabled mode */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_HSDET_CTL2,
+ CS42L42_HSDET_CTRL_MASK |
+ CS42L42_HSDET_SET_MASK |
+ CS42L42_HSBIAS_REF_MASK |
+ CS42L42_HSDET_AUTO_TIME_MASK,
+ (3 << CS42L42_HSDET_CTRL_SHIFT) |
+ (2 << CS42L42_HSDET_SET_SHIFT) |
+ (0 << CS42L42_HSBIAS_REF_SHIFT) |
+ (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+}
+
+static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+ /* Mask button detect interrupts */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_DET_INT2_MASK,
+ CS42L42_M_DETECT_TF_MASK |
+ CS42L42_M_DETECT_FT_MASK |
+ CS42L42_M_HSBIAS_HIZ_MASK |
+ CS42L42_M_SHORT_RLS_MASK |
+ CS42L42_M_SHORT_DET_MASK,
+ (1 << CS42L42_M_DETECT_TF_SHIFT) |
+ (1 << CS42L42_M_DETECT_FT_SHIFT) |
+ (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+ (1 << CS42L42_M_SHORT_RLS_SHIFT) |
+ (1 << CS42L42_M_SHORT_DET_SHIFT));
+
+ /* Ground HS bias */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_MISC_DET_CTL,
+ CS42L42_DETECT_MODE_MASK |
+ CS42L42_HSBIAS_CTL_MASK |
+ CS42L42_PDN_MIC_LVL_DET_MASK,
+ (0 << CS42L42_DETECT_MODE_SHIFT) |
+ (1 << CS42L42_HSBIAS_CTL_SHIFT) |
+ (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+ /* Set auto HS bias settings to default */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_HSBIAS_SC_AUTOCTL,
+ CS42L42_HSBIAS_SENSE_EN_MASK |
+ CS42L42_AUTO_HSBIAS_HIZ_MASK |
+ CS42L42_TIP_SENSE_EN_MASK |
+ CS42L42_HSBIAS_SENSE_TRIP_MASK,
+ (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+ (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+ (0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+ (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+ /* Set hs detect to manual, disabled mode */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_HSDET_CTL2,
+ CS42L42_HSDET_CTRL_MASK |
+ CS42L42_HSDET_SET_MASK |
+ CS42L42_HSBIAS_REF_MASK |
+ CS42L42_HSDET_AUTO_TIME_MASK,
+ (0 << CS42L42_HSDET_CTRL_SHIFT) |
+ (2 << CS42L42_HSDET_SET_SHIFT) |
+ (0 << CS42L42_HSBIAS_REF_SHIFT) |
+ (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+}
+
+static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
+{
+ int bias_level;
+ unsigned int detect_status;
+
+ /* Mask button detect interrupts */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_DET_INT2_MASK,
+ CS42L42_M_DETECT_TF_MASK |
+ CS42L42_M_DETECT_FT_MASK |
+ CS42L42_M_HSBIAS_HIZ_MASK |
+ CS42L42_M_SHORT_RLS_MASK |
+ CS42L42_M_SHORT_DET_MASK,
+ (1 << CS42L42_M_DETECT_TF_SHIFT) |
+ (1 << CS42L42_M_DETECT_FT_SHIFT) |
+ (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+ (1 << CS42L42_M_SHORT_RLS_SHIFT) |
+ (1 << CS42L42_M_SHORT_DET_SHIFT));
+
+ usleep_range(cs42l42->btn_det_event_dbnce * 1000,
+ cs42l42->btn_det_event_dbnce * 2000);
+
+ /* Test all 4 level detect biases */
+ bias_level = 1;
+ do {
+ /* Adjust button detect level sensitivity */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_MIC_DET_CTL1,
+ CS42L42_LATCH_TO_VP_MASK |
+ CS42L42_EVENT_STAT_SEL_MASK |
+ CS42L42_HS_DET_LEVEL_MASK,
+ (1 << CS42L42_LATCH_TO_VP_SHIFT) |
+ (0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+ (cs42l42->bias_thresholds[bias_level] <<
+ CS42L42_HS_DET_LEVEL_SHIFT));
+
+ regmap_read(cs42l42->regmap, CS42L42_DET_STATUS2,
+ &detect_status);
+ } while ((detect_status & CS42L42_HS_TRUE_MASK) &&
+ (++bias_level < CS42L42_NUM_BIASES));
+
+ switch (bias_level) {
+ case 1: /* Function C button press */
+ dev_dbg(cs42l42->codec->dev, "Function C button press\n");
+ break;
+ case 2: /* Function B button press */
+ dev_dbg(cs42l42->codec->dev, "Function B button press\n");
+ break;
+ case 3: /* Function D button press */
+ dev_dbg(cs42l42->codec->dev, "Function D button press\n");
+ break;
+ case 4: /* Function A button press */
+ dev_dbg(cs42l42->codec->dev, "Function A button press\n");
+ break;
+ }
+
+ /* Set button detect level sensitivity back to default */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_MIC_DET_CTL1,
+ CS42L42_LATCH_TO_VP_MASK |
+ CS42L42_EVENT_STAT_SEL_MASK |
+ CS42L42_HS_DET_LEVEL_MASK,
+ (1 << CS42L42_LATCH_TO_VP_SHIFT) |
+ (0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+ (cs42l42->bias_thresholds[0] << CS42L42_HS_DET_LEVEL_SHIFT));
+
+ /* Clear any button interrupts before unmasking them */
+ regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2,
+ &detect_status);
+
+ /* Unmask button detect interrupts */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_DET_INT2_MASK,
+ CS42L42_M_DETECT_TF_MASK |
+ CS42L42_M_DETECT_FT_MASK |
+ CS42L42_M_HSBIAS_HIZ_MASK |
+ CS42L42_M_SHORT_RLS_MASK |
+ CS42L42_M_SHORT_DET_MASK,
+ (0 << CS42L42_M_DETECT_TF_SHIFT) |
+ (0 << CS42L42_M_DETECT_FT_SHIFT) |
+ (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+ (1 << CS42L42_M_SHORT_RLS_SHIFT) |
+ (1 << CS42L42_M_SHORT_DET_SHIFT));
+}
+
+struct cs42l42_irq_params {
+ u16 status_addr;
+ u16 mask_addr;
+ u8 mask;
+};
+
+static const struct cs42l42_irq_params irq_params_table[] = {
+ {CS42L42_ADC_OVFL_STATUS, CS42L42_ADC_OVFL_INT_MASK,
+ CS42L42_ADC_OVFL_VAL_MASK},
+ {CS42L42_MIXER_STATUS, CS42L42_MIXER_INT_MASK,
+ CS42L42_MIXER_VAL_MASK},
+ {CS42L42_SRC_STATUS, CS42L42_SRC_INT_MASK,
+ CS42L42_SRC_VAL_MASK},
+ {CS42L42_ASP_RX_STATUS, CS42L42_ASP_RX_INT_MASK,
+ CS42L42_ASP_RX_VAL_MASK},
+ {CS42L42_ASP_TX_STATUS, CS42L42_ASP_TX_INT_MASK,
+ CS42L42_ASP_TX_VAL_MASK},
+ {CS42L42_CODEC_STATUS, CS42L42_CODEC_INT_MASK,
+ CS42L42_CODEC_VAL_MASK},
+ {CS42L42_DET_INT_STATUS1, CS42L42_DET_INT1_MASK,
+ CS42L42_DET_INT_VAL1_MASK},
+ {CS42L42_DET_INT_STATUS2, CS42L42_DET_INT2_MASK,
+ CS42L42_DET_INT_VAL2_MASK},
+ {CS42L42_SRCPL_INT_STATUS, CS42L42_SRCPL_INT_MASK,
+ CS42L42_SRCPL_VAL_MASK},
+ {CS42L42_VPMON_STATUS, CS42L42_VPMON_INT_MASK,
+ CS42L42_VPMON_VAL_MASK},
+ {CS42L42_PLL_LOCK_STATUS, CS42L42_PLL_LOCK_INT_MASK,
+ CS42L42_PLL_LOCK_VAL_MASK},
+ {CS42L42_TSRS_PLUG_STATUS, CS42L42_TSRS_PLUG_INT_MASK,
+ CS42L42_TSRS_PLUG_VAL_MASK}
+};
+
+static irqreturn_t cs42l42_irq_thread(int irq, void *data)
+{
+ struct cs42l42_private *cs42l42 = (struct cs42l42_private *)data;
+ struct snd_soc_codec *codec = cs42l42->codec;
+ unsigned int stickies[12];
+ unsigned int masks[12];
+ unsigned int current_plug_status;
+ unsigned int current_button_status;
+ unsigned int i;
+
+ /* Read sticky registers to clear interurpt */
+ for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+ regmap_read(cs42l42->regmap, irq_params_table[i].status_addr,
+ &(stickies[i]));
+ regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr,
+ &(masks[i]));
+ stickies[i] = stickies[i] & (~masks[i]) &
+ irq_params_table[i].mask;
+ }
+
+ /* Read tip sense status before handling type detect */
+ current_plug_status = (stickies[11] &
+ (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >>
+ CS42L42_TS_PLUG_SHIFT;
+
+ /* Read button sense status */
+ current_button_status = stickies[7] &
+ (CS42L42_M_DETECT_TF_MASK |
+ CS42L42_M_DETECT_FT_MASK |
+ CS42L42_M_HSBIAS_HIZ_MASK);
+
+ /* Check auto-detect status */
+ if ((~masks[5]) & irq_params_table[5].mask) {
+ if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) {
+ cs42l42_process_hs_type_detect(cs42l42);
+ dev_dbg(codec->dev,
+ "Auto detect done (%d)\n",
+ cs42l42->hs_type);
+ }
+ }
+
+ /* Check tip sense status */
+ if ((~masks[11]) & irq_params_table[11].mask) {
+ switch (current_plug_status) {
+ case CS42L42_TS_PLUG:
+ if (cs42l42->plug_state != CS42L42_TS_PLUG) {
+ cs42l42->plug_state = CS42L42_TS_PLUG;
+ cs42l42_init_hs_type_detect(cs42l42);
+ }
+ break;
+
+ case CS42L42_TS_UNPLUG:
+ if (cs42l42->plug_state != CS42L42_TS_UNPLUG) {
+ cs42l42->plug_state = CS42L42_TS_UNPLUG;
+ cs42l42_cancel_hs_type_detect(cs42l42);
+ dev_dbg(codec->dev,
+ "Unplug event\n");
+ }
+ break;
+
+ default:
+ if (cs42l42->plug_state != CS42L42_TS_TRANS)
+ cs42l42->plug_state = CS42L42_TS_TRANS;
+ }
+ }
+
+ /* Check button detect status */
+ if ((~masks[7]) & irq_params_table[7].mask) {
+ if (!(current_button_status &
+ CS42L42_M_HSBIAS_HIZ_MASK)) {
+
+ if (current_button_status &
+ CS42L42_M_DETECT_TF_MASK) {
+ dev_dbg(codec->dev,
+ "Button released\n");
+ } else if (current_button_status &
+ CS42L42_M_DETECT_FT_MASK) {
+ cs42l42_handle_button_press(cs42l42);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42)
+{
+ regmap_update_bits(cs42l42->regmap, CS42L42_ADC_OVFL_INT_MASK,
+ CS42L42_ADC_OVFL_MASK,
+ (1 << CS42L42_ADC_OVFL_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_MIXER_INT_MASK,
+ CS42L42_MIX_CHB_OVFL_MASK |
+ CS42L42_MIX_CHA_OVFL_MASK |
+ CS42L42_EQ_OVFL_MASK |
+ CS42L42_EQ_BIQUAD_OVFL_MASK,
+ (1 << CS42L42_MIX_CHB_OVFL_SHIFT) |
+ (1 << CS42L42_MIX_CHA_OVFL_SHIFT) |
+ (1 << CS42L42_EQ_OVFL_SHIFT) |
+ (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_SRC_INT_MASK,
+ CS42L42_SRC_ILK_MASK |
+ CS42L42_SRC_OLK_MASK |
+ CS42L42_SRC_IUNLK_MASK |
+ CS42L42_SRC_OUNLK_MASK,
+ (1 << CS42L42_SRC_ILK_SHIFT) |
+ (1 << CS42L42_SRC_OLK_SHIFT) |
+ (1 << CS42L42_SRC_IUNLK_SHIFT) |
+ (1 << CS42L42_SRC_OUNLK_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_ASP_RX_INT_MASK,
+ CS42L42_ASPRX_NOLRCK_MASK |
+ CS42L42_ASPRX_EARLY_MASK |
+ CS42L42_ASPRX_LATE_MASK |
+ CS42L42_ASPRX_ERROR_MASK |
+ CS42L42_ASPRX_OVLD_MASK,
+ (1 << CS42L42_ASPRX_NOLRCK_SHIFT) |
+ (1 << CS42L42_ASPRX_EARLY_SHIFT) |
+ (1 << CS42L42_ASPRX_LATE_SHIFT) |
+ (1 << CS42L42_ASPRX_ERROR_SHIFT) |
+ (1 << CS42L42_ASPRX_OVLD_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_ASP_TX_INT_MASK,
+ CS42L42_ASPTX_NOLRCK_MASK |
+ CS42L42_ASPTX_EARLY_MASK |
+ CS42L42_ASPTX_LATE_MASK |
+ CS42L42_ASPTX_SMERROR_MASK,
+ (1 << CS42L42_ASPTX_NOLRCK_SHIFT) |
+ (1 << CS42L42_ASPTX_EARLY_SHIFT) |
+ (1 << CS42L42_ASPTX_LATE_SHIFT) |
+ (1 << CS42L42_ASPTX_SMERROR_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_CODEC_INT_MASK,
+ CS42L42_PDN_DONE_MASK |
+ CS42L42_HSDET_AUTO_DONE_MASK,
+ (1 << CS42L42_PDN_DONE_SHIFT) |
+ (1 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_SRCPL_INT_MASK,
+ CS42L42_SRCPL_ADC_LK_MASK |
+ CS42L42_SRCPL_DAC_LK_MASK |
+ CS42L42_SRCPL_ADC_UNLK_MASK |
+ CS42L42_SRCPL_DAC_UNLK_MASK,
+ (1 << CS42L42_SRCPL_ADC_LK_SHIFT) |
+ (1 << CS42L42_SRCPL_DAC_LK_SHIFT) |
+ (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) |
+ (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT1_MASK,
+ CS42L42_TIP_SENSE_UNPLUG_MASK |
+ CS42L42_TIP_SENSE_PLUG_MASK |
+ CS42L42_HSBIAS_SENSE_MASK,
+ (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) |
+ (1 << CS42L42_TIP_SENSE_PLUG_SHIFT) |
+ (1 << CS42L42_HSBIAS_SENSE_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK,
+ CS42L42_M_DETECT_TF_MASK |
+ CS42L42_M_DETECT_FT_MASK |
+ CS42L42_M_HSBIAS_HIZ_MASK |
+ CS42L42_M_SHORT_RLS_MASK |
+ CS42L42_M_SHORT_DET_MASK,
+ (1 << CS42L42_M_DETECT_TF_SHIFT) |
+ (1 << CS42L42_M_DETECT_FT_SHIFT) |
+ (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+ (1 << CS42L42_M_SHORT_RLS_SHIFT) |
+ (1 << CS42L42_M_SHORT_DET_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_VPMON_INT_MASK,
+ CS42L42_VPMON_MASK,
+ (1 << CS42L42_VPMON_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_PLL_LOCK_INT_MASK,
+ CS42L42_PLL_LOCK_MASK,
+ (1 << CS42L42_PLL_LOCK_SHIFT));
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK,
+ CS42L42_RS_PLUG_MASK |
+ CS42L42_RS_UNPLUG_MASK |
+ CS42L42_TS_PLUG_MASK |
+ CS42L42_TS_UNPLUG_MASK,
+ (1 << CS42L42_RS_PLUG_SHIFT) |
+ (1 << CS42L42_RS_UNPLUG_SHIFT) |
+ (0 << CS42L42_TS_PLUG_SHIFT) |
+ (0 << CS42L42_TS_UNPLUG_SHIFT));
+}
+
+static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+ unsigned int reg;
+
+ cs42l42->hs_type = CS42L42_PLUG_INVALID;
+
+ /* Latch analog controls to VP power domain */
+ regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1,
+ CS42L42_LATCH_TO_VP_MASK |
+ CS42L42_EVENT_STAT_SEL_MASK |
+ CS42L42_HS_DET_LEVEL_MASK,
+ (1 << CS42L42_LATCH_TO_VP_SHIFT) |
+ (0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+ (cs42l42->bias_thresholds[0] <<
+ CS42L42_HS_DET_LEVEL_SHIFT));
+
+ /* Remove ground noise-suppression clamps */
+ regmap_update_bits(cs42l42->regmap,
+ CS42L42_HS_CLAMP_DISABLE,
+ CS42L42_HS_CLAMP_DISABLE_MASK,
+ (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT));
+
+ /* Enable the tip sense circuit */
+ regmap_update_bits(cs42l42->regmap, CS42L42_TIPSENSE_CTL,
+ CS42L42_TIP_SENSE_CTRL_MASK |
+ CS42L42_TIP_SENSE_INV_MASK |
+ CS42L42_TIP_SENSE_DEBOUNCE_MASK,
+ (3 << CS42L42_TIP_SENSE_CTRL_SHIFT) |
+ (0 << CS42L42_TIP_SENSE_INV_SHIFT) |
+ (2 << CS42L42_TIP_SENSE_DEBOUNCE_SHIFT));
+
+ /* Save the initial status of the tip sense */
+ regmap_read(cs42l42->regmap,
+ CS42L42_TSRS_PLUG_STATUS,
+ ®);
+ cs42l42->plug_state = (((char) reg) &
+ (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >>
+ CS42L42_TS_PLUG_SHIFT;
+}
+
+static const unsigned int threshold_defaults[] = {
+ CS42L42_HS_DET_LEVEL_15,
+ CS42L42_HS_DET_LEVEL_8,
+ CS42L42_HS_DET_LEVEL_4,
+ CS42L42_HS_DET_LEVEL_1
+};
+
+static int cs42l42_handle_device_data(struct i2c_client *i2c_client,
+ struct cs42l42_private *cs42l42)
+{
+ struct device_node *np = i2c_client->dev.of_node;
+ unsigned int val;
+ unsigned int thresholds[CS42L42_NUM_BIASES];
+ int ret;
+ int i;
+
+ ret = of_property_read_u32(np, "cirrus,ts-inv", &val);
+
+ if (!ret) {
+ switch (val) {
+ case CS42L42_TS_INV_EN:
+ case CS42L42_TS_INV_DIS:
+ cs42l42->ts_inv = val;
+ break;
+ default:
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,ts-inv DT value %d\n",
+ val);
+ cs42l42->ts_inv = CS42L42_TS_INV_DIS;
+ }
+ } else {
+ cs42l42->ts_inv = CS42L42_TS_INV_DIS;
+ }
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
+ CS42L42_TS_INV_MASK,
+ (cs42l42->ts_inv << CS42L42_TS_INV_SHIFT));
+
+ ret = of_property_read_u32(np, "cirrus,ts-dbnc-rise", &val);
+
+ if (!ret) {
+ switch (val) {
+ case CS42L42_TS_DBNCE_0:
+ case CS42L42_TS_DBNCE_125:
+ case CS42L42_TS_DBNCE_250:
+ case CS42L42_TS_DBNCE_500:
+ case CS42L42_TS_DBNCE_750:
+ case CS42L42_TS_DBNCE_1000:
+ case CS42L42_TS_DBNCE_1250:
+ case CS42L42_TS_DBNCE_1500:
+ cs42l42->ts_dbnc_rise = val;
+ break;
+ default:
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,ts-dbnc-rise DT value %d\n",
+ val);
+ cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000;
+ }
+ } else {
+ cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000;
+ }
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
+ CS42L42_TS_RISE_DBNCE_TIME_MASK,
+ (cs42l42->ts_dbnc_rise <<
+ CS42L42_TS_RISE_DBNCE_TIME_SHIFT));
+
+ ret = of_property_read_u32(np, "cirrus,ts-dbnc-fall", &val);
+
+ if (!ret) {
+ switch (val) {
+ case CS42L42_TS_DBNCE_0:
+ case CS42L42_TS_DBNCE_125:
+ case CS42L42_TS_DBNCE_250:
+ case CS42L42_TS_DBNCE_500:
+ case CS42L42_TS_DBNCE_750:
+ case CS42L42_TS_DBNCE_1000:
+ case CS42L42_TS_DBNCE_1250:
+ case CS42L42_TS_DBNCE_1500:
+ cs42l42->ts_dbnc_fall = val;
+ break;
+ default:
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,ts-dbnc-fall DT value %d\n",
+ val);
+ cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0;
+ }
+ } else {
+ cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0;
+ }
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
+ CS42L42_TS_FALL_DBNCE_TIME_MASK,
+ (cs42l42->ts_dbnc_fall <<
+ CS42L42_TS_FALL_DBNCE_TIME_SHIFT));
+
+ ret = of_property_read_u32(np, "cirrus,btn-det-init-dbnce", &val);
+
+ if (!ret) {
+ if ((val >= CS42L42_BTN_DET_INIT_DBNCE_MIN) &&
+ (val <= CS42L42_BTN_DET_INIT_DBNCE_MAX))
+ cs42l42->btn_det_init_dbnce = val;
+ else {
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,btn-det-init-dbnce DT value %d\n",
+ val);
+ cs42l42->btn_det_init_dbnce =
+ CS42L42_BTN_DET_INIT_DBNCE_DEFAULT;
+ }
+ } else {
+ cs42l42->btn_det_init_dbnce =
+ CS42L42_BTN_DET_INIT_DBNCE_DEFAULT;
+ }
+
+ ret = of_property_read_u32(np, "cirrus,btn-det-event-dbnce", &val);
+
+ if (!ret) {
+ if ((val >= CS42L42_BTN_DET_EVENT_DBNCE_MIN) &&
+ (val <= CS42L42_BTN_DET_EVENT_DBNCE_MAX))
+ cs42l42->btn_det_event_dbnce = val;
+ else {
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,btn-det-event-dbnce DT value %d\n", val);
+ cs42l42->btn_det_event_dbnce =
+ CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT;
+ }
+ } else {
+ cs42l42->btn_det_event_dbnce =
+ CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT;
+ }
+
+ ret = of_property_read_u32_array(np, "cirrus,bias-lvls",
+ (u32 *)thresholds, CS42L42_NUM_BIASES);
+
+ if (!ret) {
+ for (i = 0; i < CS42L42_NUM_BIASES; i++) {
+ if ((thresholds[i] >= CS42L42_HS_DET_LEVEL_MIN) &&
+ (thresholds[i] <= CS42L42_HS_DET_LEVEL_MAX))
+ cs42l42->bias_thresholds[i] = thresholds[i];
+ else {
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,bias-lvls[%d] DT value %d\n", i,
+ thresholds[i]);
+ cs42l42->bias_thresholds[i] =
+ threshold_defaults[i];
+ }
+ }
+ } else {
+ for (i = 0; i < CS42L42_NUM_BIASES; i++)
+ cs42l42->bias_thresholds[i] = threshold_defaults[i];
+ }
+
+ ret = of_property_read_u32(np, "cirrus,hs-bias-ramp-rate", &val);
+
+ if (!ret) {
+ switch (val) {
+ case CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL:
+ cs42l42->hs_bias_ramp_rate = val;
+ cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME0;
+ break;
+ case CS42L42_HSBIAS_RAMP_FAST:
+ cs42l42->hs_bias_ramp_rate = val;
+ cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME1;
+ break;
+ case CS42L42_HSBIAS_RAMP_SLOW:
+ cs42l42->hs_bias_ramp_rate = val;
+ cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2;
+ break;
+ case CS42L42_HSBIAS_RAMP_SLOWEST:
+ cs42l42->hs_bias_ramp_rate = val;
+ cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME3;
+ break;
+ default:
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,hs-bias-ramp-rate DT value %d\n",
+ val);
+ cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW;
+ cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2;
+ }
+ } else {
+ cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW;
+ cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2;
+ }
+
+ regmap_update_bits(cs42l42->regmap, CS42L42_HS_BIAS_CTL,
+ CS42L42_HSBIAS_RAMP_MASK,
+ (cs42l42->hs_bias_ramp_rate <<
+ CS42L42_HSBIAS_RAMP_SHIFT));
+
+ return 0;
+}
+
+static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct cs42l42_private *cs42l42;
+ int ret, i;
+ unsigned int devid = 0;
+ unsigned int reg;
+
+ cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private),
+ GFP_KERNEL);
+ if (!cs42l42)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c_client, cs42l42);
+
+ cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap);
+ if (IS_ERR(cs42l42->regmap)) {
+ ret = PTR_ERR(cs42l42->regmap);
+ dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++)
+ cs42l42->supplies[i].supply = cs42l42_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c_client->dev,
+ ARRAY_SIZE(cs42l42->supplies),
+ cs42l42->supplies);
+ if (ret != 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies),
+ cs42l42->supplies);
+ if (ret != 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ /* Reset the Device */
+ cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+ "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(cs42l42->reset_gpio))
+ return PTR_ERR(cs42l42->reset_gpio);
+
+ if (cs42l42->reset_gpio) {
+ dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+ }
+ mdelay(3);
+
+ /* Request IRQ */
+ ret = devm_request_threaded_irq(&i2c_client->dev,
+ i2c_client->irq,
+ NULL, cs42l42_irq_thread,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ "cs42l42", cs42l42);
+
+ if (ret != 0)
+ dev_err(&i2c_client->dev,
+ "Failed to request IRQ: %d\n", ret);
+
+ /* initialize codec */
+ ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_AB, ®);
+ devid = (reg & 0xFF) << 12;
+
+ ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_CD, ®);
+ devid |= (reg & 0xFF) << 4;
+
+ ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_E, ®);
+ devid |= (reg & 0xF0) >> 4;
+
+ if (devid != CS42L42_CHIP_ID) {
+ ret = -ENODEV;
+ dev_err(&i2c_client->dev,
+ "CS42L42 Device ID (%X). Expected %X\n",
+ devid, CS42L42_CHIP_ID);
+ return ret;
+ }
+
+ ret = regmap_read(cs42l42->regmap, CS42L42_REVID, ®);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+ return ret;
+ }
+
+ dev_info(&i2c_client->dev,
+ "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF);
+
+ /* Power up the codec */
+ regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL1,
+ CS42L42_ASP_DAO_PDN_MASK |
+ CS42L42_ASP_DAI_PDN_MASK |
+ CS42L42_MIXER_PDN_MASK |
+ CS42L42_EQ_PDN_MASK |
+ CS42L42_HP_PDN_MASK |
+ CS42L42_ADC_PDN_MASK |
+ CS42L42_PDN_ALL_MASK,
+ (1 << CS42L42_ASP_DAO_PDN_SHIFT) |
+ (1 << CS42L42_ASP_DAI_PDN_SHIFT) |
+ (1 << CS42L42_MIXER_PDN_SHIFT) |
+ (1 << CS42L42_EQ_PDN_SHIFT) |
+ (1 << CS42L42_HP_PDN_SHIFT) |
+ (1 << CS42L42_ADC_PDN_SHIFT) |
+ (0 << CS42L42_PDN_ALL_SHIFT));
+
+ if (i2c_client->dev.of_node) {
+ ret = cs42l42_handle_device_data(i2c_client, cs42l42);
+ if (ret != 0)
+ return ret;
+ }
+
+ /* Setup headset detection */
+ cs42l42_setup_hs_type_detect(cs42l42);
+
+ /* Mask/Unmask Interrupts */
+ cs42l42_set_interrupt_masks(cs42l42);
+
+ /* Register codec for machine driver */
+ ret = snd_soc_register_codec(&i2c_client->dev,
+ &soc_codec_dev_cs42l42, &cs42l42_dai, 1);
+ if (ret < 0)
+ goto err_disable;
+ return 0;
+
+err_disable:
+ regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
+ cs42l42->supplies);
+ return ret;
+}
+
+static int cs42l42_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client);
+
+ snd_soc_unregister_codec(&i2c_client->dev);
+
+ /* Hold down reset */
+ if (cs42l42->reset_gpio)
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int cs42l42_runtime_suspend(struct device *dev)
+{
+ struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
+
+ regcache_cache_only(cs42l42->regmap, true);
+ regcache_mark_dirty(cs42l42->regmap);
+
+ /* Hold down reset */
+ if (cs42l42->reset_gpio)
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+
+ /* remove power */
+ regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
+ cs42l42->supplies);
+
+ return 0;
+}
+
+static int cs42l42_runtime_resume(struct device *dev)
+{
+ struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
+ int ret;
+
+ /* Enable power */
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies),
+ cs42l42->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+
+ if (cs42l42->reset_gpio)
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+
+ regcache_cache_only(cs42l42->regmap, false);
+ regcache_sync(cs42l42->regmap);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs42l42_runtime_pm = {
+ SET_RUNTIME_PM_OPS(cs42l42_runtime_suspend, cs42l42_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id cs42l42_of_match[] = {
+ { .compatible = "cirrus,cs42l42", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cs42l42_of_match);
+
+
+static const struct i2c_device_id cs42l42_id[] = {
+ {"cs42l42", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs42l42_id);
+
+static struct i2c_driver cs42l42_i2c_driver = {
+ .driver = {
+ .name = "cs42l42",
+ .owner = THIS_MODULE,
+ .pm = &cs42l42_runtime_pm,
+ .of_match_table = cs42l42_of_match,
+ },
+ .id_table = cs42l42_id,
+ .probe = cs42l42_i2c_probe,
+ .remove = cs42l42_i2c_remove,
+};
+
+module_i2c_driver(cs42l42_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L42 driver");
+MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_AUTHOR("Michael White, Cirrus Logic Inc, <michael.white@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
new file mode 100644
index 000000000000..d87a0a5322d5
--- /dev/null
+++ b/sound/soc/codecs/cs42l42.h
@@ -0,0 +1,776 @@
+/*
+ * cs42l42.h -- CS42L42 ALSA SoC audio driver header
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: James Schulman <james.schulman@cirrus.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ * Author: Michael White <michael.white@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS42L42_H__
+#define __CS42L42_H__
+
+#define CS42L42_PAGE_REGISTER 0x00 /* Page Select Register */
+#define CS42L42_WIN_START 0x00
+#define CS42L42_WIN_LEN 0x100
+#define CS42L42_RANGE_MIN 0x00
+#define CS42L42_RANGE_MAX 0x7F
+
+#define CS42L42_PAGE_10 0x1000
+#define CS42L42_PAGE_11 0x1100
+#define CS42L42_PAGE_12 0x1200
+#define CS42L42_PAGE_13 0x1300
+#define CS42L42_PAGE_15 0x1500
+#define CS42L42_PAGE_19 0x1900
+#define CS42L42_PAGE_1B 0x1B00
+#define CS42L42_PAGE_1C 0x1C00
+#define CS42L42_PAGE_1D 0x1D00
+#define CS42L42_PAGE_1F 0x1F00
+#define CS42L42_PAGE_20 0x2000
+#define CS42L42_PAGE_21 0x2100
+#define CS42L42_PAGE_23 0x2300
+#define CS42L42_PAGE_24 0x2400
+#define CS42L42_PAGE_25 0x2500
+#define CS42L42_PAGE_26 0x2600
+#define CS42L42_PAGE_28 0x2800
+#define CS42L42_PAGE_29 0x2900
+#define CS42L42_PAGE_2A 0x2A00
+#define CS42L42_PAGE_30 0x3000
+
+#define CS42L42_CHIP_ID 0x42A42
+
+/* Page 0x10 Global Registers */
+#define CS42L42_DEVID_AB (CS42L42_PAGE_10 + 0x01)
+#define CS42L42_DEVID_CD (CS42L42_PAGE_10 + 0x02)
+#define CS42L42_DEVID_E (CS42L42_PAGE_10 + 0x03)
+#define CS42L42_FABID (CS42L42_PAGE_10 + 0x04)
+#define CS42L42_REVID (CS42L42_PAGE_10 + 0x05)
+#define CS42L42_FRZ_CTL (CS42L42_PAGE_10 + 0x06)
+
+#define CS42L42_SRC_CTL (CS42L42_PAGE_10 + 0x07)
+#define CS42L42_SRC_BYPASS_DAC_SHIFT 1
+#define CS42L42_SRC_BYPASS_DAC_MASK (1 << CS42L42_SRC_BYPASS_DAC_SHIFT)
+
+#define CS42L42_MCLK_STATUS (CS42L42_PAGE_10 + 0x08)
+
+#define CS42L42_MCLK_CTL (CS42L42_PAGE_10 + 0x09)
+#define CS42L42_INTERNAL_FS_SHIFT 1
+#define CS42L42_INTERNAL_FS_MASK (1 << CS42L42_INTERNAL_FS_SHIFT)
+
+#define CS42L42_SFTRAMP_RATE (CS42L42_PAGE_10 + 0x0A)
+#define CS42L42_I2C_DEBOUNCE (CS42L42_PAGE_10 + 0x0E)
+#define CS42L42_I2C_STRETCH (CS42L42_PAGE_10 + 0x0F)
+#define CS42L42_I2C_TIMEOUT (CS42L42_PAGE_10 + 0x10)
+
+/* Page 0x11 Power and Headset Detect Registers */
+#define CS42L42_PWR_CTL1 (CS42L42_PAGE_11 + 0x01)
+#define CS42L42_ASP_DAO_PDN_SHIFT 7
+#define CS42L42_ASP_DAO_PDN_MASK (1 << CS42L42_ASP_DAO_PDN_SHIFT)
+#define CS42L42_ASP_DAI_PDN_SHIFT 6
+#define CS42L42_ASP_DAI_PDN_MASK (1 << CS42L42_ASP_DAI_PDN_SHIFT)
+#define CS42L42_MIXER_PDN_SHIFT 5
+#define CS42L42_MIXER_PDN_MASK (1 << CS42L42_MIXER_PDN_SHIFT)
+#define CS42L42_EQ_PDN_SHIFT 4
+#define CS42L42_EQ_PDN_MASK (1 << CS42L42_EQ_PDN_SHIFT)
+#define CS42L42_HP_PDN_SHIFT 3
+#define CS42L42_HP_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT)
+#define CS42L42_ADC_PDN_SHIFT 2
+#define CS42L42_ADC_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT)
+#define CS42L42_PDN_ALL_SHIFT 0
+#define CS42L42_PDN_ALL_MASK (1 << CS42L42_PDN_ALL_SHIFT)
+
+#define CS42L42_PWR_CTL2 (CS42L42_PAGE_11 + 0x02)
+#define CS42L42_ADC_SRC_PDNB_SHIFT 0
+#define CS42L42_ADC_SRC_PDNB_MASK (1 << CS42L42_ADC_SRC_PDNB_SHIFT)
+#define CS42L42_DAC_SRC_PDNB_SHIFT 1
+#define CS42L42_DAC_SRC_PDNB_MASK (1 << CS42L42_DAC_SRC_PDNB_SHIFT)
+#define CS42L42_ASP_DAI1_PDN_SHIFT 2
+#define CS42L42_ASP_DAI1_PDN_MASK (1 << CS42L42_ASP_DAI1_PDN_SHIFT)
+#define CS42L42_SRC_PDN_OVERRIDE_SHIFT 3
+#define CS42L42_SRC_PDN_OVERRIDE_MASK (1 << CS42L42_SRC_PDN_OVERRIDE_SHIFT)
+#define CS42L42_DISCHARGE_FILT_SHIFT 4
+#define CS42L42_DISCHARGE_FILT_MASK (1 << CS42L42_DISCHARGE_FILT_SHIFT)
+
+#define CS42L42_PWR_CTL3 (CS42L42_PAGE_11 + 0x03)
+#define CS42L42_RING_SENSE_PDNB_SHIFT 1
+#define CS42L42_RING_SENSE_PDNB_MASK (1 << \
+ CS42L42_RING_SENSE_PDNB_SHIFT)
+#define CS42L42_VPMON_PDNB_SHIFT 2
+#define CS42L42_VPMON_PDNB_MASK (1 << \
+ CS42L42_VPMON_PDNB_SHIFT)
+#define CS42L42_SW_CLK_STP_STAT_SEL_SHIFT 5
+#define CS42L42_SW_CLK_STP_STAT_SEL_MASK (3 << \
+ CS42L42_SW_CLK_STP_STAT_SEL_SHIFT)
+
+#define CS42L42_RSENSE_CTL1 (CS42L42_PAGE_11 + 0x04)
+#define CS42L42_RS_TRIM_R_SHIFT 0
+#define CS42L42_RS_TRIM_R_MASK (1 << \
+ CS42L42_RS_TRIM_R_SHIFT)
+#define CS42L42_RS_TRIM_T_SHIFT 1
+#define CS42L42_RS_TRIM_T_MASK (1 << \
+ CS42L42_RS_TRIM_T_SHIFT)
+#define CS42L42_HPREF_RS_SHIFT 2
+#define CS42L42_HPREF_RS_MASK (1 << \
+ CS42L42_HPREF_RS_SHIFT)
+#define CS42L42_HSBIAS_FILT_REF_RS_SHIFT 3
+#define CS42L42_HSBIAS_FILT_REF_RS_MASK (1 << \
+ CS42L42_HSBIAS_FILT_REF_RS_SHIFT)
+#define CS42L42_RING_SENSE_PU_HIZ_SHIFT 6
+#define CS42L42_RING_SENSE_PU_HIZ_MASK (1 << \
+ CS42L42_RING_SENSE_PU_HIZ_SHIFT)
+
+#define CS42L42_RSENSE_CTL2 (CS42L42_PAGE_11 + 0x05)
+#define CS42L42_TS_RS_GATE_SHIFT 7
+#define CS42L42_TS_RS_GATE_MAS (1 << CS42L42_TS_RS_GATE_SHIFT)
+
+#define CS42L42_OSC_SWITCH (CS42L42_PAGE_11 + 0x07)
+#define CS42L42_SCLK_PRESENT_SHIFT 0
+#define CS42L42_SCLK_PRESENT_MASK (1 << CS42L42_SCLK_PRESENT_SHIFT)
+
+#define CS42L42_OSC_SWITCH_STATUS (CS42L42_PAGE_11 + 0x09)
+#define CS42L42_OSC_SW_SEL_STAT_SHIFT 0
+#define CS42L42_OSC_SW_SEL_STAT_MASK (3 << CS42L42_OSC_SW_SEL_STAT_SHIFT)
+#define CS42L42_OSC_PDNB_STAT_SHIFT 2
+#define CS42L42_OSC_PDNB_STAT_MASK (1 << CS42L42_OSC_SW_SEL_STAT_SHIFT)
+
+#define CS42L42_RSENSE_CTL3 (CS42L42_PAGE_11 + 0x12)
+#define CS42L42_RS_RISE_DBNCE_TIME_SHIFT 0
+#define CS42L42_RS_RISE_DBNCE_TIME_MASK (7 << \
+ CS42L42_RS_RISE_DBNCE_TIME_SHIFT)
+#define CS42L42_RS_FALL_DBNCE_TIME_SHIFT 3
+#define CS42L42_RS_FALL_DBNCE_TIME_MASK (7 << \
+ CS42L42_RS_FALL_DBNCE_TIME_SHIFT)
+#define CS42L42_RS_PU_EN_SHIFT 6
+#define CS42L42_RS_PU_EN_MASK (1 << \
+ CS42L42_RS_PU_EN_SHIFT)
+#define CS42L42_RS_INV_SHIFT 7
+#define CS42L42_RS_INV_MASK (1 << \
+ CS42L42_RS_INV_SHIFT)
+
+#define CS42L42_TSENSE_CTL (CS42L42_PAGE_11 + 0x13)
+#define CS42L42_TS_RISE_DBNCE_TIME_SHIFT 0
+#define CS42L42_TS_RISE_DBNCE_TIME_MASK (7 << \
+ CS42L42_TS_RISE_DBNCE_TIME_SHIFT)
+#define CS42L42_TS_FALL_DBNCE_TIME_SHIFT 3
+#define CS42L42_TS_FALL_DBNCE_TIME_MASK (7 << \
+ CS42L42_TS_FALL_DBNCE_TIME_SHIFT)
+#define CS42L42_TS_INV_SHIFT 7
+#define CS42L42_TS_INV_MASK (1 << \
+ CS42L42_TS_INV_SHIFT)
+
+#define CS42L42_TSRS_INT_DISABLE (CS42L42_PAGE_11 + 0x14)
+#define CS42L42_D_RS_PLUG_DBNC_SHIFT 0
+#define CS42L42_D_RS_PLUG_DBNC_MASK (1 << CS42L42_D_RS_PLUG_DBNC_SHIFT)
+#define CS42L42_D_RS_UNPLUG_DBNC_SHIFT 1
+#define CS42L42_D_RS_UNPLUG_DBNC_MASK (1 << CS42L42_D_RS_UNPLUG_DBNC_SHIFT)
+#define CS42L42_D_TS_PLUG_DBNC_SHIFT 2
+#define CS42L42_D_TS_PLUG_DBNC_MASK (1 << CS42L42_D_TS_PLUG_DBNC_SHIFT)
+#define CS42L42_D_TS_UNPLUG_DBNC_SHIFT 3
+#define CS42L42_D_TS_UNPLUG_DBNC_MASK (1 << CS42L42_D_TS_UNPLUG_DBNC_SHIFT)
+
+#define CS42L42_TRSENSE_STATUS (CS42L42_PAGE_11 + 0x15)
+#define CS42L42_RS_PLUG_DBNC_SHIFT 0
+#define CS42L42_RS_PLUG_DBNC_MASK (1 << CS42L42_RS_PLUG_DBNC_SHIFT)
+#define CS42L42_RS_UNPLUG_DBNC_SHIFT 1
+#define CS42L42_RS_UNPLUG_DBNC_MASK (1 << CS42L42_RS_UNPLUG_DBNC_SHIFT)
+#define CS42L42_TS_PLUG_DBNC_SHIFT 2
+#define CS42L42_TS_PLUG_DBNC_MASK (1 << CS42L42_TS_PLUG_DBNC_SHIFT)
+#define CS42L42_TS_UNPLUG_DBNC_SHIFT 3
+#define CS42L42_TS_UNPLUG_DBNC_MASK (1 << CS42L42_TS_UNPLUG_DBNC_SHIFT)
+
+#define CS42L42_HSDET_CTL1 (CS42L42_PAGE_11 + 0x1F)
+#define CS42L42_HSDET_COMP1_LVL_SHIFT 0
+#define CS42L42_HSDET_COMP1_LVL_MASK (15 << CS42L42_HSDET_COMP1_LVL_SHIFT)
+#define CS42L42_HSDET_COMP2_LVL_SHIFT 4
+#define CS42L42_HSDET_COMP2_LVL_MASK (15 << CS42L42_HSDET_COMP2_LVL_SHIFT)
+
+#define CS42L42_HSDET_CTL2 (CS42L42_PAGE_11 + 0x20)
+#define CS42L42_HSDET_AUTO_TIME_SHIFT 0
+#define CS42L42_HSDET_AUTO_TIME_MASK (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)
+#define CS42L42_HSBIAS_REF_SHIFT 3
+#define CS42L42_HSBIAS_REF_MASK (1 << CS42L42_HSBIAS_REF_SHIFT)
+#define CS42L42_HSDET_SET_SHIFT 4
+#define CS42L42_HSDET_SET_MASK (3 << CS42L42_HSDET_SET_SHIFT)
+#define CS42L42_HSDET_CTRL_SHIFT 6
+#define CS42L42_HSDET_CTRL_MASK (3 << CS42L42_HSDET_CTRL_SHIFT)
+
+#define CS42L42_HS_SWITCH_CTL (CS42L42_PAGE_11 + 0x21)
+#define CS42L42_SW_GNDHS_HS4_SHIFT 0
+#define CS42L42_SW_GNDHS_HS4_MASK (1 << CS42L42_SW_GNDHS_HS4_SHIFT)
+#define CS42L42_SW_GNDHS_HS3_SHIFT 1
+#define CS42L42_SW_GNDHS_HS3_MASK (1 << CS42L42_SW_GNDHS_HS3_SHIFT)
+#define CS42L42_SW_HSB_HS4_SHIFT 2
+#define CS42L42_SW_HSB_HS4_MASK (1 << CS42L42_SW_HSB_HS4_SHIFT)
+#define CS42L42_SW_HSB_HS3_SHIFT 3
+#define CS42L42_SW_HSB_HS3_MASK (1 << CS42L42_SW_HSB_HS3_SHIFT)
+#define CS42L42_SW_HSB_FILT_HS4_SHIFT 4
+#define CS42L42_SW_HSB_FILT_HS4_MASK (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT)
+#define CS42L42_SW_HSB_FILT_HS3_SHIFT 5
+#define CS42L42_SW_HSB_FILT_HS3_MASK (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT)
+#define CS42L42_SW_REF_HS4_SHIFT 6
+#define CS42L42_SW_REF_HS4_MASK (1 << CS42L42_SW_REF_HS4_SHIFT)
+#define CS42L42_SW_REF_HS3_SHIFT 7
+#define CS42L42_SW_REF_HS3_MASK (1 << CS42L42_SW_REF_HS3_SHIFT)
+
+#define CS42L42_HS_DET_STATUS (CS42L42_PAGE_11 + 0x24)
+#define CS42L42_HSDET_TYPE_SHIFT 0
+#define CS42L42_HSDET_TYPE_MASK (3 << CS42L42_HSDET_TYPE_SHIFT)
+#define CS42L42_HSDET_COMP1_OUT_SHIFT 6
+#define CS42L42_HSDET_COMP1_OUT_MASK (1 << CS42L42_HSDET_COMP1_OUT_SHIFT)
+#define CS42L42_HSDET_COMP2_OUT_SHIFT 7
+#define CS42L42_HSDET_COMP2_OUT_MASK (1 << CS42L42_HSDET_COMP2_OUT_SHIFT)
+#define CS42L42_PLUG_CTIA 0
+#define CS42L42_PLUG_OMTP 1
+#define CS42L42_PLUG_HEADPHONE 2
+#define CS42L42_PLUG_INVALID 3
+
+#define CS42L42_HS_CLAMP_DISABLE (CS42L42_PAGE_11 + 0x29)
+#define CS42L42_HS_CLAMP_DISABLE_SHIFT 0
+#define CS42L42_HS_CLAMP_DISABLE_MASK (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT)
+
+/* Page 0x12 Clocking Registers */
+#define CS42L42_MCLK_SRC_SEL (CS42L42_PAGE_12 + 0x01)
+#define CS42L42_MCLKDIV_SHIFT 1
+#define CS42L42_MCLKDIV_MASK (1 << CS42L42_MCLKDIV_SHIFT)
+#define CS42L42_MCLK_SRC_SEL_SHIFT 0
+#define CS42L42_MCLK_SRC_SEL_MASK (1 << CS42L42_MCLK_SRC_SEL_SHIFT)
+
+#define CS42L42_SPDIF_CLK_CFG (CS42L42_PAGE_12 + 0x02)
+#define CS42L42_FSYNC_PW_LOWER (CS42L42_PAGE_12 + 0x03)
+
+#define CS42L42_FSYNC_PW_UPPER (CS42L42_PAGE_12 + 0x04)
+#define CS42L42_FSYNC_PULSE_WIDTH_SHIFT 0
+#define CS42L42_FSYNC_PULSE_WIDTH_MASK (0xff << \
+ CS42L42_FSYNC_PULSE_WIDTH_SHIFT)
+
+#define CS42L42_FSYNC_P_LOWER (CS42L42_PAGE_12 + 0x05)
+
+#define CS42L42_FSYNC_P_UPPER (CS42L42_PAGE_12 + 0x06)
+#define CS42L42_FSYNC_PERIOD_SHIFT 0
+#define CS42L42_FSYNC_PERIOD_MASK (0xff << CS42L42_FSYNC_PERIOD_SHIFT)
+
+#define CS42L42_ASP_CLK_CFG (CS42L42_PAGE_12 + 0x07)
+#define CS42L42_ASP_SCLK_EN_SHIFT 5
+#define CS42L42_ASP_SCLK_EN_MASK (1 << CS42L42_ASP_SCLK_EN_SHIFT)
+#define CS42L42_ASP_MASTER_MODE 0x01
+#define CS42L42_ASP_SLAVE_MODE 0x00
+#define CS42L42_ASP_MODE_SHIFT 4
+#define CS42L42_ASP_MODE_MASK (1 << CS42L42_ASP_MODE_SHIFT)
+#define CS42L42_ASP_SCPOL_IN_DAC_SHIFT 2
+#define CS42L42_ASP_SCPOL_IN_DAC_MASK (1 << CS42L42_ASP_SCPOL_IN_DAC_SHIFT)
+#define CS42L42_ASP_LCPOL_IN_SHIFT 0
+#define CS42L42_ASP_LCPOL_IN_MASK (1 << CS42L42_ASP_LCPOL_IN_SHIFT)
+#define CS42L42_ASP_POL_INV 1
+
+#define CS42L42_ASP_FRM_CFG (CS42L42_PAGE_12 + 0x08)
+#define CS42L42_ASP_STP_SHIFT 4
+#define CS42L42_ASP_STP_MASK (1 << CS42L42_ASP_STP_SHIFT)
+#define CS42L42_ASP_5050_SHIFT 3
+#define CS42L42_ASP_5050_MASK (1 << CS42L42_ASP_5050_SHIFT)
+#define CS42L42_ASP_FSD_SHIFT 0
+#define CS42L42_ASP_FSD_MASK (7 << CS42L42_ASP_FSD_SHIFT)
+#define CS42L42_ASP_FSD_0_5 1
+#define CS42L42_ASP_FSD_1_0 2
+#define CS42L42_ASP_FSD_1_5 3
+#define CS42L42_ASP_FSD_2_0 4
+
+#define CS42L42_FS_RATE_EN (CS42L42_PAGE_12 + 0x09)
+#define CS42L42_FS_EN_SHIFT 0
+#define CS42L42_FS_EN_MASK (0xf << CS42L42_FS_EN_SHIFT)
+#define CS42L42_FS_EN_IASRC_96K 0x1
+#define CS42L42_FS_EN_OASRC_96K 0x2
+
+#define CS42L42_IN_ASRC_CLK (CS42L42_PAGE_12 + 0x0A)
+#define CS42L42_CLK_IASRC_SEL_SHIFT 0
+#define CS42L42_CLK_IASRC_SEL_MASK (1 << CS42L42_CLK_IASRC_SEL_SHIFT)
+#define CS42L42_CLK_IASRC_SEL_12 1
+
+#define CS42L42_OUT_ASRC_CLK (CS42L42_PAGE_12 + 0x0B)
+#define CS42L42_CLK_OASRC_SEL_SHIFT 0
+#define CS42L42_CLK_OASRC_SEL_MASK (1 << CS42L42_CLK_OASRC_SEL_SHIFT)
+#define CS42L42_CLK_OASRC_SEL_12 1
+
+#define CS42L42_PLL_DIV_CFG1 (CS42L42_PAGE_12 + 0x0C)
+#define CS42L42_SCLK_PREDIV_SHIFT 0
+#define CS42L42_SCLK_PREDIV_MASK (3 << CS42L42_SCLK_PREDIV_SHIFT)
+
+/* Page 0x13 Interrupt Registers */
+/* Interrupts */
+#define CS42L42_ADC_OVFL_STATUS (CS42L42_PAGE_13 + 0x01)
+#define CS42L42_MIXER_STATUS (CS42L42_PAGE_13 + 0x02)
+#define CS42L42_SRC_STATUS (CS42L42_PAGE_13 + 0x03)
+#define CS42L42_ASP_RX_STATUS (CS42L42_PAGE_13 + 0x04)
+#define CS42L42_ASP_TX_STATUS (CS42L42_PAGE_13 + 0x05)
+#define CS42L42_CODEC_STATUS (CS42L42_PAGE_13 + 0x08)
+#define CS42L42_DET_INT_STATUS1 (CS42L42_PAGE_13 + 0x09)
+#define CS42L42_DET_INT_STATUS2 (CS42L42_PAGE_13 + 0x0A)
+#define CS42L42_SRCPL_INT_STATUS (CS42L42_PAGE_13 + 0x0B)
+#define CS42L42_VPMON_STATUS (CS42L42_PAGE_13 + 0x0D)
+#define CS42L42_PLL_LOCK_STATUS (CS42L42_PAGE_13 + 0x0E)
+#define CS42L42_TSRS_PLUG_STATUS (CS42L42_PAGE_13 + 0x0F)
+/* Masks */
+#define CS42L42_ADC_OVFL_INT_MASK (CS42L42_PAGE_13 + 0x16)
+#define CS42L42_ADC_OVFL_SHIFT 0
+#define CS42L42_ADC_OVFL_MASK (1 << CS42L42_ADC_OVFL_SHIFT)
+#define CS42L42_ADC_OVFL_VAL_MASK CS42L42_ADC_OVFL_MASK
+
+#define CS42L42_MIXER_INT_MASK (CS42L42_PAGE_13 + 0x17)
+#define CS42L42_MIX_CHB_OVFL_SHIFT 0
+#define CS42L42_MIX_CHB_OVFL_MASK (1 << CS42L42_MIX_CHB_OVFL_SHIFT)
+#define CS42L42_MIX_CHA_OVFL_SHIFT 1
+#define CS42L42_MIX_CHA_OVFL_MASK (1 << CS42L42_MIX_CHA_OVFL_SHIFT)
+#define CS42L42_EQ_OVFL_SHIFT 2
+#define CS42L42_EQ_OVFL_MASK (1 << CS42L42_EQ_OVFL_SHIFT)
+#define CS42L42_EQ_BIQUAD_OVFL_SHIFT 3
+#define CS42L42_EQ_BIQUAD_OVFL_MASK (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT)
+#define CS42L42_MIXER_VAL_MASK (CS42L42_MIX_CHB_OVFL_MASK | \
+ CS42L42_MIX_CHA_OVFL_MASK | \
+ CS42L42_EQ_OVFL_MASK | \
+ CS42L42_EQ_BIQUAD_OVFL_MASK)
+
+#define CS42L42_SRC_INT_MASK (CS42L42_PAGE_13 + 0x18)
+#define CS42L42_SRC_ILK_SHIFT 0
+#define CS42L42_SRC_ILK_MASK (1 << CS42L42_SRC_ILK_SHIFT)
+#define CS42L42_SRC_OLK_SHIFT 1
+#define CS42L42_SRC_OLK_MASK (1 << CS42L42_SRC_OLK_SHIFT)
+#define CS42L42_SRC_IUNLK_SHIFT 2
+#define CS42L42_SRC_IUNLK_MASK (1 << CS42L42_SRC_IUNLK_SHIFT)
+#define CS42L42_SRC_OUNLK_SHIFT 3
+#define CS42L42_SRC_OUNLK_MASK (1 << CS42L42_SRC_OUNLK_SHIFT)
+#define CS42L42_SRC_VAL_MASK (CS42L42_SRC_ILK_MASK | \
+ CS42L42_SRC_OLK_MASK | \
+ CS42L42_SRC_IUNLK_MASK | \
+ CS42L42_SRC_OUNLK_MASK)
+
+#define CS42L42_ASP_RX_INT_MASK (CS42L42_PAGE_13 + 0x19)
+#define CS42L42_ASPRX_NOLRCK_SHIFT 0
+#define CS42L42_ASPRX_NOLRCK_MASK (1 << CS42L42_ASPRX_NOLRCK_SHIFT)
+#define CS42L42_ASPRX_EARLY_SHIFT 1
+#define CS42L42_ASPRX_EARLY_MASK (1 << CS42L42_ASPRX_EARLY_SHIFT)
+#define CS42L42_ASPRX_LATE_SHIFT 2
+#define CS42L42_ASPRX_LATE_MASK (1 << CS42L42_ASPRX_LATE_SHIFT)
+#define CS42L42_ASPRX_ERROR_SHIFT 3
+#define CS42L42_ASPRX_ERROR_MASK (1 << CS42L42_ASPRX_ERROR_SHIFT)
+#define CS42L42_ASPRX_OVLD_SHIFT 4
+#define CS42L42_ASPRX_OVLD_MASK (1 << CS42L42_ASPRX_OVLD_SHIFT)
+#define CS42L42_ASP_RX_VAL_MASK (CS42L42_ASPRX_NOLRCK_MASK | \
+ CS42L42_ASPRX_EARLY_MASK | \
+ CS42L42_ASPRX_LATE_MASK | \
+ CS42L42_ASPRX_ERROR_MASK | \
+ CS42L42_ASPRX_OVLD_MASK)
+
+#define CS42L42_ASP_TX_INT_MASK (CS42L42_PAGE_13 + 0x1A)
+#define CS42L42_ASPTX_NOLRCK_SHIFT 0
+#define CS42L42_ASPTX_NOLRCK_MASK (1 << CS42L42_ASPTX_NOLRCK_SHIFT)
+#define CS42L42_ASPTX_EARLY_SHIFT 1
+#define CS42L42_ASPTX_EARLY_MASK (1 << CS42L42_ASPTX_EARLY_SHIFT)
+#define CS42L42_ASPTX_LATE_SHIFT 2
+#define CS42L42_ASPTX_LATE_MASK (1 << CS42L42_ASPTX_LATE_SHIFT)
+#define CS42L42_ASPTX_SMERROR_SHIFT 3
+#define CS42L42_ASPTX_SMERROR_MASK (1 << CS42L42_ASPTX_SMERROR_SHIFT)
+#define CS42L42_ASP_TX_VAL_MASK (CS42L42_ASPTX_NOLRCK_MASK | \
+ CS42L42_ASPTX_EARLY_MASK | \
+ CS42L42_ASPTX_LATE_MASK | \
+ CS42L42_ASPTX_SMERROR_MASK)
+
+#define CS42L42_CODEC_INT_MASK (CS42L42_PAGE_13 + 0x1B)
+#define CS42L42_PDN_DONE_SHIFT 0
+#define CS42L42_PDN_DONE_MASK (1 << CS42L42_PDN_DONE_SHIFT)
+#define CS42L42_HSDET_AUTO_DONE_SHIFT 1
+#define CS42L42_HSDET_AUTO_DONE_MASK (1 << CS42L42_HSDET_AUTO_DONE_SHIFT)
+#define CS42L42_CODEC_VAL_MASK (CS42L42_PDN_DONE_MASK | \
+ CS42L42_HSDET_AUTO_DONE_MASK)
+
+#define CS42L42_SRCPL_INT_MASK (CS42L42_PAGE_13 + 0x1C)
+#define CS42L42_SRCPL_ADC_LK_SHIFT 0
+#define CS42L42_SRCPL_ADC_LK_MASK (1 << CS42L42_SRCPL_ADC_LK_SHIFT)
+#define CS42L42_SRCPL_DAC_LK_SHIFT 2
+#define CS42L42_SRCPL_DAC_LK_MASK (1 << CS42L42_SRCPL_DAC_LK_SHIFT)
+#define CS42L42_SRCPL_ADC_UNLK_SHIFT 5
+#define CS42L42_SRCPL_ADC_UNLK_MASK (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT)
+#define CS42L42_SRCPL_DAC_UNLK_SHIFT 6
+#define CS42L42_SRCPL_DAC_UNLK_MASK (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT)
+#define CS42L42_SRCPL_VAL_MASK (CS42L42_SRCPL_ADC_LK_MASK | \
+ CS42L42_SRCPL_DAC_LK_MASK | \
+ CS42L42_SRCPL_ADC_UNLK_MASK | \
+ CS42L42_SRCPL_DAC_UNLK_MASK)
+
+#define CS42L42_VPMON_INT_MASK (CS42L42_PAGE_13 + 0x1E)
+#define CS42L42_VPMON_SHIFT 0
+#define CS42L42_VPMON_MASK (1 << CS42L42_VPMON_SHIFT)
+#define CS42L42_VPMON_VAL_MASK CS42L42_VPMON_MASK
+
+#define CS42L42_PLL_LOCK_INT_MASK (CS42L42_PAGE_13 + 0x1F)
+#define CS42L42_PLL_LOCK_SHIFT 0
+#define CS42L42_PLL_LOCK_MASK (1 << CS42L42_PLL_LOCK_SHIFT)
+#define CS42L42_PLL_LOCK_VAL_MASK CS42L42_PLL_LOCK_MASK
+
+#define CS42L42_TSRS_PLUG_INT_MASK (CS42L42_PAGE_13 + 0x20)
+#define CS42L42_RS_PLUG_SHIFT 0
+#define CS42L42_RS_PLUG_MASK (1 << CS42L42_RS_PLUG_SHIFT)
+#define CS42L42_RS_UNPLUG_SHIFT 1
+#define CS42L42_RS_UNPLUG_MASK (1 << CS42L42_RS_UNPLUG_SHIFT)
+#define CS42L42_TS_PLUG_SHIFT 2
+#define CS42L42_TS_PLUG_MASK (1 << CS42L42_TS_PLUG_SHIFT)
+#define CS42L42_TS_UNPLUG_SHIFT 3
+#define CS42L42_TS_UNPLUG_MASK (1 << CS42L42_TS_UNPLUG_SHIFT)
+#define CS42L42_TSRS_PLUG_VAL_MASK (CS42L42_RS_PLUG_MASK | \
+ CS42L42_RS_UNPLUG_MASK | \
+ CS42L42_TS_PLUG_MASK | \
+ CS42L42_TS_UNPLUG_MASK)
+#define CS42L42_TS_PLUG 3
+#define CS42L42_TS_UNPLUG 0
+#define CS42L42_TS_TRANS 1
+
+/* Page 0x15 Fractional-N PLL Registers */
+#define CS42L42_PLL_CTL1 (CS42L42_PAGE_15 + 0x01)
+#define CS42L42_PLL_START_SHIFT 0
+#define CS42L42_PLL_START_MASK (1 << CS42L42_PLL_START_SHIFT)
+
+#define CS42L42_PLL_DIV_FRAC0 (CS42L42_PAGE_15 + 0x02)
+#define CS42L42_PLL_DIV_FRAC_SHIFT 0
+#define CS42L42_PLL_DIV_FRAC_MASK (0xff << CS42L42_PLL_DIV_FRAC_SHIFT)
+
+#define CS42L42_PLL_DIV_FRAC1 (CS42L42_PAGE_15 + 0x03)
+#define CS42L42_PLL_DIV_FRAC2 (CS42L42_PAGE_15 + 0x04)
+
+#define CS42L42_PLL_DIV_INT (CS42L42_PAGE_15 + 0x05)
+#define CS42L42_PLL_DIV_INT_SHIFT 0
+#define CS42L42_PLL_DIV_INT_MASK (0xff << CS42L42_PLL_DIV_INT_SHIFT)
+
+#define CS42L42_PLL_CTL3 (CS42L42_PAGE_15 + 0x08)
+#define CS42L42_PLL_DIVOUT_SHIFT 0
+#define CS42L42_PLL_DIVOUT_MASK (0xff << CS42L42_PLL_DIVOUT_SHIFT)
+
+#define CS42L42_PLL_CAL_RATIO (CS42L42_PAGE_15 + 0x0A)
+#define CS42L42_PLL_CAL_RATIO_SHIFT 0
+#define CS42L42_PLL_CAL_RATIO_MASK (0xff << CS42L42_PLL_CAL_RATIO_SHIFT)
+
+#define CS42L42_PLL_CTL4 (CS42L42_PAGE_15 + 0x1B)
+#define CS42L42_PLL_MODE_SHIFT 0
+#define CS42L42_PLL_MODE_MASK (3 << CS42L42_PLL_MODE_SHIFT)
+
+/* Page 0x19 HP Load Detect Registers */
+#define CS42L42_LOAD_DET_RCSTAT (CS42L42_PAGE_19 + 0x25)
+#define CS42L42_RLA_STAT_SHIFT 0
+#define CS42L42_RLA_STAT_MASK (3 << CS42L42_RLA_STAT_SHIFT)
+#define CS42L42_RLA_STAT_15_OHM 0
+
+#define CS42L42_LOAD_DET_DONE (CS42L42_PAGE_19 + 0x26)
+#define CS42L42_HPLOAD_DET_DONE_SHIFT 0
+#define CS42L42_HPLOAD_DET_DONE_MASK (1 << CS42L42_HPLOAD_DET_DONE_SHIFT)
+
+#define CS42L42_LOAD_DET_EN (CS42L42_PAGE_19 + 0x27)
+#define CS42L42_HP_LD_EN_SHIFT 0
+#define CS42L42_HP_LD_EN_MASK (1 << CS42L42_HP_LD_EN_SHIFT)
+
+/* Page 0x1B Headset Interface Registers */
+#define CS42L42_HSBIAS_SC_AUTOCTL (CS42L42_PAGE_1B + 0x70)
+#define CS42L42_HSBIAS_SENSE_TRIP_SHIFT 0
+#define CS42L42_HSBIAS_SENSE_TRIP_MASK (7 << \
+ CS42L42_HSBIAS_SENSE_TRIP_SHIFT)
+#define CS42L42_TIP_SENSE_EN_SHIFT 5
+#define CS42L42_TIP_SENSE_EN_MASK (1 << \
+ CS42L42_TIP_SENSE_EN_SHIFT)
+#define CS42L42_AUTO_HSBIAS_HIZ_SHIFT 6
+#define CS42L42_AUTO_HSBIAS_HIZ_MASK (1 << \
+ CS42L42_AUTO_HSBIAS_HIZ_SHIFT)
+#define CS42L42_HSBIAS_SENSE_EN_SHIFT 7
+#define CS42L42_HSBIAS_SENSE_EN_MASK (1 << \
+ CS42L42_HSBIAS_SENSE_EN_SHIFT)
+
+#define CS42L42_WAKE_CTL (CS42L42_PAGE_1B + 0x71)
+#define CS42L42_WAKEB_CLEAR_SHIFT 0
+#define CS42L42_WAKEB_CLEAR_MASK (1 << CS42L42_WAKEB_CLEAR_SHIFT)
+#define CS42L42_WAKEB_MODE_SHIFT 5
+#define CS42L42_WAKEB_MODE_MASK (1 << CS42L42_WAKEB_MODE_SHIFT)
+#define CS42L42_M_HP_WAKE_SHIFT 6
+#define CS42L42_M_HP_WAKE_MASK (1 << CS42L42_M_HP_WAKE_SHIFT)
+#define CS42L42_M_MIC_WAKE_SHIFT 7
+#define CS42L42_M_MIC_WAKE_MASK (1 << CS42L42_M_MIC_WAKE_SHIFT)
+
+#define CS42L42_ADC_DISABLE_MUTE (CS42L42_PAGE_1B + 0x72)
+#define CS42L42_ADC_DISABLE_S0_MUTE_SHIFT 7
+#define CS42L42_ADC_DISABLE_S0_MUTE_MASK (1 << \
+ CS42L42_ADC_DISABLE_S0_MUTE_SHIFT)
+
+#define CS42L42_TIPSENSE_CTL (CS42L42_PAGE_1B + 0x73)
+#define CS42L42_TIP_SENSE_DEBOUNCE_SHIFT 0
+#define CS42L42_TIP_SENSE_DEBOUNCE_MASK (3 << \
+ CS42L42_TIP_SENSE_DEBOUNCE_SHIFT)
+#define CS42L42_TIP_SENSE_INV_SHIFT 5
+#define CS42L42_TIP_SENSE_INV_MASK (1 << \
+ CS42L42_TIP_SENSE_INV_SHIFT)
+#define CS42L42_TIP_SENSE_CTRL_SHIFT 6
+#define CS42L42_TIP_SENSE_CTRL_MASK (3 << \
+ CS42L42_TIP_SENSE_CTRL_SHIFT)
+
+#define CS42L42_MISC_DET_CTL (CS42L42_PAGE_1B + 0x74)
+#define CS42L42_PDN_MIC_LVL_DET_SHIFT 0
+#define CS42L42_PDN_MIC_LVL_DET_MASK (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)
+#define CS42L42_HSBIAS_CTL_SHIFT 1
+#define CS42L42_HSBIAS_CTL_MASK (3 << CS42L42_HSBIAS_CTL_SHIFT)
+#define CS42L42_DETECT_MODE_SHIFT 3
+#define CS42L42_DETECT_MODE_MASK (3 << CS42L42_DETECT_MODE_SHIFT)
+
+#define CS42L42_MIC_DET_CTL1 (CS42L42_PAGE_1B + 0x75)
+#define CS42L42_HS_DET_LEVEL_SHIFT 0
+#define CS42L42_HS_DET_LEVEL_MASK (0x3F << CS42L42_HS_DET_LEVEL_SHIFT)
+#define CS42L42_EVENT_STAT_SEL_SHIFT 6
+#define CS42L42_EVENT_STAT_SEL_MASK (1 << CS42L42_EVENT_STAT_SEL_SHIFT)
+#define CS42L42_LATCH_TO_VP_SHIFT 7
+#define CS42L42_LATCH_TO_VP_MASK (1 << CS42L42_LATCH_TO_VP_SHIFT)
+
+#define CS42L42_MIC_DET_CTL2 (CS42L42_PAGE_1B + 0x76)
+#define CS42L42_DEBOUNCE_TIME_SHIFT 5
+#define CS42L42_DEBOUNCE_TIME_MASK (0x07 << CS42L42_DEBOUNCE_TIME_SHIFT)
+
+#define CS42L42_DET_STATUS1 (CS42L42_PAGE_1B + 0x77)
+#define CS42L42_HSBIAS_HIZ_MODE_SHIFT 6
+#define CS42L42_HSBIAS_HIZ_MODE_MASK (1 << CS42L42_HSBIAS_HIZ_MODE_SHIFT)
+#define CS42L42_TIP_SENSE_SHIFT 7
+#define CS42L42_TIP_SENSE_MASK (1 << CS42L42_TIP_SENSE_SHIFT)
+
+#define CS42L42_DET_STATUS2 (CS42L42_PAGE_1B + 0x78)
+#define CS42L42_SHORT_TRUE_SHIFT 0
+#define CS42L42_SHORT_TRUE_MASK (1 << CS42L42_SHORT_TRUE_SHIFT)
+#define CS42L42_HS_TRUE_SHIFT 1
+#define CS42L42_HS_TRUE_MASK (1 << CS42L42_HS_TRUE_SHIFT)
+
+#define CS42L42_DET_INT1_MASK (CS42L42_PAGE_1B + 0x79)
+#define CS42L42_TIP_SENSE_UNPLUG_SHIFT 5
+#define CS42L42_TIP_SENSE_UNPLUG_MASK (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT)
+#define CS42L42_TIP_SENSE_PLUG_SHIFT 6
+#define CS42L42_TIP_SENSE_PLUG_MASK (1 << CS42L42_TIP_SENSE_PLUG_SHIFT)
+#define CS42L42_HSBIAS_SENSE_SHIFT 7
+#define CS42L42_HSBIAS_SENSE_MASK (1 << CS42L42_HSBIAS_SENSE_SHIFT)
+#define CS42L42_DET_INT_VAL1_MASK (CS42L42_TIP_SENSE_UNPLUG_MASK | \
+ CS42L42_TIP_SENSE_PLUG_MASK | \
+ CS42L42_HSBIAS_SENSE_MASK)
+
+#define CS42L42_DET_INT2_MASK (CS42L42_PAGE_1B + 0x7A)
+#define CS42L42_M_SHORT_DET_SHIFT 0
+#define CS42L42_M_SHORT_DET_MASK (1 << \
+ CS42L42_M_SHORT_DET_SHIFT)
+#define CS42L42_M_SHORT_RLS_SHIFT 1
+#define CS42L42_M_SHORT_RLS_MASK (1 << \
+ CS42L42_M_SHORT_RLS_SHIFT)
+#define CS42L42_M_HSBIAS_HIZ_SHIFT 2
+#define CS42L42_M_HSBIAS_HIZ_MASK (1 << \
+ CS42L42_M_HSBIAS_HIZ_SHIFT)
+#define CS42L42_M_DETECT_FT_SHIFT 6
+#define CS42L42_M_DETECT_FT_MASK (1 << \
+ CS42L42_M_DETECT_FT_SHIFT)
+#define CS42L42_M_DETECT_TF_SHIFT 7
+#define CS42L42_M_DETECT_TF_MASK (1 << \
+ CS42L42_M_DETECT_TF_SHIFT)
+#define CS42L42_DET_INT_VAL2_MASK (CS42L42_M_SHORT_DET_MASK | \
+ CS42L42_M_SHORT_RLS_MASK | \
+ CS42L42_M_HSBIAS_HIZ_MASK | \
+ CS42L42_M_DETECT_FT_MASK | \
+ CS42L42_M_DETECT_TF_MASK)
+
+/* Page 0x1C Headset Bias Registers */
+#define CS42L42_HS_BIAS_CTL (CS42L42_PAGE_1C + 0x03)
+#define CS42L42_HSBIAS_RAMP_SHIFT 0
+#define CS42L42_HSBIAS_RAMP_MASK (3 << CS42L42_HSBIAS_RAMP_SHIFT)
+#define CS42L42_HSBIAS_PD_SHIFT 4
+#define CS42L42_HSBIAS_PD_MASK (1 << CS42L42_HSBIAS_PD_SHIFT)
+#define CS42L42_HSBIAS_CAPLESS_SHIFT 7
+#define CS42L42_HSBIAS_CAPLESS_MASK (1 << CS42L42_HSBIAS_CAPLESS_SHIFT)
+
+/* Page 0x1D ADC Registers */
+#define CS42L42_ADC_CTL (CS42L42_PAGE_1D + 0x01)
+#define CS42L42_ADC_NOTCH_DIS_SHIFT 5
+#define CS42L42_ADC_FORCE_WEAK_VCM_SHIFT 4
+#define CS42L42_ADC_INV_SHIFT 2
+#define CS42L42_ADC_DIG_BOOST_SHIFT 0
+
+#define CS42L42_ADC_VOLUME (CS42L42_PAGE_1D + 0x03)
+#define CS42L42_ADC_VOL_SHIFT 0
+
+#define CS42L42_ADC_WNF_HPF_CTL (CS42L42_PAGE_1D + 0x04)
+#define CS42L42_ADC_WNF_CF_SHIFT 4
+#define CS42L42_ADC_WNF_EN_SHIFT 3
+#define CS42L42_ADC_HPF_CF_SHIFT 1
+#define CS42L42_ADC_HPF_EN_SHIFT 0
+
+/* Page 0x1F DAC Registers */
+#define CS42L42_DAC_CTL1 (CS42L42_PAGE_1F + 0x01)
+#define CS42L42_DACB_INV_SHIFT 1
+#define CS42L42_DACA_INV_SHIFT 0
+
+#define CS42L42_DAC_CTL2 (CS42L42_PAGE_1F + 0x06)
+#define CS42L42_HPOUT_PULLDOWN_SHIFT 4
+#define CS42L42_HPOUT_PULLDOWN_MASK (15 << CS42L42_HPOUT_PULLDOWN_SHIFT)
+#define CS42L42_HPOUT_LOAD_SHIFT 3
+#define CS42L42_HPOUT_LOAD_MASK (1 << CS42L42_HPOUT_LOAD_SHIFT)
+#define CS42L42_HPOUT_CLAMP_SHIFT 2
+#define CS42L42_HPOUT_CLAMP_MASK (1 << CS42L42_HPOUT_CLAMP_SHIFT)
+#define CS42L42_DAC_HPF_EN_SHIFT 1
+#define CS42L42_DAC_HPF_EN_MASK (1 << CS42L42_DAC_HPF_EN_SHIFT)
+#define CS42L42_DAC_MON_EN_SHIFT 0
+#define CS42L42_DAC_MON_EN_MASK (1 << CS42L42_DAC_MON_EN_SHIFT)
+
+/* Page 0x20 HP CTL Registers */
+#define CS42L42_HP_CTL (CS42L42_PAGE_20 + 0x01)
+#define CS42L42_HP_ANA_BMUTE_SHIFT 3
+#define CS42L42_HP_ANA_BMUTE_MASK (1 << CS42L42_HP_ANA_BMUTE_SHIFT)
+#define CS42L42_HP_ANA_AMUTE_SHIFT 2
+#define CS42L42_HP_ANA_AMUTE_MASK (1 << CS42L42_HP_ANA_AMUTE_SHIFT)
+#define CS42L42_HP_FULL_SCALE_VOL_SHIFT 1
+#define CS42L42_HP_FULL_SCALE_VOL_MASK (1 << CS42L42_HP_FULL_SCALE_VOL_SHIFT)
+
+/* Page 0x21 Class H Registers */
+#define CS42L42_CLASSH_CTL (CS42L42_PAGE_21 + 0x01)
+
+/* Page 0x23 Mixer Volume Registers */
+#define CS42L42_MIXER_CHA_VOL (CS42L42_PAGE_23 + 0x01)
+#define CS42L42_MIXER_ADC_VOL (CS42L42_PAGE_23 + 0x02)
+
+#define CS42L42_MIXER_CHB_VOL (CS42L42_PAGE_23 + 0x03)
+#define CS42L42_MIXER_CH_VOL_SHIFT 0
+#define CS42L42_MIXER_CH_VOL_MASK (0x3f << CS42L42_MIXER_CH_VOL_SHIFT)
+
+/* Page 0x24 EQ Registers */
+#define CS42L42_EQ_COEF_IN0 (CS42L42_PAGE_24 + 0x01)
+#define CS42L42_EQ_COEF_IN1 (CS42L42_PAGE_24 + 0x02)
+#define CS42L42_EQ_COEF_IN2 (CS42L42_PAGE_24 + 0x03)
+#define CS42L42_EQ_COEF_IN3 (CS42L42_PAGE_24 + 0x04)
+#define CS42L42_EQ_COEF_RW (CS42L42_PAGE_24 + 0x06)
+#define CS42L42_EQ_COEF_OUT0 (CS42L42_PAGE_24 + 0x07)
+#define CS42L42_EQ_COEF_OUT1 (CS42L42_PAGE_24 + 0x08)
+#define CS42L42_EQ_COEF_OUT2 (CS42L42_PAGE_24 + 0x09)
+#define CS42L42_EQ_COEF_OUT3 (CS42L42_PAGE_24 + 0x0A)
+#define CS42L42_EQ_INIT_STAT (CS42L42_PAGE_24 + 0x0B)
+#define CS42L42_EQ_START_FILT (CS42L42_PAGE_24 + 0x0C)
+#define CS42L42_EQ_MUTE_CTL (CS42L42_PAGE_24 + 0x0E)
+
+/* Page 0x25 Audio Port Registers */
+#define CS42L42_SP_RX_CH_SEL (CS42L42_PAGE_25 + 0x01)
+
+#define CS42L42_SP_RX_ISOC_CTL (CS42L42_PAGE_25 + 0x02)
+#define CS42L42_SP_RX_RSYNC_SHIFT 6
+#define CS42L42_SP_RX_RSYNC_MASK (1 << CS42L42_SP_RX_RSYNC_SHIFT)
+#define CS42L42_SP_RX_NSB_POS_SHIFT 3
+#define CS42L42_SP_RX_NSB_POS_MASK (7 << CS42L42_SP_RX_NSB_POS_SHIFT)
+#define CS42L42_SP_RX_NFS_NSBB_SHIFT 2
+#define CS42L42_SP_RX_NFS_NSBB_MASK (1 << CS42L42_SP_RX_NFS_NSBB_SHIFT)
+#define CS42L42_SP_RX_ISOC_MODE_SHIFT 0
+#define CS42L42_SP_RX_ISOC_MODE_MASK (3 << CS42L42_SP_RX_ISOC_MODE_SHIFT)
+
+#define CS42L42_SP_RX_FS (CS42L42_PAGE_25 + 0x03)
+#define CS42l42_SPDIF_CH_SEL (CS42L42_PAGE_25 + 0x04)
+#define CS42L42_SP_TX_ISOC_CTL (CS42L42_PAGE_25 + 0x05)
+#define CS42L42_SP_TX_FS (CS42L42_PAGE_25 + 0x06)
+#define CS42L42_SPDIF_SW_CTL1 (CS42L42_PAGE_25 + 0x07)
+
+/* Page 0x26 SRC Registers */
+#define CS42L42_SRC_SDIN_FS (CS42L42_PAGE_26 + 0x01)
+#define CS42L42_SRC_SDIN_FS_SHIFT 0
+#define CS42L42_SRC_SDIN_FS_MASK (0x1f << CS42L42_SRC_SDIN_FS_SHIFT)
+
+#define CS42L42_SRC_SDOUT_FS (CS42L42_PAGE_26 + 0x09)
+
+/* Page 0x28 S/PDIF Registers */
+#define CS42L42_SPDIF_CTL1 (CS42L42_PAGE_28 + 0x01)
+#define CS42L42_SPDIF_CTL2 (CS42L42_PAGE_28 + 0x02)
+#define CS42L42_SPDIF_CTL3 (CS42L42_PAGE_28 + 0x03)
+#define CS42L42_SPDIF_CTL4 (CS42L42_PAGE_28 + 0x04)
+
+/* Page 0x29 Serial Port TX Registers */
+#define CS42L42_ASP_TX_SZ_EN (CS42L42_PAGE_29 + 0x01)
+#define CS42L42_ASP_TX_CH_EN (CS42L42_PAGE_29 + 0x02)
+#define CS42L42_ASP_TX_CH_AP_RES (CS42L42_PAGE_29 + 0x03)
+#define CS42L42_ASP_TX_CH1_BIT_MSB (CS42L42_PAGE_29 + 0x04)
+#define CS42L42_ASP_TX_CH1_BIT_LSB (CS42L42_PAGE_29 + 0x05)
+#define CS42L42_ASP_TX_HIZ_DLY_CFG (CS42L42_PAGE_29 + 0x06)
+#define CS42L42_ASP_TX_CH2_BIT_MSB (CS42L42_PAGE_29 + 0x0A)
+#define CS42L42_ASP_TX_CH2_BIT_LSB (CS42L42_PAGE_29 + 0x0B)
+
+/* Page 0x2A Serial Port RX Registers */
+#define CS42L42_ASP_RX_DAI0_EN (CS42L42_PAGE_2A + 0x01)
+#define CS42L42_ASP_RX0_CH_EN_SHIFT 2
+#define CS42L42_ASP_RX0_CH_EN_MASK (0xf << CS42L42_ASP_RX0_CH_EN_SHIFT)
+#define CS42L42_ASP_RX0_CH1_EN 1
+#define CS42L42_ASP_RX0_CH2_EN 2
+#define CS42L42_ASP_RX0_CH3_EN 4
+#define CS42L42_ASP_RX0_CH4_EN 8
+
+#define CS42L42_ASP_RX_DAI0_CH1_AP_RES (CS42L42_PAGE_2A + 0x02)
+#define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x03)
+#define CS42L42_ASP_RX_DAI0_CH1_BIT_LSB (CS42L42_PAGE_2A + 0x04)
+#define CS42L42_ASP_RX_DAI0_CH2_AP_RES (CS42L42_PAGE_2A + 0x05)
+#define CS42L42_ASP_RX_DAI0_CH2_BIT_MSB (CS42L42_PAGE_2A + 0x06)
+#define CS42L42_ASP_RX_DAI0_CH2_BIT_LSB (CS42L42_PAGE_2A + 0x07)
+#define CS42L42_ASP_RX_DAI0_CH3_AP_RES (CS42L42_PAGE_2A + 0x08)
+#define CS42L42_ASP_RX_DAI0_CH3_BIT_MSB (CS42L42_PAGE_2A + 0x09)
+#define CS42L42_ASP_RX_DAI0_CH3_BIT_LSB (CS42L42_PAGE_2A + 0x0A)
+#define CS42L42_ASP_RX_DAI0_CH4_AP_RES (CS42L42_PAGE_2A + 0x0B)
+#define CS42L42_ASP_RX_DAI0_CH4_BIT_MSB (CS42L42_PAGE_2A + 0x0C)
+#define CS42L42_ASP_RX_DAI0_CH4_BIT_LSB (CS42L42_PAGE_2A + 0x0D)
+#define CS42L42_ASP_RX_DAI1_CH1_AP_RES (CS42L42_PAGE_2A + 0x0E)
+#define CS42L42_ASP_RX_DAI1_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x0F)
+#define CS42L42_ASP_RX_DAI1_CH1_BIT_LSB (CS42L42_PAGE_2A + 0x10)
+#define CS42L42_ASP_RX_DAI1_CH2_AP_RES (CS42L42_PAGE_2A + 0x11)
+#define CS42L42_ASP_RX_DAI1_CH2_BIT_MSB (CS42L42_PAGE_2A + 0x12)
+#define CS42L42_ASP_RX_DAI1_CH2_BIT_LSB (CS42L42_PAGE_2A + 0x13)
+
+#define CS42L42_ASP_RX_CH_AP_SHIFT 6
+#define CS42L42_ASP_RX_CH_AP_MASK (1 << CS42L42_ASP_RX_CH_AP_SHIFT)
+#define CS42L42_ASP_RX_CH_AP_LOW 0
+#define CS42L42_ASP_RX_CH_AP_HI 1
+#define CS42L42_ASP_RX_CH_RES_SHIFT 0
+#define CS42L42_ASP_RX_CH_RES_MASK (3 << CS42L42_ASP_RX_CH_RES_SHIFT)
+#define CS42L42_ASP_RX_CH_RES_32 3
+#define CS42L42_ASP_RX_CH_RES_16 1
+#define CS42L42_ASP_RX_CH_BIT_ST_SHIFT 0
+#define CS42L42_ASP_RX_CH_BIT_ST_MASK (0xff << CS42L42_ASP_RX_CH_BIT_ST_SHIFT)
+
+/* Page 0x30 ID Registers */
+#define CS42L42_SUB_REVID (CS42L42_PAGE_30 + 0x14)
+#define CS42L42_MAX_REGISTER (CS42L42_PAGE_30 + 0x14)
+
+/* Defines for fracturing values spread across multiple registers */
+#define CS42L42_FRAC0_VAL(val) ((val) & 0x0000ff)
+#define CS42L42_FRAC1_VAL(val) (((val) & 0x00ff00) >> 8)
+#define CS42L42_FRAC2_VAL(val) (((val) & 0xff0000) >> 16)
+
+#define CS42L42_NUM_SUPPLIES 5
+
+static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = {
+ "VA",
+ "VP",
+ "VCP",
+ "VD_FILT",
+ "VL",
+};
+
+struct cs42l42_private {
+ struct regmap *regmap;
+ struct snd_soc_codec *codec;
+ struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES];
+ struct gpio_desc *reset_gpio;
+ struct completion pdn_done;
+ u32 sclk;
+ u32 srate;
+ u32 swidth;
+ u8 plug_state;
+ u8 hs_type;
+ u8 ts_inv;
+ u8 ts_dbnc_rise;
+ u8 ts_dbnc_fall;
+ u8 btn_det_init_dbnce;
+ u8 btn_det_event_dbnce;
+ u8 bias_thresholds[CS42L42_NUM_BIASES];
+ u8 hs_bias_ramp_rate;
+ u8 hs_bias_ramp_time;
+};
+
+#endif /* __CS42L42_H__ */
--
2.10.2
^ permalink raw reply related
* [PATCH] cec: zero counters in cec_received_msg()
From: Hans Verkuil @ 2016-11-09 15:22 UTC (permalink / raw)
To: linux-media
Make sure the TX counters are zeroed in the cec_msg struct.
Non-zero TX counters make no sense when a message is received,
and applications should not see non-zero values here.
Signed-off-by: Hans Verkuil <hansverk@cisco.com>
---
This sits on top of my earlier cec pull request that moves cec to the
mainline.
---
drivers/media/cec/cec-adap.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index ed76d70..d9c6f2c 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -874,6 +874,10 @@ void cec_received_msg(struct cec_adapter *adap,
struct cec_msg *msg)
msg->sequence = msg->reply = msg->timeout = 0;
msg->tx_status = 0;
msg->tx_ts = 0;
+ msg->tx_arb_lost_cnt = 0;
+ msg->tx_nack_cnt = 0;
+ msg->tx_low_drive_cnt = 0;
+ msg->tx_error_cnt = 0;
msg->flags = 0;
memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len);
--
2.7.0
^ permalink raw reply related
* [Qemu-devel] [PATCH v2 3/3] net: virtio-net discards TX data after link down
From: yuri.benditovich @ 2016-11-09 15:22 UTC (permalink / raw)
To: Michael S . Tsirkin, Jason Wang, qemu-devel; +Cc: dmitry, yan
In-Reply-To: <1478704922-3400-1-git-send-email-yuri.benditovich@daynix.com>
From: Yuri Benditovich <yuri.benditovich@daynix.com>
https://bugzilla.redhat.com/show_bug.cgi?id=1295637
Upon set_link monitor command or upon netdev deletion
virtio-net sends link down indication to the guest
and stops vhost if one is used.
Guest driver can still submit data for TX until it
recognizes link loss. If these packets not returned by
the host, the Windows guest will never be able to finish
disable/removal/shutdown.
Now each packet sent by guest after NIC indicated link
down will be completed immediately.
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
---
hw/net/virtio-net.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 06bfe4b..ab4e18a 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -218,6 +218,16 @@ static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status)
}
}
+static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtQueueElement *elem;
+ while ((elem = virtqueue_pop(vq, sizeof(VirtQueueElement)))) {
+ virtqueue_push(vq, elem, 0);
+ virtio_notify(vdev, vq);
+ g_free(elem);
+ }
+}
+
static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
{
VirtIONet *n = VIRTIO_NET(vdev);
@@ -262,6 +272,14 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
} else {
qemu_bh_cancel(q->tx_bh);
}
+ if ((n->status & VIRTIO_NET_S_LINK_UP) == 0 &&
+ (queue_status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ /* if tx is waiting we are likely have some packets in tx queue
+ * and disabled notification */
+ q->tx_waiting = 0;
+ virtio_queue_set_notification(q->tx_vq, 1);
+ virtio_net_drop_tx_queue_data(vdev, q->tx_vq);
+ }
}
}
}
@@ -1319,6 +1337,11 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
VirtIONet *n = VIRTIO_NET(vdev);
VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
+ if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) {
+ virtio_net_drop_tx_queue_data(vdev, vq);
+ return;
+ }
+
/* This happens when device was stopped but VCPU wasn't. */
if (!vdev->vm_running) {
q->tx_waiting = 1;
@@ -1345,6 +1368,11 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
VirtIONet *n = VIRTIO_NET(vdev);
VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
+ if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) {
+ virtio_net_drop_tx_queue_data(vdev, vq);
+ return;
+ }
+
if (unlikely(q->tx_waiting)) {
return;
}
--
1.9.1
^ permalink raw reply related
* [Qemu-devel] [PATCH v2 0/3] virtio-net discards TX data after link down
From: yuri.benditovich @ 2016-11-09 15:21 UTC (permalink / raw)
To: Michael S . Tsirkin, Jason Wang, qemu-devel; +Cc: dmitry, yan
From: Yuri Benditovich <yuri.benditovich@daynix.com>
https://bugzilla.redhat.com/show_bug.cgi?id=1295637
Upon set_link monitor command or upon netdev deletion
virtio-net sends link down indication to the guest
and stops vhost if one is used.
Guest driver can still submit data for TX until it
recognizes link loss. If these packets not returned by
the host, the Windows guest will never be able to finish
disable/removal/shutdown. In order to allow qemu to
discard these packets, virtio queue shall update
its internal structure upon vhost stop.
Changes from v1:
- added drop for outstanding tx packets for tx=timer
- (mainly for case of vhost=off)
fixed link down flow to drop outstanding packets and
ensure tx queue notification enabled
Yuri Benditovich (3):
net: Add virtio queue interface to update used index from vring state
net: vhost stop updates virtio queue state
net: virtio-net discards TX data after link down
hw/net/virtio-net.c | 28 ++++++++++++++++++++++++++++
hw/virtio/vhost.c | 1 +
hw/virtio/virtio.c | 5 +++++
include/hw/virtio/virtio.h | 1 +
4 files changed, 35 insertions(+)
--
1.9.1
^ permalink raw reply
* [Qemu-devel] [PATCH v2 1/3] net: Add virtio queue interface to update used index from vring state
From: yuri.benditovich @ 2016-11-09 15:22 UTC (permalink / raw)
To: Michael S . Tsirkin, Jason Wang, qemu-devel; +Cc: dmitry, yan
In-Reply-To: <1478704922-3400-1-git-send-email-yuri.benditovich@daynix.com>
From: Yuri Benditovich <yuri.benditovich@daynix.com>
Bring virtio queue to correct internal state for host-to-guest
operations when vhost is temporary stopped.
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
---
hw/virtio/virtio.c | 5 +++++
include/hw/virtio/virtio.h | 1 +
2 files changed, 6 insertions(+)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index d48d1a9..7e1274a 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1983,6 +1983,11 @@ void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
vdev->vq[n].shadow_avail_idx = idx;
}
+void virtio_queue_update_used_idx(VirtIODevice *vdev, int n)
+{
+ vdev->vq[n].used_idx = vring_used_idx(&vdev->vq[n]);
+}
+
void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n)
{
vdev->vq[n].signalled_used_valid = false;
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index b913aac..b9a9d6e 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -260,6 +260,7 @@ hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n);
uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n);
void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n);
+void virtio_queue_update_used_idx(VirtIODevice *vdev, int n);
VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
uint16_t virtio_get_queue_index(VirtQueue *vq);
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
--
1.9.1
^ permalink raw reply related
* [Qemu-devel] [PATCH v2 2/3] net: vhost stop updates virtio queue state
From: yuri.benditovich @ 2016-11-09 15:22 UTC (permalink / raw)
To: Michael S . Tsirkin, Jason Wang, qemu-devel; +Cc: dmitry, yan
In-Reply-To: <1478704922-3400-1-git-send-email-yuri.benditovich@daynix.com>
From: Yuri Benditovich <yuri.benditovich@daynix.com>
Make virtio queue suitable for push operation from qemu
after vhost was stopped.
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
---
hw/virtio/vhost.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index bd051ab..2e990d0 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -963,6 +963,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
virtio_queue_set_last_avail_idx(vdev, idx, state.num);
}
virtio_queue_invalidate_signalled_used(vdev, idx);
+ virtio_queue_update_used_idx(vdev, idx);
/* In the cross-endian case, we need to reset the vring endianness to
* native as legacy devices expect so by default.
--
1.9.1
^ permalink raw reply related
* Re: [PATCH] sound: soc-core: make kernel complaints on -EPROBE_DEFER dev_dbg
From: Mark Brown @ 2016-11-09 15:22 UTC (permalink / raw)
To: Ladislav Michl; +Cc: alsa-devel, Liam Girdwood
In-Reply-To: <20161109151426.GA21280@localhost.localdomain>
[-- Attachment #1.1: Type: text/plain, Size: 1138 bytes --]
On Wed, Nov 09, 2016 at 04:14:26PM +0100, Ladislav Michl wrote:
> On Wed, Nov 09, 2016 at 02:36:42PM +0000, Mark Brown wrote:
> > No, errors are errors and not displaying them just makes it harder for
> > people to debug things. If you don't want to see errors just change
> > your system configuratiion to hide them.
> For sure I want to see all errors, but this is not hardware error nor
> kernel misconfiguration, so showing it to the user is a bit pointless.
How do we know that it's not a kernel misconfiguration? It's common for
people to not build some of the component drivers they need.
> > If you don't like deferred probing please contribute to the efforts
> > to order probing.
> I just tried to make it consistend to other subsystems where patches to
> silence deferred probing warnings are accepted...
Which subsystems are these? We should look at fixing them...
>
> > Please use subject lines matching the style for the subsystem. This
> > makes it easier for people to identify relevant patches.
>
> I wasn't aware of it, sorry. Will fix it next time.
>
> Best regards,
> ladis
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* Re: [Drbd-dev] WDRBD 1.3.5 released (drbd9 modified by mantech)
From: Philipp Reisner @ 2016-11-09 15:22 UTC (permalink / raw)
To: Kim, Sung-eun
Cc: J.H., Jin Lee (이진현), Windows DRBD,
박현석, 박성환, Philipp Marek,
drbd-dev, 배종무
In-Reply-To: <CAHRYDji-LUDdvOhzSfQi=kPzR9mS+xcRM4Juz8LWb7RZnAo41w@mail.gmail.com>
Am Dienstag, 8. November 2016, 14:35:08 CET schrieb Kim, Sung-eun:
> Hi, Philipp
>
> WDRBD 1.3.5 is released.
>
> https://github.com/mantechnology/wdrbd/releases
>
>
> we have test and debugging wdrbd for a long time, and finally met WDRBD
> 1.3.5.
>
> We have modified a drbd9 original source code, and a one big thing was
> changed from origin code. that is,
>
> *- A Only Primary node can be SyncSource.*
>
> we have met a many situation for a 1:N node test, in those there were
> problems. If sync direction is different with replication direction from
> each nodes, OOS remaining and replication Consistency issues was happened,
> and we cannot solve these.
>
I see.
Would help if you could describe such a case, step by step.
> and we decided to restrict a sync direction.
>
> you can check this below link,
>
> https://github.com/mantechnology/wdrbd/commit/7cc1f27f915d604b0ebcd10761a722
> f5b6c7701c
>
>
>
> Another things is Fast Sync(we call it).
>
> Do you remember that we talks about a Fast initial Sync on a way to airport
> in Seoul?
>
> finally, we make it this. (
> https://github.com/mantechnology/wdrbd/commit/28a484b2259002c92e578e2f84ee5a
> 88c72c1ac5 )
Interesting. I do not know if it possible to do a comparable thing
in Linux... We will have a look.
> and, you can check a source code modified by mantech in a below contents.
> we will wait for your opinion about MODIFIED_BY_MANTECH.
>
It will take a bit. I try to do it somwhen next week
I.e. bevor November 18.
best regards,
Phil
^ permalink raw reply
* Re: krogoth 2.1.2 status
From: akuster808 @ 2016-11-09 15:20 UTC (permalink / raw)
To: Richard Purdie, openembedded-core
In-Reply-To: <1478694607.23123.176.camel@linuxfoundation.org>
On 11/09/2016 04:30 AM, Richard Purdie wrote:
> I ran a krogoth 2.1.2 build. It did have some issues:
>
> * one runtime sanity test had a timeout issue
> * some urls are stale (perpetual problem)
> * musl runtime testing fails (never tested on krogoth previously)
> * no-x11 runtime testing had a failure (never tested on krogoth
> previously)
Can we get those issues bugged ( if not done so already) so we can make
decisions on what to do with each.
>
> I suspect we can call this good enough to put into QA but there were
> enough 'failures' I wanted to send this out in case someone objects.
>
> Part of the problem here is we apply our current autobuilder test setup
> to the older releases as well. I'm aware there may be better ways to do
> this but I don't know anyone with time to work on that, we have other
> more pressing problems.
I suspect Jethro will have similar or worse issues.
- Armin
>
> Cheers,
>
> Richard
>
^ permalink raw reply
* Re: [PATCH v2 0/2] pinctrl: single: fixes for davinci
From: Tony Lindgren @ 2016-11-09 15:20 UTC (permalink / raw)
To: Axel Haslam
Cc: haojian.zhuang, linus.walleij, khilman, nsekhar, linux-arm-kernel,
linux-omap, linux-gpio, linux-kernel
In-Reply-To: <20161109145401.25327-1-ahaslam@baylibre.com>
* Axel Haslam <ahaslam@baylibre.com> [161109 07:54]:
> After recent pinctl patches we see a warning when booting davinci
> due to a bad memory allocation:
>
> ------------[ cut here ]------------
> WARNING: CPU: 0 PID: 1 at mm/page_alloc.c:3511 __alloc_pages_nodemask+0x16c/0xb18
> Modules linked in:
> CPU: 0 PID: 1 Comm: swapper Not tainted 4.9.0-rc2-00023-g22d5127-dirty #1019
> Hardware name: Generic DA850/OMAP-L138/AM18x
> Backtrace:
> [<c000d670>] (dump_backtrace) from [<c000d794>] (show_stack+0x18/0x1c)
> [<c000d77c>] (show_stack) from [<c021a0d0>] (dump_stack+0x20/0x28)
> [<c021a0b0>] (dump_stack) from [<c001bb10>] (__warn+0xe8/0x100)
> [<c001ba28>] (__warn) from [<c001bb50>] (warn_slowpath_null+0x28/0x30)
> [<c001bb28>] (warn_slowpath_null) from [<c0097e7c>] (__alloc_pages_nodemask+0x16c/0xb18)
> [<c0097d10>] (__alloc_pages_nodemask) from [<c00afef4>] (kmalloc_order+0x20/0x58)
> [<c00afed4>] (kmalloc_order) from [<c00ce7ac>] (__kmalloc_track_caller+0x188/0x190)
> [<c00ce624>] (__kmalloc_track_caller) from [<c02a762c>] (devm_kmalloc+0x24/0x70)
> [<c02a7608>] (devm_kmalloc) from [<c0247d10>] (pcs_dt_node_to_map+0x1d0/0xa40)
> [<c0245ec8>] (pinctrl_dt_to_map) from [<c0242fd0>] (pinctrl_get+0xe8/0x484)
> [snip]
>
> This series fixes this error.
Thanks for fixing these and sorry about breaking pinctrl-bits:
Acked-by: Tony Lindgren <tony@atomide.com>
^ permalink raw reply
* [PATCH v2 0/2] pinctrl: single: fixes for davinci
From: Tony Lindgren @ 2016-11-09 15:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161109145401.25327-1-ahaslam@baylibre.com>
* Axel Haslam <ahaslam@baylibre.com> [161109 07:54]:
> After recent pinctl patches we see a warning when booting davinci
> due to a bad memory allocation:
>
> ------------[ cut here ]------------
> WARNING: CPU: 0 PID: 1 at mm/page_alloc.c:3511 __alloc_pages_nodemask+0x16c/0xb18
> Modules linked in:
> CPU: 0 PID: 1 Comm: swapper Not tainted 4.9.0-rc2-00023-g22d5127-dirty #1019
> Hardware name: Generic DA850/OMAP-L138/AM18x
> Backtrace:
> [<c000d670>] (dump_backtrace) from [<c000d794>] (show_stack+0x18/0x1c)
> [<c000d77c>] (show_stack) from [<c021a0d0>] (dump_stack+0x20/0x28)
> [<c021a0b0>] (dump_stack) from [<c001bb10>] (__warn+0xe8/0x100)
> [<c001ba28>] (__warn) from [<c001bb50>] (warn_slowpath_null+0x28/0x30)
> [<c001bb28>] (warn_slowpath_null) from [<c0097e7c>] (__alloc_pages_nodemask+0x16c/0xb18)
> [<c0097d10>] (__alloc_pages_nodemask) from [<c00afef4>] (kmalloc_order+0x20/0x58)
> [<c00afed4>] (kmalloc_order) from [<c00ce7ac>] (__kmalloc_track_caller+0x188/0x190)
> [<c00ce624>] (__kmalloc_track_caller) from [<c02a762c>] (devm_kmalloc+0x24/0x70)
> [<c02a7608>] (devm_kmalloc) from [<c0247d10>] (pcs_dt_node_to_map+0x1d0/0xa40)
> [<c0245ec8>] (pinctrl_dt_to_map) from [<c0242fd0>] (pinctrl_get+0xe8/0x484)
> [snip]
>
> This series fixes this error.
Thanks for fixing these and sorry about breaking pinctrl-bits:
Acked-by: Tony Lindgren <tony@atomide.com>
^ permalink raw reply
* [PATCH] pinctrl: single: check for any error when getting rows
From: Tony Lindgren @ 2016-11-09 15:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161109141706.12624-1-ahaslam@baylibre.com>
* Axel Haslam <ahaslam@baylibre.com> [161109 07:19]:
> pinctrl_count_index_with_args returns -ENOENT not
> -EINVAL. The return check would pass, and we would
> try to kzalloc with a negative error size throwing
> a warning.
>
> Instead of checking for -EINVAL specifically, lets
> check for any error and avoid negative size allocations.
>
> Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
Thanks for fixing that:
Acked-by: Tony Lindgren <tony@atomide.com>
> ---
> drivers/pinctrl/pinctrl-single.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
> index 539f31c..56e22be 100644
> --- a/drivers/pinctrl/pinctrl-single.c
> +++ b/drivers/pinctrl/pinctrl-single.c
> @@ -1228,7 +1228,7 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
> struct pcs_function *function;
>
> rows = pinctrl_count_index_with_args(np, name);
> - if (rows == -EINVAL)
> + if (rows < 0)
> return rows;
>
> npins_in_row = pcs->width / pcs->bits_per_pin;
> --
> 2.10.1
>
^ permalink raw reply
* Re: [PATCH] pinctrl: single: check for any error when getting rows
From: Tony Lindgren @ 2016-11-09 15:19 UTC (permalink / raw)
To: Axel Haslam
Cc: haojian.zhuang, linus.walleij, khilman, nsekhar, linux-arm-kernel,
linux-omap, linux-gpio, linux-kernel
In-Reply-To: <20161109141706.12624-1-ahaslam@baylibre.com>
* Axel Haslam <ahaslam@baylibre.com> [161109 07:19]:
> pinctrl_count_index_with_args returns -ENOENT not
> -EINVAL. The return check would pass, and we would
> try to kzalloc with a negative error size throwing
> a warning.
>
> Instead of checking for -EINVAL specifically, lets
> check for any error and avoid negative size allocations.
>
> Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
Thanks for fixing that:
Acked-by: Tony Lindgren <tony@atomide.com>
> ---
> drivers/pinctrl/pinctrl-single.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
> index 539f31c..56e22be 100644
> --- a/drivers/pinctrl/pinctrl-single.c
> +++ b/drivers/pinctrl/pinctrl-single.c
> @@ -1228,7 +1228,7 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
> struct pcs_function *function;
>
> rows = pinctrl_count_index_with_args(np, name);
> - if (rows == -EINVAL)
> + if (rows < 0)
> return rows;
>
> npins_in_row = pcs->width / pcs->bits_per_pin;
> --
> 2.10.1
>
^ permalink raw reply
* Re: auto stop of scrubbing and deep scrubbing while backfilling or recovering
From: Wido den Hollander @ 2016-11-09 15:19 UTC (permalink / raw)
To: Sage Weil; +Cc: Stefan Priebe - Profihost AG, ceph-devel
In-Reply-To: <alpine.DEB.2.11.1611082029590.29278@piezo.us.to>
> Op 8 november 2016 om 21:30 schreef Sage Weil <sage@newdream.net>:
>
>
> On Tue, 8 Nov 2016, Wido den Hollander wrote:
> > > Op 8 november 2016 om 15:19 schreef Sage Weil <sage@newdream.net>:
> > >
> > >
> > > On Tue, 8 Nov 2016, Wido den Hollander wrote:
> > > > > Op 8 november 2016 om 9:35 schreef Stefan Priebe - Profihost AG <s.priebe@profihost.ag>:
> > > > >
> > > > >
> > > > > Hello,
> > > > >
> > > > > i'm wondering if anybody has already thought about automatically
> > > > > stopping srub and deep-scrub in case of backfilling or recovering. I've
> > > > > seen several situations where scrubbing massivly raises the latency
> > > > > while doing backfilling or recovering.
> > > > >
> > > >
> > > > Seems like a sane change to me, but maybe a dev has a better option. I
> > > > don't think a stop is easy, but a 'noscrub' flag could be set inside the
> > > > OSD.
> > > >
> > > > Maybe a config option: osd_scrub_during_recovery
> > > >
> > > > Defaults to true, but can be set to false by the admin.
> > > >
> > > > Before a scrub starts the OSD will check if there is recovery /
> > > > backfilling active on the OSD and if so it will not initiate the scrub.
> > >
> > > Yeah, it seems reasonable. I think there are two basic options:
> > >
> > > - Disable scrubbing locally on each OSD if it has scrubbing PGs. Two
> > > unrelated OSDs would be free to scrub and backfill at the same time.
> > >
> > > - Disable scrubbing globally if any pgs are backfilling. The reasoning
> > > here is that if backfilling is increasing the latency on some PGs, we
> > > don't want to increase the latency on others (by scrubbing) too.
> > >
> > > The other consideration is that if backfil is happening it probably
> > > doesn't mean we want to prevent scrubbing indefinitely. Instead, I'd
> > > suggest increasing the scrub intervals by some factor (e.g., 2x).
> > >
> > > The first option would probably be a change in the scrub scheduling in
> > > the OSD.
> > >
> >
> > I would go for the first one. Imagine a large cluster where one backfill is busy, that would otherwise halt all scrubs while only a few OSDs are involved.
> >
> > Option one isn't that hard to implement either I think.
>
> I added a card to trello: https://trello.com/b/ugTc2QFH/ceph-backlog
>
Wouldn't this be enough?
https://github.com/ceph/ceph/pull/11874
Wido
> Thanks!
> sage
> --
> To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH kvm-unit-tests v2 00/17] VT-d unit test
From: Peter Xu @ 2016-11-09 15:19 UTC (permalink / raw)
To: kvm; +Cc: drjones, rkrcmar, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>
On Wed, Nov 09, 2016 at 10:10:07AM -0500, Peter Xu wrote:
> This is v2 of vt-d unit test series.
>
> Patch "libcflat: add IS_ALIGNED() macro, and page sizes" is picked up
> by Drew in the ARM GIC framework series, so please feel free to drop
> it when needed.
Forget to mention: Series v2 is rebased to Alex's PCI v11 series.
Online repo for better reference:
https://github.com/xzpeter/kvm-unit-tests.git iommu-ut-v2
Thanks,
-- peterx
^ permalink raw reply
* Re: [RFC i-g-t 4/4] Add support for hotplug testing with the Chamelium
From: Tomeu Vizoso @ 2016-11-09 15:18 UTC (permalink / raw)
To: Lyude; +Cc: Intel Graphics Development
In-Reply-To: <1478563516-23568-5-git-send-email-lyude@redhat.com>
On 8 November 2016 at 01:05, Lyude <lyude@redhat.com> wrote:
> For the purpose of testing things such as hotplugging and bad monitors,
> the ChromeOS team ended up designing a neat little device known as the
> Chamelium. More information on this can be found here:
>
> https://www.chromium.org/chromium-os/testing/chamelium
>
> This adds support for a couple of things to intel-gpu-tools:
> - igt library functions for connecting to udev and monitoring it for
> hotplug events, loosely based off of the unfinished hotplugging
> implementation in testdisplay
> - Library functions for controlling the chamelium in tests using
> xmlrpc. A couple of RPC calls were ommitted here, mainly because they
> didn't seem very useful for our needs or because they're just plain
> broken
> - A set of basic tests using the chamelium.
I think it would be good to split this patch in a few smaller bits,
each with its logical change.
> Because there's no surefire way that I know of where we can map which
> chamelium port belongs to which port on the system being tested (we
> could just use hotplugging, but then we'd be relying on something that
> might be broken on the machine and potentially give false positives for
> certain tests), most of the chamelium tests will figure out whether or
> not a connection happened by counting the number of connectors matching
> the status we're looking for before hotplugging with the chamelium, vs.
> after hotplugging it.
Back when I started work on this, it was agreed with Daniel Vetter
that a config file would be used for this mapping (and other
configuration). This is the $HOME/.igtrc I was using during
development:
[Chamelium]
server_ip=192.168.100.123
server_port=9992
port_names=HDMI
connector_names=HDMI-A-1
I used the keyfile API in glib, as we are already depending on it (and
that's also why I chose libsoup instead of libxmlrpc).
For reference, this is the WIP branch that I was using to test frame
CRC capture with Chamelium:
https://git.collabora.com/cgit/user/tomeu/intel-gpu-tools.git/commit/?h=chamelium-crc
Regards,
Tomeu
> Tests which require that we know which port belongs to a certain port
> (such as ones where we actually perform a modeset) will unplug all of
> the chamelium ports, plug the desired port, then use the first DRM
> connector with the desired connector type that's marked as connected. In
> order to ensure we don't end up using the wrong connector, these tests
> will skip if they find any connectors with the desired type marked as
> connected before performing the hotplug on the chamelium.
>
> Running these tests requires (of course) a working Chamelium, along with
> the RPC URL for the chamelium being specified in the environment
> variable CHAMELIUM_HOST. If no URL is specified, the tests will just
> skip on their own. As well, tests for connectors which are not actually
> present on the system or the chamelium will skip on their own as well.
>
> Signed-off-by: Lyude <lyude@redhat.com>
> ---
> configure.ac | 13 +
> lib/Makefile.am | 10 +-
> lib/igt.h | 1 +
> lib/igt_chamelium.c | 628 +++++++++++++++++++++++++++++++++++++++++++++++++
> lib/igt_chamelium.h | 77 ++++++
> lib/igt_kms.c | 107 +++++++++
> lib/igt_kms.h | 13 +-
> scripts/run-tests.sh | 4 +-
> tests/Makefile.am | 5 +-
> tests/Makefile.sources | 1 +
> tests/chamelium.c | 549 ++++++++++++++++++++++++++++++++++++++++++
> 11 files changed, 1403 insertions(+), 5 deletions(-)
> create mode 100644 lib/igt_chamelium.c
> create mode 100644 lib/igt_chamelium.h
> create mode 100644 tests/chamelium.c
>
> diff --git a/configure.ac b/configure.ac
> index 735cfd5..88113b2 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -259,6 +259,18 @@ if test "x$with_libunwind" = xyes; then
> AC_MSG_ERROR([libunwind not found. Use --without-libunwind to disable libunwind support.]))
> fi
>
> +# enable support for using the chamelium
> +AC_ARG_ENABLE(chamelium,
> + AS_HELP_STRING([--without-chamelium],
> + [Build tests without chamelium support]),
> + [], [with_chamelium=yes])
> +
> +AM_CONDITIONAL(HAVE_CHAMELIUM, [test "x$with_chamelium" = xyes])
> +if test "x$with_chamelium" = xyes; then
> + AC_DEFINE(HAVE_CHAMELIUM, 1, [chamelium suport])
> + PKG_CHECK_MODULES(XMLRPC, xmlrpc_client)
> +fi
> +
> # enable debug symbols
> AC_ARG_ENABLE(debug,
> AS_HELP_STRING([--disable-debug],
> @@ -356,6 +368,7 @@ echo " Assembler : ${enable_assembler}"
> echo " Debugger : ${enable_debugger}"
> echo " Overlay : X: ${enable_overlay_xlib}, Xv: ${enable_overlay_xvlib}"
> echo " x86-specific tools : ${build_x86}"
> +echo " Chamelium support : ${with_chamelium}"
> echo ""
> echo " • API-Documentation : ${enable_gtk_doc}"
> echo " • Fail on warnings : ${enable_werror}"
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index 4c0893d..aeac43a 100644
> --- a/lib/Makefile.am
> +++ b/lib/Makefile.am
> @@ -22,8 +22,14 @@ if !HAVE_LIBDRM_INTEL
> stubs/drm/intel_bufmgr.h
> endif
>
> +if HAVE_CHAMELIUM
> + libintel_tools_la_SOURCES += \
> + igt_chamelium.c \
> + igt_chamelium.h
> +endif
> +
> AM_CPPFLAGS = -I$(top_srcdir)
> -AM_CFLAGS = $(CWARNFLAGS) $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(LIBUNWIND_CFLAGS) $(DEBUG_CFLAGS) \
> +AM_CFLAGS = $(CWARNFLAGS) $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(LIBUNWIND_CFLAGS) $(DEBUG_CFLAGS) $(XMLRPC_CFLAGS) $(UDEV_CFLAGS) \
> -DIGT_SRCDIR=\""$(abs_top_srcdir)/tests"\" \
> -DIGT_DATADIR=\""$(pkgdatadir)"\" \
> -DIGT_LOG_DOMAIN=\""$(subst _,-,$*)"\" \
> @@ -38,5 +44,7 @@ libintel_tools_la_LIBADD = \
> $(LIBUDEV_LIBS) \
> $(LIBUNWIND_LIBS) \
> $(TIMER_LIBS) \
> + $(XMLRPC_LIBS) \
> + $(UDEV_LIBS) \
> -lm
>
> diff --git a/lib/igt.h b/lib/igt.h
> index d751f24..0ea03e4 100644
> --- a/lib/igt.h
> +++ b/lib/igt.h
> @@ -30,6 +30,7 @@
> #include "igt_aux.h"
> #include "igt_core.h"
> #include "igt_core.h"
> +#include "igt_chamelium.h"
> #include "igt_debugfs.h"
> #include "igt_draw.h"
> #include "igt_fb.h"
> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> new file mode 100644
> index 0000000..a281ef6
> --- /dev/null
> +++ b/lib/igt_chamelium.c
> @@ -0,0 +1,628 @@
> +/*
> + * Copyright © 2016 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Lyude Paul <lyude@redhat.com>
> + */
> +
> +#include "config.h"
> +
> +#include <string.h>
> +#include <errno.h>
> +#include <xmlrpc-c/base.h>
> +#include <xmlrpc-c/client.h>
> +
> +#include "igt.h"
> +
> +#define check_rpc() \
> + igt_assert_f(!env.fault_occurred, "Chamelium RPC call failed: %s\n", \
> + env.fault_string);
> +
> +/**
> + * chamelium_ports:
> + *
> + * Contains information on all of the ports that are physically connected from
> + * the chamelium to the system. This information is initialized when
> + * #chamelium_init is called.
> + */
> +struct chamelium_port *chamelium_ports;
> +
> +/**
> + * chamelium_port_count:
> + *
> + * How many ports are physically connected from the chamelium to the system.
> + */
> +int chamelium_port_count;
> +
> +static const char *chamelium_url;
> +static xmlrpc_env env;
> +
> +struct chamelium_edid {
> + int id;
> + struct igt_list link;
> +};
> +struct chamelium_edid *allocated_edids;
> +
> +/**
> + * chamelium_plug:
> + * @id: The ID of the port on the chamelium to plug in
> + *
> + * Simulate a display connector being plugged into the system using the
> + * chamelium.
> + */
> +void chamelium_plug(int id)
> +{
> + xmlrpc_value *res;
> +
> + igt_debug("Plugging port %d\n", id);
> + res = xmlrpc_client_call(&env, chamelium_url, "Plug", "(i)", id);
> + check_rpc();
> +
> + xmlrpc_DECREF(res);
> +}
> +
> +/**
> + * chamelium_unplug:
> + * @id: The ID of the port on the chamelium to unplug
> + *
> + * Simulate a display connector being unplugged from the system using the
> + * chamelium.
> + */
> +void chamelium_unplug(int id)
> +{
> + xmlrpc_value *res;
> +
> + igt_debug("Unplugging port %d\n", id);
> + res = xmlrpc_client_call(&env, chamelium_url, "Unplug", "(i)", id);
> + check_rpc();
> +
> + xmlrpc_DECREF(res);
> +}
> +
> +/**
> + * chamelium_is_plugged:
> + * @id: The ID of the port on the chamelium to check the status of
> + *
> + * Check whether or not the given port has been plugged into the system using
> + * #chamelium_plug.
> + *
> + * Returns: True if the connector is set to plugged in, false otherwise.
> + */
> +bool chamelium_is_plugged(int id)
> +{
> + xmlrpc_value *res;
> + xmlrpc_bool is_plugged;
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "IsPlugged", "(i)", id);
> + check_rpc();
> +
> + xmlrpc_read_bool(&env, res, &is_plugged);
> + xmlrpc_DECREF(res);
> +
> + return is_plugged;
> +}
> +
> +/**
> + * chamelium_port_wait_video_input_stable:
> + * @id: The ID of the port on the chamelium to check the status of
> + * @timeout_secs: How long to wait for a video signal to appear before timing
> + * out
> + *
> + * Waits for a video signal to appear on the given port. This is useful for
> + * checking whether or not we've setup a monitor correctly.
> + *
> + * Returns: True if a video signal was detected, false if we timed out
> + */
> +bool chamelium_port_wait_video_input_stable(int id, int timeout_secs)
> +{
> + xmlrpc_value *res;
> + xmlrpc_bool is_on;
> +
> + igt_debug("Waiting for video input to stabalize on port %d\n", id);
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "WaitVideoInputStable",
> + "(ii)", id, timeout_secs);
> + check_rpc();
> +
> + xmlrpc_read_bool(&env, res, &is_on);
> + xmlrpc_DECREF(res);
> +
> + return is_on;
> +}
> +
> +/**
> + * chamelium_fire_hpd_pulses:
> + * @id: The ID of the port to fire hotplug pulses on
> + * @width_msec: How long each pulse should last
> + * @count: The number of pulses to send
> + *
> + * A convienence function for sending multiple hotplug pulses to the system.
> + * The pulses start at low (e.g. connector is disconnected), and then alternate
> + * from high (e.g. connector is plugged in) to low. This is the equivalent of
> + * repeatedly calling #chamelium_plug and #chamelium_unplug, waiting
> + * @width_msec between each call.
> + *
> + * If @count is even, the last pulse sent will be high, and if it's odd then it
> + * will be low. Resetting the HPD line back to it's previous state, if desired,
> + * is the responsibility of the caller.
> + */
> +void chamelium_fire_hpd_pulses(int port, int width_msec, int count)
> +{
> + xmlrpc_value *pulse_widths = xmlrpc_array_new(&env),
> + *width = xmlrpc_int_new(&env, width_msec), *res;
> + int i;
> +
> + igt_debug("Firing %d HPD pulses with width of %d msec on port %d\n",
> + count, width_msec, port);
> +
> + for (i = 0; i < count; i++)
> + xmlrpc_array_append_item(&env, pulse_widths, width);
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "FireMixedHpdPulses",
> + "(iA)", port, pulse_widths);
> + check_rpc();
> +
> + xmlrpc_DECREF(res);
> + xmlrpc_DECREF(width);
> + xmlrpc_DECREF(pulse_widths);
> +}
> +
> +/**
> + * chamelium_fire_mixed_hpd_pulses:
> + * @id: The ID of the port to fire hotplug pulses on
> + * @...: The length of each pulse in milliseconds, terminated with a %0
> + *
> + * Does the same thing as #chamelium_fire_hpd_pulses, but allows the caller to
> + * specify the length of each individual pulse.
> + */
> +void chamelium_fire_mixed_hpd_pulses(int id, ...)
> +{
> + va_list args;
> + xmlrpc_value *pulse_widths = xmlrpc_array_new(&env), *width, *res;
> + int arg;
> +
> + igt_debug("Firing mixed HPD pulses on port %d\n", id);
> +
> + va_start(args, id);
> + for (arg = va_arg(args, int); arg; arg = va_arg(args, int)) {
> + width = xmlrpc_int_new(&env, arg);
> + xmlrpc_array_append_item(&env, pulse_widths, width);
> + xmlrpc_DECREF(width);
> + }
> + va_end(args);
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "FireMixedHpdPulses",
> + "(iA)", id, pulse_widths);
> + check_rpc();
> + xmlrpc_DECREF(res);
> +
> + xmlrpc_DECREF(pulse_widths);
> +}
> +
> +static void async_rpc_handler(const char *server_url, const char *method_name,
> + xmlrpc_value *param_array, void *user_data,
> + xmlrpc_env *fault, xmlrpc_value *result)
> +{
> + /* We don't care about the responses */
> +}
> +
> +/**
> + * chamelium_async_hpd_pulse_start:
> + * @id: The ID of the port to fire a hotplug pulse on
> + * @high: Whether to fire a high pulse (e.g. simulate a connect), or a low
> + * pulse (e.g. simulate a disconnect)
> + * @delay_secs: How long to wait before sending the HPD pulse.
> + *
> + * Instructs the chamelium to send an hpd pulse after @delay_secs seconds have
> + * passed, without waiting for the chamelium to finish. This is useful for
> + * testing things such as hpd after a suspend/resume cycle, since we can't tell
> + * the chamelium to send a hotplug at the same time that our system is
> + * suspended.
> + *
> + * It is required that the user eventually call
> + * #chamelium_async_hpd_pulse_finish, to clean up the leftover XML-RPC
> + * responses from the chamelium.
> + */
> +void chamelium_async_hpd_pulse_start(int id, bool high, int delay_secs)
> +{
> + xmlrpc_value *pulse_widths = xmlrpc_array_new(&env), *width;
> +
> + /* TODO: Actually implement something in the chameleon server to allow
> + * for delayed actions such as hotplugs. This would work a bit better
> + * and allow us to test suspend/resume on ports without hpd like VGA
> + */
> +
> + igt_debug("Sending HPD pulse (%s) on port %d with %d second delay\n",
> + high ? "high->low" : "low->high", id, delay_secs);
> +
> + /* If we're starting at high, make the first pulse width 0 so we keep
> + * the port connected */
> + if (high) {
> + width = xmlrpc_int_new(&env, 0);
> + xmlrpc_array_append_item(&env, pulse_widths, width);
> + xmlrpc_DECREF(width);
> + }
> +
> + width = xmlrpc_int_new(&env, delay_secs * 1000);
> + xmlrpc_array_append_item(&env, pulse_widths, width);
> + xmlrpc_DECREF(width);
> +
> + xmlrpc_client_call_asynch(chamelium_url, "FireMixedHpdPulses",
> + async_rpc_handler, NULL, "(iA)",
> + id, pulse_widths);
> + xmlrpc_DECREF(pulse_widths);
> +}
> +
> +/**
> + * chamelium_async_hpd_pulse_finish:
> + *
> + * Waits for any asynchronous RPC started by #chamelium_async_hpd_pulse_start
> + * to complete, and then cleans up any leftover responses from the chamelium.
> + * If all of the RPC calls have already completed, this function returns
> + * immediately.
> + */
> +void chamelium_async_hpd_pulse_finish(void)
> +{
> + xmlrpc_client_event_loop_finish_asynch();
> +}
> +
> +/**
> + * chamelium_new_edid:
> + * @edid: The edid blob to upload to the chamelium
> + *
> + * Uploads and registers a new EDID with the chamelium. The EDID will be
> + * destroyed automatically when #chamelium_deinit is called.
> + *
> + * Returns: The ID of the EDID uploaded to the chamelium.
> + */
> +int chamelium_new_edid(const unsigned char *edid)
> +{
> + xmlrpc_value *res;
> + struct chamelium_edid *allocated_edid;
> + int edid_id;
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "CreateEdid",
> + "(6)", edid, EDID_LENGTH);
> + check_rpc();
> +
> + xmlrpc_read_int(&env, res, &edid_id);
> + xmlrpc_DECREF(res);
> +
> + allocated_edid = malloc(sizeof(struct chamelium_edid));
> + igt_assert(allocated_edid);
> +
> + allocated_edid->id = edid_id;
> + if (allocated_edids) {
> + igt_list_insert(&allocated_edids->link, &allocated_edid->link);
> + } else {
> + igt_list_init(&allocated_edid->link);
> + allocated_edids = allocated_edid;
> + }
> +
> + return edid_id;
> +}
> +
> +static void chamelium_destroy_edid(int edid_id)
> +{
> + xmlrpc_value *res;
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "DestroyEdid",
> + "(i)", edid_id);
> + check_rpc();
> +
> + xmlrpc_DECREF(res);
> +}
> +
> +/**
> + * chamelium_port_set_edid:
> + * @id: The ID of the port to set the EDID on
> + * @edid_id: The ID of an EDID on the chamelium created with
> + * #chamelium_new_edid, or 0 to disable the EDID on the port
> + *
> + * Sets a port on the chamelium to use the specified EDID. This does not fire a
> + * hotplug pulse on it's own, and merely changes what EDID the chamelium port
> + * will report to us the next time we probe it. Users will need to reprobe the
> + * connectors themselves if they want to see the EDID reported by the port
> + * change.
> + */
> +void chamelium_port_set_edid(int id, int edid_id)
> +{
> + xmlrpc_value *res;
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "ApplyEdid",
> + "(ii)", id, edid_id);
> + check_rpc();
> +
> + xmlrpc_DECREF(res);
> +}
> +
> +/**
> + * chamelium_port_set_ddc_state:
> + * @id: The ID of the port whose DDC bus we want to modify
> + * @enabled: Whether or not to enable the DDC bus
> + *
> + * This disables the DDC bus (e.g. the i2c line on the connector that gives us
> + * an EDID) of the specified port on the chamelium. This is useful for testing
> + * behavior on legacy connectors such as VGA, where the presence of a DDC bus
> + * is not always guaranteed.
> + */
> +void chamelium_port_set_ddc_state(int port, bool enabled)
> +{
> + xmlrpc_value *res;
> +
> + igt_debug("%sabling DDC bus on port %d\n",
> + enabled ? "En" : "Dis", port);
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "SetDdcState",
> + "(ib)", port, enabled);
> + check_rpc();
> +
> + xmlrpc_DECREF(res);
> +}
> +
> +/**
> + * chamelium_port_get_ddc_state:
> + * @id: The ID of the port whose DDC bus we want to check the status of
> + *
> + * Check whether or not the DDC bus on the specified chamelium port is enabled
> + * or not.
> + *
> + * Returns: True if the DDC bus is enabled, false otherwise.
> + */
> +bool chamelium_port_get_ddc_state(int id)
> +{
> + xmlrpc_value *res;
> + xmlrpc_bool enabled;
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "IsDdcEnabled",
> + "(i)", id);
> + check_rpc();
> +
> + xmlrpc_read_bool(&env, res, &enabled);
> +
> + xmlrpc_DECREF(res);
> + return enabled;
> +}
> +
> +/**
> + * chamelium_port_get_resolution:
> + * @id: The ID of the port whose display resolution we want to check
> + * @x: Where to store the horizontal resolution of the port
> + * @y: Where to store the verical resolution of the port
> + *
> + * Check the current reported display resolution of the specified port on the
> + * chamelium. This information is provided by the chamelium itself, not DRM.
> + * Useful for verifying that we really are scanning out at the resolution we
> + * think we are.
> + */
> +void chamelium_port_get_resolution(int id, int *x, int *y)
> +{
> + xmlrpc_value *res, *res_x, *res_y;
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "DetectResolution",
> + "(i)", id);
> + check_rpc();
> +
> + xmlrpc_array_read_item(&env, res, 0, &res_x);
> + xmlrpc_array_read_item(&env, res, 1, &res_y);
> + xmlrpc_read_int(&env, res_x, x);
> + xmlrpc_read_int(&env, res_y, y);
> +
> + xmlrpc_DECREF(res_x);
> + xmlrpc_DECREF(res_y);
> + xmlrpc_DECREF(res);
> +}
> +
> +/**
> + * chamelium_get_crc_for_area:
> + * @id: The ID of the port from which we want to retrieve the CRC
> + * @x: The X coordinate on the emulated display to start calculating the CRC
> + * from
> + * @y: The Y coordinate on the emulated display to start calculating the CRC
> + * from
> + * @w: The width of the area to fetch the CRC from
> + * @h: The height of the area to fetch the CRC from
> + *
> + * Reads back the pixel CRC for an area on the specified chamelium port. This
> + * is the same as using the CRC readback from a GPU, the main difference being
> + * the data is provided by the chamelium and also allows us to specify a region
> + * of the screen to use as opposed to the entire thing.
> + *
> + * Returns: The CRC read back from the chamelium
> + */
> +unsigned int chamelium_get_crc_for_area(int id, int x, int y, int w, int h)
> +{
> + xmlrpc_value *res;
> + unsigned int crc;
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "ComputePixelChecksum",
> + "(iiiii)", id, x, y, w, h);
> + check_rpc();
> +
> + xmlrpc_read_int(&env, res, (int*)(&crc));
> +
> + xmlrpc_DECREF(res);
> + return crc;
> +}
> +
> +static unsigned int chamelium_get_port_type(int port)
> +{
> + xmlrpc_value *res;
> + const char *port_type_str;
> + unsigned int port_type;
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "GetConnectorType",
> + "(i)", port);
> + check_rpc();
> +
> + xmlrpc_read_string(&env, res, &port_type_str);
> + igt_debug("Port %d is of type '%s'\n", port, port_type_str);
> +
> + if (strcmp(port_type_str, "DP") == 0)
> + port_type = DRM_MODE_CONNECTOR_DisplayPort;
> + else if (strcmp(port_type_str, "HDMI") == 0)
> + port_type = DRM_MODE_CONNECTOR_HDMIA;
> + else if (strcmp(port_type_str, "VGA") == 0)
> + port_type = DRM_MODE_CONNECTOR_VGA;
> + else
> + port_type = DRM_MODE_CONNECTOR_Unknown;
> +
> + free((void*)port_type_str);
> + xmlrpc_DECREF(res);
> +
> + return port_type;
> +}
> +
> +static void chamelium_probe_ports(void)
> +{
> + xmlrpc_value *res, *port_val;
> + struct chamelium_port *port;
> + unsigned int port_type;
> + int id, i, len;
> +
> + /* Figure out what ports are connected, along with their types */
> + res = xmlrpc_client_call(&env, chamelium_url, "ProbeInputs", "()");
> + check_rpc();
> +
> + len = xmlrpc_array_size(&env, res);
> + chamelium_ports = calloc(sizeof(struct chamelium_port), len);
> +
> + igt_assert(chamelium_ports);
> +
> + for (i = 0; i < len; i++) {
> + xmlrpc_array_read_item(&env, res, i, &port_val);
> + xmlrpc_read_int(&env, port_val, &id);
> + xmlrpc_DECREF(port_val);
> +
> + port_type = chamelium_get_port_type(id);
> + if (port_type == DRM_MODE_CONNECTOR_Unknown)
> + continue;
> +
> + port = &chamelium_ports[chamelium_port_count];
> + port->id = id;
> + port->type = port_type;
> + port->original_plugged = chamelium_is_plugged(id);
> + chamelium_port_count++;
> + }
> +
> + chamelium_ports = realloc(chamelium_ports,
> + sizeof(struct chamelium_port) *
> + chamelium_port_count);
> + igt_assert(chamelium_ports);
> +
> + xmlrpc_DECREF(res);
> +}
> +
> +/**
> + * chamelium_reset:
> + *
> + * Resets the chamelium's IO board. As well, this also has the effect of
> + * causing all of the chamelium ports to get set to unplugged
> + */
> +void chamelium_reset(void)
> +{
> + xmlrpc_value *res;
> +
> + igt_debug("Resetting the chamelium\n");
> +
> + res = xmlrpc_client_call(&env, chamelium_url, "Reset", "()");
> + check_rpc();
> +
> + xmlrpc_DECREF(res);
> +}
> +
> +static void chamelium_exit_handler(int sig)
> +{
> + chamelium_deinit();
> +}
> +
> +/**
> + * chamelium_init:
> + *
> + * Sets up a connection with a chamelium, using the url provided in the
> + * CHAMELIUM_HOST enviornment variable. This must be called first before trying
> + * to use the chamelium. When the connection is no longer needed, the user
> + * should call #chamelium_deinit to free the resources used by the connection.
> + *
> + * If we fail to establish a connection with the chamelium, we fail the current
> + * test.
> + */
> +void chamelium_init(void)
> +{
> + chamelium_url = getenv("CHAMELIUM_HOST");
> + igt_assert(chamelium_url != NULL);
> +
> + xmlrpc_env_init(&env);
> +
> + xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, PACKAGE,
> + PACKAGE_VERSION, NULL, 0);
> + igt_fail_on_f(env.fault_occurred,
> + "Failed to init xmlrpc: %s\n",
> + env.fault_string);
> +
> + chamelium_probe_ports();
> + chamelium_reset();
> +
> + igt_install_exit_handler(chamelium_exit_handler);
> +}
> +
> +/**
> + * chamelium_deinit:
> + *
> + * Frees the resources used by a connection to the chamelium that was set up
> + * with #chamelium_init. As well, this function restores the state of the
> + * chamelium like it was before calling #chamelium_init. This function is also
> + * called as an exit handler, so users only need to call manually if they don't
> + * want the chamelium interfering with other tests in the same file.
> + */
> +void chamelium_deinit(void)
> +{
> + int i;
> + struct chamelium_edid *pos, *tmp;
> +
> + if (!chamelium_url)
> + return;
> +
> + /* Restore the original state of all of the chamelium ports */
> + igt_debug("Restoring original state of chamelium\n");
> + chamelium_reset();
> + for (i = 0; i < chamelium_port_count; i++) {
> + if (chamelium_ports[i].original_plugged)
> + chamelium_plug(chamelium_ports[i].id);
> + }
> +
> + /* Destroy any EDIDs we created to make sure we don't leak them */
> + igt_list_for_each_safe(pos, tmp, &allocated_edids->link, link) {
> + chamelium_destroy_edid(pos->id);
> + free(pos);
> + }
> +
> + xmlrpc_client_cleanup();
> + xmlrpc_env_clean(&env);
> +
> + free(chamelium_ports);
> + allocated_edids = NULL;
> + chamelium_url = NULL;
> + chamelium_ports = NULL;
> + chamelium_port_count = 0;
> +}
> +
> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> new file mode 100644
> index 0000000..900615c
> --- /dev/null
> +++ b/lib/igt_chamelium.h
> @@ -0,0 +1,77 @@
> +/*
> + * Copyright © 2016 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors: Lyude Paul <lyude@redhat.com>
> + */
> +
> +#ifndef IGT_CHAMELIUM_H
> +#define IGT_CHAMELIUM_H
> +
> +#include "config.h"
> +#include "igt.h"
> +#include <stdbool.h>
> +
> +/**
> + * chamelium_port:
> + * @type: The DRM connector type of the chamelium port
> + * @id: The ID of the chamelium port
> + */
> +struct chamelium_port {
> + unsigned int type;
> + int id;
> +
> + /* For restoring the original port state after finishing tests */
> + bool original_plugged;
> +};
> +
> +extern int chamelium_port_count;
> +extern struct chamelium_port *chamelium_ports;
> +
> +/**
> + * igt_require_chamelium:
> + *
> + * Checks whether or not the environment variable CHAMELIUM_HOST is non-null,
> + * otherwise skips the current test.
> + */
> +#define igt_require_chamelium() \
> + igt_require(getenv("CHAMELIUM_HOST") != NULL);
> +
> +void chamelium_init(void);
> +void chamelium_deinit(void);
> +void chamelium_reset(void);
> +
> +void chamelium_plug(int id);
> +void chamelium_unplug(int id);
> +bool chamelium_is_plugged(int id);
> +bool chamelium_port_wait_video_input_stable(int id, int timeout_secs);
> +void chamelium_fire_mixed_hpd_pulses(int id, ...);
> +void chamelium_fire_hpd_pulses(int id, int width, int count);
> +void chamelium_async_hpd_pulse_start(int id, bool high, int delay_secs);
> +void chamelium_async_hpd_pulse_finish(void);
> +int chamelium_new_edid(const unsigned char *edid);
> +void chamelium_port_set_edid(int id, int edid_id);
> +bool chamelium_port_get_ddc_state(int id);
> +void chamelium_port_set_ddc_state(int id, bool enabled);
> +void chamelium_port_get_resolution(int id, int *x, int *y);
> +unsigned int chamelium_get_crc_for_area(int id, int x, int y, int w, int h);
> +
> +#endif /* IGT_CHAMELIUM_H */
> diff --git a/lib/igt_kms.c b/lib/igt_kms.c
> index 989704e..7768d7b 100644
> --- a/lib/igt_kms.c
> +++ b/lib/igt_kms.c
> @@ -40,6 +40,10 @@
> #endif
> #include <errno.h>
> #include <time.h>
> +#ifdef HAVE_CHAMELIUM
> +#include <libudev.h>
> +#include <poll.h>
> +#endif
>
> #include <i915_drm.h>
>
> @@ -2760,6 +2764,109 @@ void igt_reset_connectors(void)
> "detect");
> }
>
> +#ifdef HAVE_CHAMELIUM
> +static struct udev_monitor *hotplug_mon;
> +
> +/**
> + * igt_watch_hotplug:
> + *
> + * Begin monitoring udev for hotplug events.
> + */
> +void igt_watch_hotplug(void)
> +{
> + struct udev *udev;
> + int ret, flags, fd;
> +
> + if (hotplug_mon)
> + igt_cleanup_hotplug();
> +
> + udev = udev_new();
> + igt_assert(udev != NULL);
> +
> + hotplug_mon = udev_monitor_new_from_netlink(udev, "udev");
> + igt_assert(hotplug_mon != NULL);
> +
> + ret = udev_monitor_filter_add_match_subsystem_devtype(hotplug_mon,
> + "drm",
> + "drm_minor");
> + igt_assert_eq(ret, 0);
> + ret = udev_monitor_filter_update(hotplug_mon);
> + igt_assert_eq(ret, 0);
> + ret = udev_monitor_enable_receiving(hotplug_mon);
> + igt_assert_eq(ret, 0);
> +
> + /* Set the fd for udev as non blocking */
> + fd = udev_monitor_get_fd(hotplug_mon);
> + flags = fcntl(fd, F_GETFL, 0);
> + igt_assert(flags);
> +
> + flags |= O_NONBLOCK;
> + igt_assert_neq(fcntl(fd, F_SETFL, flags), -1);
> +}
> +
> +/**
> + * igt_hotplug_detected:
> + * @timeout_secs: How long to wait for a hotplug event to occur.
> + *
> + * Assert that a hotplug event was received since we last checked the monitor.
> + */
> +bool igt_hotplug_detected(int timeout_secs)
> +{
> + struct udev_device *dev;
> + const char *hotplug_val;
> + struct pollfd fd = {
> + .fd = udev_monitor_get_fd(hotplug_mon),
> + .events = POLLIN
> + };
> + bool hotplug_received = false;
> +
> + /* Go through all of the events pending on the udev monitor. Once we
> + * receive a hotplug, we continue going through the rest of the events
> + * so that redundant hotplug events don't change the results of future
> + * checks
> + */
> + while (!hotplug_received && poll(&fd, 1, timeout_secs * 1000)) {
> + dev = udev_monitor_receive_device(hotplug_mon);
> +
> + hotplug_val = udev_device_get_property_value(dev, "HOTPLUG");
> + if (hotplug_val && atoi(hotplug_val) == 1)
> + hotplug_received = true;
> +
> + udev_device_unref(dev);
> + }
> +
> + return hotplug_received;
> +}
> +
> +/**
> + * igt_flush_hotplugs:
> + * @mon: A udev monitor created by #igt_watch_hotplug
> + *
> + * Get rid of any pending hotplug events waiting on the udev monitor
> + */
> +void igt_flush_hotplugs(void)
> +{
> + struct udev_device *dev;
> +
> + while ((dev = udev_monitor_receive_device(hotplug_mon)))
> + udev_device_unref(dev);
> +}
> +
> +/**
> + * igt_cleanup_hotplug:
> + *
> + * Cleanup the resources allocated by #igt_watch_hotplug
> + */
> +void igt_cleanup_hotplug(void)
> +{
> + struct udev *udev = udev_monitor_get_udev(hotplug_mon);
> +
> + udev_monitor_unref(hotplug_mon);
> + hotplug_mon = NULL;
> + udev_unref(udev);
> +}
> +#endif
> +
> /**
> * kmstest_get_vbl_flag:
> * @pipe_id: Pipe to convert to flag representation.
> diff --git a/lib/igt_kms.h b/lib/igt_kms.h
> index 6422adc..d0b67e0 100644
> --- a/lib/igt_kms.h
> +++ b/lib/igt_kms.h
> @@ -31,6 +31,9 @@
> #include <stdbool.h>
> #include <stdint.h>
> #include <stddef.h>
> +#ifdef HAVE_CHAMELIUM
> +#include <libudev.h>
> +#endif
>
> #include <xf86drmMode.h>
>
> @@ -333,6 +336,7 @@ igt_plane_t *igt_output_get_plane(igt_output_t *output, enum igt_plane plane);
> bool igt_pipe_get_property(igt_pipe_t *pipe, const char *name,
> uint32_t *prop_id, uint64_t *value,
> drmModePropertyPtr *prop);
> +void igt_output_get_edid(igt_output_t *output, unsigned char *edid_out);
>
> static inline bool igt_plane_supports_rotation(igt_plane_t *plane)
> {
> @@ -478,6 +482,13 @@ uint32_t kmstest_get_vbl_flag(uint32_t pipe_id);
> #define EDID_LENGTH 128
> const unsigned char* igt_kms_get_base_edid(void);
> const unsigned char* igt_kms_get_alt_edid(void);
> -
> +bool igt_compare_output_edid(igt_output_t *output, const unsigned char *edid);
> +
> +#ifdef HAVE_CHAMELIUM
> +void igt_watch_hotplug(void);
> +bool igt_hotplug_detected(int timeout_secs);
> +void igt_flush_hotplugs(void);
> +void igt_cleanup_hotplug(void);
> +#endif
>
> #endif /* __IGT_KMS_H__ */
> diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh
> index 97ba9e5..6539bf9 100755
> --- a/scripts/run-tests.sh
> +++ b/scripts/run-tests.sh
> @@ -122,10 +122,10 @@ if [ ! -x "$PIGLIT" ]; then
> fi
>
> if [ "x$RESUME" != "x" ]; then
> - sudo IGT_TEST_ROOT="$IGT_TEST_ROOT" "$PIGLIT" resume "$RESULTS" $NORETRY
> + sudo IGT_TEST_ROOT="$IGT_TEST_ROOT" CHAMELIUM_HOST="$CHAMELIUM_HOST" "$PIGLIT" resume "$RESULTS" $NORETRY
> else
> mkdir -p "$RESULTS"
> - sudo IGT_TEST_ROOT="$IGT_TEST_ROOT" "$PIGLIT" run igt -o "$RESULTS" -s $VERBOSE $EXCLUDE $FILTER
> + sudo IGT_TEST_ROOT="$IGT_TEST_ROOT" CHAMELIUM_HOST="$CHAMELIUM_HOST" "$PIGLIT" run igt -o "$RESULTS" -s $VERBOSE $EXCLUDE $FILTER
> fi
>
> if [ "$SUMMARY" == "html" ]; then
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index a408126..06a8e6b 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -63,7 +63,7 @@ AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) -Wno-unused-result $(DEBUG_CFLAGS)\
> $(LIBUNWIND_CFLAGS) $(WERROR_CFLAGS) \
> $(NULL)
>
> -LDADD = ../lib/libintel_tools.la $(GLIB_LIBS)
> +LDADD = ../lib/libintel_tools.la $(GLIB_LIBS) $(XMLRPC_LIBS)
>
> AM_CFLAGS += $(CAIRO_CFLAGS) $(LIBUDEV_CFLAGS) $(GLIB_CFLAGS)
> AM_LDFLAGS = -Wl,--as-needed
> @@ -119,5 +119,8 @@ vc4_wait_bo_CFLAGS = $(AM_CFLAGS) $(DRM_VC4_CFLAGS)
> vc4_wait_bo_LDADD = $(LDADD) $(DRM_VC4_LIBS)
> vc4_wait_seqno_CFLAGS = $(AM_CFLAGS) $(DRM_VC4_CFLAGS)
> vc4_wait_seqno_LDADD = $(LDADD) $(DRM_VC4_LIBS)
> +
> +chamelium_CFLAGS = $(AM_CFLAGS) $(XMLRPC_CFLAGS) $(UDEV_CFLAGS)
> +chamelium_LDADD = $(LDADD) $(XMLRPC_LIBS) $(UDEV_LIBS)
> endif
>
> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
> index 6d081c3..3e01852 100644
> --- a/tests/Makefile.sources
> +++ b/tests/Makefile.sources
> @@ -131,6 +131,7 @@ TESTS_progs_M = \
> template \
> vgem_basic \
> vgem_slow \
> + chamelium \
> $(NULL)
>
> TESTS_progs_XM = \
> diff --git a/tests/chamelium.c b/tests/chamelium.c
> new file mode 100644
> index 0000000..769cfdc
> --- /dev/null
> +++ b/tests/chamelium.c
> @@ -0,0 +1,549 @@
> +/*
> + * Copyright © 2016 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Lyude Paul <lyude@redhat.com>
> + */
> +
> +#include "config.h"
> +#include "igt.h"
> +
> +#include <fcntl.h>
> +#include <string.h>
> +
> +struct connector_info {
> + int id;
> + unsigned int type;
> +};
> +
> +typedef struct {
> + int drm_fd;
> + struct connector_info *connectors;
> + int connector_count;
> +} data_t;
> +
> +#define HOTPLUG_TIMEOUT 30 /* seconds */
> +
> +/*
> + * Since we can't get an exact mapping of which chamelium ports are connected
> + * to each of the DUT's ports, we have to figure out whether or not the status
> + * of a port on the chamelium has changed by counting the number of connectors
> + * with the connector type and status we want, and then comparing the values
> + * from before hotplugging and after
> + */
> +static void
> +reprobe_connectors(data_t *data, unsigned int type)
> +{
> + drmModeConnector *connector;
> + int i;
> +
> + igt_debug("Reprobing %s connectors...\n",
> + kmstest_connector_type_str(type));
> +
> + for (i = 0; i < data->connector_count; i++) {
> + if (data->connectors[i].type != type)
> + continue;
> +
> + connector = drmModeGetConnector(data->drm_fd,
> + data->connectors[i].id);
> + igt_assert(connector);
> +
> + drmModeFreeConnector(connector);
> + }
> +}
> +
> +static void
> +reset_chamelium_state(data_t *data)
> +{
> + chamelium_reset();
> + reprobe_connectors(data, DRM_MODE_CONNECTOR_DisplayPort);
> + reprobe_connectors(data, DRM_MODE_CONNECTOR_HDMIA);
> + reprobe_connectors(data, DRM_MODE_CONNECTOR_VGA);
> +}
> +
> +static int
> +connector_status_count(data_t *data, unsigned int type, unsigned int status)
> +{
> + struct connector_info *info;
> + drmModeConnector *connector;
> + int count = 0;
> +
> + for (int i = 0; i < data->connector_count; i++) {
> + info = &data->connectors[i];
> + if (info->type != type)
> + continue;
> +
> + connector = drmModeGetConnectorCurrent(data->drm_fd, info->id);
> + igt_assert(connector);
> +
> + if (connector->connection == status)
> + count++;
> +
> + drmModeFreeConnector(connector);
> + }
> +
> + return count;
> +}
> +
> +static void
> +require_connector_present(data_t *data, unsigned int type)
> +{
> + int i;
> + bool found = false;
> +
> + for (i = 0; i < data->connector_count && !found; i++) {
> + if (data->connectors[i].type == type)
> + found = true;
> + }
> +
> + igt_require_f(found, "No port of type %s was found on the system\n",
> + kmstest_connector_type_str(type));
> +
> + for (i = 0, found = false; i < chamelium_port_count && !found; i++) {
> + if (chamelium_ports[i].type == type)
> + found = true;
> + }
> +
> + igt_require_f(found, "No connected port of type %s was found on the chamelium\n",
> + kmstest_connector_type_str(type));
> +}
> +
> +static drmModeConnector *
> +find_connected(data_t *data, unsigned int type)
> +{
> + drmModeConnector *connector;
> + int i;
> +
> + for (i = 0; i < data->connector_count; i++) {
> + if (data->connectors[i].type != type)
> + continue;
> +
> + connector = drmModeGetConnector(data->drm_fd,
> + data->connectors[i].id);
> + igt_assert(connector);
> +
> + if (connector->connection == DRM_MODE_CONNECTED)
> + return connector;
> +
> + drmModeFreeConnector(connector);
> + }
> +
> + return NULL;
> +}
> +
> +/*
> + * Skips the test if we find any connectors with a matching type connected.
> + * This is necessary when we need to identify which port on the machine is
> + * connected to which port on the chamelium, since any other ports that are
> + * connected to other displays could cause us to choose the wrong port.
> + *
> + * This also has the effect of reprobing all of the connected ports.
> + */
> +static void
> +skip_on_any_connected(data_t *data, unsigned int type)
> +{
> + drmModeConnector *connector;
> +
> + connector = find_connected(data, type);
> + if (connector)
> + drmModeFreeConnector(connector);
> +
> + igt_skip_on(connector);
> +}
> +
> +static void
> +test_basic_hotplug(data_t *data, struct chamelium_port *port)
> +{
> + int before, after;
> + int i;
> +
> + reset_chamelium_state(data);
> + igt_watch_hotplug();
> +
> + for (i = 0; i < 15; i++) {
> + igt_flush_hotplugs();
> +
> + /* Check if we get a sysfs hotplug event */
> + before = connector_status_count(data, port->type,
> + DRM_MODE_CONNECTED);
> + chamelium_plug(port->id);
> + igt_assert(igt_hotplug_detected(HOTPLUG_TIMEOUT));
> +
> + /* Now we should have one additional port connected */
> + reprobe_connectors(data, port->type);
> + after = connector_status_count(data, port->type,
> + DRM_MODE_CONNECTED);
> + igt_assert_lt(before, after);
> +
> + igt_flush_hotplugs();
> +
> + /* Now check if we get a hotplug from disconnection */
> + before = connector_status_count(data, port->type,
> + DRM_MODE_DISCONNECTED);
> + chamelium_unplug(port->id);
> + igt_assert(igt_hotplug_detected(HOTPLUG_TIMEOUT));
> +
> + /* And make sure we now have one more disconnected port */
> + reprobe_connectors(data, port->type);
> + after = connector_status_count(data, port->type,
> + DRM_MODE_DISCONNECTED);
> + igt_assert_lt(before, after);
> +
> + /* Sleep so we don't accidentally cause an hpd storm */
> + sleep(1);
> + }
> +}
> +
> +static void
> +test_edid_read(data_t *data, struct chamelium_port *port,
> + int edid_id, const unsigned char *edid)
> +{
> + drmModeConnector *connector;
> + drmModeObjectProperties *props;
> + drmModePropertyBlobPtr edid_blob = NULL;
> + bool edid_found = false;
> + int i;
> +
> + reset_chamelium_state(data);
> + skip_on_any_connected(data, port->type);
> +
> + chamelium_port_set_edid(port->id, edid_id);
> + chamelium_plug(port->id);
> + sleep(1);
> + igt_assert(connector = find_connected(data, port->type));
> +
> + props = drmModeObjectGetProperties(data->drm_fd,
> + connector->connector_id,
> + DRM_MODE_OBJECT_CONNECTOR);
> + igt_assert(props);
> +
> + /* Get the edid */
> + for (i = 0; i < props->count_props && !edid_blob; i++) {
> + drmModePropertyPtr prop =
> + drmModeGetProperty(data->drm_fd,
> + props->props[i]);
> +
> + igt_assert(prop);
> +
> + if (strcmp(prop->name, "EDID") == 0) {
> + edid_blob = drmModeGetPropertyBlob(
> + data->drm_fd, props->prop_values[i]);
> + }
> +
> + drmModeFreeProperty(prop);
> + }
> +
> + /* And make sure it matches to what we expected */
> + edid_found = memcmp(edid, edid_blob->data, EDID_LENGTH) == 0;
> +
> + drmModeFreePropertyBlob(edid_blob);
> + drmModeFreeObjectProperties(props);
> + drmModeFreeConnector(connector);
> +
> + igt_assert(edid_found);
> +}
> +
> +static void
> +test_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
> + enum igt_suspend_state state,
> + enum igt_suspend_test test)
> +{
> + int before, after;
> + int delay = 7;
> +
> + igt_skip_without_suspend_support(state, test);
> + reset_chamelium_state(data);
> + igt_watch_hotplug();
> +
> + igt_set_autoresume_delay(15);
> +
> + /* Make sure we notice new connectors after resuming */
> + before = connector_status_count(data, port->type, DRM_MODE_CONNECTED);
> + sleep(1);
> + igt_flush_hotplugs();
> +
> + chamelium_async_hpd_pulse_start(port->id, false, delay);
> + igt_system_suspend_autoresume(state, test);
> + chamelium_async_hpd_pulse_finish();
> +
> + igt_assert(igt_hotplug_detected(HOTPLUG_TIMEOUT));
> +
> + reprobe_connectors(data, port->type);
> + after = connector_status_count(data, port->type, DRM_MODE_CONNECTED);
> + igt_assert_lt(before, after);
> +
> + igt_flush_hotplugs();
> +
> + /* Now make sure we notice disconnected connectors after resuming */
> + before = connector_status_count(data, port->type, DRM_MODE_DISCONNECTED);
> +
> + chamelium_async_hpd_pulse_start(port->id, true, delay);
> + igt_system_suspend_autoresume(state, test);
> + chamelium_async_hpd_pulse_finish();
> +
> + igt_assert(igt_hotplug_detected(HOTPLUG_TIMEOUT));
> +
> + reprobe_connectors(data, port->type);
> + after = connector_status_count(data, port->type, DRM_MODE_DISCONNECTED);
> + igt_assert_lt(before, after);
> +}
> +
> +static void
> +test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
> + enum igt_suspend_state state,
> + enum igt_suspend_test test,
> + int edid_id,
> + int alt_edid_id)
> +{
> + igt_skip_without_suspend_support(state, test);
> + reset_chamelium_state(data);
> + igt_watch_hotplug();
> +
> + /* First plug in the port */
> + chamelium_port_set_edid(port->id, edid_id);
> + chamelium_plug(port->id);
> +
> + reprobe_connectors(data, port->type);
> + sleep(1);
> + igt_flush_hotplugs();
> +
> + /*
> + * Change the edid before we suspend. On resume, the machine should
> + * notice the EDID change and fire a hotplug event.
> + */
> + chamelium_port_set_edid(port->id, alt_edid_id);
> +
> + igt_system_suspend_autoresume(state, test);
> + igt_assert(igt_hotplug_detected(HOTPLUG_TIMEOUT));
> +}
> +
> +static void
> +test_display(data_t *data, struct chamelium_port *port)
> +{
> + igt_display_t display;
> + igt_output_t *output;
> + igt_plane_t *primary;
> + struct igt_fb fb;
> + drmModeRes *res;
> + drmModeModeInfo *mode;
> + int connector_found = false, fb_id;
> +
> + chamelium_plug(port->id);
> + igt_assert(res = drmModeGetResources(data->drm_fd));
> + kmstest_unset_all_crtcs(data->drm_fd, res);
> +
> + igt_display_init(&display, data->drm_fd);
> +
> + /* Find the active connector */
> + for_each_connected_output(&display, output) {
> + drmModeConnector *connector = output->config.connector;
> +
> + if (connector && connector->connector_type == port->type &&
> + connector->connection == DRM_MODE_CONNECTED) {
> + connector_found = true;
> + break;
> + }
> + }
> + igt_assert(connector_found);
> +
> + /* Setup the display */
> + igt_output_set_pipe(output, PIPE_A);
> + mode = igt_output_get_mode(output);
> + primary = igt_output_get_plane(output, IGT_PLANE_PRIMARY);
> + igt_assert(primary);
> +
> + fb_id = igt_create_pattern_fb(data->drm_fd,
> + mode->hdisplay,
> + mode->vdisplay,
> + DRM_FORMAT_XRGB8888,
> + LOCAL_DRM_FORMAT_MOD_NONE,
> + &fb);
> + igt_assert(fb_id > 0);
> + igt_plane_set_fb(primary, &fb);
> +
> + igt_display_commit(&display);
> +
> + igt_assert(chamelium_port_wait_video_input_stable(port->id,
> + HOTPLUG_TIMEOUT));
> +
> + drmModeFreeResources(res);
> + igt_display_fini(&display);
> +}
> +
> +static void
> +test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
> +{
> + reset_chamelium_state(data);
> + igt_watch_hotplug();
> +
> + /* Disable the DDC on the connector and make sure we still get a
> + * hotplug
> + */
> + chamelium_port_set_ddc_state(port->id, false);
> + chamelium_plug(port->id);
> +
> + igt_assert(igt_hotplug_detected(HOTPLUG_TIMEOUT));
> +}
> +
> +static void
> +cache_connector_info(data_t *data)
> +{
> + drmModeRes *res = drmModeGetResources(data->drm_fd);
> + drmModeConnector *connector;
> + int i;
> +
> + igt_assert(res);
> +
> + data->connector_count = res->count_connectors;
> + data->connectors = calloc(sizeof(struct connector_info),
> + res->count_connectors);
> + igt_assert(data->connectors);
> +
> + for (i = 0; i < res->count_connectors; i++) {
> + connector = drmModeGetConnectorCurrent(data->drm_fd,
> + res->connectors[i]);
> + igt_assert(connector);
> +
> + data->connectors[i].id = connector->connector_id;
> + data->connectors[i].type = connector->connector_type;
> +
> + drmModeFreeConnector(connector);
> + }
> +
> + drmModeFreeResources(res);
> +}
> +
> +#define for_each_port(p, port) \
> + for (p = 0, port = &chamelium_ports[p]; \
> + p < chamelium_port_count; \
> + p++, port = &chamelium_ports[p]) \
> +
> +#define connector_subtest(name__, type__) \
> + igt_subtest(name__) \
> + for_each_port(p, port) \
> + if (port->type == DRM_MODE_CONNECTOR_ ## type__)
> +
> +#define define_common_connector_tests(type_str__, type__) \
> + connector_subtest(type_str__ "-hpd", type__) \
> + test_basic_hotplug(&data, port); \
> + \
> + connector_subtest(type_str__ "-edid-read", type__) { \
> + test_edid_read(&data, port, edid_id, \
> + igt_kms_get_base_edid()); \
> + test_edid_read(&data, port, alt_edid_id, \
> + igt_kms_get_alt_edid()); \
> + } \
> + \
> + connector_subtest(type_str__ "-hpd-after-suspend", type__) \
> + test_suspend_resume_hpd(&data, port, \
> + SUSPEND_STATE_MEM, \
> + SUSPEND_TEST_NONE); \
> + \
> + connector_subtest(type_str__ "-hpd-after-hibernate", type__) \
> + test_suspend_resume_hpd(&data, port, \
> + SUSPEND_STATE_DISK, \
> + SUSPEND_TEST_DEVICES); \
> + \
> + connector_subtest(type_str__ "-edid-change-during-suspend", type__) \
> + test_suspend_resume_edid_change(&data, port, \
> + SUSPEND_STATE_MEM, \
> + SUSPEND_TEST_NONE, \
> + edid_id, alt_edid_id); \
> + \
> + connector_subtest(type_str__ "-edid-change-during-hibernate", type__) \
> + test_suspend_resume_edid_change(&data, port, \
> + SUSPEND_STATE_DISK, \
> + SUSPEND_TEST_DEVICES, \
> + edid_id, alt_edid_id); \
> + \
> + connector_subtest(type_str__ "-display", type__) \
> + test_display(&data, port);
> +
> +static data_t data;
> +
> +igt_main
> +{
> + struct chamelium_port *port;
> + int edid_id, alt_edid_id, p;
> +
> + igt_fixture {
> + igt_require_chamelium();
> + igt_skip_on_simulation();
> +
> + chamelium_init();
> +
> + edid_id = chamelium_new_edid(igt_kms_get_base_edid());
> + alt_edid_id = chamelium_new_edid(igt_kms_get_alt_edid());
> +
> + data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
> + cache_connector_info(&data);
> +
> + /* So fbcon doesn't try to reprobe things itself */
> + kmstest_set_vt_graphics_mode();
> + }
> +
> + igt_subtest_group {
> + igt_fixture {
> + require_connector_present(
> + &data, DRM_MODE_CONNECTOR_DisplayPort);
> + }
> +
> + define_common_connector_tests("dp", DisplayPort);
> + }
> +
> + igt_subtest_group {
> + igt_fixture {
> + require_connector_present(
> + &data, DRM_MODE_CONNECTOR_HDMIA);
> + }
> +
> + define_common_connector_tests("hdmi", HDMIA);
> + }
> +
> + igt_subtest_group {
> + igt_fixture {
> + require_connector_present(
> + &data, DRM_MODE_CONNECTOR_VGA);
> + }
> +
> + connector_subtest("vga-hpd", VGA)
> + test_basic_hotplug(&data, port);
> +
> + connector_subtest("vga-edid-read", VGA) {
> + test_edid_read(&data, port, edid_id,
> + igt_kms_get_base_edid());
> + test_edid_read(&data, port, alt_edid_id,
> + igt_kms_get_alt_edid());
> + }
> +
> + /* FIXME: Right now there isn't a way to do any sort of delayed
> + * psuedo-hotplug with VGA, so testing detection after a
> + * suspend/resume cycle isn't possible yet
> + */
> +
> + connector_subtest("vga-hpd-without-ddc", VGA)
> + test_hpd_without_ddc(&data, port);
> +
> + connector_subtest("vga-display", VGA)
> + test_display(&data, port);
> + }
> +}
> --
> 2.7.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH 2/2] Documentation: DT: Add bmi160 imu binding
From: Marcin Niestroj @ 2016-11-09 15:18 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring,
Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <e46a4b5e-a347-f268-80f4-0ee1edc77aac-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On 06.11.2016 13:41, Jonathan Cameron wrote:
> On 03/11/16 11:25, Marcin Niestroj wrote:
>> This adds documentation for Bosch BMI160 Inertial Measurement Unit
>> device-tree bindings.
>>
>> Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org>
> Unless I missed it in the previous patch we should also have of tables
> added to the i2c and spi files (which is why the various tests haven't
> been screaming at me that this device doesn't have documented bindings).
Ok, I will add them.
>
> Otherwise, the use of interrupt names to indicate which pin on the chip
> is a little unusual (if you cribbed this from somewhere I've forgotten
> about then do say so!), so will want a devicetree bindings maintainer
> input on this.
I have used interrupt names similar as in other driver. Please see [1]
for it's DT documentation and [2] for implementation.
[1] Documentation/devicetree/bindings/iio/accel/mma8452.txt
[2] drivers/iio/accel/mma8452.c
>
> Thanks,
>
> Jonathan
>> ---
>> .../devicetree/bindings/iio/imu/bmi160.txt | 34 ++++++++++++++++++++++
>> 1 file changed, 34 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/iio/imu/bmi160.txt
>>
>> diff --git a/Documentation/devicetree/bindings/iio/imu/bmi160.txt b/Documentation/devicetree/bindings/iio/imu/bmi160.txt
>> new file mode 100644
>> index 0000000..b02ef3e
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/imu/bmi160.txt
>> @@ -0,0 +1,34 @@
>> +Bosch BMI160 - Inertial Measurement Unit with Accelerometer, Gyroscope
>> +and externally connectable Magnetometer
>> +
>> +https://www.bosch-sensortec.com/bst/products/all_products/bmi160
>> +
>> +Required properties:
>> + - compatible : should be "bosch,bmi160"
>> + - reg : the I2C address or SPI chip select number of the sensor
>> + - spi-max-frequency : set maximum clock frequency (only for SPI)
>> +
>> +Optional properties:
>> + - interrupt-parent : should be the phandle of the interrupt controller
>> + - interrupts : interrupt mapping for GPIO IRQ, must be IRQ_TYPE_LEVEL_LOW
>> + - interrupt-names : set to "INT2" if using INT2 pin
>> +
>> +Examples:
>> +
>> +bmi160@68 {
>> + compatible = "bosch,bmi160";
>> + reg = <0x68>;
>> +
>> + interrupt-parent = <&gpio4>;
>> + interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
>> +};
>> +
>> +bmi160@0 {
>> + compatible = "bosch,bmi160";
>> + reg = <0>;
>> + spi-max-frequency = <10000000>;
>> +
>> + interrupt-parent = <&gpio2>;
>> + interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
>> + interrupt-names = "INT2";
>> +};
>>
>
--
Marcin Niestroj
^ permalink raw reply
* Re: [PATCH 2/2] Documentation: DT: Add bmi160 imu binding
From: Marcin Niestroj @ 2016-11-09 15:18 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring,
Mark Rutland, linux-iio, devicetree
In-Reply-To: <e46a4b5e-a347-f268-80f4-0ee1edc77aac@kernel.org>
On 06.11.2016 13:41, Jonathan Cameron wrote:
> On 03/11/16 11:25, Marcin Niestroj wrote:
>> This adds documentation for Bosch BMI160 Inertial Measurement Unit
>> device-tree bindings.
>>
>> Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
> Unless I missed it in the previous patch we should also have of tables
> added to the i2c and spi files (which is why the various tests haven't
> been screaming at me that this device doesn't have documented bindings).
Ok, I will add them.
>
> Otherwise, the use of interrupt names to indicate which pin on the chip
> is a little unusual (if you cribbed this from somewhere I've forgotten
> about then do say so!), so will want a devicetree bindings maintainer
> input on this.
I have used interrupt names similar as in other driver. Please see [1]
for it's DT documentation and [2] for implementation.
[1] Documentation/devicetree/bindings/iio/accel/mma8452.txt
[2] drivers/iio/accel/mma8452.c
>
> Thanks,
>
> Jonathan
>> ---
>> .../devicetree/bindings/iio/imu/bmi160.txt | 34 ++++++++++++++++++++++
>> 1 file changed, 34 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/iio/imu/bmi160.txt
>>
>> diff --git a/Documentation/devicetree/bindings/iio/imu/bmi160.txt b/Documentation/devicetree/bindings/iio/imu/bmi160.txt
>> new file mode 100644
>> index 0000000..b02ef3e
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/imu/bmi160.txt
>> @@ -0,0 +1,34 @@
>> +Bosch BMI160 - Inertial Measurement Unit with Accelerometer, Gyroscope
>> +and externally connectable Magnetometer
>> +
>> +https://www.bosch-sensortec.com/bst/products/all_products/bmi160
>> +
>> +Required properties:
>> + - compatible : should be "bosch,bmi160"
>> + - reg : the I2C address or SPI chip select number of the sensor
>> + - spi-max-frequency : set maximum clock frequency (only for SPI)
>> +
>> +Optional properties:
>> + - interrupt-parent : should be the phandle of the interrupt controller
>> + - interrupts : interrupt mapping for GPIO IRQ, must be IRQ_TYPE_LEVEL_LOW
>> + - interrupt-names : set to "INT2" if using INT2 pin
>> +
>> +Examples:
>> +
>> +bmi160@68 {
>> + compatible = "bosch,bmi160";
>> + reg = <0x68>;
>> +
>> + interrupt-parent = <&gpio4>;
>> + interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
>> +};
>> +
>> +bmi160@0 {
>> + compatible = "bosch,bmi160";
>> + reg = <0>;
>> + spi-max-frequency = <10000000>;
>> +
>> + interrupt-parent = <&gpio2>;
>> + interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
>> + interrupt-names = "INT2";
>> +};
>>
>
--
Marcin Niestroj
^ permalink raw reply
* [PATCH] fpga zynq: Check the bitstream for validity
From: Matthias Brugger @ 2016-11-09 15:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <609bc971-bb6d-8cd2-8e64-23c0082a6216@topic.nl>
On 11/09/2016 03:21 PM, Mike Looijmans wrote:
> On 08-11-16 01:05, Jason Gunthorpe wrote:
>> On Tue, Nov 01, 2016 at 06:48:42PM +0100, Michal Simek wrote:
>>> On 1.11.2016 16:33, Jason Gunthorpe wrote:
>>>> On Tue, Nov 01, 2016 at 07:39:22AM +0100, Michal Simek wrote:
>>>>
>>>>> Regarding BIT and BIN format. This support is in vivado for a long
>>>>> time
>>>>> and it is up2you what you want to support. We have removed that BIT
>>>>> support and not doing any swap by saying only BIN format is supported.
>>>>
>>>> BIN is not supported, it needs a swap as well.
>>>>
>>>> Moritz has it right, you have to use vivado to create a PROM image
>>>> to be
>>>> compatible with the driver.
>>>
>>> hm than that's bad.
>>
>> IMHO, Xilinx made an error with Zynq DevC, the DMA does not accept a
>> memory image that is output by the usual Xilinx tools. It should have
>> accepted a byte swapped input.
>>
>> I think Moritz is right, the fpgamgr *should not* alter the bitstream
>> in any way. This is important for future work to make the DMA do
>> gather and avoid the really bad high-order allocation.
>>
>> So users will have to provide byte swapped .bin files - the vivado
>> write_cfgmem command will produce them - this all needs to be
>> documented.
>>
>> Also, I think Punnaiah (?) was telling me that bitstream encryption
>> does not work - DevC must be told the bitstream is encrypted.
>> That seems like something that needs work at the fpgamgr level - and
>> maybe this driver should auto-detect encryption by looking at the
>> bitfile (as is typical for Xilinx programming)
>>
>
> I think the basic idea behind the commit is flawed to begin with and the
> patch should be discarded completely. The same discussion was done for
> the Xilinx FPGA manager driver, which resulted in the decision that the
> tooling should create a proper file. This driver should either become
> obsolete or at least move into the same direction as the FPGA manager
> rather than away from that.
>
> Besides political arguments, there's a more pressing technical argument
> against this theck as well: The whole check is pointless since the hardware
> itself already verifies the validity of the stream. Sending bitstreams
> intended for other devices has no effect at all. Even sending random
> data doesn't have any effect, the hardware will discard it. There's no
> reason to waste CPU cycles duplicating this check in software.
>
I get your point. Especially looping to the whole file to find the sync
header can take a while, especially if the file is big and the sync
header is not present.
So I think the whole idea behind this patch is to provide feedback to
the user about what went wrong when trying to update the FPGA. Is there
a way to get this information from the hardware which discards the update?
Regards,
Matthias
^ permalink raw reply
* Re: [PATCH v2] fs/nfsd/nfs4callback: Remove deprecated create_singlethread_workqueue
From: Jeff Layton @ 2016-11-09 15:17 UTC (permalink / raw)
To: Trond Myklebust, bfields@fieldses.org, tj@kernel.org
Cc: bhaktipriya96@gmail.com, linux-kernel@vger.kernel.org,
linux-nfs@vger.kernel.org
In-Reply-To: <1478704129.15658.1.camel@primarydata.com>
On Wed, 2016-11-09 at 15:08 +0000, Trond Myklebust wrote:
> On Wed, 2016-11-09 at 08:18 -0500, Jeff Layton wrote:
> >
> > On Tue, 2016-11-08 at 20:27 -0500, J. Bruce Fields wrote:
> > >
> > >
> > > On Tue, Nov 08, 2016 at 05:52:21PM -0500, Tejun Heo wrote:
> > > >
> > > >
> > > >
> > > > Hello, Bruce.
> > > >
> > > > On Tue, Nov 08, 2016 at 04:39:11PM -0500, J. Bruce Fields wrote:
> > > > >
> > > > >
> > > > >
> > > > > Apologies, just cleaning out old mail and finding some I should
> > > > > have
> > > > > responded to long ago:
> > > > >
> > > > > On Wed, Aug 31, 2016 at 02:23:48AM +0530, Bhaktipriya Shridhar
> > > > > wrote:
> > > > > >
> > > > > >
> > > > > >
> > > > > > The workqueue "callback_wq" queues a single work item &cb-
> > > > > > >
> > > > > > > cb_work per
> > > > > > nfsd4_callback instance and thus, it doesn't require
> > > > > > execution ordering.
> > > > >
> > > > > What's "execution ordering"?
> > > > >
> >
> > AIUI, it means that jobs are always run in the order queued and are
> > serialized.
> >
> > >
> > >
> > > >
> > > >
> > > > >
> > > > >
> > > > > We definitely do depend on the fact that at most one of these
> > > > > is running
> > > > > at a time.
> > > >
> >
> > We do?
> >
> > >
> > >
> > > >
> > > >
> > > > If there can be multiple cb's and thus cb->cb_work's per
> > > > callback_wq,
> > > > it'd need explicit ordering. Is that the case?
> > >
> >
> > These are basically client RPC tasks, and the cb_work just handles
> > the
> > submission into the client RPC state machine. Just because we're
> > running
> > several callbacks at the same time doesn't mean that they need to be
> > strictly ordered. The client state machine can certainly handle
> > running
> > these in parallel.
> >
> > >
> > >
> > > Yes, there can be multiple cb_work's.
> > >
> >
> > Yes, but each is effectively a separate work unit. I see no reason
> > why
> > we'd need to order them at all.
> >
>
> There needs to be serialisation at the session level (i.e. the
> callbacks have to respect the slot limits set by the client) however
> there shouldn’t be a need for serialisation at the RPC level.
>
> Cheers
> Trond
Yes, that all happens in nfsd4_cb_prepare, which is the rpc_call_prepare
operation for the callback. That gets run by the rpc state machine in
the context of the rpciod workqueues. None of that happens in the
context of the cb_work here.
If you have a look at nfsd4_run_cb_work, you can see that it just does a
cb_ops->prepare and then submits it to the client rpc engine with
rpc_call_async. None of that should require singlethreaded workqueue
semantics.
--
Jeff Layton <jlayton@poochiereds.net>
^ permalink raw reply
* Re: [GIT PULL] kvm/page_track changes for i915 KVMGT
From: Paolo Bonzini @ 2016-11-09 15:16 UTC (permalink / raw)
To: linux-kernel, kvm, rkrcmar, intel-gfx, Jike Song, Jani Nikula,
Zhenyu Wang
In-Reply-To: <20161109151545.w2fhldk6o7illb2g@phenom.ffwll.local>
On 09/11/2016 16:15, Daniel Vetter wrote:
> On Wed, Nov 09, 2016 at 03:25:19PM +0100, Paolo Bonzini wrote:
>> Daniel,
>>
>> The following changes since commit d9092f52d7e61dd1557f2db2400ddb430e85937e:
>>
>> kvm: x86: Check memopp before dereference (CVE-2016-8630) (2016-11-02 21:31:53 +0100)
>>
>> are available in the git repository at:
>>
>> git://git.kernel.org/pub/scm/virt/kvm/kvm.git tags/for-kvmgt
>>
>> for you to fetch changes up to 871b7ef2a1850d0b435c8b324bf4a5d391adde3f:
>>
>> kvm/page_track: export symbols for external usage (2016-11-04 12:13:20 +0100)
>
> Pulled into drm-intel, thanks. Please also pull this into your kvm-next
> tree to make sure we can land kvm/drm trees in any order for the 4.10
> merge window.
Yes, I've already done that (though I have not pushed yet).
Paolo
> Thanks, Daniel
>
>>
>> ----------------------------------------------------------------
>> The three KVM patches that KVMGT needs.
>>
>> ----------------------------------------------------------------
>> Jike Song (2):
>> kvm/page_track: call notifiers with kvm_page_track_notifier_node
>> kvm/page_track: export symbols for external usage
>>
>> Xiaoguang Chen (1):
>> KVM: x86: add track_flush_slot page track notifier
>>
>> arch/x86/include/asm/kvm_page_track.h | 14 +++++++++++++-
>> arch/x86/kvm/mmu.c | 11 ++++++++++-
>> arch/x86/kvm/page_track.c | 31 ++++++++++++++++++++++++++++++-
>> arch/x86/kvm/x86.c | 2 +-
>> 4 files changed, 54 insertions(+), 4 deletions(-)
>
^ permalink raw reply
* Re: [GIT PULL] kvm/page_track changes for i915 KVMGT
From: Paolo Bonzini @ 2016-11-09 15:16 UTC (permalink / raw)
To: linux-kernel, kvm, rkrcmar, intel-gfx, Jike Song, Jani Nikula,
Zhenyu Wang
In-Reply-To: <20161109151545.w2fhldk6o7illb2g@phenom.ffwll.local>
On 09/11/2016 16:15, Daniel Vetter wrote:
> On Wed, Nov 09, 2016 at 03:25:19PM +0100, Paolo Bonzini wrote:
>> Daniel,
>>
>> The following changes since commit d9092f52d7e61dd1557f2db2400ddb430e85937e:
>>
>> kvm: x86: Check memopp before dereference (CVE-2016-8630) (2016-11-02 21:31:53 +0100)
>>
>> are available in the git repository at:
>>
>> git://git.kernel.org/pub/scm/virt/kvm/kvm.git tags/for-kvmgt
>>
>> for you to fetch changes up to 871b7ef2a1850d0b435c8b324bf4a5d391adde3f:
>>
>> kvm/page_track: export symbols for external usage (2016-11-04 12:13:20 +0100)
>
> Pulled into drm-intel, thanks. Please also pull this into your kvm-next
> tree to make sure we can land kvm/drm trees in any order for the 4.10
> merge window.
Yes, I've already done that (though I have not pushed yet).
Paolo
> Thanks, Daniel
>
>>
>> ----------------------------------------------------------------
>> The three KVM patches that KVMGT needs.
>>
>> ----------------------------------------------------------------
>> Jike Song (2):
>> kvm/page_track: call notifiers with kvm_page_track_notifier_node
>> kvm/page_track: export symbols for external usage
>>
>> Xiaoguang Chen (1):
>> KVM: x86: add track_flush_slot page track notifier
>>
>> arch/x86/include/asm/kvm_page_track.h | 14 +++++++++++++-
>> arch/x86/kvm/mmu.c | 11 ++++++++++-
>> arch/x86/kvm/page_track.c | 31 ++++++++++++++++++++++++++++++-
>> arch/x86/kvm/x86.c | 2 +-
>> 4 files changed, 54 insertions(+), 4 deletions(-)
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH] curl: Upgrade 7.50.1.bb -> curl_7.51.0.bb
From: akuster808 @ 2016-11-09 15:16 UTC (permalink / raw)
To: Sona Sarmadi, Richard Purdie (richard.purdie@linuxfoundation.org)
Cc: openembedded-core@lists.openembedded.org
In-Reply-To: <3230301C09DEF9499B442BBE162C5E48ABEB644D@SESTOEX04.enea.se>
On 11/09/2016 03:58 AM, Sona Sarmadi wrote:
> Hi guys,
>
> curl 7.51.0-r0 addresses all these CVEs. I wonder if we can upgrade krogoth and morty to curl 7.51.0-r0 as well?
Updating morty seems plausible . I appears the changes are mostly bug fixes.
Krogoth is a large jump and I would not recommend upgrading the package.
- Armin
> Both package versions are using same share library version i.e. libcurl.so.4.4.0 so I assume full ABI compatibility.
>
> tmp/work/i586-poky-linux/curl/7.47.1-r0/sysroot-destdir/usr/lib/libcurl.so.4.4.0
> tmp/work/i586-poky-linux/curl/7.51.0-r0/sysroot-destdir/usr/lib/libcurl.so.4.4.0
>
> For more info see:
> https://bugzilla.yoctoproject.org/show_bug.cgi?id=10617
>
> Thanks
> //Sona
> -----Original Message-----
> From: openembedded-core-bounces@lists.openembedded.org [mailto:openembedded-core-bounces@lists.openembedded.org] On Behalf Of Sona Sarmadi
> Sent: den 8 november 2016 11:42
> To: openembedded-core@lists.openembedded.org
> Subject: [OE-core] [PATCH] curl: Upgrade 7.50.1.bb -> curl_7.51.0.bb
>
> The upgrade addresses following CVEs:
> CVE-2016-8615: cookie injection for other servers
> CVE-2016-8616: case insensitive password comparison
> CVE-2016-8617: OOB write via unchecked multiplication
> CVE-2016-8618: double-free in curl_maprintf
> CVE-2016-8619: double-free in krb5 code
> CVE-2016-8620: glob parser write/read out of bounds
> CVE-2016-8621: curl_getdate read out of bounds
> CVE-2016-8622: URL unescape heap overflow via integer truncation
> CVE-2016-8623: Use-after-free via shared cookies
> CVE-2016-8624: invalid URL parsing with '#'
> CVE-2016-8625: IDNA 2003 makes curl use wrong host
>
> Reference:
> https://curl.haxx.se/docs/security.html
>
> Fixes [Yocto #10617]
>
> Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
> ---
> meta/recipes-support/curl/{curl_7.50.1.bb => curl_7.51.0.bb} | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-) rename meta/recipes-support/curl/{curl_7.50.1.bb => curl_7.51.0.bb} (94%)
>
> diff --git a/meta/recipes-support/curl/curl_7.50.1.bb b/meta/recipes-support/curl/curl_7.51.0.bb
> similarity index 94%
> rename from meta/recipes-support/curl/curl_7.50.1.bb
> rename to meta/recipes-support/curl/curl_7.51.0.bb
> index a21419a..e1a996b 100644
> --- a/meta/recipes-support/curl/curl_7.50.1.bb
> +++ b/meta/recipes-support/curl/curl_7.51.0.bb
> @@ -14,8 +14,8 @@ SRC_URI = "http://curl.haxx.se/download/curl-${PV}.tar.bz2 \ # SRC_URI += " file://configure_ac.patch"
>
> -SRC_URI[md5sum] = "015f6a0217ca6f2c5442ca406476920b"
> -SRC_URI[sha256sum] = "3c12c5f54ccaa1d40abc65d672107dcc75d3e1fcb38c267484334280096e5156"
> +SRC_URI[md5sum] = "09a7c5769a7eae676d5e2c86d51f167e"
> +SRC_URI[sha256sum] = "7f8240048907e5030f67be0a6129bc4b333783b9cca1391026d700835a788dde"
>
> inherit autotools pkgconfig binconfig multilib_header
>
> --
> 1.9.1
>
> --
> _______________________________________________
> Openembedded-core mailing list
> Openembedded-core@lists.openembedded.org
> http://lists.openembedded.org/mailman/listinfo/openembedded-core
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.