* [PATCH net-next 1/2 v8] net: ethernet: Add DT bindings for the Gemini ethernet
From: Linus Walleij @ 2017-12-10 22:45 UTC (permalink / raw)
To: linux-arm-kernel
This adds the device tree bindings for the Gemini ethernet
controller. It is pretty straight-forward, using standard
bindings and modelling the two child ports as child devices
under the parent ethernet controller device.
Cc: devicetree at vger.kernel.org
Cc: Tobias Waldvogel <tobias.waldvogel@gmail.com>
Cc: Micha? Miros?aw <mirq-linux@rere.qmqm.pl>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v7->v8:
- Use ethernet-port at 0 and ethernet-port at 1 with unit names
and following OF graph requirements.
---
.../bindings/net/cortina,gemini-ethernet.txt | 92 ++++++++++++++++++++++
1 file changed, 92 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt
diff --git a/Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt b/Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt
new file mode 100644
index 000000000000..6c559981d110
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt
@@ -0,0 +1,92 @@
+Cortina Systems Gemini Ethernet Controller
+==========================================
+
+This ethernet controller is found in the Gemini SoC family:
+StorLink SL3512 and SL3516, also known as Cortina Systems
+CS3512 and CS3516.
+
+Required properties:
+- compatible: must be "cortina,gemini-ethernet"
+- reg: must contain the global registers and the V-bit and A-bit
+ memory areas, in total three register sets.
+- syscon: a phandle to the system controller
+- #address-cells: must be specified, must be <1>
+- #size-cells: must be specified, must be <1>
+- ranges: should be state like this giving a 1:1 address translation
+ for the subnodes
+
+The subnodes represents the two ethernet ports in this device.
+They are not independent of each other since they share resources
+in the parent node, and are thus children.
+
+Required subnodes:
+- port0: contains the resources for ethernet port 0
+- port1: contains the resources for ethernet port 1
+
+Required subnode properties:
+- compatible: must be "cortina,gemini-ethernet-port"
+- reg: must contain two register areas: the DMA/TOE memory and
+ the GMAC memory area of the port
+- interrupts: should contain the interrupt line of the port.
+ this is nominally a level interrupt active high.
+- resets: this must provide an SoC-integrated reset line for
+ the port.
+- clocks: this should contain a handle to the PCLK clock for
+ clocking the silicon in this port
+- clock-names: must be "PCLK"
+
+Optional subnode properties:
+- phy-mode: see ethernet.txt
+- phy-handle: see ethernet.txt
+
+Example:
+
+mdio-bus {
+ (...)
+ phy0: ethernet-phy at 1 {
+ reg = <1>;
+ device_type = "ethernet-phy";
+ };
+ phy1: ethernet-phy at 3 {
+ reg = <3>;
+ device_type = "ethernet-phy";
+ };
+};
+
+
+ethernet at 60000000 {
+ compatible = "cortina,gemini-ethernet";
+ reg = <0x60000000 0x4000>, /* Global registers, queue */
+ <0x60004000 0x2000>, /* V-bit */
+ <0x60006000 0x2000>; /* A-bit */
+ syscon = <&syscon>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ gmac0: ethernet-port at 0 {
+ compatible = "cortina,gemini-ethernet-port";
+ reg = <0x60008000 0x2000>, /* Port 0 DMA/TOE */
+ <0x6000a000 0x2000>; /* Port 0 GMAC */
+ interrupt-parent = <&intcon>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&syscon GEMINI_RESET_GMAC0>;
+ clocks = <&syscon GEMINI_CLK_GATE_GMAC0>;
+ clock-names = "PCLK";
+ phy-mode = "rgmii";
+ phy-handle = <&phy0>;
+ };
+
+ gmac1: ethernet-port at 1 {
+ compatible = "cortina,gemini-ethernet-port";
+ reg = <0x6000c000 0x2000>, /* Port 1 DMA/TOE */
+ <0x6000e000 0x2000>; /* Port 1 GMAC */
+ interrupt-parent = <&intcon>;
+ interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&syscon GEMINI_RESET_GMAC1>;
+ clocks = <&syscon GEMINI_CLK_GATE_GMAC1>;
+ clock-names = "PCLK";
+ phy-mode = "rgmii";
+ phy-handle = <&phy1>;
+ };
+};
--
2.14.3
^ permalink raw reply related
* WARNING: suspicious RCU usage
From: Russell King - ARM Linux @ 2017-12-10 21:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171210213930.GL7829@linux.vnet.ibm.com>
On Sun, Dec 10, 2017 at 01:39:30PM -0800, Paul E. McKenney wrote:
> On Sun, Dec 10, 2017 at 07:34:39PM +0000, Russell King - ARM Linux wrote:
> > On Sun, Dec 10, 2017 at 11:07:27AM -0800, Paul E. McKenney wrote:
> > > On Sun, Dec 10, 2017 at 12:00:12PM +0000, Russell King - ARM Linux wrote:
> > > > +Paul
> > > >
> > > > Annoyingly, it looks like calling "complete()" from a dying CPU is
> > > > triggering the RCU usage warning. From what I remember, this is an
> > > > old problem, and we still have no better solution for this other than
> > > > to persist with the warning.
> > >
> > > I thought that this issue was resolved with tglx's use of IPIs from
> > > the outgoing CPU. Or is this due to an additional complete() from the
> > > ARM code? If so, could it also use tglx's IPI trick?
> >
> > I don't think it was tglx's IPI trick, I've had code sitting in my tree
> > for a while for it, but it has its own set of problems which are not
> > resolvable:
> >
> > 1. it needs more IPIs than we have available on all platforms
>
> OK, I will ask the stupid question... Is it possible to multiplex
> the IPIs, for example, by using smp_call_function_single()?
>
> > 2. there's some optional locking in the GIC driver that cause problems
> > for the cpu dying path.
>
> On this, I must plead ignorance.
>
> > The concensus last time around was that the IPI solution is a non-
> > starter, so the seven year proven-reliable solution (disregarding the
> > RCU warning) persists because I don't think anyone came up with a
> > better solution.
>
> Seven years already? Sigh, I don't have the heart to check because
> I wouldn't want to find out that it has actually been longer. ;-)
*Sigh* thanks for what you just said, you do realise that you've just
said that you don't believe what I write in emails? FFS. Is there
any point in continuing to discuss this if that's the case? Really?
commit 3c030beabf937b1d3b4ecaedfd1fb2f1e2aa0c70
Author: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue Nov 30 11:07:35 2010 +0000
ARM: CPU hotplug: move cpu_killed completion to core code
We always need to wait for the dying CPU to reach a safe state before
taking it down, irrespective of the requirements of the platform.
Move the completion code into the ARM SMP hotplug code rather than
having each platform re-implement this.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index a30c4094db3a..8c81ff9b3732 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -24,6 +24,7 @@
#include <linux/irq.h>
#include <linux/percpu.h>
#include <linux/clockchips.h>
+#include <linux/completion.h>
#include <asm/atomic.h>
#include <asm/cacheflush.h>
@@ -238,12 +239,20 @@ int __cpu_disable(void)
return 0;
}
+static DECLARE_COMPLETION(cpu_died);
+
/*
* called on the thread which is asking for a CPU to be shutdown -
* waits until shutdown has completed, or it is timed out.
*/
void __cpu_die(unsigned int cpu)
{
+ if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) {
+ pr_err("CPU%u: cpu didn't die\n", cpu);
+ return;
+ }
+ printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+
if (!platform_cpu_kill(cpu))
printk("CPU%u: unable to kill\n", cpu);
}
@@ -263,9 +272,12 @@ void __ref cpu_die(void)
local_irq_disable();
idle_task_exit();
+ /* Tell __cpu_die() that this CPU is now safe to dispose of */
+ complete(&cpu_died);
+
/*
* actual CPU shutdown procedure is at least platform (if not
- * CPU) specific
+ * CPU) specific.
*/
platform_cpu_die(cpu);
So, 30th Nov 2010 to 10th Dec 2017 is seven years, one week and three
days to be exact.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up
^ permalink raw reply related
* WARNING: suspicious RCU usage
From: Paul E. McKenney @ 2017-12-10 21:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171210193438.GP10595@n2100.armlinux.org.uk>
On Sun, Dec 10, 2017 at 07:34:39PM +0000, Russell King - ARM Linux wrote:
> On Sun, Dec 10, 2017 at 11:07:27AM -0800, Paul E. McKenney wrote:
> > On Sun, Dec 10, 2017 at 12:00:12PM +0000, Russell King - ARM Linux wrote:
> > > +Paul
> > >
> > > Annoyingly, it looks like calling "complete()" from a dying CPU is
> > > triggering the RCU usage warning. From what I remember, this is an
> > > old problem, and we still have no better solution for this other than
> > > to persist with the warning.
> >
> > I thought that this issue was resolved with tglx's use of IPIs from
> > the outgoing CPU. Or is this due to an additional complete() from the
> > ARM code? If so, could it also use tglx's IPI trick?
>
> I don't think it was tglx's IPI trick, I've had code sitting in my tree
> for a while for it, but it has its own set of problems which are not
> resolvable:
>
> 1. it needs more IPIs than we have available on all platforms
OK, I will ask the stupid question... Is it possible to multiplex
the IPIs, for example, by using smp_call_function_single()?
> 2. there's some optional locking in the GIC driver that cause problems
> for the cpu dying path.
On this, I must plead ignorance.
> The concensus last time around was that the IPI solution is a non-
> starter, so the seven year proven-reliable solution (disregarding the
> RCU warning) persists because I don't think anyone came up with a
> better solution.
Seven years already? Sigh, I don't have the heart to check because
I wouldn't want to find out that it has actually been longer. ;-)
Thanx, Paul
> > > I suspect the following lockdep warning is triggered by the RCU code
> > > bringing the console semaphore into the mix of locks.
> >
> > It does indeed look to me that it is quite possible that resolving
> > the complete() issue would prevent the lockdep splat from appearing,
> > which might in turn prevent acquisition of the console semaphore.
>
> Yea, if only it was simple to resolve that.
>
> --
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
> According to speedtest.net: 8.21Mbps down 510kbps up
>
^ permalink raw reply
* [PATCH 0/2] acpi, x86: Add SPCR table support
From: Jon Masters @ 2017-12-10 20:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <f078ada7-1e30-41cc-28dc-077ed2a5986d@redhat.com>
On 12/08/2017 09:29 AM, Prarit Bhargava wrote:
> If I disable "Serial Port Console Debug" in my BIOS I still see the SPCR configured:
>
> [root at prarit-lab ~]# dmesg | grep SPCR
> [ 0.000000] ACPI: SPCR 0x0000000069031000 000050 (v01
> 00000000 00000000)
>
> AFAICT the SPCR is always enabled on some systems.
It's part of some of the Windows design flows that it gets incorporated,
and it should always be present.
Jon (not talking about AArch64/ARM/arm/ARMv8-A/64-bit ARM/Go ARM Go).
^ permalink raw reply
* WARNING: suspicious RCU usage
From: Russell King - ARM Linux @ 2017-12-10 19:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171210190727.GJ7829@linux.vnet.ibm.com>
On Sun, Dec 10, 2017 at 11:07:27AM -0800, Paul E. McKenney wrote:
> On Sun, Dec 10, 2017 at 12:00:12PM +0000, Russell King - ARM Linux wrote:
> > +Paul
> >
> > Annoyingly, it looks like calling "complete()" from a dying CPU is
> > triggering the RCU usage warning. From what I remember, this is an
> > old problem, and we still have no better solution for this other than
> > to persist with the warning.
>
> I thought that this issue was resolved with tglx's use of IPIs from
> the outgoing CPU. Or is this due to an additional complete() from the
> ARM code? If so, could it also use tglx's IPI trick?
I don't think it was tglx's IPI trick, I've had code sitting in my tree
for a while for it, but it has its own set of problems which are not
resolvable:
1. it needs more IPIs than we have available on all platforms
2. there's some optional locking in the GIC driver that cause problems
for the cpu dying path.
The concensus last time around was that the IPI solution is a non-
starter, so the seven year proven-reliable solution (disregarding the
RCU warning) persists because I don't think anyone came up with a
better solution.
> > I suspect the following lockdep warning is triggered by the RCU code
> > bringing the console semaphore into the mix of locks.
>
> It does indeed look to me that it is quite possible that resolving
> the complete() issue would prevent the lockdep splat from appearing,
> which might in turn prevent acquisition of the console semaphore.
Yea, if only it was simple to resolve that.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up
^ permalink raw reply
* WARNING: suspicious RCU usage
From: Paul E. McKenney @ 2017-12-10 19:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171210120012.GM10595@n2100.armlinux.org.uk>
On Sun, Dec 10, 2017 at 12:00:12PM +0000, Russell King - ARM Linux wrote:
> +Paul
>
> Annoyingly, it looks like calling "complete()" from a dying CPU is
> triggering the RCU usage warning. From what I remember, this is an
> old problem, and we still have no better solution for this other than
> to persist with the warning.
I thought that this issue was resolved with tglx's use of IPIs from
the outgoing CPU. Or is this due to an additional complete() from the
ARM code? If so, could it also use tglx's IPI trick?
> I suspect the following lockdep warning is triggered by the RCU code
> bringing the console semaphore into the mix of locks.
It does indeed look to me that it is quite possible that resolving
the complete() issue would prevent the lockdep splat from appearing,
which might in turn prevent acquisition of the console semaphore.
Thanx, Paul
> On Sun, Dec 10, 2017 at 07:39:33PM +0800, Peng Fan wrote:
> > Hi All,
> >
> > I met an RCU warning when test suspend/resume on i.MX6Q-SDB(4 cortex-A9 cores).
> > The suspend/resume function still work, but I do not have good idea about
> > the RCU warning. Please help if you any ideas.
> >
> > The defconfig is imx_v6_v7_defconfig of "4.15.0-rc2-00483-g4ded3bec65a0"
> >
> > Test log:
> > root at imx6qpdlsolox:~# /unit_tests/Power_Management/suspend_quick_auto.sh
> >
> > ---- Running < suspend_quick_auto.sh > test ----
> >
> > ---- Running < /unit_tests/SRTC/rtcwakeup.out > test ----
> >
> > rtcwakeup.out: wakeup from "mem" using rtc0 at Thu Sep 7 00:06:21 2017
> > [ 21.688752] PM: suspend entry (deep)
> > [ 21.693550] PM: Syncing filesystems ... done.
> > [ 21.728528] Freezing user space processes ... (elapsed 0.002 seconds) done.
> > [ 21.739020] OOM killer disabled.
> > [ 21.742326] Freezing remaining freezable tasks ... (elapsed 0.002 seconds) done.
> > [ 21.816672] PM: suspend devices took 0.060 seconds
> > [ 21.832558] Disabling non-boot CPUs ...
> > [ 21.932773]
> > [ 21.933333] =============================
> > [ 21.933338] WARNING: suspicious RCU usage
> > [ 21.933342] 4.15.0-rc2-00483-g4ded3bec65a0 #85 Not tainted
> > [ 21.933348] -----------------------------
> > [ 21.933354] kernel/sched/fair.c:6333 suspicious rcu_dereference_check() usage!
> > [ 21.933358]
> > [ 21.933358] other info that might help us debug this:
> > [ 21.933358]
> > [ 21.933364]
> > [ 21.933364] RCU used illegally from offline CPU!
> > [ 21.933364] rcu_scheduler_active = 2, debug_locks = 0
> > [ 21.933369] 3 locks held by swapper/2/0:
> > [ 21.933373] #0: ((cpu_died).wait.lock){....}, at: [<4f528fc4>] complete+0x1c/0x58
> > [ 21.933396] #1: (&p->pi_lock){-.-.}, at: [<656ae3ef>] try_to_wake_up+0x28/0x368
> > [ 21.933415] #2: (rcu_read_lock){....}, at: [<73be2596>] select_task_rq_fair+0x150/0xf0c
> > [ 21.933433]
> > [ 21.933433] stack backtrace:
> > [ 21.933441] CPU: 2 PID: 0 Comm: swapper/2 Not tainted 4.15.0-rc2-00483-g4ded3bec65a0 #85
> > [ 21.933445] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
> > [ 21.933448] Backtrace:
> > [ 21.933459] [<c010c890>] (dump_backtrace) from [<c010cb60>] (show_stack+0x18/0x1c)
> > [ 21.933466] r7:00000000 r6:60070093 r5:00000000 r4:c107bd50
> > [ 21.933475] [<c010cb48>] (show_stack) from [<c09eca50>] (dump_stack+0xb4/0xe8)
> > [ 21.933484] [<c09ec99c>] (dump_stack) from [<c016e47c>] (lockdep_rcu_suspicious+0xb0/0x110)
> > [ 21.933493] r9:c0f7a380 r8:c107cd92 r7:c0cfc5c8 r6:000018bd r5:c0cff438 r4:ec0a0cc0
> > [ 21.933503] [<c016e3cc>] (lockdep_rcu_suspicious) from [<c015a4e8>] (select_task_rq_fair+0xcf8/0xf0c)
> > [ 21.933509] r7:00000000 r6:00000000 r5:00000000 r4:00000000
> > [ 21.933518] [<c01597f0>] (select_task_rq_fair) from [<c01505e4>] (try_to_wake_up+0x108/0x368)
> > [ 21.933526] r10:c1009290 r9:c0f7a380 r8:c01597f0 r7:40070093 r6:ec8e1e00 r5:00000000
> > [ 21.933531] r4:ec8e1980
> > [ 21.933540] [<c01504dc>] (try_to_wake_up) from [<c0150918>] (default_wake_function+0x14/0x18)
> > [ 21.933548] r10:00000000 r9:00000000 r8:c0150904 r7:00000000 r6:c100e470 r5:00000001
> > [ 21.933552] r4:c100e464
> > [ 21.933562] [<c0150904>] (default_wake_function) from [<c0166bd4>] (__wake_up_common+0x94/0x154)
> > [ 21.933572] [<c0166b40>] (__wake_up_common) from [<c0166d8c>] (__wake_up_locked+0x20/0x28)
> > [ 21.933580] r10:00000000 r9:412fc09a r8:c0f79840 r7:c1009174 r6:60070093 r5:c100e44c
> > [ 21.933584] r4:c100e448
> > [ 21.933594] [<c0166d6c>] (__wake_up_locked) from [<c0167970>] (complete+0x48/0x58)
> > [ 21.933605] [<c0167928>] (complete) from [<c010fb98>] (arch_cpu_idle_dead+0x3c/0xa4)
> > [ 21.933611] r7:c1009174 r6:00000004 r5:00000002 r4:c0db0054
> > [ 21.933622] [<c010fb5c>] (arch_cpu_idle_dead) from [<c0167d2c>] (do_idle+0x170/0x230)
> > [ 21.933629] r5:c1009128 r4:ec0b0000
> > [ 21.933638] [<c0167bbc>] (do_idle) from [<c0168178>] (cpu_startup_entry+0x20/0x24)
> > [ 21.933647] r10:00000000 r9:412fc09a r8:1000406a r7:c107dbe0 r6:10c0387d r5:00000002
> > [ 21.933653] r4:00000085 r3:ec0a0cc0
> > [ 21.933663] [<c0168158>] (cpu_startup_entry) from [<c010fd48>] (secondary_start_kernel+0x148/0x174)
> > [ 21.933672] [<c010fc00>] (secondary_start_kernel) from [<10101a0c>] (0x10101a0c)
> > [ 21.933677] r5:00000051 r4:3c08c06a
> > [ 21.991289] Enabling non-boot CPUs ...
> > [ 22.278265] CPU1 is up
> > [ 22.281305] CPU2 is up
> > [ 22.284299] CPU3 is up
> > [ 23.183405]
> > [ 23.183409] ======================================================
> > [ 23.183413] WARNING: possible circular locking dependency detected
> > [ 23.183415] 4.15.0-rc2-00483-g4ded3bec65a0 #85 Not tainted
> > [ 23.183418] ------------------------------------------------------
> > [ 23.183421] swapper/2/0 is trying to acquire lock:
> > [ 23.183423] ((console_sem).lock){....}, at: [<66600b38>] down_trylock+0x14/0x34
> > [ 23.183431]
> > [ 23.183433] but task is already holding lock:
> > [ 23.183435] (&p->pi_lock){-.-.}, at: [<656ae3ef>] try_to_wake_up+0x28/0x368
> > [ 23.183442]
> > [ 23.183444] which lock already depends on the new lock.
> > [ 23.183446]
> > [ 23.183448]
> > [ 23.183450] the existing dependency chain (in reverse order) is:
> > [ 23.183452]
> > [ 23.183453] -> #1 (&p->pi_lock){-.-.}:
> > [ 23.183461] lock_acquire+0x70/0x90
> > [ 23.183463] _raw_spin_lock_irqsave+0x40/0x54
> > [ 23.183466] try_to_wake_up+0x28/0x368
> > [ 23.183468] wake_up_process+0x18/0x1c
> > [ 23.183470] __up+0x3c/0x40
> > [ 23.183472] up+0x54/0x68
> > [ 23.183474] __up_console_sem+0x34/0x60
> > [ 23.183476] console_unlock+0x374/0x4d0
> > [ 23.183478] vprintk_emit+0x220/0x2bc
> > [ 23.183480] dev_vprintk_emit+0x9c/0x1d4
> > [ 23.183483] dev_printk_emit+0x28/0x30
> > [ 23.183485] __dev_printk+0x4c/0x90
> > [ 23.183487] dev_warn+0x3c/0x48
> > [ 23.183489] _request_firmware+0x448/0x610
> > [ 23.183491] request_firmware_work_func+0x34/0x6c
> > [ 23.183493] process_one_work+0x254/0x4f0
> > [ 23.183496] worker_thread+0x40/0x5a8
> > [ 23.183498] kthread+0x144/0x194
> > [ 23.183500] ret_from_fork+0x14/0x20
> > [ 23.183501]
> > [ 23.183503] -> #0 ((console_sem).lock){....}:
> > [ 23.183510] __lock_acquire+0x131c/0x14a8
> > [ 23.183513] lock_acquire+0x70/0x90
> > [ 23.183515] _raw_spin_lock_irqsave+0x40/0x54
> > [ 23.183517] down_trylock+0x14/0x34
> > [ 23.183519] __down_trylock_console_sem+0x2c/0x88
> > [ 23.183522] console_trylock+0x18/0x60
> > [ 23.183524] vprintk_emit+0x214/0x2bc
> > [ 23.183526] vprintk_default+0x28/0x30
> > [ 23.183528] vprintk_func+0x78/0xcc
> > [ 23.183530] printk+0x28/0x30
> > [ 23.183532] lockdep_rcu_suspicious+0x30/0x110
> > [ 23.183535] select_task_rq_fair+0xcf8/0xf0c
> > [ 23.183537] try_to_wake_up+0x108/0x368
> > [ 23.183539] default_wake_function+0x14/0x18
> > [ 23.183541] __wake_up_common+0x94/0x154
> > [ 23.183543] __wake_up_locked+0x20/0x28
> > [ 23.183545] complete+0x48/0x58
> > [ 23.183548] arch_cpu_idle_dead+0x3c/0xa4
> > [ 23.183550] do_idle+0x170/0x230
> > [ 23.183552] cpu_startup_entry+0x20/0x24
> > [ 23.183554] secondary_start_kernel+0x148/0x174
> > [ 23.183556] 0x10101a0c
> > [ 23.183557]
> > [ 23.183560] other info that might help us debug this:
> > [ 23.183561]
> > [ 23.183563] Possible unsafe locking scenario:
> > [ 23.183565]
> > [ 23.183567] CPU0 CPU1
> > [ 23.183569] ---- ----
> > [ 23.183571] lock(&p->pi_lock);
> > [ 23.183576] lock((console_sem).lock);
> > [ 23.183581] lock(&p->pi_lock);
> > [ 23.183586] lock((console_sem).lock);
> > [ 23.183590]
> > [ 23.183592] *** DEADLOCK ***
> > [ 23.183594]
> > [ 23.183596] 3 locks held by swapper/2/0:
> > [ 23.183597] #0: ((cpu_died).wait.lock){....}, at: [<4f528fc4>] complete+0x1c/0x58
> > [ 23.183605] #1: (&p->pi_lock){-.-.}, at: [<656ae3ef>] try_to_wake_up+0x28/0x368
> > [ 23.183613] #2: (rcu_read_lock){....}, at: [<73be2596>] select_task_rq_fair+0x150/0xf0c
> > [ 23.183621]
> > [ 23.183623] stack backtrace:
> > [ 23.183626] CPU: 2 PID: 0 Comm: swapper/2 Not tainted 4.15.0-rc2-00483-g4ded3bec65a0 #85
> > [ 23.183629] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
> > [ 23.183630] Backtrace:
> > [ 23.183635] [<c010c890>] (dump_backtrace) from [<c010cb60>] (show_stack+0x18/0x1c)
> > [ 23.183638] r7:00000000 r6:60070093 r5:00000000 r4:c107bd50
> > [ 23.183641] [<c010cb48>] (show_stack) from [<c09eca50>] (dump_stack+0xb4/0xe8)
> > [ 23.183643] [<c09ec99c>] (dump_stack) from [<c016e750>] (print_circular_bug+0x218/0x3c8)
> > [ 23.183646] r9:00000000 r8:ec0a0cc0 r7:c11a4120 r6:c11a4120 r5:ec0a11e0 r4:c11a8700
> > [ 23.183649] [<c016e538>] (print_circular_bug) from [<c016f938>] (check_prev_add+0x42c/0x7b4)
> > [ 23.183652] r10:c1029bac r9:ec0a0cc0 r8:ec0a11e0 r7:ec0a1220 r6:ec0a11e0 r5:00000000
> > [ 23.183654] r4:ec0a0cc0 r3:ec0a11e0
> > [ 23.183657] [<c016f50c>] (check_prev_add) from [<c0172678>] (__lock_acquire+0x131c/0x14a8)
> > [ 23.183660] r10:c1029bac r9:ec0a0cc0 r8:ec0a11e0 r7:c17cad80 r6:00000001 r5:00000000
> > [ 23.183661] r4:ec0a1220
> > [ 23.183664] [<c017135c>] (__lock_acquire) from [<c017307c>] (lock_acquire+0x70/0x90)
> > [ 23.183667] r10:00000000 r9:60070093 r8:00000001 r7:00000001 r6:60070093 r5:00000000
> > [ 23.183669] r4:ffffe000
> > [ 23.183672] [<c017300c>] (lock_acquire) from [<c0a094dc>] (_raw_spin_lock_irqsave+0x40/0x54)
> > [ 23.183674] r8:00000000 r7:00000004 r6:c016b368 r5:60070093 r4:c101ba28
> > [ 23.183677] [<c0a0949c>] (_raw_spin_lock_irqsave) from [<c016b368>] (down_trylock+0x14/0x34)
> > [ 23.183679] r6:c017cb30 r5:c101ba28 r4:00000000
> > [ 23.183682] [<c016b354>] (down_trylock) from [<c017b684>] (__down_trylock_console_sem+0x2c/0x88)
> > [ 23.183684] r5:60070093 r4:00000000
> > [ 23.183687] [<c017b658>] (__down_trylock_console_sem) from [<c017b6f8>] (console_trylock+0x18/0x60)
> > [ 23.183690] r6:00000006 r5:c017cb30 r4:00000000
> > [ 23.183692] [<c017b6e0>] (console_trylock) from [<c017cb30>] (vprintk_emit+0x214/0x2bc)
> > [ 23.183694] r5:00000000 r4:00000000
> > [ 23.183697] [<c017c91c>] (vprintk_emit) from [<c017cd74>] (vprintk_default+0x28/0x30)
> > [ 23.183700] r10:ec8e1980 r9:c0f7a380 r8:c107cd92 r7:c0cfc5c8 r6:000018bd r5:c0cffdfc
> > [ 23.183702] r4:c1009290
> > [ 23.183705] [<c017cd4c>] (vprintk_default) from [<c017e130>] (vprintk_func+0x78/0xcc)
> > [ 23.183707] [<c017e0b8>] (vprintk_func) from [<c017da50>] (printk+0x28/0x30)
> > [ 23.183709] r5:c0cff438 r4:ec0a0cc0
> > [ 23.183712] [<c017da2c>] (printk) from [<c016e3fc>] (lockdep_rcu_suspicious+0x30/0x110)
> > [ 23.183715] r3:ec0b1df0 r2:c0cfc5c8 r1:000018bd r0:c0cffdfc
> > [ 23.183718] [<c016e3cc>] (lockdep_rcu_suspicious) from [<c015a4e8>] (select_task_rq_fair+0xcf8/0xf0c)
> > [ 23.183720] r7:00000000 r6:00000000 r5:00000000 r4:00000000
> > [ 23.183723] [<c01597f0>] (select_task_rq_fair) from [<c01505e4>] (try_to_wake_up+0x108/0x368)
> > [ 23.183726] r10:c1009290 r9:c0f7a380 r8:c01597f0 r7:40070093 r6:ec8e1e00 r5:00000000
> > [ 23.183728] r4:ec8e1980
> > [ 23.183731] [<c01504dc>] (try_to_wake_up) from [<c0150918>] (default_wake_function+0x14/0x18)
> > [ 23.183734] r10:00000000 r9:00000000 r8:c0150904 r7:00000000 r6:c100e470 r5:00000001
> > [ 23.183736] r4:c100e464
> > [ 23.183739] [<c0150904>] (default_wake_function) from [<c0166bd4>] (__wake_up_common+0x94/0x154)
> > [ 23.183741] [<c0166b40>] (__wake_up_common) from [<c0166d8c>] (__wake_up_locked+0x20/0x28)
> > [ 23.183744] r10:00000000 r9:412fc09a r8:c0f79840 r7:c1009174 r6:60070093 r5:c100e44c
> > [ 23.183746] r4:c100e448
> > [ 23.183749] [<c0166d6c>] (__wake_up_locked) from [<c0167970>] (complete+0x48/0x58)
> > [ 23.183752] [<c0167928>] (complete) from [<c010fb98>] (arch_cpu_idle_dead+0x3c/0xa4)
> > [ 23.183754] r7:c1009174 r6:00000004 r5:00000002 r4:c0db0054
> > [ 23.183757] [<c010fb5c>] (arch_cpu_idle_dead) from [<c0167d2c>] (do_idle+0x170/0x230)
> > [ 23.183759] r5:c1009128 r4:ec0b0000
> > [ 23.183762] [<c0167bbc>] (do_idle) from [<c0168178>] (cpu_startup_entry+0x20/0x24)
> > [ 23.183765] r10:00000000 r9:412fc09a r8:1000406a r7:c107dbe0 r6:10c0387d r5:00000002
> > [ 23.183767] r4:00000085 r3:ec0a0cc0
> > [ 23.183770] [<c0168158>] (cpu_startup_entry) from [<c010fd48>] (secondary_start_kernel+0x148/0x174)
> > [ 23.183773] [<c010fc00>] (secondary_start_kernel) from [<10101a0c>] (0x10101a0c)
> > [ 23.183775] r5:00000051 r4:3c08c06a
> > [ 23.471735] ata1: SATA link down (SStatus 0 SControl 300)
> > [ 23.899204] PM: resume devices took 0.750 seconds
> > [ 23.903961] OOM killer enabled.
> > [ 23.907111] Restarting tasks ... done.
> > [ 23.938591] PM: suspend exit
> > ===============================
> > suspend 1 times
> > ===============================
> >
> > Thanks,
> > Peng.
> >
> > --
> >
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
> --
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
> According to speedtest.net: 8.21Mbps down 510kbps up
>
^ permalink raw reply
* [PATCH v2 2/5] ARM: dts: imx53: add srtc node
From: Fabio Estevam @ 2017-12-10 19:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3BB206AB2B1BD448954845CE6FF69A8E01CB531C1F@NT-Mail07.beckhoff.com>
On Tue, Dec 5, 2017 at 12:20 PM, Patrick Br?nn <P.Bruenn@beckhoff.com> wrote:
> I will wait a few days for more reviewers and then integrate your comments in a v3. If nothing major show up I will wait until the imx53.dtsi revert landed in Linus tree.
It is in Linus' tree now as commit e501506d3ea0 ("Revert "ARM: dts:
imx53: add srtc node"").
^ permalink raw reply
* [PATCH 43/45] sound/soc/zte: remove duplicate includes
From: Pravin Shedge @ 2017-12-10 18:32 UTC (permalink / raw)
To: linux-arm-kernel
These duplicate includes have been found with scripts/checkincludes.pl but
they have been removed manually to avoid removing false positives.
Signed-off-by: Pravin Shedge <pravin.shedge4linux@gmail.com>
---
sound/soc/zte/zx-i2s.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/sound/soc/zte/zx-i2s.c b/sound/soc/zte/zx-i2s.c
index 9a05659..93428e1 100644
--- a/sound/soc/zte/zx-i2s.c
+++ b/sound/soc/zte/zx-i2s.c
@@ -20,9 +20,6 @@
#include <sound/core.h>
#include <sound/dmaengine_pcm.h>
#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
#define ZX_I2S_PROCESS_CTRL 0x04
#define ZX_I2S_TIMING_CTRL 0x08
--
2.7.4
^ permalink raw reply related
* [PATCH v7 13/13] ASoC: stm32: add DFSDM DAI support
From: Jonathan Cameron @ 2017-12-10 18:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512744566-13233-14-git-send-email-arnaud.pouliquen@st.com>
On Fri, 8 Dec 2017 15:49:26 +0100
Arnaud Pouliquen <arnaud.pouliquen@st.com> wrote:
> Add driver to handle DAI interface for PDM microphones connected
> to Digital Filter for Sigma Delta Modulators IP.
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
I don't know nearly enough about the sound side to comment on the details
in here, but a few nitpicks inline I saw whilst glancing through it.
Thanks,
Jonathan
> ---
> V6 to V7 updates:
> - SPDX-Licensing.
> - Supress workaround in stm32_adfsdm_pcm_new as issue fixed in generic code in recent kernel version.
> - Fix kbuild report issue on a log parameter type.
> - Suppress test in stm32_adfsdm_set_sysclk on clock direction.
>
> sound/soc/stm/Kconfig | 11 ++
> sound/soc/stm/Makefile | 3 +
> sound/soc/stm/stm32_adfsdm.c | 351 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 365 insertions(+)
> create mode 100644 sound/soc/stm/stm32_adfsdm.c
>
> diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig
> index 3398e6c..a78f770 100644
> --- a/sound/soc/stm/Kconfig
> +++ b/sound/soc/stm/Kconfig
> @@ -28,4 +28,15 @@ config SND_SOC_STM32_SPDIFRX
> help
> Say Y if you want to enable S/PDIF capture for STM32
>
> +config SND_SOC_STM32_DFSDM
> + tristate "SoC Audio support for STM32 DFSDM"
> + depends on (ARCH_STM32 && OF && STM32_DFSDM_ADC) || COMPILE_TEST
> + depends on SND_SOC
> + select SND_SOC_GENERIC_DMAENGINE_PCM
> + select SND_SOC_DMIC
> + select IIO_BUFFER_CB
> + help
> + Select this option to enable the STM32 Digital Filter
> + for Sigma Delta Modulators (DFSDM) driver used
> + in various STM32 series for digital microphone capture.
> endmenu
> diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile
> index 4ed22e6..53e90e6 100644
> --- a/sound/soc/stm/Makefile
> +++ b/sound/soc/stm/Makefile
> @@ -12,3 +12,6 @@ obj-$(CONFIG_SND_SOC_STM32_I2S) += snd-soc-stm32-i2s.o
> # SPDIFRX
> snd-soc-stm32-spdifrx-objs := stm32_spdifrx.o
> obj-$(CONFIG_SND_SOC_STM32_SPDIFRX) += snd-soc-stm32-spdifrx.o
> +
> +#DFSDM
> +obj-$(CONFIG_SND_SOC_STM32_DFSDM) += stm32_adfsdm.o
> diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
> new file mode 100644
> index 0000000..eef725e
> --- /dev/null
> +++ b/sound/soc/stm/stm32_adfsdm.c
> @@ -0,0 +1,351 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * This file is part of STM32 DFSDM ASoC DAI driver
> + *
> + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
> + * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> + * Olivier Moysan <olivier.moysan@st.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/consumer.h>
> +#include <linux/iio/adc/stm32-dfsdm-adc.h>
> +
> +#include <sound/pcm.h>
> +#include <sound/soc.h>
> +
> +#define STM32_ADFSDM_DRV_NAME "stm32-adfsdm"
> +
> +#define DFSDM_MAX_PERIOD_SIZE (PAGE_SIZE / 2)
> +#define DFSDM_MAX_PERIODS 6
> +
> +struct stm32_adfsdm_priv {
> + struct snd_soc_dai_driver dai_drv;
> + struct snd_pcm_substream *substream;
> + struct device *dev;
> +
> + /* IIO */
> + struct iio_channel *iio_ch;
> + struct iio_cb_buffer *iio_cb;
> + bool iio_active;
> +
> + /* PCM buffer */
> + unsigned char *pcm_buff;
> + unsigned int pos;
> +};
> +
> +static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = {
> + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
> + SNDRV_PCM_INFO_PAUSE,
> + .formats = SNDRV_PCM_FMTBIT_S32_LE,
> +
> + .rate_min = 8000,
> + .rate_max = 32000,
> +
> + .channels_min = 1,
> + .channels_max = 1,
> +
> + .periods_min = 2,
> + .periods_max = DFSDM_MAX_PERIODS,
> +
> + .period_bytes_max = DFSDM_MAX_PERIOD_SIZE,
> + .buffer_bytes_max = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE
> +};
> +
> +static void stm32_adfsdm_shutdown(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
> +
> + if (priv->iio_active) {
> + iio_channel_stop_all_cb(priv->iio_cb);
> + priv->iio_active = false;
> + }
> +}
> +
> +static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
> + int ret;
> +
> + ret = iio_write_channel_attribute(priv->iio_ch,
> + substream->runtime->rate, 0,
> + IIO_CHAN_INFO_SAMP_FREQ);
> + if (ret < 0) {
> + dev_err(dai->dev, "%s: Failed to set %d sampling rate\n",
> + __func__, substream->runtime->rate);
> + return ret;
> + }
> +
> + if (!priv->iio_active) {
> + ret = iio_channel_start_all_cb(priv->iio_cb);
> + if (!ret)
> + priv->iio_active = true;
> + else
> + dev_err(dai->dev, "%s: IIO channel start failed (%d)\n",
> + __func__, ret);
> + }
> +
> + return ret;
> +}
> +
> +static int stm32_adfsdm_set_sysclk(struct snd_soc_dai *dai, int clk_id,
> + unsigned int freq, int dir)
> +{
> + struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
> + ssize_t size;
> + char str_freq[10];
> +
> + dev_dbg(dai->dev, "%s: Enter for freq %d\n", __func__, freq);
> +
> + /* Set IIO frequency if CODEC is master as clock comes from SPI_IN*/
Space before */
> +
> + snprintf(str_freq, sizeof(str_freq), "%d\n", freq);
> + size = iio_write_channel_ext_info(priv->iio_ch, "spi_clk_freq",
> + str_freq, sizeof(str_freq));
> + if (size != sizeof(str_freq)) {
> + dev_err(dai->dev, "%s: Failed to set SPI clock\n",
> + __func__);
> + return -EINVAL;
> + }
> + return 0;
> +}
> +
> +static const struct snd_soc_dai_ops stm32_adfsdm_dai_ops = {
> + .shutdown = stm32_adfsdm_shutdown,
> + .prepare = stm32_adfsdm_dai_prepare,
> + .set_sysclk = stm32_adfsdm_set_sysclk,
> +};
> +
> +static const struct snd_soc_dai_driver stm32_adfsdm_dai = {
> + .capture = {
> + .channels_min = 1,
> + .channels_max = 1,
> + .formats = SNDRV_PCM_FMTBIT_S32_LE,
> + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
> + SNDRV_PCM_RATE_32000),
> + },
> + .ops = &stm32_adfsdm_dai_ops,
> +};
> +
> +static const struct snd_soc_component_driver stm32_adfsdm_dai_component = {
> + .name = "stm32_dfsdm_audio",
> +};
> +
> +static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
> +{
> + struct stm32_adfsdm_priv *priv = private;
> + struct snd_soc_pcm_runtime *rtd = priv->substream->private_data;
> + u8 *pcm_buff = priv->pcm_buff;
> + u8 *src_buff = (u8 *)data;
> + unsigned int buff_size = snd_pcm_lib_buffer_bytes(priv->substream);
> + unsigned int period_size = snd_pcm_lib_period_bytes(priv->substream);
> + unsigned int old_pos = priv->pos;
> + unsigned int cur_size = size;
> +
> + dev_dbg(rtd->dev, "%s: buff_add :%p, pos = %d, size = %zu\n",
> + __func__, &pcm_buff[priv->pos], priv->pos, size);
> +
> + if ((priv->pos + size) > buff_size) {
> + memcpy(&pcm_buff[priv->pos], src_buff, buff_size - priv->pos);
> + cur_size -= buff_size - priv->pos;
> + priv->pos = 0;
> + }
> +
> + memcpy(&pcm_buff[priv->pos], &src_buff[size - cur_size], cur_size);
> + priv->pos = (priv->pos + cur_size) % buff_size;
> +
> + if (cur_size != size || (old_pos && (old_pos % period_size < size)))
> + snd_pcm_period_elapsed(priv->substream);
> +
> + return 0;
> +}
> +
> +static int stm32_adfsdm_trigger(struct snd_pcm_substream *substream, int cmd)
> +{
> + struct snd_soc_pcm_runtime *rtd = substream->private_data;
> + struct stm32_adfsdm_priv *priv =
> + snd_soc_dai_get_drvdata(rtd->cpu_dai);
> +
> + switch (cmd) {
> + case SNDRV_PCM_TRIGGER_START:
> + case SNDRV_PCM_TRIGGER_RESUME:
> + priv->pos = 0;
> + return stm32_dfsdm_get_buff_cb(priv->iio_ch->indio_dev,
> + stm32_afsdm_pcm_cb, priv);
> + case SNDRV_PCM_TRIGGER_SUSPEND:
> + case SNDRV_PCM_TRIGGER_STOP:
> + return stm32_dfsdm_release_buff_cb(priv->iio_ch->indio_dev);
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int stm32_adfsdm_pcm_open(struct snd_pcm_substream *substream)
> +{
> + struct snd_soc_pcm_runtime *rtd = substream->private_data;
> + struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
> + int ret;
> +
> + ret = snd_soc_set_runtime_hwparams(substream, &stm32_adfsdm_pcm_hw);
> + if (!ret)
> + priv->substream = substream;
> +
> + return ret;
> +}
> +
> +static int stm32_adfsdm_pcm_close(struct snd_pcm_substream *substream)
> +{
> + struct snd_soc_pcm_runtime *rtd = substream->private_data;
> + struct stm32_adfsdm_priv *priv =
> + snd_soc_dai_get_drvdata(rtd->cpu_dai);
> +
> + snd_pcm_lib_free_pages(substream);
> + priv->substream = NULL;
> +
> + return 0;
> +}
> +
> +static snd_pcm_uframes_t stm32_adfsdm_pcm_pointer(
> + struct snd_pcm_substream *substream)
> +{
> + struct snd_soc_pcm_runtime *rtd = substream->private_data;
> + struct stm32_adfsdm_priv *priv =
> + snd_soc_dai_get_drvdata(rtd->cpu_dai);
> +
> + return bytes_to_frames(substream->runtime, priv->pos);
> +}
> +
> +static int stm32_adfsdm_pcm_hw_params(struct snd_pcm_substream *substream,
> + struct snd_pcm_hw_params *params)
> +{
> + struct snd_soc_pcm_runtime *rtd = substream->private_data;
> + struct stm32_adfsdm_priv *priv =
> + snd_soc_dai_get_drvdata(rtd->cpu_dai);
> + int ret;
> +
> + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
> + if (ret < 0)
> + return ret;
> + priv->pcm_buff = substream->runtime->dma_area;
> +
> + return iio_channel_cb_set_buffer_watermark(priv->iio_cb,
> + params_period_size(params));
> +}
> +
> +static int stm32_adfsdm_pcm_hw_free(struct snd_pcm_substream *substream)
> +{
> + snd_pcm_lib_free_pages(substream);
> +
> + return 0;
> +}
> +
> +static struct snd_pcm_ops stm32_adfsdm_pcm_ops = {
> + .open = stm32_adfsdm_pcm_open,
> + .close = stm32_adfsdm_pcm_close,
> + .hw_params = stm32_adfsdm_pcm_hw_params,
> + .hw_free = stm32_adfsdm_pcm_hw_free,
> + .trigger = stm32_adfsdm_trigger,
> + .pointer = stm32_adfsdm_pcm_pointer,
> +};
> +
> +static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime *rtd)
> +{
> + struct snd_pcm *pcm = rtd->pcm;
> + struct stm32_adfsdm_priv *priv =
> + snd_soc_dai_get_drvdata(rtd->cpu_dai);
> + unsigned int size = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE;
> + int ret;
> +
> + ret = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
> + priv->dev, size, size);
> + return ret;
nitpick. Nicer as
return snd_pcm_lib_preallocate_pages_for_all(..
> +}
> +
> +static void stm32_adfsdm_pcm_free(struct snd_pcm *pcm)
> +{
> + struct snd_pcm_substream *substream;
> + struct snd_soc_pcm_runtime *rtd;
> + struct stm32_adfsdm_priv *priv;
> +
> + substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
> + if (substream) {
> + rtd = substream->private_data;
> + priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
> +
> + snd_pcm_lib_preallocate_free_for_all(pcm);
> + }
> +}
> +
> +static struct snd_soc_platform_driver stm32_adfsdm_soc_platform = {
> + .ops = &stm32_adfsdm_pcm_ops,
> + .pcm_new = stm32_adfsdm_pcm_new,
> + .pcm_free = stm32_adfsdm_pcm_free,
> +};
> +
> +static const struct of_device_id stm32_adfsdm_of_match[] = {
> + {.compatible = "st,stm32h7-dfsdm-dai"},
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, stm32_adfsdm_of_match);
> +
> +static int stm32_adfsdm_probe(struct platform_device *pdev)
> +{
> + struct stm32_adfsdm_priv *priv;
> + int ret;
> +
> + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->dev = &pdev->dev;
> + priv->dai_drv = stm32_adfsdm_dai;
> +
> + dev_set_drvdata(&pdev->dev, priv);
> +
> + ret = devm_snd_soc_register_component(&pdev->dev,
> + &stm32_adfsdm_dai_component,
> + &priv->dai_drv, 1);
> + if (ret < 0)
> + return ret;
> +
> + /* Associate iio channel */
> + priv->iio_ch = devm_iio_channel_get_all(&pdev->dev);
> + if (IS_ERR(priv->iio_ch))
> + return PTR_ERR(priv->iio_ch);
> +
> + priv->iio_cb = iio_channel_get_all_cb(&pdev->dev, NULL, NULL);
> + if (IS_ERR(priv->iio_cb))
> + return PTR_ERR(priv->iio_ch);
> +
> + ret = devm_snd_soc_register_platform(&pdev->dev,
> + &stm32_adfsdm_soc_platform);
> + if (ret < 0)
> + dev_err(&pdev->dev, "%s: Failed to register PCM platform\n",
> + __func__);
> +
> + return ret;
> +}
> +
> +static struct platform_driver stm32_adfsdm_driver = {
> + .driver = {
> + .name = STM32_ADFSDM_DRV_NAME,
> + .of_match_table = stm32_adfsdm_of_match,
> + },
> + .probe = stm32_adfsdm_probe,
> +};
> +
> +module_platform_driver(stm32_adfsdm_driver);
> +
> +MODULE_DESCRIPTION("stm32 DFSDM DAI driver");
> +MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME);
^ permalink raw reply
* [PATCH v7 10/13] IIO: ADC: add stm32 DFSDM support for PDM microphone
From: Jonathan Cameron @ 2017-12-10 18:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512744566-13233-11-git-send-email-arnaud.pouliquen@st.com>
On Fri, 8 Dec 2017 15:49:23 +0100
Arnaud Pouliquen <arnaud.pouliquen@st.com> wrote:
> This code offers a way to handle PDM audio microphones in
> ASOC framework. Audio driver should use consumer API.
> A specific management is implemented for DMA, with a
> callback, to allows to handle audio buffers efficiently.
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
Hi Arnaud,
I'm afraid I missed a few things on the earlier versions.
Around the use of the iio_triggered_buffer_setup
(which does some stuff we don't need here)
Also ordering isn't quite consistent between probe and
remove.
Jonathan
> ---
> V6 to V7 updates:
> - SPDX-Licensing.
> - Minor typo fixes.
>
> .../ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 | 16 +
> drivers/iio/adc/stm32-dfsdm-adc.c | 508 ++++++++++++++++++++-
> include/linux/iio/adc/stm32-dfsdm-adc.h | 18 +
> 3 files changed, 534 insertions(+), 8 deletions(-)
> create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32
> create mode 100644 include/linux/iio/adc/stm32-dfsdm-adc.h
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32
> new file mode 100644
> index 0000000..da98223
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32
> @@ -0,0 +1,16 @@
> +What: /sys/bus/iio/devices/iio:deviceX/in_voltage_spi_clk_freq
> +KernelVersion: 4.14
> +Contact: arnaud.pouliquen at st.com
> +Description:
> + For audio purpose only.
> + Used by audio driver to set/get the spi input frequency.
> + This is mandatory if DFSDM is slave on SPI bus, to
> + provide information on the SPI clock frequency during runtime
> + Notice that the SPI frequency should be a multiple of sample
> + frequency to ensure the precision.
> + if DFSDM input is SPI master
> + Reading SPI clkout frequency,
> + error on writing
> + If DFSDM input is SPI Slave:
> + Reading returns value previously set.
> + Writing value before starting conversions.
> \ No newline at end of file
> diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
> index 68b5920..2d6aed5 100644
> --- a/drivers/iio/adc/stm32-dfsdm-adc.c
> +++ b/drivers/iio/adc/stm32-dfsdm-adc.c
> @@ -6,19 +6,25 @@
> * Author: Arnaud Pouliquen <arnaud.pouliquen@st.com>.
> */
>
> +#include <linux/dmaengine.h>
> +#include <linux/dma-mapping.h>
> #include <linux/interrupt.h>
> #include <linux/iio/buffer.h>
> #include <linux/iio/hw-consumer.h>
> #include <linux/iio/iio.h>
> #include <linux/iio/sysfs.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/iio/triggered_buffer.h>
> #include <linux/module.h>
> -#include <linux/of.h>
> +#include <linux/of_device.h>
> #include <linux/platform_device.h>
> #include <linux/regmap.h>
> #include <linux/slab.h>
>
> #include "stm32-dfsdm.h"
>
> +#define DFSDM_DMA_BUFFER_SIZE (4 * PAGE_SIZE)
> +
> /* Conversion timeout */
> #define DFSDM_TIMEOUT_US 100000
> #define DFSDM_TIMEOUT (msecs_to_jiffies(DFSDM_TIMEOUT_US / 1000))
> @@ -58,6 +64,18 @@ struct stm32_dfsdm_adc {
> struct completion completion;
> u32 *buffer;
>
> + /* Audio specific */
> + unsigned int spi_freq; /* SPI bus clock frequency */
> + unsigned int sample_freq; /* Sample frequency after filter decimation */
> + int (*cb)(const void *data, size_t size, void *cb_priv);
> + void *cb_priv;
> +
> + /* DMA */
> + u8 *rx_buf;
> + unsigned int bufi; /* Buffer current position */
> + unsigned int buf_sz; /* Buffer size */
> + struct dma_chan *dma_chan;
> + dma_addr_t dma_buf;
> };
>
> struct stm32_dfsdm_str2field {
> @@ -351,10 +369,63 @@ int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm,
> return 0;
> }
>
> +static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev,
> + uintptr_t priv,
> + const struct iio_chan_spec *chan,
> + char *buf)
> +{
> + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> +
> + return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq);
> +}
> +
> +static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
> + uintptr_t priv,
> + const struct iio_chan_spec *chan,
> + const char *buf, size_t len)
> +{
> + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> + struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
> + struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[adc->ch_id];
> + unsigned int sample_freq = adc->sample_freq;
> + unsigned int spi_freq;
> + int ret;
> +
> + dev_err(&indio_dev->dev, "enter %s\n", __func__);
> + /* If DFSDM is master on SPI, SPI freq can not be updated */
> + if (ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL)
> + return -EPERM;
> +
> + ret = kstrtoint(buf, 0, &spi_freq);
> + if (ret)
> + return ret;
> +
> + if (!spi_freq)
> + return -EINVAL;
> +
> + if (sample_freq) {
> + if (spi_freq % sample_freq)
> + dev_warn(&indio_dev->dev,
> + "Sampling rate not accurate (%d)\n",
> + spi_freq / (spi_freq / sample_freq));
> +
> + ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / sample_freq));
> + if (ret < 0) {
> + dev_err(&indio_dev->dev,
> + "No filter parameters that match!\n");
> + return ret;
> + }
> + }
> + adc->spi_freq = spi_freq;
> +
> + return len;
> +}
> +
> static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, bool dma)
> {
> struct regmap *regmap = adc->dfsdm->regmap;
> int ret;
> + unsigned int dma_en = 0, cont_en = 0;
>
> ret = stm32_dfsdm_start_channel(adc->dfsdm, adc->ch_id);
> if (ret < 0)
> @@ -365,6 +436,24 @@ static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, bool dma)
> if (ret < 0)
> goto stop_channels;
>
> + if (dma) {
> + /* Enable DMA transfer*/
> + dma_en = DFSDM_CR1_RDMAEN(1);
> + /* Enable conversion triggered by SPI clock*/
> + cont_en = DFSDM_CR1_RCONT(1);
> + }
> + /* Enable DMA transfer*/
> + ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
> + DFSDM_CR1_RDMAEN_MASK, dma_en);
> + if (ret < 0)
> + goto stop_channels;
> +
> + /* Enable conversion triggered by SPI clock*/
> + ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
> + DFSDM_CR1_RCONT_MASK, cont_en);
> + if (ret < 0)
> + goto stop_channels;
> +
> ret = stm32_dfsdm_start_filter(adc->dfsdm, adc->fl_id);
> if (ret < 0)
> goto stop_channels;
> @@ -398,6 +487,231 @@ static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc)
> stm32_dfsdm_stop_channel(adc->dfsdm, adc->ch_id);
> }
>
> +static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev,
> + unsigned int val)
> +{
> + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> + unsigned int watermark = DFSDM_DMA_BUFFER_SIZE / 2;
> +
> + /*
> + * DMA cyclic transfers are used, buffer is split into two periods.
> + * There should be :
> + * - always one buffer (period) DMA is working on
> + * - one buffer (period) driver pushed to ASoC side.
> + */
> + watermark = min(watermark, val * (unsigned int)(sizeof(u32)));
> + adc->buf_sz = watermark * 2;
> +
> + return 0;
> +}
> +
> +static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc)
> +{
> + struct dma_tx_state state;
> + enum dma_status status;
> +
> + status = dmaengine_tx_status(adc->dma_chan,
> + adc->dma_chan->cookie,
> + &state);
> + if (status == DMA_IN_PROGRESS) {
> + /* Residue is size in bytes from end of buffer */
> + unsigned int i = adc->buf_sz - state.residue;
> + unsigned int size;
> +
> + /* Return available bytes */
> + if (i >= adc->bufi)
> + size = i - adc->bufi;
> + else
> + size = adc->buf_sz + i - adc->bufi;
> +
> + return size;
> + }
> +
> + return 0;
> +}
> +
> +static void stm32_dfsdm_audio_dma_buffer_done(void *data)
> +{
> + struct iio_dev *indio_dev = data;
> + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> + int available = stm32_dfsdm_adc_dma_residue(adc);
> + size_t old_pos;
> +
> + /*
> + * FIXME: In Kernel interface does not support cyclic DMA buffer,and
> + * offers only an interface to push data samples per samples.
> + * For this reason IIO buffer interface is not used and interface is
> + * bypassed using a private callback registered by ASoC.
> + * This should be a temporary solution waiting a cyclic DMA engine
> + * support in IIO.
> + */
> +
> + dev_dbg(&indio_dev->dev, "%s: pos = %d, available = %d\n", __func__,
> + adc->bufi, available);
> + old_pos = adc->bufi;
> +
> + while (available >= indio_dev->scan_bytes) {
> + u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi];
> +
> + /* Mask 8 LSB that contains the channel ID */
> + *buffer = (*buffer & 0xFFFFFF00) << 8;
> + available -= indio_dev->scan_bytes;
> + adc->bufi += indio_dev->scan_bytes;
> + if (adc->bufi >= adc->buf_sz) {
> + if (adc->cb)
> + adc->cb(&adc->rx_buf[old_pos],
> + adc->buf_sz - old_pos, adc->cb_priv);
> + adc->bufi = 0;
> + old_pos = 0;
> + }
> + }
> + if (adc->cb)
> + adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos,
> + adc->cb_priv);
> +}
> +
> +static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
> +{
> + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> + struct dma_async_tx_descriptor *desc;
> + dma_cookie_t cookie;
> + int ret;
> +
> + if (!adc->dma_chan)
> + return -EINVAL;
> +
> + dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__,
> + adc->buf_sz, adc->buf_sz / 2);
> +
> + /* Prepare a DMA cyclic transaction */
> + desc = dmaengine_prep_dma_cyclic(adc->dma_chan,
> + adc->dma_buf,
> + adc->buf_sz, adc->buf_sz / 2,
> + DMA_DEV_TO_MEM,
> + DMA_PREP_INTERRUPT);
> + if (!desc)
> + return -EBUSY;
> +
> + desc->callback = stm32_dfsdm_audio_dma_buffer_done;
> + desc->callback_param = indio_dev;
> +
> + cookie = dmaengine_submit(desc);
> + ret = dma_submit_error(cookie);
> + if (ret) {
> + dmaengine_terminate_all(adc->dma_chan);
> + return ret;
> + }
> +
> + /* Issue pending DMA requests */
> + dma_async_issue_pending(adc->dma_chan);
> +
> + return 0;
> +}
> +
> +static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
> +{
> + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> + int ret;
> +
> + /* Reset adc buffer index */
> + adc->bufi = 0;
> +
> + ret = stm32_dfsdm_start_dfsdm(adc->dfsdm);
> + if (ret < 0)
> + return ret;
> +
> + ret = stm32_dfsdm_start_conv(adc, true);
> + if (ret) {
> + dev_err(&indio_dev->dev, "Can't start conversion\n");
> + goto stop_dfsdm;
> + }
> +
> + if (adc->dma_chan) {
> + ret = stm32_dfsdm_adc_dma_start(indio_dev);
> + if (ret) {
> + dev_err(&indio_dev->dev, "Can't start DMA\n");
> + goto err_stop_conv;
> + }
> + }
> +
> + return 0;
> +
> +err_stop_conv:
> + stm32_dfsdm_stop_conv(adc);
> +stop_dfsdm:
> + stm32_dfsdm_stop_dfsdm(adc->dfsdm);
> +
> + return ret;
> +}
> +
> +static int stm32_dfsdm_predisable(struct iio_dev *indio_dev)
> +{
> + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> +
> + if (adc->dma_chan)
> + dmaengine_terminate_all(adc->dma_chan);
> +
> + stm32_dfsdm_stop_conv(adc);
> +
> + stm32_dfsdm_stop_dfsdm(adc->dfsdm);
> +
> + return 0;
> +}
> +
> +static const struct iio_buffer_setup_ops stm32_dfsdm_buffer_setup_ops = {
> + .postenable = &stm32_dfsdm_postenable,
> + .predisable = &stm32_dfsdm_predisable,
> +};
> +
> +/**
> + * stm32_dfsdm_get_buff_cb() - register a callback that will be called when
> + * DMA transfer period is achieved.
> + *
> + * @iio_dev: Handle to IIO device.
> + * @cb: Pointer to callback function:
> + * - data: pointer to data buffer
> + * - size: size in byte of the data buffer
> + * - private: pointer to consumer private structure.
> + * @private: Pointer to consumer private structure.
> + */
> +int stm32_dfsdm_get_buff_cb(struct iio_dev *iio_dev,
> + int (*cb)(const void *data, size_t size,
> + void *private),
> + void *private)
> +{
> + struct stm32_dfsdm_adc *adc;
> +
> + if (!iio_dev)
> + return -EINVAL;
> + adc = iio_priv(iio_dev);
> +
> + adc->cb = cb;
> + adc->cb_priv = private;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(stm32_dfsdm_get_buff_cb);
> +
> +/**
> + * stm32_dfsdm_release_buff_cb - unregister buffer callback
> + *
> + * @iio_dev: Handle to IIO device.
> + */
> +int stm32_dfsdm_release_buff_cb(struct iio_dev *iio_dev)
> +{
> + struct stm32_dfsdm_adc *adc;
> +
> + if (!iio_dev)
> + return -EINVAL;
> + adc = iio_priv(iio_dev);
> +
> + adc->cb = NULL;
> + adc->cb_priv = NULL;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(stm32_dfsdm_release_buff_cb);
> +
> static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
> const struct iio_chan_spec *chan, int *res)
> {
> @@ -453,15 +767,41 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
> {
> struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
> + struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[adc->ch_id];
> + unsigned int spi_freq = adc->spi_freq;
> int ret = -EINVAL;
>
> - if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO) {
> + switch (mask) {
> + case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
> ret = stm32_dfsdm_set_osrs(fl, 0, val);
> if (!ret)
> adc->oversamp = val;
> +
> + return ret;
> +
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + if (!val)
> + return -EINVAL;
> + if (ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL)
> + spi_freq = adc->dfsdm->spi_master_freq;
> +
> + if (spi_freq % val)
> + dev_warn(&indio_dev->dev,
> + "Sampling rate not accurate (%d)\n",
> + spi_freq / (spi_freq / val));
> +
> + ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / val));
> + if (ret < 0) {
> + dev_err(&indio_dev->dev,
> + "Not able to find parameter that match!\n");
> + return ret;
> + }
> + adc->sample_freq = val;
> +
> + return 0;
> }
>
> - return ret;
> + return -EINVAL;
> }
>
> static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
> @@ -494,11 +834,22 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
> *val = adc->oversamp;
>
> return IIO_VAL_INT;
> +
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + *val = adc->sample_freq;
> +
> + return IIO_VAL_INT;
> }
>
> return -EINVAL;
> }
>
> +static const struct iio_info stm32_dfsdm_info_audio = {
> + .hwfifo_set_watermark = stm32_dfsdm_set_watermark,
> + .read_raw = stm32_dfsdm_read_raw,
> + .write_raw = stm32_dfsdm_write_raw,
> +};
> +
> static const struct iio_info stm32_dfsdm_info_adc = {
> .read_raw = stm32_dfsdm_read_raw,
> .write_raw = stm32_dfsdm_write_raw,
> @@ -531,6 +882,60 @@ static irqreturn_t stm32_dfsdm_irq(int irq, void *arg)
> return IRQ_HANDLED;
> }
>
> +/*
> + * Define external info for SPI Frequency and audio sampling rate that can be
> + * configured by ASoC driver through consumer.h API
> + */
> +static const struct iio_chan_spec_ext_info dfsdm_adc_audio_ext_info[] = {
> + /* spi_clk_freq : clock freq on SPI/manchester bus used by channel */
> + {
> + .name = "spi_clk_freq",
> + .shared = IIO_SHARED_BY_TYPE,
> + .read = dfsdm_adc_audio_get_spiclk,
> + .write = dfsdm_adc_audio_set_spiclk,
> + },
> + {},
> +};
> +
> +static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev)
> +{
> + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> + struct dma_slave_config config;
> + int ret;
> +
> + adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx");
> + if (!adc->dma_chan)
> + return -EINVAL;
> +
> + adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev,
> + DFSDM_DMA_BUFFER_SIZE,
> + &adc->dma_buf, GFP_KERNEL);
> + if (!adc->rx_buf) {
> + ret = -ENOMEM;
> + goto err_release;
> + }
> +
> + /* Configure DMA channel to read data register */
> + memset(&config, 0, sizeof(config));
> + config.src_addr = (dma_addr_t)adc->dfsdm->phys_base;
> + config.src_addr += DFSDM_RDATAR(adc->fl_id);
> + config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
Superficially looks like this could be more elegantly done
using C99 structure init above.
struct dma_slave_config config = {
.src_addr = (dma_addr_t)adc-dfsdm->phys_base +
DFSDM_RDATAR(adc->fl_ix),
.src_addr_width = DMA_SLAVE_BUS_WIDTH_4_BYTES
};
All the rest will be zeroed by the compiler..
> +
> + ret = dmaengine_slave_config(adc->dma_chan, &config);
> + if (ret)
> + goto err_free;
> +
> + return 0;
> +
> +err_free:
> + dma_free_coherent(adc->dma_chan->device->dev, DFSDM_DMA_BUFFER_SIZE,
> + adc->rx_buf, adc->dma_buf);
> +err_release:
> + dma_release_channel(adc->dma_chan);
> +
> + return ret;
> +}
> +
> static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
> struct iio_chan_spec *ch)
> {
> @@ -551,7 +956,12 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
> ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
> ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
>
> - ch->scan_type.sign = 'u';
> + if (adc->dev_data->type == DFSDM_AUDIO) {
> + ch->scan_type.sign = 's';
> + ch->ext_info = dfsdm_adc_audio_ext_info;
> + } else {
> + ch->scan_type.sign = 'u';
> + }
> ch->scan_type.realbits = 24;
> ch->scan_type.storagebits = 32;
> adc->ch_id = ch->channel;
> @@ -560,6 +970,64 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
> &adc->dfsdm->ch_list[ch->channel]);
> }
>
> +static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev)
> +{
> + struct iio_chan_spec *ch;
> + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> + struct stm32_dfsdm_channel *d_ch;
> + int ret;
> +
> + ret = stm32_dfsdm_dma_request(indio_dev);
> + if (ret) {
> + dev_err(&indio_dev->dev, "DMA request failed\n");
> + return ret;
> + }
> +
> + indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
> +
> + ret = iio_triggered_buffer_setup(indio_dev,
> + &iio_pollfunc_store_time,
Why? What reads the time?
I'm not terribly keen on this being used here given we don't actually
have a triggered_buffer... This is going to allocate an IIO kfifo
that we don't use as well (not huge, but not elegant to allocate
one we don't use).
> + NULL,
> + &stm32_dfsdm_buffer_setup_ops);
> + if (ret) {
> + dev_err(&indio_dev->dev, "Buffer setup failed\n");
> + goto err_dma_disable;
> + }
> +
> + ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL);
> + if (!ch)
> + return -ENOMEM;
> +
> + ch->scan_index = 0;
> + ret = stm32_dfsdm_adc_chan_init_one(indio_dev, ch);
> + if (ret < 0) {
> + dev_err(&indio_dev->dev, "channels init failed\n");
> + goto err_buffer_cleanup;
> + }
> + ch->info_mask_separate = BIT(IIO_CHAN_INFO_SAMP_FREQ);
> +
> + d_ch = &adc->dfsdm->ch_list[adc->ch_id];
> + if (d_ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL)
> + adc->spi_freq = adc->dfsdm->spi_master_freq;
> +
> + indio_dev->num_channels = 1;
> + indio_dev->channels = ch;
> +
> + return 0;
> +
> +err_buffer_cleanup:
> + iio_triggered_buffer_cleanup(indio_dev);
> +
> +err_dma_disable:
> + if (adc->dma_chan) {
> + dma_free_coherent(adc->dma_chan->device->dev,
> + DFSDM_DMA_BUFFER_SIZE,
> + adc->rx_buf, adc->dma_buf);
> + dma_release_channel(adc->dma_chan);
> + }
> + return ret;
> +}
> +
> static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
> {
> struct iio_chan_spec *ch;
> @@ -612,11 +1080,20 @@ static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_adc_data = {
> .init = stm32_dfsdm_adc_init,
> };
>
> +static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_audio_data = {
> + .type = DFSDM_AUDIO,
> + .init = stm32_dfsdm_audio_init,
> +};
> +
> static const struct of_device_id stm32_dfsdm_adc_match[] = {
> {
> .compatible = "st,stm32-dfsdm-adc",
> .data = &stm32h7_dfsdm_adc_data,
> },
> + {
> + .compatible = "st,stm32-dfsdm-dmic",
> + .data = &stm32h7_dfsdm_audio_data,
> + },
> {}
> };
>
> @@ -667,8 +1144,13 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
> name = devm_kzalloc(dev, sizeof("dfsdm-adc0"), GFP_KERNEL);
> if (!name)
> return -ENOMEM;
> - iio->info = &stm32_dfsdm_info_adc;
> - snprintf(name, sizeof("dfsdm-adc0"), "dfsdm-adc%d", adc->fl_id);
> + if (dev_data->type == DFSDM_AUDIO) {
> + iio->info = &stm32_dfsdm_info_audio;
> + snprintf(name, sizeof("dfsdm-pdm0"), "dfsdm-pdm%d", adc->fl_id);
> + } else {
> + iio->info = &stm32_dfsdm_info_adc;
> + snprintf(name, sizeof("dfsdm-adc0"), "dfsdm-adc%d", adc->fl_id);
> + }
> iio->name = name;
>
> /*
> @@ -700,7 +1182,10 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
> if (ret < 0)
> return ret;
>
> - return iio_device_register(iio);
> + iio_device_register(iio);
> + if (dev_data->type == DFSDM_AUDIO)
> + return devm_of_platform_populate(&pdev->dev);
Hmm. This is a little ugly in that the devm call will get
unwound after the IIO device is unregistered and all if it's
interfaces have gone away.
I don't think it 'matters' as such here but it would be
nicer if the remove order was the precise reverse of the probe order
and to do that you can't use a managed function here.
> + return 0;
> }
>
> static int stm32_dfsdm_adc_remove(struct platform_device *pdev)
> @@ -709,7 +1194,14 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev)
> struct iio_dev *indio_dev = iio_priv_to_dev(adc);
>
> iio_device_unregister(indio_dev);
> -
> + if (indio_dev->pollfunc)
> + iio_triggered_buffer_cleanup(indio_dev);
> + if (adc->dma_chan) {
> + dma_free_coherent(adc->dma_chan->device->dev,
> + DFSDM_DMA_BUFFER_SIZE,
> + adc->rx_buf, adc->dma_buf);
> + dma_release_channel(adc->dma_chan);
This is not in the reverse order of the probe as these are (I think)
set up in the audio init as a result of the platform populate?
So these should be before the iio_device_unregister.
This whole chunk is really an unwind of the audio init. I would
make that explicit by having an audio exit function called here.
> + }
> return 0;
> }
>
> diff --git a/include/linux/iio/adc/stm32-dfsdm-adc.h b/include/linux/iio/adc/stm32-dfsdm-adc.h
> new file mode 100644
> index 0000000..e7dc7a5
> --- /dev/null
> +++ b/include/linux/iio/adc/stm32-dfsdm-adc.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * This file discribe the STM32 DFSDM IIO driver API for audio part
> + *
> + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
> + * Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com>.
> + */
> +
> +#ifndef STM32_DFSDM_ADC_H
> +#define STM32_DFSDM_ADC_H
> +
> +int stm32_dfsdm_get_buff_cb(struct iio_dev *iio_dev,
> + int (*cb)(const void *data, size_t size,
> + void *private),
> + void *private);
> +int stm32_dfsdm_release_buff_cb(struct iio_dev *iio_dev);
> +
> +#endif
^ permalink raw reply
* [PATCH] nvmem: meson-mx-efuse: fix reading from an offset other than 0
From: Martin Blumenstingl @ 2017-12-10 18:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAFBinCBRs-enwX_-uRBOo0dXYPY3q0keD_-RZ_G=ZgsqhM1ARQ@mail.gmail.com>
Hi Srinivas, Hi Greg,
On Fri, Dec 1, 2017 at 10:24 PM, Martin Blumenstingl
<martin.blumenstingl@googlemail.com> wrote:
> Hi Srinivas, Hi Greg,
>
> On Sun, Nov 12, 2017 at 7:34 PM, Martin Blumenstingl
> <martin.blumenstingl@googlemail.com> wrote:
>> meson_mx_efuse_read calculates the address internal to the eFuse based
>> on the offset and the word size. This works fine with any given offset.
>> However, the offset is also included when writing to the output buffer.
>> This means that reading 4 bytes at offset 500 tries to write beyond the
>> array allocated by the nvmem core as it wants to write the 4 bytes to
>> "buffer address + offset (500)".
>> This issue did not show up in the previous tests since no driver uses
>> any value from the eFuse yet and reading the eFuse via sysfs simply
>> reads the whole eFuse, starting at offset 0.
>>
>> Fix this by only including the offset in the internal address
>> calculation.
>>
>> Fixes: 8caef1fa9176 ("nvmem: add a driver for the Amlogic Meson6/Meson8/Meson8b SoCs")
> if you don't have any comments on this patch: could you please queue
> it as a fix for 4.15 (which is where above commit landed)?
(gentle ping) do you have any comments for this patch?
Regards
Martin
^ permalink raw reply
* [PATCH v7 04/13] IIO: inkern: API for manipulating channel attributes
From: Jonathan Cameron @ 2017-12-10 17:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512744566-13233-5-git-send-email-arnaud.pouliquen@st.com>
On Fri, 8 Dec 2017 15:49:17 +0100
Arnaud Pouliquen <arnaud.pouliquen@st.com> wrote:
> Extend the inkern API with functions for reading and writing
> attribute of iio channels.
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
One nitpick inline. If you aren't rerolling can get sorted
whilst applying the series.
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> ---
> V6 to V7 update:
> - Move iio_chan_info_enum from iio.h to types.h.
>
> drivers/iio/inkern.c | 18 +++++++++++++-----
> include/linux/iio/consumer.h | 26 ++++++++++++++++++++++++++
> include/linux/iio/iio.h | 28 ----------------------------
> include/linux/iio/types.h | 28 ++++++++++++++++++++++++++++
> 4 files changed, 67 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
> index 069defc..f2e7824 100644
> --- a/drivers/iio/inkern.c
> +++ b/drivers/iio/inkern.c
> @@ -664,9 +664,8 @@ int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
> }
> EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed);
>
> -static int iio_read_channel_attribute(struct iio_channel *chan,
> - int *val, int *val2,
> - enum iio_chan_info_enum attribute)
> +int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2,
> + enum iio_chan_info_enum attribute)
> {
> int ret;
>
> @@ -682,6 +681,8 @@ static int iio_read_channel_attribute(struct iio_channel *chan,
>
> return ret;
> }
> +EXPORT_SYMBOL_GPL(iio_read_channel_attribute);
> +
Nitpick if you are rerolling the series. Don't need the extra line here.
>
> int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2)
> {
> @@ -850,7 +851,8 @@ static int iio_channel_write(struct iio_channel *chan, int val, int val2,
> chan->channel, val, val2, info);
> }
>
> -int iio_write_channel_raw(struct iio_channel *chan, int val)
> +int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2,
> + enum iio_chan_info_enum attribute)
> {
> int ret;
>
> @@ -860,12 +862,18 @@ int iio_write_channel_raw(struct iio_channel *chan, int val)
> goto err_unlock;
> }
>
> - ret = iio_channel_write(chan, val, 0, IIO_CHAN_INFO_RAW);
> + ret = iio_channel_write(chan, val, val2, attribute);
> err_unlock:
> mutex_unlock(&chan->indio_dev->info_exist_lock);
>
> return ret;
> }
> +EXPORT_SYMBOL_GPL(iio_write_channel_attribute);
> +
> +int iio_write_channel_raw(struct iio_channel *chan, int val)
> +{
> + return iio_write_channel_attribute(chan, val, 0, IIO_CHAN_INFO_RAW);
> +}
> EXPORT_SYMBOL_GPL(iio_write_channel_raw);
>
> unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
> diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
> index 5e347a9..2017f35 100644
> --- a/include/linux/iio/consumer.h
> +++ b/include/linux/iio/consumer.h
> @@ -216,6 +216,32 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val);
> int iio_read_channel_processed(struct iio_channel *chan, int *val);
>
> /**
> + * iio_write_channel_attribute() - Write values to the device attribute.
> + * @chan: The channel being queried.
> + * @val: Value being written.
> + * @val2: Value being written.val2 use depends on attribute type.
> + * @attribute: info attribute to be read.
> + *
> + * Returns an error code or 0.
> + */
> +int iio_write_channel_attribute(struct iio_channel *chan, int val,
> + int val2, enum iio_chan_info_enum attribute);
> +
> +/**
> + * iio_read_channel_attribute() - Read values from the device attribute.
> + * @chan: The channel being queried.
> + * @val: Value being written.
> + * @val2: Value being written.Val2 use depends on attribute type.
> + * @attribute: info attribute to be written.
> + *
> + * Returns an error code if failed. Else returns a description of what is in val
> + * and val2, such as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val
> + * + val2/1e6
> + */
> +int iio_read_channel_attribute(struct iio_channel *chan, int *val,
> + int *val2, enum iio_chan_info_enum attribute);
> +
> +/**
> * iio_write_channel_raw() - write to a given channel
> * @chan: The channel being queried.
> * @val: Value being written.
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index c380daa..007caf7 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -20,34 +20,6 @@
> * Currently assumes nano seconds.
> */
>
> -enum iio_chan_info_enum {
> - IIO_CHAN_INFO_RAW = 0,
> - IIO_CHAN_INFO_PROCESSED,
> - IIO_CHAN_INFO_SCALE,
> - IIO_CHAN_INFO_OFFSET,
> - IIO_CHAN_INFO_CALIBSCALE,
> - IIO_CHAN_INFO_CALIBBIAS,
> - IIO_CHAN_INFO_PEAK,
> - IIO_CHAN_INFO_PEAK_SCALE,
> - IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW,
> - IIO_CHAN_INFO_AVERAGE_RAW,
> - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY,
> - IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY,
> - IIO_CHAN_INFO_SAMP_FREQ,
> - IIO_CHAN_INFO_FREQUENCY,
> - IIO_CHAN_INFO_PHASE,
> - IIO_CHAN_INFO_HARDWAREGAIN,
> - IIO_CHAN_INFO_HYSTERESIS,
> - IIO_CHAN_INFO_INT_TIME,
> - IIO_CHAN_INFO_ENABLE,
> - IIO_CHAN_INFO_CALIBHEIGHT,
> - IIO_CHAN_INFO_CALIBWEIGHT,
> - IIO_CHAN_INFO_DEBOUNCE_COUNT,
> - IIO_CHAN_INFO_DEBOUNCE_TIME,
> - IIO_CHAN_INFO_CALIBEMISSIVITY,
> - IIO_CHAN_INFO_OVERSAMPLING_RATIO,
> -};
> -
> enum iio_shared_by {
> IIO_SEPARATE,
> IIO_SHARED_BY_TYPE,
> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
> index 2aa7b63..6eb3d683 100644
> --- a/include/linux/iio/types.h
> +++ b/include/linux/iio/types.h
> @@ -34,4 +34,32 @@ enum iio_available_type {
> IIO_AVAIL_RANGE,
> };
>
> +enum iio_chan_info_enum {
> + IIO_CHAN_INFO_RAW = 0,
> + IIO_CHAN_INFO_PROCESSED,
> + IIO_CHAN_INFO_SCALE,
> + IIO_CHAN_INFO_OFFSET,
> + IIO_CHAN_INFO_CALIBSCALE,
> + IIO_CHAN_INFO_CALIBBIAS,
> + IIO_CHAN_INFO_PEAK,
> + IIO_CHAN_INFO_PEAK_SCALE,
> + IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW,
> + IIO_CHAN_INFO_AVERAGE_RAW,
> + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY,
> + IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY,
> + IIO_CHAN_INFO_SAMP_FREQ,
> + IIO_CHAN_INFO_FREQUENCY,
> + IIO_CHAN_INFO_PHASE,
> + IIO_CHAN_INFO_HARDWAREGAIN,
> + IIO_CHAN_INFO_HYSTERESIS,
> + IIO_CHAN_INFO_INT_TIME,
> + IIO_CHAN_INFO_ENABLE,
> + IIO_CHAN_INFO_CALIBHEIGHT,
> + IIO_CHAN_INFO_CALIBWEIGHT,
> + IIO_CHAN_INFO_DEBOUNCE_COUNT,
> + IIO_CHAN_INFO_DEBOUNCE_TIME,
> + IIO_CHAN_INFO_CALIBEMISSIVITY,
> + IIO_CHAN_INFO_OVERSAMPLING_RATIO,
> +};
> +
> #endif /* _IIO_TYPES_H_ */
^ permalink raw reply
* [PATCH 5/8] power: supply: axp20x_battery: add support for AXP813
From: Jonathan Cameron @ 2017-12-10 16:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <545d3aa6339c9e33060d651c42d652d0b848c06b.1512396054.git-series.quentin.schulz@free-electrons.com>
On Mon, 4 Dec 2017 15:12:51 +0100
Quentin Schulz <quentin.schulz@free-electrons.com> wrote:
> The X-Powers AXP813 PMIC has got some slight differences from
> AXP20X/AXP22X PMICs:
> - the maximum voltage supplied by the PMIC is 4.35 instead of 4.36/4.24
> for AXP20X/AXP22X,
> - the constant charge current formula is different,
>
> It also has a bit to tell whether the battery percentage returned by the
> PMIC is valid.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
I'd use switch statements when matching the IDs as that'll be more elegant
as you perhaps add further devices going forward...
Other than that, looks good to me.
Jonathan
> ---
> drivers/power/supply/axp20x_battery.c | 44 +++++++++++++++++++++++++++-
> 1 file changed, 43 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
> index 7494f0f..cb30302 100644
> --- a/drivers/power/supply/axp20x_battery.c
> +++ b/drivers/power/supply/axp20x_battery.c
> @@ -46,6 +46,8 @@
> #define AXP20X_CHRG_CTRL1_TGT_4_2V (2 << 5)
> #define AXP20X_CHRG_CTRL1_TGT_4_36V (3 << 5)
>
> +#define AXP813_CHRG_CTRL1_TGT_4_35V (3 << 5)
> +
> #define AXP22X_CHRG_CTRL1_TGT_4_22V (1 << 5)
> #define AXP22X_CHRG_CTRL1_TGT_4_24V (3 << 5)
>
> @@ -123,10 +125,41 @@ static int axp22x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
> return 0;
> }
>
> +static int axp813_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
> + int *val)
> +{
> + int ret, reg;
> +
> + ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, ®);
> + if (ret)
> + return ret;
> +
> + switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
You could do a lookup based from a table instead which might
be ever so slightly more elegant..
> + case AXP20X_CHRG_CTRL1_TGT_4_1V:
> + *val = 4100000;
> + break;
> + case AXP20X_CHRG_CTRL1_TGT_4_15V:
> + *val = 4150000;
> + break;
> + case AXP20X_CHRG_CTRL1_TGT_4_2V:
> + *val = 4200000;
> + break;
> + case AXP813_CHRG_CTRL1_TGT_4_35V:
> + *val = 4350000;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> static void raw_to_constant_charge_current(struct axp20x_batt_ps *axp, int *val)
> {
> if (axp->axp_id == AXP209_ID)
> *val = *val * 100000 + 300000;
> + else if (axp->axp_id == AXP813_ID)
> + *val = *val * 200000 + 200000;
> else
> *val = *val * 150000 + 300000;
Switch?
> }
> @@ -135,6 +168,8 @@ static void constant_charge_current_to_raw(struct axp20x_batt_ps *axp, int *val)
> {
> if (axp->axp_id == AXP209_ID)
> *val = (*val - 300000) / 100000;
> + else if (axp->axp_id == AXP813_ID)
> + *val = (*val - 200000) / 200000;
> else
> *val = (*val - 300000) / 150000;
> }
> @@ -269,7 +304,8 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
> if (ret)
> return ret;
>
> - if (axp20x_batt->axp_id == AXP221_ID &&
> + if ((axp20x_batt->axp_id == AXP221_ID ||
> + axp20x_batt->axp_id == AXP813_ID) &&
> !(reg & AXP22X_FG_VALID))
> return -EINVAL;
>
> @@ -284,6 +320,9 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
> if (axp20x_batt->axp_id == AXP209_ID)
> return axp20x_battery_get_max_voltage(axp20x_batt,
> &val->intval);
> + else if (axp20x_batt->axp_id == AXP813_ID)
> + return axp813_battery_get_max_voltage(axp20x_batt,
> + &val->intval);
> return axp22x_battery_get_max_voltage(axp20x_batt,
> &val->intval);
Worth converting to a switch statement to make it more elegant for future
devices?
>
> @@ -467,6 +506,9 @@ static const struct of_device_id axp20x_battery_ps_id[] = {
> }, {
> .compatible = "x-powers,axp221-battery-power-supply",
> .data = (void *)AXP221_ID,
> + }, {
> + .compatible = "x-powers,axp813-battery-power-supply",
> + .data = (void *)AXP813_ID,
> }, { /* sentinel */ },
> };
> MODULE_DEVICE_TABLE(of, axp20x_battery_ps_id);
^ permalink raw reply
* [PATCH 4/8] dt-bindings: power: supply: axp20x: add AXP813 battery DT binding
From: Jonathan Cameron @ 2017-12-10 16:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <bf3682e87c75532884881d7b08840c61678cbce1.1512396054.git-series.quentin.schulz@free-electrons.com>
On Mon, 4 Dec 2017 15:12:50 +0100
Quentin Schulz <quentin.schulz@free-electrons.com> wrote:
> The AXP813 can have a battery as power supply, so let's add it to the
> list of compatibles.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
> ---
> Documentation/devicetree/bindings/power/supply/axp20x_battery.txt | 8 +++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt b/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
> index c248866..4614c8e 100644
> --- a/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
> +++ b/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
> @@ -4,12 +4,12 @@ Required Properties:
> - compatible, one of:
> "x-powers,axp209-battery-power-supply"
> "x-powers,axp221-battery-power-supply"
> + "x-powers,axp813-battery-power-supply"
>
> -This node is a subnode of the axp20x/axp22x PMIC.
> +This node is a subnode of the axp20x/axp22x/axp81x PMIC.
>
> -The AXP20X and AXP22X can read the battery voltage, charge and discharge
> -currents of the battery by reading ADC channels from the AXP20X/AXP22X
> -ADC.
> +The AXP20X, AXP22X and AXP81X can read the battery voltage, charge and
> +discharge currents of the battery by reading ADC channels from the ADC.
Might just be me, but this looks like a recipe for unneeded churn in future.
The supported devices can read...
Maybe also
This node is a subnode of the PMIC with the same part number. ?
I don't really care though!
>
> Example:
>
^ permalink raw reply
* [PATCH 3/8] mfd: axp20x: probe axp20x_adc driver for AXP813
From: Jonathan Cameron @ 2017-12-10 16:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v66esOimRhDHL6QgYU3iWg2a6JiQm__0ivv3SdnQv=SGQg@mail.gmail.com>
On Thu, 7 Dec 2017 17:14:30 +0800
Chen-Yu Tsai <wens@csie.org> wrote:
> On Thu, Dec 7, 2017 at 5:03 PM, Quentin Schulz
> <quentin.schulz@free-electrons.com> wrote:
> > Hi Chen-Yu,
> >
> > On 07/12/2017 09:54, Chen-Yu Tsai wrote:
> >> On Thu, Dec 7, 2017 at 4:51 PM, Quentin Schulz
> >> <quentin.schulz@free-electrons.com> wrote:
> >>> Hi Maxime,
> >>>
> >>> On 05/12/2017 09:08, Maxime Ripard wrote:
> >>>> On Mon, Dec 04, 2017 at 03:12:49PM +0100, Quentin Schulz wrote:
> >>>>> This makes the axp20x_adc driver probe with platform device id
> >>>>> "axp813-adc".
> >>>>>
> >>>>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
> >>>>> ---
> >>>>> drivers/mfd/axp20x.c | 4 +++-
> >>>>> 1 file changed, 3 insertions(+), 1 deletion(-)
> >>>>>
> >>>>> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
> >>>>> index 2468b43..42e54d1 100644
> >>>>> --- a/drivers/mfd/axp20x.c
> >>>>> +++ b/drivers/mfd/axp20x.c
> >>>>> @@ -878,7 +878,9 @@ static struct mfd_cell axp813_cells[] = {
> >>>>> .resources = axp803_pek_resources,
> >>>>> }, {
> >>>>> .name = "axp20x-regulator",
> >>>>> - }
> >>>>> + }, {
> >>>>> + .name = "axp813-adc",
> >>>>> + },
> >>>>
> >>>> Any particular reason you're not adding it to the DT?
> >>>>
> >>>
> >>> No, no particular reason. It's just the way it is currently for AXP209
> >>> and AXP22x so did the same for AXP813.
> >>>
> >>> I'll add DT "support" in next version for all AXPs supported by this
> >>> driver. Or is it worthy of a small separate patch series?
> >>
> >> IIRC there's no DT support because there's no need to reference
> >> it in the device tree.
> >>
> >
> > No current need but that does not mean there won't be a need later for
> > drivers to map IIO channels from the ADC driver (i.e. some components
> > wired to GPIOs of the PMIC for example).
>
> Hmm... Why would you map the IIO channels from the ADC? I thought those
> were all accessible from userspace?
There is a reasonably fully featured consumer interface for IIO channels
as well. Here it's being used internal to the hardware, but yes if
you want to do the mappings to other devices, it will need to 'exist'
in the device tree.
I'm guessing that you have something in mind that needs this. If not I'd
leave it until there is a real user.
>
> However, proper muxing of the GPIO pin to the ADC function makes sense.
>
Agreed.
Jonathan
> ChenYu
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH V7 0/7] dmaengine: qcom_hidma: add support for bugfixed HW
From: Vinod Koul @ 2017-12-10 16:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <bad52be7-4ff8-4f06-4bd0-83e97701f495@codeaurora.org>
On Fri, Dec 08, 2017 at 09:44:46AM -0500, Sinan Kaya wrote:
> On 12/8/2017 8:48 AM, Rafael J. Wysocki wrote:
> > The series is fine by me, by how do you want to route it?
>
> Probably through the DMA engine route as it has pieces that didn't get any
> review from Vinod yet.
>
> Vinod,
>
> Do you have any preference?
Yeah sure sounds okay to me as DMA parts are dependent on these.
Rafael if you need an immutable tag to pull this, let me know.
Thanks
--
~Vinod
^ permalink raw reply
* [linux-sunxi] [PATCH 1/8] iio: adc: axp20x_adc: put ADC rate setting in a per-variant function
From: Jonathan Cameron @ 2017-12-10 16:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v64er1xMXCFDfNKqGjGN-TysQyjK+vfHdx0t+kaCchQfCg@mail.gmail.com>
On Tue, 5 Dec 2017 11:35:49 +0800
Chen-Yu Tsai <wens@csie.org> wrote:
> On Mon, Dec 4, 2017 at 10:12 PM, Quentin Schulz
> <quentin.schulz@free-electrons.com> wrote:
> > To prepare for a new comer that set a different register with different
> > values, move rate setting in a function that is specific to each AXP
> > variant.
> >
> > Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
> > ---
> > drivers/iio/adc/axp20x_adc.c | 17 ++++++++++-------
> > 1 file changed, 10 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
> > index a30a972..7274f4f 100644
> > --- a/drivers/iio/adc/axp20x_adc.c
> > +++ b/drivers/iio/adc/axp20x_adc.c
> > @@ -470,14 +470,18 @@ static const struct iio_info axp22x_adc_iio_info = {
> > .read_raw = axp22x_read_raw,
> > };
> >
> > -static int axp20x_adc_rate(int rate)
> > +static int axp20x_adc_rate(struct axp20x_adc_iio *info, int rate)
> > {
> > - return AXP20X_ADC_RATE_HZ(rate);
> > + return regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
> > + AXP20X_ADC_RATE_MASK,
> > + AXP20X_ADC_RATE_HZ(rate));
> > }
> >
> > -static int axp22x_adc_rate(int rate)
> > +static int axp22x_adc_rate(struct axp20x_adc_iio *info, int rate)
> > {
> > - return AXP22X_ADC_RATE_HZ(rate);
> > + return regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
> > + AXP20X_ADC_RATE_MASK,
> > + AXP22X_ADC_RATE_HZ(rate));
> > }
> >
> > struct axp_data {
> > @@ -485,7 +489,7 @@ struct axp_data {
> > int num_channels;
> > struct iio_chan_spec const *channels;
> > unsigned long adc_en1_mask;
> > - int (*adc_rate)(int rate);
> > + int (*adc_rate)(struct axp20x_adc_iio *info, int rate);
>
> Could you also change the name of the callback, to say, adc_set_rate?
> This would make it much clearer what the callback does. Previously
> it was just a conversion helper.
>
Agreed.
With that change you can add my
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Thanks,
Jonathan
> ChenYu
>
> > bool adc_en2;
> > struct iio_map *maps;
> > };
> > @@ -554,8 +558,7 @@ static int axp20x_probe(struct platform_device *pdev)
> > AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
> >
> > /* Configure ADCs rate */
> > - regmap_update_bits(info->regmap, AXP20X_ADC_RATE, AXP20X_ADC_RATE_MASK,
> > - info->data->adc_rate(100));
> > + info->data->adc_rate(info, 100);
> >
> > ret = iio_map_array_register(indio_dev, info->data->maps);
> > if (ret < 0) {
> > --
> > git-series 0.9.1
> >
> > --
> > You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> > To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe at googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 2/8] iio: adc: axp20x_adc: add support for AXP813 ADC
From: Jonathan Cameron @ 2017-12-10 16:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <ef830ce470a4f0f4be6040a776b6928bf89c0143.1512396054.git-series.quentin.schulz@free-electrons.com>
On Mon, 4 Dec 2017 15:12:48 +0100
Quentin Schulz <quentin.schulz@free-electrons.com> wrote:
> The X-Powers AXP813 PMIC is really close to what is already done for
> AXP20X/AXP22X.
>
> There are two pairs of bits to set the rate (one for Voltage and Current
> measurements and one for TS/GPIO0 voltage measurements) instead of one.
This would normally imply we need to split the device into two logical
IIO devices. However, that only becomes relevant if we are using
buffered output which this driver doesn't support.
It'll be nasty to deal with this if we add that support down the line
though. Up to you though as it's more likely to be your problem than
anyone else's :)
For now you could elect to support the different sampling frequencies
if you wanted to but just providing controls for each channel.
Given the driver doesn't currently expose these at all (I think)
this is all rather immaterial ;)
>
> The register to set the ADC rates is different from the one for
> AXP20X/AXP22X.
>
> GPIO0 can be used as an ADC (measuring Volts) unlike for AXP22X.
>
> The scales to apply to the different inputs are unlike the ones from
> AXP20X and AXP22X.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Looks good to me.
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
I'm assuming these will probably go via MFD..
Jonathan
> ---
> drivers/iio/adc/axp20x_adc.c | 122 ++++++++++++++++++++++++++++++++++++-
> include/linux/mfd/axp20x.h | 2 +-
> 2 files changed, 124 insertions(+)
>
> diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
> index 7274f4f..03d489b 100644
> --- a/drivers/iio/adc/axp20x_adc.c
> +++ b/drivers/iio/adc/axp20x_adc.c
> @@ -35,8 +35,13 @@
> #define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x) (((x) & BIT(0)) << 1)
>
> #define AXP20X_ADC_RATE_MASK GENMASK(7, 6)
> +#define AXP813_V_I_ADC_RATE_MASK GENMASK(5, 4)
> +#define AXP813_ADC_RATE_MASK (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK)
> #define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
> #define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
> +#define AXP813_TS_GPIO0_ADC_RATE_HZ(x) AXP20X_ADC_RATE_HZ(x)
> +#define AXP813_V_I_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 4) & AXP813_V_I_ADC_RATE_MASK)
> +#define AXP813_ADC_RATE_HZ(x) (AXP20X_ADC_RATE_HZ(x) | AXP813_V_I_ADC_RATE_HZ(x))
>
> #define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg) \
> { \
> @@ -95,6 +100,12 @@ enum axp22x_adc_channel_i {
> AXP22X_BATT_DISCHRG_I,
> };
>
> +enum axp813_adc_channel_v {
> + AXP813_TS_IN = 0,
> + AXP813_GPIO0_V,
> + AXP813_BATT_V,
> +};
> +
> static struct iio_map axp20x_maps[] = {
> {
> .consumer_dev_name = "axp20x-usb-power-supply",
> @@ -197,6 +208,25 @@ static const struct iio_chan_spec axp22x_adc_channels[] = {
> AXP20X_BATT_DISCHRG_I_H),
> };
>
> +static const struct iio_chan_spec axp813_adc_channels[] = {
> + {
> + .type = IIO_TEMP,
> + .address = AXP22X_PMIC_TEMP_H,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> + BIT(IIO_CHAN_INFO_SCALE) |
> + BIT(IIO_CHAN_INFO_OFFSET),
> + .datasheet_name = "pmic_temp",
> + },
> + AXP20X_ADC_CHANNEL(AXP813_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
> + AXP288_GP_ADC_H),
> + AXP20X_ADC_CHANNEL(AXP813_BATT_V, "batt_v", IIO_VOLTAGE,
> + AXP20X_BATT_V_H),
> + AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
> + AXP20X_BATT_CHRG_I_H),
> + AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
> + AXP20X_BATT_DISCHRG_I_H),
> +};
> +
> static int axp20x_adc_raw(struct iio_dev *indio_dev,
> struct iio_chan_spec const *chan, int *val)
> {
> @@ -243,6 +273,18 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev,
> return IIO_VAL_INT;
> }
>
> +static int axp813_adc_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val)
> +{
> + struct axp20x_adc_iio *info = iio_priv(indio_dev);
> +
> + *val = axp20x_read_variable_width(info->regmap, chan->address, 12);
> + if (*val < 0)
> + return *val;
> +
> + return IIO_VAL_INT;
> +}
> +
> static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
> {
> switch (channel) {
> @@ -273,6 +315,24 @@ static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
> }
> }
>
> +static int axp813_adc_scale_voltage(int channel, int *val, int *val2)
> +{
> + switch (channel) {
> + case AXP813_GPIO0_V:
> + *val = 0;
> + *val2 = 800000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + case AXP813_BATT_V:
> + *val = 1;
> + *val2 = 100000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> static int axp20x_adc_scale_current(int channel, int *val, int *val2)
> {
> switch (channel) {
> @@ -342,6 +402,26 @@ static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
> }
> }
>
> +static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val,
> + int *val2)
> +{
> + switch (chan->type) {
> + case IIO_VOLTAGE:
> + return axp813_adc_scale_voltage(chan->channel, val, val2);
> +
> + case IIO_CURRENT:
> + *val = 1;
> + return IIO_VAL_INT;
> +
> + case IIO_TEMP:
> + *val = 100;
> + return IIO_VAL_INT;
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
> int *val)
> {
> @@ -425,6 +505,26 @@ static int axp22x_read_raw(struct iio_dev *indio_dev,
> }
> }
>
> +static int axp813_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + switch (mask) {
> + case IIO_CHAN_INFO_OFFSET:
> + *val = -2667;
> + return IIO_VAL_INT;
> +
> + case IIO_CHAN_INFO_SCALE:
> + return axp813_adc_scale(chan, val, val2);
> +
> + case IIO_CHAN_INFO_RAW:
> + return axp813_adc_raw(indio_dev, chan, val);
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> static int axp20x_write_raw(struct iio_dev *indio_dev,
> struct iio_chan_spec const *chan, int val, int val2,
> long mask)
> @@ -470,6 +570,10 @@ static const struct iio_info axp22x_adc_iio_info = {
> .read_raw = axp22x_read_raw,
> };
>
> +static const struct iio_info axp813_adc_iio_info = {
> + .read_raw = axp813_read_raw,
> +};
> +
> static int axp20x_adc_rate(struct axp20x_adc_iio *info, int rate)
> {
> return regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
> @@ -484,6 +588,13 @@ static int axp22x_adc_rate(struct axp20x_adc_iio *info, int rate)
> AXP22X_ADC_RATE_HZ(rate));
> }
>
> +static int axp813_adc_rate(struct axp20x_adc_iio *info, int rate)
> +{
> + return regmap_update_bits(info->regmap, AXP813_ADC_RATE,
> + AXP813_ADC_RATE_MASK,
> + AXP813_ADC_RATE_HZ(rate));
> +}
> +
> struct axp_data {
> const struct iio_info *iio_info;
> int num_channels;
> @@ -514,9 +625,20 @@ static const struct axp_data axp22x_data = {
> .maps = axp22x_maps,
> };
>
> +static const struct axp_data axp813_data = {
> + .iio_info = &axp813_adc_iio_info,
> + .num_channels = ARRAY_SIZE(axp813_adc_channels),
> + .channels = axp813_adc_channels,
> + .adc_en1_mask = AXP22X_ADC_EN1_MASK,
> + .adc_rate = axp813_adc_rate,
> + .adc_en2 = false,
> + .maps = axp22x_maps,
> +};
> +
> static const struct platform_device_id axp20x_adc_id_match[] = {
> { .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
> { .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
> + { .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, },
> { /* sentinel */ },
> };
> MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);
> diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
> index 78dc853..ff95414 100644
> --- a/include/linux/mfd/axp20x.h
> +++ b/include/linux/mfd/axp20x.h
> @@ -266,6 +266,8 @@ enum axp20x_variants {
> #define AXP288_RT_BATT_V_H 0xa0
> #define AXP288_RT_BATT_V_L 0xa1
>
> +#define AXP813_ADC_RATE 0x85
> +
> /* Fuel Gauge */
> #define AXP288_FG_RDC1_REG 0xba
> #define AXP288_FG_RDC0_REG 0xbb
^ permalink raw reply
* [PATCH v1 6/6] ARM: dts: imx7s: add usb hsic phy domain
From: Fabio Estevam @ 2017-12-10 15:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171205222707.11302-7-tyler@opensourcefoundries.com>
On Tue, Dec 5, 2017 at 8:27 PM, <tyler@opensourcefoundries.com> wrote:
> From: Tyler Baker <tyler@opensourcefoundries.com>
>
> The GPCv2 driver should control the MIPI, PCIe,
> and USB HSIC PHY regulators. Add the USB HSIC
> power domain to the GPC node.
>
> Signed-off-by: Tyler Baker <tyler@opensourcefoundries.com>
Looks good. I am assuming you tested USB HSIC operation on the mx7
compulab board, right?
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
^ permalink raw reply
* [PATCH v1 5/6] ARM: dts: imx7d-sbc-iot: enable PCIe peripheral
From: Fabio Estevam @ 2017-12-10 15:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171205222707.11302-6-tyler@opensourcefoundries.com>
On Tue, Dec 5, 2017 at 8:27 PM, <tyler@opensourcefoundries.com> wrote:
> From: Tyler Baker <tyler@opensourcefoundries.com>
>
> Add a PCIe device tree node to enable PCIe support.
>
> Signed-off-by: Tyler Baker <tyler@opensourcefoundries.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
^ permalink raw reply
* [PATCH v1 4/6] ARM: dts: imx7s: add node and supplies for vdd1p2
From: Fabio Estevam @ 2017-12-10 15:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171205222707.11302-5-tyler@opensourcefoundries.com>
On Tue, Dec 5, 2017 at 8:27 PM, <tyler@opensourcefoundries.com> wrote:
> From: Tyler Baker <tyler@opensourcefoundries.com>
>
> Add the regulator nodes and supplies for vdd1p2. This regulator is
> used to power the GPC and USB HSIC PHY.
>
> Signed-off-by: Tyler Baker <tyler@opensourcefoundries.com>
> ---
> arch/arm/boot/dts/imx7s.dtsi | 17 ++++++++++++++++-
> 1 file changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
> index 7b85659..151ab34 100644
> --- a/arch/arm/boot/dts/imx7s.dtsi
> +++ b/arch/arm/boot/dts/imx7s.dtsi
> @@ -522,6 +522,20 @@
> anatop-max-voltage = <1200000>;
> anatop-enable-bit = <0>;
> };
> +
> + reg_1p2: regulator-vdd1p2 at 220 {
Using a unit address without a corresponding reg would give you a
warning with W=1.
Please see the patch I sent with Subject:
ARM: dts: imx7s: Add unit address and reg for the anatop nodes
^ permalink raw reply
* [PATCH v1 3/6] ARM: dts: imx7s: add dma support
From: Fabio Estevam @ 2017-12-10 15:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171205222707.11302-4-tyler@opensourcefoundries.com>
On Tue, Dec 5, 2017 at 8:27 PM, <tyler@opensourcefoundries.com> wrote:
> From: Tyler Baker <tyler@opensourcefoundries.com>
>
> Enable dma on all SPI interfaces.
>
> Signed-off-by: Tyler Baker <tyler@opensourcefoundries.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
^ permalink raw reply
* [PATCH v1 2/6] ARM: dts: imx7d-cl-som: add nodes for usbh, and usbotg2
From: Fabio Estevam @ 2017-12-10 15:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171205222707.11302-3-tyler@opensourcefoundries.com>
On Tue, Dec 5, 2017 at 8:27 PM, <tyler@opensourcefoundries.com> wrote:
> From: Tyler Baker <tyler@opensourcefoundries.com>
>
> Add device tree nodes for the USB hub, and USB OTG. i2c2 on this
> platform supports low state retention power state so lets use it.
Looks like the I2C2 fix should be a separate patch.
^ permalink raw reply
* [PATCH v1 1/6] ARM: dts: imx7d-sbc-iot: add initial iot gateway dts
From: Fabio Estevam @ 2017-12-10 15:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171205222707.11302-2-tyler@opensourcefoundries.com>
On Tue, Dec 5, 2017 at 8:27 PM, <tyler@opensourcefoundries.com> wrote:
> +&usdhc1 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usdhc1>;
> + cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
> + wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
> + enable-sdio-wakeup;
This is a deprecated property.
Please use wakeup-source as stated in
Documentation/devicetree/bindings/mmc/mmc.txt
^ permalink raw reply
* [PATCH] arm: imx: suspend/resume: use outer_disable/resume
From: Peng Fan @ 2017-12-10 12:07 UTC (permalink / raw)
To: linux-arm-kernel
Use outer_disable/resume for suspend/resume.
With the two APIs used, code could be simplified and easy to extend
to introduce l2c_write_sec for i.MX platforms when moving Linux Kernel
runs in non-secure world.
Signed-off-by: Peng Fan <peng.fan@nxp.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Dong Aisheng <aisheng.dong@nxp.com>
---
arch/arm/mach-imx/pm-imx6.c | 2 ++
arch/arm/mach-imx/suspend-imx6.S | 24 ------------------------
2 files changed, 2 insertions(+), 24 deletions(-)
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index ecdf071653d4..153a0afc7645 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -392,8 +392,10 @@ static int imx6q_pm_enter(suspend_state_t state)
imx6_enable_rbc(true);
imx_gpc_pre_suspend(true);
imx_anatop_pre_suspend();
+ outer_disable();
/* Zzz ... */
cpu_suspend(0, imx6q_suspend_finish);
+ outer_resume();
if (cpu_is_imx6q() || cpu_is_imx6dl())
imx_smp_prepare();
imx_anatop_post_resume();
diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index 76ee2ceec8d5..324f6b165e82 100644
--- a/arch/arm/mach-imx/suspend-imx6.S
+++ b/arch/arm/mach-imx/suspend-imx6.S
@@ -74,24 +74,6 @@
.align 3
- .macro sync_l2_cache
-
- /* sync L2 cache to drain L2's buffers to DRAM. */
-#ifdef CONFIG_CACHE_L2X0
- ldr r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
- teq r11, #0
- beq 6f
- mov r6, #0x0
- str r6, [r11, #L2X0_CACHE_SYNC]
-1:
- ldr r6, [r11, #L2X0_CACHE_SYNC]
- ands r6, r6, #0x1
- bne 1b
-6:
-#endif
-
- .endm
-
.macro resume_mmdc
/* restore MMDC IO */
@@ -185,9 +167,6 @@ ENTRY(imx6_suspend)
str r9, [r11, #MX6Q_SRC_GPR1]
str r1, [r11, #MX6Q_SRC_GPR2]
- /* need to sync L2 cache before DSM. */
- sync_l2_cache
-
ldr r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
/*
* put DDR explicitly into self-refresh and
@@ -342,8 +321,5 @@ ENDPROC(imx6_suspend)
ENTRY(v7_cpu_resume)
bl v7_invalidate_l1
-#ifdef CONFIG_CACHE_L2X0
- bl l2c310_early_resume
-#endif
b cpu_resume
ENDPROC(v7_cpu_resume)
--
2.14.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox