* [PATCH 4/5] regulator: Add support for TI TWL6032
From: Rosia, Nicolae @ 2016-11-26 20:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201611270236.UFgW5zDA%fengguang.wu@intel.com>
Hi,
On Sun, 2016-11-27 at 02:55 +0800, kbuild test robot wrote:
> Hi Nicolae,
>
> [auto build test ERROR on omap/for-next]
> [also build test ERROR on v4.9-rc6]
> [cannot apply to next-20161125]
> [if your patch is applied to the wrong git tree, please drop us a
> note to help improve the system]
>
> url:????https://github.com/0day-ci/linux/commits/Nicolae-Rosia/mfd-tw
> l-improvements-and-new-regulator-driver/20161127-022201
> base:???https://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-
> omap.git for-next
> config: i386-allmodconfig (attached as .config)
> compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
> reproduce:
> ????????# save the attached .config to linux build tree
> ????????make ARCH=i386?
>
> All error/warnings (new ones prefixed by >>):
>
> ???In file included from drivers/regulator/twl6032-regulator.c:11:0:
> > > drivers/regulator/twl6032-regulator.c:557:31: error:
> > > 'twl6032_regulator_driver_ids' undeclared here (not in a
> > > function)
>
> ????MODULE_DEVICE_TABLE(platform, twl6032_regulator_driver_ids);
> ??????????????????????????????????^
> ???include/linux/module.h:213:21: note: in definition of macro
> 'MODULE_DEVICE_TABLE'
> ????extern const typeof(name)
> __mod_##type##__##name##_device_table??\
> ????????????????????????^~~~
> > > include/linux/module.h:213:27: error:
> > > '__mod_platform__twl6032_regulator_driver_ids_device_table'
> > > aliased to undefined symbol 'twl6032_regulator_driver_ids'
>
> ????extern const typeof(name)
> __mod_##type##__##name##_device_table??\
> ??????????????????????????????^
> > > drivers/regulator/twl6032-regulator.c:557:1: note: in expansion
> > > of macro 'MODULE_DEVICE_TABLE'
>
> ????MODULE_DEVICE_TABLE(platform, twl6032_regulator_driver_ids);
> ????^~~~~~~~~~~~~~~~~~~
>
> vim +/twl6032_regulator_driver_ids +557 drivers/regulator/twl6032-
> regulator.c
>
> ???551
> ???552 static const struct of_device_id twl6032_dt_match[] = {
> ???553 { .compatible = "ti,twl6032-regulator" },
> ???554 { /* last entry */ }
> ???555 };
> ???556
> ?> 557 MODULE_DEVICE_TABLE(platform,
> twl6032_regulator_driver_ids);
> ???558
> ???559 static struct platform_driver twl6032_regulator_driver
> = {
> ???560 .driver = {
Thanks, I did not notice this since I was only testing using built-in
module.
I will wait for comments before sending V2, untill then here's an
inline patch with the fix.
Best regards,
Nicolae
^ permalink raw reply
* [PATCH 2/2] crypto: arm/crc32 - accelerated support based on x86 SSE implementation
From: Ard Biesheuvel @ 2016-11-26 20:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480191314-2331-1-git-send-email-ard.biesheuvel@linaro.org>
This is a combination of the the Intel algorithm implemented using SSE
and PCLMULQDQ instructions from arch/x86/crypto/crc32-pclmul_asm.S, and
the new CRC32 extensions introduced for both 32-bit and 64-bit ARM in
version 8 of the architecture.
The PMULL/NEON algorithm is faster, but operates on blocks of at least
64 bytes, and on multiples of 16 bytes only. For the remaining input,
or for all input on systems that lack the PMULL 64x64->128 instructions,
the CRC32 instructions will be used.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm/crypto/Kconfig | 5 +
arch/arm/crypto/Makefile | 2 +
arch/arm/crypto/crc32-ce-core.S | 257 ++++++++++++++++++++
arch/arm/crypto/crc32-ce-glue.c | 129 ++++++++++
4 files changed, 393 insertions(+)
diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig
index fce801fa52a1..be5cb5a7d3fa 100644
--- a/arch/arm/crypto/Kconfig
+++ b/arch/arm/crypto/Kconfig
@@ -125,4 +125,9 @@ config CRYPTO_CRCT10DIF_ARM_CE
depends on KERNEL_MODE_NEON && CRC_T10DIF
select CRYPTO_HASH
+config CRYPTO_CRC32_ARM_CE
+ tristate "CRC32 digest algorithm using CRC and/or PMULL instructions"
+ depends on KERNEL_MODE_NEON && CRC32
+ select CRYPTO_HASH
+
endif
diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile
index fc77265014b7..b578a1820ab1 100644
--- a/arch/arm/crypto/Makefile
+++ b/arch/arm/crypto/Makefile
@@ -14,6 +14,7 @@ ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o
ce-obj-$(CONFIG_CRYPTO_SHA2_ARM_CE) += sha2-arm-ce.o
ce-obj-$(CONFIG_CRYPTO_GHASH_ARM_CE) += ghash-arm-ce.o
ce-obj-$(CONFIG_CRYPTO_CRCT10DIF_ARM_CE) += crct10dif-arm-ce.o
+ce-obj-$(CONFIG_CRYPTO_CRC32_ARM_CE) += crc32-arm-ce.o
ifneq ($(ce-obj-y)$(ce-obj-m),)
ifeq ($(call as-instr,.fpu crypto-neon-fp-armv8,y,n),y)
@@ -38,6 +39,7 @@ sha2-arm-ce-y := sha2-ce-core.o sha2-ce-glue.o
aes-arm-ce-y := aes-ce-core.o aes-ce-glue.o
ghash-arm-ce-y := ghash-ce-core.o ghash-ce-glue.o
crct10dif-arm-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o
+crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o
quiet_cmd_perl = PERL $@
cmd_perl = $(PERL) $(<) > $(@)
diff --git a/arch/arm/crypto/crc32-ce-core.S b/arch/arm/crypto/crc32-ce-core.S
new file mode 100644
index 000000000000..ef671f040672
--- /dev/null
+++ b/arch/arm/crypto/crc32-ce-core.S
@@ -0,0 +1,257 @@
+/*
+ * Accelerated CRC32 using ARM CRC, NEON and Crypto Extensions instructions
+ *
+ * Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ *
+ * Using hardware provided PCLMULQDQ instruction to accelerate the CRC32
+ * calculation.
+ * CRC32 polynomial:0x04c11db7(BE)/0xEDB88320(LE)
+ * PCLMULQDQ is a new instruction in Intel SSE4.2, the reference can be found
+ * at:
+ * http://www.intel.com/products/processor/manuals/
+ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual
+ * Volume 2B: Instruction Set Reference, N-Z
+ *
+ * Authors: Gregory Prestas <Gregory_Prestas@us.xyratex.com>
+ * Alexander Boyko <Alexander_Boyko@xyratex.com>
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+ .text
+ .align 4
+ .arch armv8-a
+ .arch_extension crc
+ .fpu crypto-neon-fp-armv8
+
+ /*
+ * [x4*128+32 mod P(x) << 32)]' << 1 = 0x154442bd4
+ * #define CONSTANT_R1 0x154442bd4LL
+ *
+ * [(x4*128-32 mod P(x) << 32)]' << 1 = 0x1c6e41596
+ * #define CONSTANT_R2 0x1c6e41596LL
+ */
+.Lconstant_R2R1:
+ .quad 0x0000000154442bd4
+ .quad 0x00000001c6e41596
+
+ /*
+ * [(x128+32 mod P(x) << 32)]' << 1 = 0x1751997d0
+ * #define CONSTANT_R3 0x1751997d0LL
+ *
+ * [(x128-32 mod P(x) << 32)]' << 1 = 0x0ccaa009e
+ * #define CONSTANT_R4 0x0ccaa009eLL
+ */
+.Lconstant_R4R3:
+ .quad 0x00000001751997d0
+ .quad 0x00000000ccaa009e
+
+ /*
+ * [(x64 mod P(x) << 32)]' << 1 = 0x163cd6124
+ * #define CONSTANT_R5 0x163cd6124LL
+ */
+.Lconstant_R5:
+ .quad 0x0000000163cd6124
+
+.Lconstant_mask32:
+ .quad 0x00000000FFFFFFFF
+
+ /*
+ * #define CRCPOLY_TRUE_LE_FULL 0x1DB710641LL
+ *
+ * Barrett Reduction constant (u64`) = u` = (x**64 / P(x))`
+ * = 0x1F7011641LL
+ * #define CONSTANT_RU 0x1F7011641LL
+ */
+.Lconstant_RUpoly:
+ .quad 0x00000001DB710641
+ .quad 0x00000001F7011641
+
+ dCONSTANTl .req d0
+ dCONSTANTh .req d1
+ qCONSTANT .req q0
+
+ BUF .req r0
+ LEN .req r1
+ CRC .req r2
+
+ qzr .req q9
+
+ /**
+ * Calculate crc32
+ * BUF - buffer
+ * LEN - sizeof buffer (multiple of 16 bytes), LEN should be > 63
+ * CRC - initial crc32
+ * return %eax crc32
+ * uint crc32_pmull_le(unsigned char const *buffer,
+ * size_t len, uint crc32)
+ */
+ENTRY(crc32_pmull_le)
+ bic LEN, LEN, #15
+ vld1.8 {q1-q2}, [BUF]!
+ vld1.8 {q3-q4}, [BUF]!
+ vmov.i8 qzr, #0
+ vmov.i8 qCONSTANT, #0
+ vmov dCONSTANTl[0], CRC
+ veor.8 d2, d2, dCONSTANTl
+ sub LEN, LEN, #0x40
+ cmp LEN, #0x40
+ blt less_64
+
+ vldr dCONSTANTl, .Lconstant_R2R1
+ vldr dCONSTANTh, .Lconstant_R2R1 + 8
+
+loop_64: /* 64 bytes Full cache line folding */
+ sub LEN, LEN, #0x40
+
+ vmull.p64 q5, d3, dCONSTANTh
+ vmull.p64 q6, d5, dCONSTANTh
+ vmull.p64 q7, d7, dCONSTANTh
+ vmull.p64 q8, d9, dCONSTANTh
+
+ vmull.p64 q1, d2, dCONSTANTl
+ vmull.p64 q2, d4, dCONSTANTl
+ vmull.p64 q3, d6, dCONSTANTl
+ vmull.p64 q4, d8, dCONSTANTl
+
+ veor.8 q1, q1, q5
+ vld1.8 {q5}, [BUF]!
+ veor.8 q2, q2, q6
+ vld1.8 {q6}, [BUF]!
+ veor.8 q3, q3, q7
+ vld1.8 {q7}, [BUF]!
+ veor.8 q4, q4, q8
+ vld1.8 {q8}, [BUF]!
+
+ veor.8 q1, q1, q5
+ veor.8 q2, q2, q6
+ veor.8 q3, q3, q7
+ veor.8 q4, q4, q8
+
+ cmp LEN, #0x40
+ bge loop_64
+
+less_64: /* Folding cache line into 128bit */
+ vldr dCONSTANTl, .Lconstant_R4R3
+ vldr dCONSTANTh, .Lconstant_R4R3 + 8
+
+ vmull.p64 q5, d3, dCONSTANTh
+ vmull.p64 q1, d2, dCONSTANTl
+ veor.8 q1, q1, q5
+ veor.8 q1, q1, q2
+
+ vmull.p64 q5, d3, dCONSTANTh
+ vmull.p64 q1, d2, dCONSTANTl
+ veor.8 q1, q1, q5
+ veor.8 q1, q1, q3
+
+ vmull.p64 q5, d3, dCONSTANTh
+ vmull.p64 q1, d2, dCONSTANTl
+ veor.8 q1, q1, q5
+ veor.8 q1, q1, q4
+
+ teq LEN, #0
+ beq fold_64
+
+loop_16: /* Folding rest buffer into 128bit */
+ subs LEN, LEN, #0x10
+
+ vld1.8 {q2}, [BUF]!
+ vmull.p64 q5, d3, dCONSTANTh
+ vmull.p64 q1, d2, dCONSTANTl
+ veor.8 q1, q1, q5
+ veor.8 q1, q1, q2
+
+ bne loop_16
+
+fold_64:
+ /* perform the last 64 bit fold, also adds 32 zeroes
+ * to the input stream */
+ vmull.p64 q2, d2, dCONSTANTh
+ vext.8 q1, q1, qzr, #8
+ veor.8 q1, q1, q2
+
+ /* final 32-bit fold */
+ vldr dCONSTANTl, .Lconstant_R5
+ vldr d6, .Lconstant_mask32
+ vmov.i8 d7, #0
+
+ vext.8 q2, q1, qzr, #4
+ vand.8 d2, d2, d6
+ vmull.p64 q1, d2, dCONSTANTl
+ veor.8 q1, q1, q2
+
+ /* Finish up with the bit-reversed barrett reduction 64 ==> 32 bits */
+ vldr dCONSTANTl, .Lconstant_RUpoly
+ vldr dCONSTANTh, .Lconstant_RUpoly + 8
+
+ vand.8 q2, q1, q3
+ vext.8 q2, qzr, q2, #8
+ vmull.p64 q2, d5, dCONSTANTh
+ vand.8 q2, q2, q3
+ vmull.p64 q2, d4, dCONSTANTl
+ veor.8 q1, q1, q2
+ vmov r0, s5
+
+ bx lr
+ENDPROC(crc32_pmull_le)
+
+ENTRY(crc32_armv8_le)
+ mov ip, r2
+0: subs ip, ip, #8
+ bmi 4f
+ ldrd r2, r3, [r1], #8
+ARM_BE8(rev r2, r2 )
+ARM_BE8(rev r3, r3 )
+ crc32w r0, r0, r2
+ crc32w r0, r0, r3
+ b 0b
+
+4: tst ip, #4
+ beq 2f
+ ldr r3, [r1], #4
+ARM_BE8(rev r3, r3 )
+ crc32w r0, r0, r3
+2: tst ip, #2
+ beq 1f
+ ldrh r3, [r1], #2
+ARM_BE8(rev16 r3, r3 )
+ crc32h r0, r0, r3
+1: tst ip, #1
+ bxeq lr
+ ldrb r3, [r1]
+ crc32b r0, r0, r3
+ bx lr
+ENDPROC(crc32_armv8_le)
diff --git a/arch/arm/crypto/crc32-ce-glue.c b/arch/arm/crypto/crc32-ce-glue.c
new file mode 100644
index 000000000000..61916b6b40e9
--- /dev/null
+++ b/arch/arm/crypto/crc32-ce-glue.c
@@ -0,0 +1,129 @@
+/*
+ * Accelerated CRC32 using ARM CRC, NEON and Crypto Extensions instructions
+ *
+ * Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/crc32.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <crypto/internal/hash.h>
+
+#include <asm/hwcap.h>
+#include <asm/neon.h>
+#include <asm/simd.h>
+#include <asm/unaligned.h>
+
+#define PMULL_MIN_LEN 64L /* minimum size of buffer
+ * for crc32_pmull_le_16 */
+#define SCALE_F 16L /* size of NEON register */
+
+asmlinkage u32 crc32_pmull_le(const u8 buf[], u32 len, u32 init_crc);
+asmlinkage u32 crc32_armv8_le(u32 init_crc, const u8 buf[], u32 len);
+
+static int crc32_pmull_cra_init(struct crypto_tfm *tfm)
+{
+ u32 *key = crypto_tfm_ctx(tfm);
+
+ *key = 0;
+ return 0;
+}
+
+static int crc32_pmull_setkey(struct crypto_shash *hash, const u8 *key,
+ unsigned int keylen)
+{
+ u32 *mctx = crypto_shash_ctx(hash);
+
+ if (keylen != sizeof(u32)) {
+ crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+ *mctx = le32_to_cpup((__le32 *)key);
+ return 0;
+}
+
+static int crc32_pmull_init(struct shash_desc *desc)
+{
+ u32 *mctx = crypto_shash_ctx(desc->tfm);
+ u32 *crc = shash_desc_ctx(desc);
+
+ *crc = *mctx;
+ return 0;
+}
+
+static int crc32_pmull_update(struct shash_desc *desc, const u8 *data,
+ unsigned int length)
+{
+ u32 *crc = shash_desc_ctx(desc);
+
+ if (length >= PMULL_MIN_LEN && may_use_simd() &&
+ (elf_hwcap2 & HWCAP2_PMULL)) {
+ kernel_neon_begin();
+ *crc = crc32_pmull_le(data, round_down(length, SCALE_F), *crc);
+ kernel_neon_end();
+
+ data += round_down(length, SCALE_F);
+ length %= SCALE_F;
+ }
+
+ if (length > 0) {
+ if (elf_hwcap2 & HWCAP2_CRC32)
+ *crc = crc32_armv8_le(*crc, data, length);
+ else
+ *crc = crc32_le(*crc, data, length);
+ }
+
+ return 0;
+}
+
+static int crc32_pmull_final(struct shash_desc *desc, u8 *out)
+{
+ u32 *crc = shash_desc_ctx(desc);
+
+ put_unaligned_le32(*crc, out);
+ return 0;
+}
+
+static struct shash_alg crc32_pmull_alg = {
+ .setkey = crc32_pmull_setkey,
+ .init = crc32_pmull_init,
+ .update = crc32_pmull_update,
+ .final = crc32_pmull_final,
+ .descsize = sizeof(u32),
+ .digestsize = sizeof(u32),
+
+ .base.cra_ctxsize = sizeof(u32),
+ .base.cra_init = crc32_pmull_cra_init,
+ .base.cra_name = "crc32",
+ .base.cra_driver_name = "crc32-arm-ce",
+ .base.cra_priority = 200,
+ .base.cra_blocksize = 1,
+ .base.cra_module = THIS_MODULE,
+};
+
+static int __init crc32_pmull_mod_init(void)
+{
+ if (!(elf_hwcap2 & (HWCAP2_PMULL|HWCAP2_CRC32)))
+ return -ENODEV;
+
+ return crypto_register_shash(&crc32_pmull_alg);
+}
+
+static void __exit crc32_pmull_mod_exit(void)
+{
+ crypto_unregister_shash(&crc32_pmull_alg);
+}
+
+module_init(crc32_pmull_mod_init);
+module_exit(crc32_pmull_mod_exit);
+
+MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_CRYPTO("crc32");
--
2.7.4
^ permalink raw reply related
* [PATCH 1/2] crypto: arm64/crc32 - accelerated support based on x86 SSE implementation
From: Ard Biesheuvel @ 2016-11-26 20:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480191314-2331-1-git-send-email-ard.biesheuvel@linaro.org>
This is a combination of the the Intel algorithm implemented using SSE
and PCLMULQDQ instructions from arch/x86/crypto/crc32-pclmul_asm.S, and
the new CRC32 extensions introduced for both 32-bit and 64-bit ARM in
version 8 of the architecture.
The PMULL/NEON algorithm is faster, but operates on blocks of at least
64 bytes, and on multiples of 16 bytes only. For the remaining input,
or for all input on systems that lack the PMULL 64x64->128 instructions,
the CRC32 instructions will be used.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/crypto/Kconfig | 6 +
arch/arm64/crypto/Makefile | 3 +
arch/arm64/crypto/crc32-ce-core.S | 246 ++++++++++++++++++++
arch/arm64/crypto/crc32-ce-glue.c | 124 ++++++++++
4 files changed, 379 insertions(+)
diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig
index 1b50671ffec3..11dc2ac1f2e5 100644
--- a/arch/arm64/crypto/Kconfig
+++ b/arch/arm64/crypto/Kconfig
@@ -58,4 +58,10 @@ config CRYPTO_CRC32_ARM64
tristate "CRC32 and CRC32C using optional ARMv8 instructions"
depends on ARM64
select CRYPTO_HASH
+
+config CRYPTO_CRC32_ARM64_CE
+ tristate "CRC32 digest algorithm using PMULL instructions"
+ depends on ARM64 && KERNEL_MODE_NEON
+ select CRYPTO_HASH
+
endif
diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile
index 36fd3eb4201b..144387805a46 100644
--- a/arch/arm64/crypto/Makefile
+++ b/arch/arm64/crypto/Makefile
@@ -20,6 +20,9 @@ ghash-ce-y := ghash-ce-glue.o ghash-ce-core.o
obj-$(CONFIG_CRYPTO_CRCT10DIF_ARM64_CE) += crct10dif-ce.o
crct10dif-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o
+obj-$(CONFIG_CRYPTO_CRC32_ARM64_CE) += crc32-ce.o
+crc32-ce-y:= crc32-ce-core.o crc32-ce-glue.o
+
obj-$(CONFIG_CRYPTO_AES_ARM64_CE) += aes-ce-cipher.o
CFLAGS_aes-ce-cipher.o += -march=armv8-a+crypto
diff --git a/arch/arm64/crypto/crc32-ce-core.S b/arch/arm64/crypto/crc32-ce-core.S
new file mode 100644
index 000000000000..eff7fe100dab
--- /dev/null
+++ b/arch/arm64/crypto/crc32-ce-core.S
@@ -0,0 +1,246 @@
+/*
+ * Accelerated CRC32 using arm64 CRC, NEON and Crypto Extensions instructions
+ *
+ * Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ *
+ * Using hardware provided PCLMULQDQ instruction to accelerate the CRC32
+ * calculation.
+ * CRC32 polynomial:0x04c11db7(BE)/0xEDB88320(LE)
+ * PCLMULQDQ is a new instruction in Intel SSE4.2, the reference can be found
+ * at:
+ * http://www.intel.com/products/processor/manuals/
+ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual
+ * Volume 2B: Instruction Set Reference, N-Z
+ *
+ * Authors: Gregory Prestas <Gregory_Prestas@us.xyratex.com>
+ * Alexander Boyko <Alexander_Boyko@xyratex.com>
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+
+ .text
+ .align 4
+ .cpu generic+crypto+crc
+
+ /*
+ * [x4*128+32 mod P(x) << 32)]' << 1 = 0x154442bd4
+ * #define CONSTANT_R1 0x154442bd4LL
+ *
+ * [(x4*128-32 mod P(x) << 32)]' << 1 = 0x1c6e41596
+ * #define CONSTANT_R2 0x1c6e41596LL
+ */
+.Lconstant_R2R1:
+ .octa 0x00000001c6e415960000000154442bd4
+
+ /*
+ * [(x128+32 mod P(x) << 32)]' << 1 = 0x1751997d0
+ * #define CONSTANT_R3 0x1751997d0LL
+ *
+ * [(x128-32 mod P(x) << 32)]' << 1 = 0x0ccaa009e
+ * #define CONSTANT_R4 0x0ccaa009eLL
+ */
+.Lconstant_R4R3:
+ .octa 0x00000000ccaa009e00000001751997d0
+
+ /*
+ * [(x64 mod P(x) << 32)]' << 1 = 0x163cd6124
+ * #define CONSTANT_R5 0x163cd6124LL
+ */
+.Lconstant_R5:
+ .octa 0x00000000000000000000000163cd6124
+.Lconstant_mask32:
+ .octa 0x000000000000000000000000FFFFFFFF
+
+ /*
+ * #define CRCPOLY_TRUE_LE_FULL 0x1DB710641LL
+ *
+ * Barrett Reduction constant (u64`) = u` = (x**64 / P(x))`
+ * = 0x1F7011641LL
+ * #define CONSTANT_RU 0x1F7011641LL
+ */
+.Lconstant_RUpoly:
+ .octa 0x00000001F701164100000001DB710641
+
+ vCONSTANT .req v0
+ dCONSTANT .req d0
+ qCONSTANT .req q0
+
+ BUF .req x0
+ LEN .req x1
+ CRC .req x2
+
+ vzr .req v9
+
+ /**
+ * Calculate crc32
+ * BUF - buffer
+ * LEN - sizeof buffer (multiple of 16 bytes), LEN should be > 63
+ * CRC - initial crc32
+ * return %eax crc32
+ * uint crc32_pmull_le(unsigned char const *buffer,
+ * size_t len, uint crc32)
+ */
+ENTRY(crc32_pmull_le)
+ bic LEN, LEN, #15
+ ld1 {v1.16b-v4.16b}, [BUF], #0x40
+ movi vzr.16b, #0
+ fmov dCONSTANT, CRC
+ eor v1.16b, v1.16b, vCONSTANT.16b
+ sub LEN, LEN, #0x40
+ cmp LEN, #0x40
+ b.lt less_64
+
+ ldr qCONSTANT, .Lconstant_R2R1
+
+loop_64: /* 64 bytes Full cache line folding */
+ sub LEN, LEN, #0x40
+
+ pmull2 v5.1q, v1.2d, vCONSTANT.2d
+ pmull2 v6.1q, v2.2d, vCONSTANT.2d
+ pmull2 v7.1q, v3.2d, vCONSTANT.2d
+ pmull2 v8.1q, v4.2d, vCONSTANT.2d
+
+ pmull v1.1q, v1.1d, vCONSTANT.1d
+ pmull v2.1q, v2.1d, vCONSTANT.1d
+ pmull v3.1q, v3.1d, vCONSTANT.1d
+ pmull v4.1q, v4.1d, vCONSTANT.1d
+
+ eor v1.16b, v1.16b, v5.16b
+ ld1 {v5.16b}, [BUF], #0x10
+ eor v2.16b, v2.16b, v6.16b
+ ld1 {v6.16b}, [BUF], #0x10
+ eor v3.16b, v3.16b, v7.16b
+ ld1 {v7.16b}, [BUF], #0x10
+ eor v4.16b, v4.16b, v8.16b
+ ld1 {v8.16b}, [BUF], #0x10
+
+ eor v1.16b, v1.16b, v5.16b
+ eor v2.16b, v2.16b, v6.16b
+ eor v3.16b, v3.16b, v7.16b
+ eor v4.16b, v4.16b, v8.16b
+
+ cmp LEN, #0x40
+ b.ge loop_64
+
+less_64: /* Folding cache line into 128bit */
+ ldr qCONSTANT, .Lconstant_R4R3
+
+ pmull2 v5.1q, v1.2d, vCONSTANT.2d
+ pmull v1.1q, v1.1d, vCONSTANT.1d
+ eor v1.16b, v1.16b, v5.16b
+ eor v1.16b, v1.16b, v2.16b
+
+ pmull2 v5.1q, v1.2d, vCONSTANT.2d
+ pmull v1.1q, v1.1d, vCONSTANT.1d
+ eor v1.16b, v1.16b, v5.16b
+ eor v1.16b, v1.16b, v3.16b
+
+ pmull2 v5.1q, v1.2d, vCONSTANT.2d
+ pmull v1.1q, v1.1d, vCONSTANT.1d
+ eor v1.16b, v1.16b, v5.16b
+ eor v1.16b, v1.16b, v4.16b
+
+ cbz LEN, fold_64
+
+loop_16: /* Folding rest buffer into 128bit */
+ subs LEN, LEN, #0x10
+
+ ld1 {v2.16b}, [BUF], #0x10
+ pmull2 v5.1q, v1.2d, vCONSTANT.2d
+ pmull v1.1q, v1.1d, vCONSTANT.1d
+ eor v1.16b, v1.16b, v5.16b
+ eor v1.16b, v1.16b, v2.16b
+
+ b.ne loop_16
+
+fold_64:
+ /* perform the last 64 bit fold, also adds 32 zeroes
+ * to the input stream */
+ ext v2.16b, v1.16b, v1.16b, #8
+ pmull2 v2.1q, v2.2d, vCONSTANT.2d
+ ext v1.16b, v1.16b, vzr.16b, #8
+ eor v1.16b, v1.16b, v2.16b
+
+ /* final 32-bit fold */
+ ldr qCONSTANT, .Lconstant_R5
+ ldr q3, .Lconstant_mask32
+
+ ext v2.16b, v1.16b, vzr.16b, #4
+ and v1.16b, v1.16b, v3.16b
+ pmull v1.1q, v1.1d, vCONSTANT.1d
+ eor v1.16b, v1.16b, v2.16b
+
+ /* Finish up with the bit-reversed barrett reduction 64 ==> 32 bits */
+ ldr qCONSTANT, .Lconstant_RUpoly
+
+ and v2.16b, v1.16b, v3.16b
+ ext v2.16b, vzr.16b, v2.16b, #8
+ pmull2 v2.1q, v2.2d, vCONSTANT.2d
+ and v2.16b, v2.16b, v3.16b
+ pmull v2.1q, v2.1d, vCONSTANT.1d
+ eor v1.16b, v1.16b, v2.16b
+ mov w0, v1.s[1]
+
+ ret
+ENDPROC(crc32_pmull_le)
+
+ENTRY(crc32_armv8_le)
+0: subs x2, x2, #16
+ b.mi 8f
+ ldp x3, x4, [x1], #16
+CPU_BE( rev x3, x3 )
+CPU_BE( rev x4, x4 )
+ crc32x w0, w0, x3
+ crc32x w0, w0, x4
+ b 0b
+
+8: tbz x2, #3, 4f
+ ldr x3, [x1], #8
+CPU_BE( rev x3, x3 )
+ crc32x w0, w0, x3
+4: tbz x2, #2, 2f
+ ldr w3, [x1], #4
+CPU_BE( rev w3, w3 )
+ crc32w w0, w0, w3
+2: tbz x2, #1, 1f
+ ldrh w3, [x1], #2
+CPU_BE( rev16 w3, w3 )
+ crc32h w0, w0, w3
+1: tbz x2, #0, 0f
+ ldrb w3, [x1]
+ crc32b w0, w0, w3
+0: ret
+ENDPROC(crc32_armv8_le)
diff --git a/arch/arm64/crypto/crc32-ce-glue.c b/arch/arm64/crypto/crc32-ce-glue.c
new file mode 100644
index 000000000000..567203f29ac6
--- /dev/null
+++ b/arch/arm64/crypto/crc32-ce-glue.c
@@ -0,0 +1,124 @@
+/*
+ * Accelerated CRC32 using arm64 NEON and Crypto Extensions instructions
+ *
+ * Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/cpufeature.h>
+#include <linux/crc32.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <crypto/internal/hash.h>
+
+#include <asm/hwcap.h>
+#include <asm/neon.h>
+#include <asm/unaligned.h>
+
+#define PMULL_MIN_LEN 64L /* minimum size of buffer
+ * for crc32_pmull_le_16 */
+#define SCALE_F 16L /* size of NEON register */
+
+asmlinkage u32 crc32_pmull_le(const u8 buf[], u64 len, u32 init_crc);
+asmlinkage u32 crc32_armv8_le(u32 init_crc, const u8 buf[], u64 len);
+
+static int crc32_pmull_cra_init(struct crypto_tfm *tfm)
+{
+ u32 *key = crypto_tfm_ctx(tfm);
+
+ *key = 0;
+ return 0;
+}
+
+static int crc32_pmull_setkey(struct crypto_shash *hash, const u8 *key,
+ unsigned int keylen)
+{
+ u32 *mctx = crypto_shash_ctx(hash);
+
+ if (keylen != sizeof(u32)) {
+ crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+ *mctx = le32_to_cpup((__le32 *)key);
+ return 0;
+}
+
+static int crc32_pmull_init(struct shash_desc *desc)
+{
+ u32 *mctx = crypto_shash_ctx(desc->tfm);
+ u32 *crc = shash_desc_ctx(desc);
+
+ *crc = *mctx;
+ return 0;
+}
+
+static int crc32_pmull_update(struct shash_desc *desc, const u8 *data,
+ unsigned int length)
+{
+ u32 *crc = shash_desc_ctx(desc);
+
+ if (length >= PMULL_MIN_LEN) {
+ kernel_neon_begin_partial(10);
+ *crc = crc32_pmull_le(data, round_down(length, SCALE_F), *crc);
+ kernel_neon_end();
+
+ data += round_down(length, SCALE_F);
+ length %= SCALE_F;
+ }
+
+ if (length > 0) {
+ if (elf_hwcap & HWCAP_CRC32)
+ *crc = crc32_armv8_le(*crc, data, length);
+ else
+ *crc = crc32_le(*crc, data, length);
+ }
+
+ return 0;
+}
+
+static int crc32_pmull_final(struct shash_desc *desc, u8 *out)
+{
+ u32 *crc = shash_desc_ctx(desc);
+
+ put_unaligned_le32(*crc, out);
+ return 0;
+}
+
+static struct shash_alg crc32_pmull_alg = {
+ .setkey = crc32_pmull_setkey,
+ .init = crc32_pmull_init,
+ .update = crc32_pmull_update,
+ .final = crc32_pmull_final,
+ .descsize = sizeof(u32),
+ .digestsize = sizeof(u32),
+
+ .base.cra_ctxsize = sizeof(u32),
+ .base.cra_init = crc32_pmull_cra_init,
+ .base.cra_name = "crc32",
+ .base.cra_driver_name = "crc32-arm64-ce",
+ .base.cra_priority = 200,
+ .base.cra_blocksize = 1,
+ .base.cra_module = THIS_MODULE,
+};
+
+static int __init crc32_pmull_mod_init(void)
+{
+ return crypto_register_shash(&crc32_pmull_alg);
+}
+
+static void __exit crc32_pmull_mod_exit(void)
+{
+ crypto_unregister_shash(&crc32_pmull_alg);
+}
+
+module_cpu_feature_match(PMULL, crc32_pmull_mod_init);
+module_exit(crc32_pmull_mod_exit);
+
+MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [PATCH 0/2] CRC32 for ARM and arm64 using PMULL and CRC instructions
From: Ard Biesheuvel @ 2016-11-26 20:15 UTC (permalink / raw)
To: linux-arm-kernel
Version 8 of the ARM architecture introduces both a set of dedicated CRC32
instructions, and a 64x64 to 128 bit polynomial multiplication instruction,
both of which can be used to accelerate CRC32 calculations.
These patches contains ports of the existing polynomial multiplication based
CRC32 code that resides in arch/x86/crypto/crc32-pclmul_asm.S, but since that
algorithm operates on multiples of 16 bytes only, and requires at least 64
bytes of input, the remainders are calculated with the CRC32 instructions,
if available.
These patches apply on top of the CRC-T10DIF series I sent out last Thursday.
https://git.kernel.org/cgit/linux/kernel/git/ardb/linux.git/log/?h=crc32
Ard Biesheuvel (2):
crypto: arm64/crc32 - accelerated support based on x86 SSE
implementation
crypto: arm/crc32 - accelerated support based on x86 SSE
implementation
arch/arm/crypto/Kconfig | 5 +
arch/arm/crypto/Makefile | 2 +
arch/arm/crypto/crc32-ce-core.S | 257 ++++++++++++++++++++
arch/arm/crypto/crc32-ce-glue.c | 129 ++++++++++
arch/arm64/crypto/Kconfig | 6 +
arch/arm64/crypto/Makefile | 3 +
arch/arm64/crypto/crc32-ce-core.S | 246 +++++++++++++++++++
arch/arm64/crypto/crc32-ce-glue.c | 124 ++++++++++
8 files changed, 772 insertions(+)
create mode 100644 arch/arm/crypto/crc32-ce-core.S
create mode 100644 arch/arm/crypto/crc32-ce-glue.c
create mode 100644 arch/arm64/crypto/crc32-ce-core.S
create mode 100644 arch/arm64/crypto/crc32-ce-glue.c
--
2.7.4
^ permalink raw reply
* mmc: core: complete/wait_for_completion performance
From: Stefan Wahren @ 2016-11-26 19:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479669034.1975.1.camel@embedded.rocks>
Hi J?rg,
> J?rg Krause <joerg.krause@embedded.rocks> hat am 20. November 2016 um 20:10
> geschrieben:
>
>
> On Sun, 2016-11-20 at 16:44 +0100, Stefan Wahren wrote:
> > > J?rg Krause <joerg.krause@embedded.rocks> hat am 20. November 2016
> > > um 15:42
> > > geschrieben:
> > >
> > >
> > > Hi Stefan,
> > >
> > > On Sun, 2016-11-20 at 14:28 +0100, Stefan Wahren wrote:
> > > > Hi J?rg,
> > > >
> > > > > J?rg Krause <joerg.krause@embedded.rocks> hat am 20. November
> > > > > 2016
> > > > > um 13:27
> > > > > geschrieben:
> > > > >
> > > > >
> > > > > Hi,
> > > > >
> > > > > I started the discussion on this mailing list in another thread
> > > > > [1],
> > > > > but I'd like to move it to a new thread, because it might be
> > > > > mmc
> > > > > specific.
> > > > >
> > > > > The issue is that I am noticed low wifi network throughput on
> > > > > an
> > > > > i.MX28
> > > > > board with the mainline kernel (v4.7.10, about 6 Mbps) compared
> > > > > to
> > > > > the
> > > > > vendor kernel (Freescale v2.6.35.3, about 20 Mbps). The wifi
> > > > > chip
> > > > > is
> > > > > attached using the SDIO interface.
> > > > >
> > > > > I started investigation where the bottleneck in the mainline
> > > > > kernel?might come from. Therefore I checked that the configs
> > > > > and
> > > > > settings for the interfaces and drivers are the same. They are.
> > > >
> > > > so you're not using the mxs_defconfig settings anymore?
> > >
> > > No, I changed the settings.
> > >
> >
> > What happens to performance to if you change the following settings
> > to the same
> > like in mxs_defconfig?
> >
> > CONFIG_PREEMPT_VOLUNTARY=y
> > CONFIG_DEFAULT_IOSCHED="noop"
>
> No much change at all. The time difference between complete() and
> wait_for_complete() decreases in best case to 110 us, but also varies
> to above 130 us.
just a weird idea. Did you tried to add MMC_CAP_CMD23 into the caps [1]?
[1] - http://lxr.free-electrons.com/source/drivers/mmc/host/mxs-mmc.c?v=4.8#L642
^ permalink raw reply
* net: stmmac: Meson GXBB: attempting to execute userspace memory
From: Ben Dooks @ 2016-11-26 18:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <c8280798-453e-bd1d-bd4d-bf0956a169cc@gmx.de>
On 2016-11-26 07:53, Heinrich Schuchardt wrote:
> For Odroid C2 I have compiled kernel
> 4.9.0-rc6-next-20161124-00001-gbf7e142
> with one additional patch
> https://github.com/xypron/kernel-odroid-c2/blob/master/patch/0001-stmmac-RTL8211F-Meson-GXBB-TX-throughput-problems.patch
>
> I repeatedly see faults like the one below:
>
> [ 2557.400796] Unhandled fault: synchronous external abort (0x92000010)
> at 0x000040001e8ee4b0
> [ 2557.952413] CPU: 0 PID: 22837 Comm: cc1 Tainted: G D
> 4.9.0-rc6-next-20161124-00001-gbf7e142 #1
> [ 2557.962062] Hardware name: Hardkernel ODROID-C2 (DT)
> [ 2557.966980] task: ffff80006ddb7080 task.stack: ffff80006dd9c000
> [ 2557.972846] PC is at 0x6a0d98
> [ 2557.975776] LR is at 0x6a0e54
> [ 2557.978709] pc : [<00000000006a0d98>] lr : [<00000000006a0e54>]
> pstate: 80000000
> [ 2557.986040] sp : 0000fffff3ee5f80
> [ 2557.989318] x29: 0000fffff3ee5f80 x28: 000040000b3f1240
> [ 2557.994578] x27: 00000000012a7000 x26: 000040000b3f1288
> [ 2557.999840] x25: 0000000000f58f88 x24: 000040000b3f1240
> [ 2558.005101] x23: 0000000000000000 x22: 0000000000000001
> [ 2558.010362] x21: 0000000000000001 x20: 000040000b3f1250
> [ 2558.015623] x19: 0000000000000054 x18: 0000000000000001
> [ 2558.020885] x17: 0000400008acaa10 x16: 0000000001285050
> [ 2558.026146] x15: 000040000ad96dc8 x14: 000000000000001f
> [ 2558.031407] x13: 000040000b3f1270 x12: 000040000b3f1258
> [ 2558.036668] x11: 0000000001347000 x10: 0000000000000661
> [ 2558.041930] x9 : 0000000000000005 x8 : 0000000000000003
> [ 2558.047191] x7 : 000040000b3f1240 x6 : 0000000020020033
> [ 2558.052452] x5 : 000040000b402020 x4 : 000040000b3e1aa0
> [ 2558.057713] x3 : 000000000000000c x2 : 0000000000000020
> [ 2558.062974] x1 : 0000000000f45000 x0 : 0000000000000065
> [ 2558.068235]
> [ 2558.069712] Internal error: Attempting to execute userspace memory:
> 8600000f [#7] PREEMPT SMP
> [ 2558.078155] Modules linked in: meson_rng rng_core meson_gxbb_wdt
> ip_tables x_tables ipv6 dwmac_generic realtek dwmac_meson8b
> stmmac_platform stmmac
> [ 2558.091267] CPU: 0 PID: 22837 Comm: cc1 Tainted: G D
> 4.9.0-rc6-next-20161124-00001-gbf7e142 #1
> [ 2558.100925] Hardware name: Hardkernel ODROID-C2 (DT)
> [ 2558.105841] task: ffff80006ddb7080 task.stack: ffff80006dd9c000
> [ 2558.111706] PC is at 0x6a0e54
> [ 2558.114638] LR is at 0x6a0e54
> [ 2558.117571] pc : [<00000000006a0e54>] lr : [<00000000006a0e54>]
> pstate: 600003c5
> [ 2558.124902] sp : ffff80006dd9fec0
> [ 2558.128179] x29: 0000000000000000 x28: ffff80006ddb7080
> [ 2558.133441] x27: 00000000012a7000 x26: 000040000b3f1288
> [ 2558.138702] x25: 0000000000f58f88 x24: 000040000b3f1240
> [ 2558.143963] x23: 0000000080000000 x22: 00000000006a0d98
> [ 2558.149225] x21: ffffffffffffffff x20: 000080006e223000
> [ 2558.154486] x19: 0000000000000000 x18: 0000000000000010
> [ 2558.159747] x17: 0000400008acaa10 x16: 0000000001285050
> [ 2558.165008] x15: ffff000088e91f07 x14: 0000000000000006
> [ 2558.170270] x13: ffff000008e91f15 x12: 000000000000000f
> [ 2558.175531] x11: 0000000000000002 x10: 00000000000002ea
> [ 2558.180792] x9 : ffff80006dd9fb40 x8 : 0000000000010a8b
> [ 2558.186053] x7 : 0000000000000000 x6 : 000000000000020e
> [ 2558.191315] x5 : 00000000020f020e x4 : 0000000000000000
> [ 2558.196576] x3 : 0000000000000000 x2 : 000000000000020f
> [ 2558.201837] x1 : ffff80006ddb7080 x0 : 0000000000000000
> [ 2558.207098]
> [ 2558.208565] Process cc1 (pid: 22837, stack limit =
> 0xffff80006dd9c000)
> [ 2558.215035] Stack: (0xffff80006dd9fec0 to 0xffff80006dda0000)
> [ 2558.220728] fec0: 0000000000000065 0000000000f45000 0000000000000020
> 000000000000000c
> [ 2558.228490] fee0: 000040000b3e1aa0 000040000b402020 0000000020020033
> 000040000b3f1240
> [ 2558.236253] ff00: 0000000000000003 0000000000000005 0000000000000661
> 0000000001347000
> [ 2558.244015] ff20: 000040000b3f1258 000040000b3f1270 000000000000001f
> 000040000ad96dc8
> [ 2558.251778] ff40: 0000000001285050 0000400008acaa10 0000000000000001
> 0000000000000054
> [ 2558.259540] ff60: 000040000b3f1250 0000000000000001 0000000000000001
> 0000000000000000
> [ 2558.267303] ff80: 000040000b3f1240 0000000000f58f88 000040000b3f1288
> 00000000012a7000
> [ 2558.275065] ffa0: 000040000b3f1240 0000fffff3ee5f80 00000000006a0e54
> 0000fffff3ee5f80
> [ 2558.282828] ffc0: 00000000006a0d98 0000000080000000 0000000000000003
> ffffffffffffffff
> [ 2558.290590] ffe0: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [ 2558.298351] Call trace:
> [ 2558.300769] Exception stack(0xffff80006dd9fcf0 to
> 0xffff80006dd9fe20)
> [ 2558.307149] fce0: 0000000000000000
> 0001000000000000
> [ 2558.314913] fd00: ffff80006dd9fec0 00000000006a0e54 ffff800073acf500
> 0000000000000004
> [ 2558.322675] fd20: 0000000000000000 ffff000008dbbc18 ffff80006ddb7080
> 000000006dd9fdd0
> [ 2558.330438] fd40: ffff80006dd9fd90 ffff0000080ca878 ffff80006dd9fe40
> ffff80006ddb7080
> [ 2558.338200] fd60: 0000000000000004 00000000000003c0 ffff80006dd9fe40
> 000040000b3f1240
> [ 2558.345963] fd80: 0000000000f58f88 000040000b3f1288 0000000000000000
> ffff80006ddb7080
> [ 2558.353725] fda0: 000000000000020f 0000000000000000 0000000000000000
> 00000000020f020e
> [ 2558.361487] fdc0: 000000000000020e 0000000000000000 0000000000010a8b
> ffff80006dd9fb40
> [ 2558.369250] fde0: 00000000000002ea 0000000000000002 000000000000000f
> ffff000008e91f15
> [ 2558.377012] fe00: 0000000000000006 ffff000088e91f07 0000000001285050
> 0000400008acaa10
> [ 2558.384775] [<00000000006a0e54>] 0x6a0e54
> [ 2558.388743] Code: d503201f f9400280 2a1703e1 97ffff0a (aa0003f3)
> [ 2558.395241] ---[ end trace 7d280955c14d4ff1 ]---
> [ 2558.584022] Bad mode in Error handler detected on CPU0, code
> 0xbf000000 -- SError
> [ 2558.585871] CPU: 0 PID: 22867 Comm: cc1 Tainted: G D
> 4.9.0-rc6-next-20161124-00001-gbf7e142 #1
> [ 2558.595527] Hardware name: Hardkernel ODROID-C2 (DT)
> [ 2558.600444] task: ffff80007454d780 task.stack: ffff8000660bc000
> [ 2558.606310] PC is at 0x631928
> [ 2558.609240] LR is at 0xb59ce0
> [ 2558.612172] pc : [<0000000000631928>] lr : [<0000000000b59ce0>]
> pstate: 80000000
> [ 2558.619503] sp : 0000ffffed764d90
> [ 2558.622782] x29: 0000ffffed764d90 x28: 0000000000000028
> [ 2558.628042] x27: 000000001a1062f0 x26: 0000000001299198
> [ 2558.633303] x25: 0000000000000001 x24: 0000000000000000
> [ 2558.638564] x23: 0000000000000004 x22: 00000000013513c8
> [ 2558.643825] x21: 0000400039d43488 x20: 0000000000000000
> [ 2558.649086] x19: 0000400039d2d730 x18: 0000000000000000
> [ 2558.654348] x17: 0000400039a7c378 x16: 0000000001285138
> [ 2558.659609] x15: 0000000000000001 x14: 0000000000000000
> [ 2558.664870] x13: ffffff0000000000 x12: 0000000000000000
> [ 2558.670131] x11: 0000000000000028 x10: 000000000129b2b8
> [ 2558.675393] x9 : 0000000000000041 x8 : 0000000000000003
> [ 2558.680654] x7 : 0000000000000050 x6 : 000000000003d2c8
> [ 2558.685915] x5 : 0000000000000002 x4 : 0000000000000004
> [ 2558.691176] x3 : 0000000000000003 x2 : 0000000001349000
> [ 2558.696438] x1 : 000000000003cb90 x0 : 0000400039d45050
> [ 2558.701699]
> [ 2558.703177] Internal error: Attempting to execute userspace memory:
> 8600000f [#8] PREEMPT SMP
> [ 2558.711618] Modules linked in: meson_rng rng_core meson_gxbb_wdt
> ip_tables x_tables ipv6 dwmac_generic realtek dwmac_meson8b
> stmmac_platform stmmac
> [ 2558.724731] CPU: 0 PID: 22867 Comm: cc1 Tainted: G D
> 4.9.0-rc6-next-20161124-00001-gbf7e142 #1
> [ 2558.734388] Hardware name: Hardkernel ODROID-C2 (DT)
> [ 2558.739304] task: ffff80007454d780 task.stack: ffff8000660bc000
> [ 2558.745169] PC is at 0xb59ce0
> [ 2558.748102] LR is at 0xb59ce0
> [ 2558.751035] pc : [<0000000000b59ce0>] lr : [<0000000000b59ce0>]
> pstate: 600003c5
> [ 2558.758365] sp : ffff8000660bfec0
> [ 2558.761643] x29: 0000000000000000 x28: ffff80007454d780
> [ 2558.766904] x27: 000000001a1062f0 x26: 0000000001299198
> [ 2558.772165] x25: 0000000000000001 x24: 0000000000000000
> [ 2558.777426] x23: 0000000080000000 x22: 0000000000631928
> [ 2558.782688] x21: ffffffffffffffff x20: 000080006e223000
> [ 2558.787949] x19: 0000000000000000 x18: 0000000000000010
> [ 2558.793210] x17: 0000400039a7c378 x16: 0000000001285138
> [ 2558.798471] x15: ffff000088e91f07 x14: 0000000000000006
> [ 2558.803733] x13: ffff000008e91f15 x12: 000000000000000f
> [ 2558.808994] x11: 0000000000000002 x10: 0000000000000336
> [ 2558.814255] x9 : ffff8000660bfb40 x8 : 00000000000ab503
> [ 2558.819516] x7 : 0000000000000000 x6 : 00000000000000dd
> [ 2558.824778] x5 : 0000000000de00dd x4 : 0000000000000000
> [ 2558.830039] x3 : 0000000000000000 x2 : 00000000000000de
> [ 2558.835300] x1 : ffff80007454d780 x0 : 0000000000000000
> [ 2558.840561]
> [ 2558.842029] Process cc1 (pid: 22867, stack limit =
> 0xffff8000660bc000)
> [ 2558.848498] Stack: (0xffff8000660bfec0 to 0xffff8000660c0000)
> [ 2558.854191] fec0: 0000400039d45050 000000000003cb90 0000000001349000
> 0000000000000003
> [ 2558.861953] fee0: 0000000000000004 0000000000000002 000000000003d2c8
> 0000000000000050
> [ 2558.869716] ff00: 0000000000000003 0000000000000041 000000000129b2b8
> 0000000000000028
> [ 2558.877478] ff20: 0000000000000000 ffffff0000000000 0000000000000000
> 0000000000000001
> [ 2558.885241] ff40: 0000000001285138 0000400039a7c378 0000000000000000
> 0000400039d2d730
> [ 2558.893003] ff60: 0000000000000000 0000400039d43488 00000000013513c8
> 0000000000000004
> [ 2558.900766] ff80: 0000000000000000 0000000000000001 0000000001299198
> 000000001a1062f0
> [ 2558.908529] ffa0: 0000000000000028 0000ffffed764d90 0000000000b59ce0
> 0000ffffed764d90
> [ 2558.916291] ffc0: 0000000000631928 0000000080000000 000000001a18c000
> ffffffffffffffff
> [ 2558.924053] ffe0: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [ 2558.931814] Call trace:
> [ 2558.934232] Exception stack(0xffff8000660bfcf0 to
> 0xffff8000660bfe20)
> [ 2558.940613] fce0: 0000000000000000
> 0001000000000000
> [ 2558.948376] fd00: ffff8000660bfec0 0000000000b59ce0 ffff800073acf640
> 0000000000000004
> [ 2558.956138] fd20: 0000000000000000 ffff000008dbbc18 ffff80007454d780
> 00000000660bfdd0
> [ 2558.963901] fd40: ffff8000660bfd90 ffff0000080ca878 ffff8000660bfe40
> ffff80007454d780
> [ 2558.971663] fd60: 0000000000000004 00000000000003c0 ffff8000660bfe40
> 0000000000000000
> [ 2558.979426] fd80: 0000000000000001 0000000001299198 0000000000000000
> ffff80007454d780
> [ 2558.987188] fda0: 00000000000000de 0000000000000000 0000000000000000
> 0000000000de00dd
> [ 2558.994951] fdc0: 00000000000000dd 0000000000000000 00000000000ab503
> ffff8000660bfb40
> [ 2559.002713] fde0: 0000000000000336 0000000000000002 000000000000000f
> ffff000008e91f15
> [ 2559.010476] fe00: 0000000000000006 ffff000088e91f07 0000000001285138
> 0000400039a7c378
> [ 2559.018238] [<0000000000b59ce0>] 0xb59ce0
> [ 2559.022207] Code: d2800001 d2800002 d2800500 97eb5e9d (a9007c1f)
> [ 2559.028376] ---[ end trace 7d280955c14d4ff2 ]---
> [ 2559.034397] Bad mode in Error handler detected on CPU2, code
> 0xbf000000 -- SError
> [ 2559.040235] CPU: 2 PID: 22866 Comm: gcc Tainted: G D
> 4.9.0-rc6-next-20161124-00001-gbf7e142 #1
> [ 2559.049892] Hardware name: Hardkernel ODROID-C2 (DT)
> [ 2559.054808] task: ffff80007454e400 task.stack: ffff80006de9c000
> [ 2559.060674] PC is at 0x40003c0400d8
> [ 2559.064122] LR is at 0x46d4e0
> [ 2559.067055] pc : [<000040003c0400d8>] lr : [<000000000046d4e0>]
> pstate: 80000000
> [ 2559.074385] sp : 0000ffffe6387270
> [ 2559.077664] x29: 0000ffffe6387270 x28: 0000000016c0ff90
> [ 2559.082924] x27: 0000000000000002 x26: 0000000000000001
> [ 2559.088185] x25: 0000ffffe63873f4 x24: 0000ffffe63873f8
> [ 2559.093447] x23: 0000ffffe63873f4 x22: 0000ffffe63873f8
> [ 2559.098708] x21: 0000000016c104e0 x20: 0000000000005953
> [ 2559.103969] x19: 0000000000000000 [ 2559.107102] Unhandled fault:
> synchronous external abort (0x96000010) at 0xffff800000c1e000
> [ 2559.107108] Internal error: : 96000010 [#9] PREEMPT SMP
> [ 2559.107110] Modules linked in:
> [ 2559.107113] meson_rng rng_core meson_gxbb_wdt ip_tables x_tables
> ipv6 dwmac_generic realtek dwmac_meson8b stmmac_platform stmmac[
> 2559.107131] CPU: 0 PID: 1124 Comm: mmcqd/1 Tainted: G D 1
> [ 2559.107132] Hardware name: Hardkernel ODROID-C2 (DT)
> [ 2559.107135] task: ffff8000704abe80 task.stack: ffff8000734d0000
> [ 2559.107147] PC is at __memcpy+0x100/0x180
> [ 2559.107152] LR is at sg_copy_buffer+0xb0/0x110
> [ 2559.107155] pc : [<ffff00000837ee00>] lr : [<ffff00000838e928>]
> pstate: 200001c5
> [ 2559.107155] sp : ffff8000734d3bb0
> [ 2559.107157] x29: ffff8000734d3bb0
> [ 2559.107158] x28: ffff800073a14800 x27: ffff800073a14b68
> [ 2559.107162] x26: 0000000000000000 x25: 0000000000000140
> [ 2559.107165] x24: 0000000000000001 x23: 0000000000001000
> [ 2559.107168] x22: ffff8000746a2000 x21: 0000000000001000
> [ 2559.107170] x20: 0000000000000000 x19: 0000000000001000
> [ 2559.107172] x18: 0000000000000000 x17: ffffffffffffffff
> [ 2559.107175] x16: 00000000000006be x15: ffff000008c34000
> [ 2559.107178] x14: 747962342e090a34 x13: 3278302038323162
> [ 2559.107181] x12: 656c752e090a3864 x11: ffff800073866800
> [ 2559.107183] x10: ffff80006bf68eb0 x9 : 0000000000000000
> [ 2559.107186] x8 : ffff800073a94920 x7 : 0000000000000000
> [ 2559.107188] x6 : ffff8000746a2000 x5 : 0000820000000000
> [ 2559.107191] x4 : 0000000000000000 x3 : 0000000000000000
> [ 2559.107193] x2 : 0000000000000f80 x1 : ffff800000c1e000
> [ 2559.107196] x0 : ffff8000746a2000
> [ 2559.107199] Process mmcqd/1 (pid: 1124, stack limit =
> 0xffff8000734d0000)
> [ 2559.107202] Stack: (0xffff8000734d3bb0 to 0xffff8000734d4000)
> [ 2559.107205] 3ba0: ffff8000734d3c50
> ffff00000838e9bc
> [ 2559.107208] 3bc0: ffff800073a14000 ffff800073a14a30 ffff80006bf68eb0
> ffff800073a14a28
> [ 2559.107212] 3be0: ffff800073a14818 ffff800073a14800 0000000000000000
> ffff00000838e1c4
> [ 2559.107215] 3c00: ffff800073a94900 ffff7e0000030780 ffff800000c1e000
> 0000000000001000
> [ 2559.107218] 3c20: 0000000000001000 ffff800073ad0a00 0000000100000000
> 0000000000000001
> [ 2559.107221] 3c40: 0000100000000000 0000000000000005 ffff8000734d3c60
> ffff00000874c1bc
> [ 2559.107224] 3c60: ffff8000734d3c70 ffff000008748010 ffff8000734d3cd0
> ffff000008749908
> [ 2559.107228] 3c80: ffff80006bf68eb0 ffff800073a14000 ffff8000734c8000
> ffff800073a14818
> [ 2559.107231] 3ca0: ffff800073a14800 ffff800073a14800 ffff80006bf68eb0
> ffff800073a14a28
> [ 2559.107234] 3cc0: ffff80006bf68eb0 ffff000008749bc8 ffff8000734d3d70
> ffff00000874b298
> [ 2559.107237] 3ce0: ffff800073a14000 ffff800073a14818 ffff8000734c8000
> 0000000000000000
> [ 2559.107240] 3d00: ffff800073a14800 ffff800073a14800 ffff800073a13800
> 0000000000000000
> [ 2559.107243] 3d20: ffff80006bf68eb0 0000000000000000 00000000012853f0
> ffff000008c0fcb8
> [ 2559.107246] 3d40: 0000000000000000 000000000835bf14 ffff000008a05f58
> ffff800000000000
> [ 2559.107249] 3d60: ffff8000734c8000 0000000000000001 ffff8000734d3de0
> ffff00000874b6f4
> [ 2559.107252] 3d80: ffff800073a14818 ffff80006bf68eb0 ffff8000734c8000
> 0000000000000001
> [ 2559.107255] 3da0: ffff800073a14828 0000000000000000 0000000000000000
> 0000000000000000
> [ 2559.107258] 3dc0: 0000000000000000 0000000000000000 ffff800073a14818
> ffff00000874b6c4
> [ 2559.107261] 3de0: ffff8000734d3e20 ffff0000080daa84 ffff800073a94980
> ffff000008e8eb08
> [ 2559.107264] 3e00: ffff000008b75b50 ffff800073a14818 ffff00000874b658
> 0000000000000000
> [ 2559.107267] 3e20: 0000000000000000 ffff000008082ec0 ffff0000080da9b8
> ffff800073a94980
> [ 2559.107270] 3e40: 0000000000000000 0000000000000000 0000000000000000
> 000003ff01893600
> [ 2559.107273] 3e60: ffff8000734d3ea0 0000000000000000 ffff0000080da9b8
> ffff800073a14818
> [ 2559.107276] 3e80: 0000000000000000 0000000000000000 ffff8000734d3e90
> ffff8000734d3e90
> [ 2559.107279] 3ea0: 0000000000000000 ffff000000000000 ffff8000734d3eb0
> ffff8000734d3eb0
> [ 2559.107281] 3ec0: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [ 2559.107284] 3ee0: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [ 2559.107287] 3f00: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [ 2559.107290] 3f20: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [ 2559.107293] 3f40: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [ 2559.107295] 3f60: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [ 2559.107298] 3f80: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [ 2559.107300] 3fa0: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [ 2559.107303] 3fc0: 0000000000000000 0000000000000005 0000000000000000
> 0000000000000000
> [ 2559.107306] 3fe0: 0000000000000000 0000000000000000 0000001800002cba
> 26000000a01b3800
> [ 2559.107308] Call trace:
> [ 2559.107312] Exception stack(0xffff8000734d39e0 to
> 0xffff8000734d3b10)
> [ 2559.107315] 39e0: 0000000000001000 0001000000000000 ffff8000734d3bb0
> ffff00000837ee00
> [ 2559.107318] 3a00: 0000000000000007 ffff800000000000 ffff800000c1e000
> 0000000100100010
> [ 2559.107321] 3a20: ffff8000734d3ac0 ffff000008748d88 ffff8000734d3b8c
> 0000000000000001
> [ 2559.107324] 3a40: ffff8000734d3b40 ffff0000081c9dac ffff800074401d00
> ffff0000081745d8
> [ 2559.107327] 3a60: ffff7e0001b72f80 ffff80006dcbe300 00000000031fda40
> 0000000000000000
> [ 2559.107330] 3a80: ffff8000746a2000 ffff800000c1e000 0000000000000f80
> 0000000000000000
> [ 2559.107333] 3aa0: 0000000000000000 0000820000000000 ffff8000746a2000
> 0000000000000000
> [ 2559.107336] 3ac0: ffff800073a94920 0000000000000000 ffff80006bf68eb0
> ffff800073866800
> [ 2559.107339] 3ae0: 656c752e090a3864 3278302038323162 747962342e090a34
> ffff000008c34000
> [ 2559.107341] 3b00: 00000000000006be ffffffffffffffff
> [ 2559.107346] [<ffff00000837ee00>] __memcpy+0x100/0x180
> [ 2559.107349] [<ffff00000838e9bc>] sg_copy_to_buffer+0x14/0x20
> [ 2559.107357] [<ffff00000874c1bc>] mmc_queue_bounce_pre+0x34/0x40
> [ 2559.107362] [<ffff000008748010>] mmc_blk_rw_rq_prep+0x288/0x3a0
> [ 2559.107365] [<ffff000008749908>] mmc_blk_issue_rw_rq+0x3c0/0x998
> [ 2559.107368] [<ffff00000874b298>] mmc_blk_issue_rq+0x150/0x510
> [ 2559.107371] [<ffff00000874b6f4>] mmc_queue_thread+0x9c/0x140
> [ 2559.107377] [<ffff0000080daa84>] kthread+0xcc/0xe0
> [ 2559.107383] [<ffff000008082ec0>] ret_from_fork+0x10/0x50
Looks like it died whilst processing an mmc request.
^ permalink raw reply
* [PATCH 4/5] regulator: Add support for TI TWL6032
From: kbuild test robot @ 2016-11-26 18:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126181326.14951-5-Nicolae_Rosia@mentor.com>
Hi Nicolae,
[auto build test ERROR on omap/for-next]
[also build test ERROR on v4.9-rc6]
[cannot apply to next-20161125]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Nicolae-Rosia/mfd-twl-improvements-and-new-regulator-driver/20161127-022201
base: https://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git for-next
config: i386-allmodconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All error/warnings (new ones prefixed by >>):
In file included from drivers/regulator/twl6032-regulator.c:11:0:
>> drivers/regulator/twl6032-regulator.c:557:31: error: 'twl6032_regulator_driver_ids' undeclared here (not in a function)
MODULE_DEVICE_TABLE(platform, twl6032_regulator_driver_ids);
^
include/linux/module.h:213:21: note: in definition of macro 'MODULE_DEVICE_TABLE'
extern const typeof(name) __mod_##type##__##name##_device_table \
^~~~
>> include/linux/module.h:213:27: error: '__mod_platform__twl6032_regulator_driver_ids_device_table' aliased to undefined symbol 'twl6032_regulator_driver_ids'
extern const typeof(name) __mod_##type##__##name##_device_table \
^
>> drivers/regulator/twl6032-regulator.c:557:1: note: in expansion of macro 'MODULE_DEVICE_TABLE'
MODULE_DEVICE_TABLE(platform, twl6032_regulator_driver_ids);
^~~~~~~~~~~~~~~~~~~
vim +/twl6032_regulator_driver_ids +557 drivers/regulator/twl6032-regulator.c
551
552 static const struct of_device_id twl6032_dt_match[] = {
553 { .compatible = "ti,twl6032-regulator" },
554 { /* last entry */ }
555 };
556
> 557 MODULE_DEVICE_TABLE(platform, twl6032_regulator_driver_ids);
558
559 static struct platform_driver twl6032_regulator_driver = {
560 .driver = {
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 56830 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161127/cdcde6ff/attachment-0001.gz>
^ permalink raw reply
* [GIT PULL] omap dts changes for v4.10, part 2
From: Tony Lindgren @ 2016-11-26 18:42 UTC (permalink / raw)
To: linux-arm-kernel
The following changes since commit 7e2f8c0ae670327cbe0348ad2f3df7d9a55a8e5d:
ARM: dts: Add minimal support for motorola droid 4 xt894 (2016-11-15 10:28:49 -0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.10/dt-late-signed
for you to fetch changes up to 5817430ba7250cfc5a9c4a397935b07da16c9762:
ARM: dts: AM571x-IDK Initial Support (2016-11-23 08:40:05 -0800)
----------------------------------------------------------------
Second set of device tree changes for omaps for v4.10 merge window:
- Fix up new instances of gpio-key,wakeup to use wakeup-source
- Add beaglebone LCDC blue-and-red-wiring property to make use
of the new driver features
- Add bindings for IIO support for am335x and am437x
- Add palmas PMIC overide powerhold property for am57xx
- Update am335x-baltos to use phy-handle property
- Add initial support for am571x-idk
----------------------------------------------------------------
Andrew F. Davis (7):
ARM: dts: am335x-icev2: Add Industrial input support
ARM: dts: am335x-icev2: Disable Industrial I/O LEDs and fix naming
ARM: dts: am335x-icev2: Add ADC support
ARM: dts: am437x-idk: Add Industrial input support
ARM: dts: am437x-idk: Add Industrial output support
ARM: dts: am57xx-idk: Add Industrial input support
ARM: dts: am57xx-idk: Add Industrial output support
Jyri Sarha (1):
ARM: dts: am335x-boneblack: Add blue-and-red-wiring -property to LCDC node
Keerthy (2):
ARM: dts: am57xx-beagle-x15-common: Add overide powerhold property
ARM: dts: am57xx-idk-common: Add overide powerhold property
Schuyler Patton (1):
ARM: dts: AM571x-IDK Initial Support
Sudeep Holla (1):
ARM: dts: omap5: replace gpio-key,wakeup with wakeup-source property
Yegor Yefremov (1):
ARM: dts: am335x-baltos: use phy-phandle declarations
.../devicetree/bindings/arm/omap/omap.txt | 3 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/am335x-baltos-ir2110.dts | 10 +-
arch/arm/boot/dts/am335x-baltos-ir3220.dts | 2 +-
arch/arm/boot/dts/am335x-baltos-ir5221.dts | 2 +-
arch/arm/boot/dts/am335x-baltos.dtsi | 5 +-
arch/arm/boot/dts/am335x-boneblack.dts | 11 +++
arch/arm/boot/dts/am335x-icev2.dts | 47 ++++++++--
arch/arm/boot/dts/am437x-idk-evm.dts | 101 +++++++++++++++++++++
arch/arm/boot/dts/am571x-idk.dts | 81 +++++++++++++++++
arch/arm/boot/dts/am572x-idk.dts | 4 +
arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi | 1 +
arch/arm/boot/dts/am57xx-idk-common.dtsi | 75 +++++++++++++++
arch/arm/boot/dts/omap5-uevm.dts | 2 +-
14 files changed, 329 insertions(+), 16 deletions(-)
create mode 100644 arch/arm/boot/dts/am571x-idk.dts
^ permalink raw reply
* [PATCH v2] mfd: twl-core: make driver DT only
From: Nicolae Rosia @ 2016-11-26 18:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKP5S=3y6GAzs34c6-qsxHFZ1PaLC-_nT4LKd=3dd34wepnBMw@mail.gmail.com>
Hi,
Please ignore this patch, I've sent it in a patch series here [0]
Thanks,
Nicolae
[0] https://www.spinics.net/lists/kernel/msg2392364.html
^ permalink raw reply
* [PATCH] mfd: twl-core: export twl_get_regmap
From: Nicolae Rosia @ 2016-11-26 18:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479900128.16686.1.camel@mentor.com>
On Wed, Nov 23, 2016 at 1:22 PM, Rosia, Nicolae
<Nicolae_Rosia@mentor.com> wrote:
> I'm converting the driver to use mfd_add_devices and
> mfd_remove_devices, the subdrivers will access the parent's private
> data which will remain valid since in the remove method we will be
> calling mfd_remove_devices first.
>
> After removing all global calls to twl-core.c methods, I will also get
> rid of the "only one instance" of twl_priv and the "ready" flag.
>
> Thanks for your input,
> Nicolae
Please ignore this patch, I've sent it in a patch series here [0]
Thanks,
Nicolae
[0] https://www.spinics.net/lists/kernel/msg2392364.html
^ permalink raw reply
* [PATCH 5/5] mfd: twl: use mfd_add_devices for TWL6032 regulator
From: Nicolae Rosia @ 2016-11-26 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126181326.14951-1-Nicolae_Rosia@mentor.com>
TWL6032 regulator driver uses the drvdata twl_priv pointer.
In order to avoid accessing an invalid drvdata
when the driver gets unbinded, make sure we remove the
child devices before deleting the drvdata.
Signed-off-by: Nicolae Rosia <Nicolae_Rosia@mentor.com>
---
drivers/mfd/twl-core.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 409b836..1e94364 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -43,6 +43,7 @@
#include <linux/of_platform.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/mfd/core.h>
#include <linux/regulator/machine.h>
@@ -155,8 +156,16 @@ int twl4030_init_irq(struct device *dev, int irq_num);
int twl4030_exit_irq(void);
int twl4030_init_chip_irq(const char *chip);
+
static struct twlcore *twl_priv;
+static struct mfd_cell twl6032_devs[] = {
+ {
+ .name = "twl6032-regulator",
+ .of_compatible = "ti,twl6032-regulator",
+ },
+};
+
static struct twl_mapping twl4030_map[] = {
/*
* NOTE: don't change this table without updating the
@@ -665,6 +674,8 @@ static int twl_remove(struct i2c_client *client)
unsigned i, num_slaves;
int status;
+ mfd_remove_devices(&client->dev);
+
if (twl_class_is_4030())
status = twl4030_exit_irq();
else
@@ -834,6 +845,17 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
TWL4030_DCDC_GLOBAL_CFG);
}
+ if (id->driver_data & TWL6032_SUBCLASS) {
+ status = mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
+ twl6032_devs, ARRAY_SIZE(twl6032_devs),
+ NULL, 0, NULL);
+ if (status != 0) {
+ dev_err(&client->dev, "failed to add mfd devices: %d\n",
+ status);
+ goto fail;
+ }
+ }
+
fail:
if (status < 0)
twl_remove(client);
--
2.9.3
^ permalink raw reply related
* [PATCH 4/5] regulator: Add support for TI TWL6032
From: Nicolae Rosia @ 2016-11-26 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126181326.14951-1-Nicolae_Rosia@mentor.com>
The TWL6032 PMIC is similar to TWL6030, has different
output names, and regulator control logic.
It is used on Barnes & Noble Nook HD and HD+.
Signed-off-by: Nicolae Rosia <Nicolae_Rosia@mentor.com>
---
.../bindings/regulator/twl6032-regulator.txt | 109 ++++
drivers/regulator/Kconfig | 7 +
drivers/regulator/Makefile | 1 +
drivers/regulator/twl6032-regulator.c | 582 +++++++++++++++++++++
4 files changed, 699 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
create mode 100644 drivers/regulator/twl6032-regulator.c
diff --git a/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt b/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
new file mode 100644
index 0000000..323f5a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
@@ -0,0 +1,109 @@
+TWL6032 PMIC Voltage Regulator Bindings
+
+The parent node must be MFD TWL Core, ti,twl6032.
+
+Required properties:
+- compatible: "ti,twl6032"
+
+Optional properties:
+- regulators node containing regulator childs.
+
+The child regulators must be named after their hardware
+counterparts: LDO[1-6], LDOLN, LDOUSB and VANA.
+
+Each regulator is defined using the standard binding
+for regulators as described in ./regulator.txt
+
+Example:
+twl {
+ compatible = "ti,twl6032";
+
+ [...]
+
+ pmic {
+ compatible = "ti,twl6032-regulator";
+
+ regulators {
+ ldo1: LDO1 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2500000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo2: LDO2 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo3: LDO3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo4: LDO4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo5: LDO5 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3000000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo6: LDO6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo7: LDO7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldoln: LDOLN {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ ldousb: LDOUSB {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ vana: VANA {
+ regulator-min-microvolt = <2100000>;
+ regulator-max-microvolt = <2100000>;
+ regulator-always-on;
+ };
+ };
+ };
+
+ [...]
+};
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 936f7cc..3168aba 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -843,6 +843,13 @@ config REGULATOR_TWL4030
This driver supports the voltage regulators provided by
this family of companion chips.
+config REGULATOR_TWL6032
+ tristate "TI TWL6032 PMIC"
+ depends on TWL4030_CORE
+ depends on OF || COMPILE_TEST
+ help
+ This driver supports the Texas Instruments TWL6032 voltage regulator.
+
config REGULATOR_VEXPRESS
tristate "Versatile Express regulators"
depends on VEXPRESS_CONFIG
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 2142a5d..185a979 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
+obj-$(CONFIG_REGULATOR_TWL6032) += twl6032-regulator.o
obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
diff --git a/drivers/regulator/twl6032-regulator.c b/drivers/regulator/twl6032-regulator.c
new file mode 100644
index 0000000..70a0fdf
--- /dev/null
+++ b/drivers/regulator/twl6032-regulator.c
@@ -0,0 +1,582 @@
+/*
+ * TWL6032 regulator driver
+ * Copyright (C) 2016 Nicolae Rosia <nicolae.rosia@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/irq.h>
+#include <linux/mfd/twl-core.h>
+
+/* TWL6032 register offsets */
+#define TWL6032_VREG_TRANS 1
+#define TWL6032_VREG_STATE 2
+#define TWL6032_VREG_VOLTAGE 3
+
+#define TWL6032_LDO_MIN_MV 1000
+#define TWL6032_LDO_MAX_MV 3300
+
+/* TWL6030 LDO register values for CFG_TRANS */
+#define TWL6032_CFG_TRANS_STATE_MASK 0x03
+#define TWL6032_CFG_TRANS_STATE_OFF 0x00
+#define TWL6032_CFG_TRANS_STATE_AUTO 0x01
+#define TWL6032_CFG_TRANS_SLEEP_SHIFT 2
+
+#define TWL6032_CFG_STATE_MASK 0x03
+#define TWL6032_CFG_STATE_OFF 0x00
+#define TWL6032_CFG_STATE_ON 0x01
+#define TWL6032_CFG_STATE_OFF2 0x02
+#define TWL6032_CFG_STATE_SLEEP 0x03
+
+static const char *rdev_get_name(struct regulator_dev *rdev)
+{
+ if (rdev->constraints && rdev->constraints->name)
+ return rdev->constraints->name;
+ else if (rdev->desc->name)
+ return rdev->desc->name;
+ else
+ return "";
+}
+
+struct twl6032_regulator_info {
+ u8 base;
+ unsigned int min_mV;
+ struct regulator_desc desc;
+};
+
+struct twl6032_regulator {
+ struct twl6032_regulator_info *info;
+};
+
+static int twl6032_set_trans_state(struct regulator_dev *rdev, u8 shift, u8 val)
+{
+ struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+ struct twl6032_regulator_info *info = twl6032_reg->info;
+ unsigned int state;
+ u8 mask;
+ int ret;
+
+ /* Read CFG_TRANS register of TWL6030 */
+ ret = regmap_read(rdev->regmap, info->base + TWL6032_VREG_TRANS,
+ &state);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "%s %s: regmap_read: %d\n",
+ rdev_get_name(rdev), __func__, ret);
+ return ret;
+ }
+
+ mask = TWL6032_CFG_TRANS_STATE_MASK << shift;
+ val = (val << shift) & mask;
+
+ /* If value is already set, no need to write to reg */
+ if (val == (state & mask))
+ return 0;
+
+ state &= ~mask;
+ state |= val;
+
+ return regmap_write(rdev->regmap, info->base + TWL6032_VREG_TRANS,
+ state);
+}
+
+static int
+twl6032_ldo_list_voltage(struct regulator_dev *rdev, unsigned int sel)
+{
+ int ret;
+
+ switch (sel) {
+ case 0:
+ ret = 0;
+ break;
+ case 1 ... 24:
+ /* Linear mapping from 00000001 to 00011000:
+ * Absolute voltage value = 1.0 V + 0.1 V ? (sel ? 00000001)
+ */
+ ret = (TWL6032_LDO_MIN_MV + 100 * (sel - 1)) * 1000;
+ break;
+ case 25 ... 30:
+ ret = -EINVAL;
+ break;
+ case 31:
+ ret = 2750000;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ dev_dbg(&rdev->dev, "%s %s: sel: %d, mV: %d\n", rdev_get_name(rdev),
+ __func__, sel, ret);
+
+ return ret;
+}
+
+static int
+twl6032_ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+ struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+ struct twl6032_regulator_info *info = twl6032_reg->info;
+ int ret;
+
+ dev_dbg(&rdev->dev, "%s %s: sel: 0x%02X\n", rdev_get_name(rdev),
+ __func__, sel);
+
+ ret = regmap_write(rdev->regmap, info->base + TWL6032_VREG_VOLTAGE,
+ sel);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "%s %s: regmap_write: %d\n",
+ rdev_get_name(rdev), __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int twl6032_ldo_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+ struct twl6032_regulator_info *info = twl6032_reg->info;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, info->base + TWL6032_VREG_VOLTAGE,
+ &val);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "%s %s: regmap_read: %d\n",
+ rdev_get_name(rdev), __func__, ret);
+ return ret;
+ }
+
+ dev_dbg(&rdev->dev, "%s %s: vsel: 0x%02X\n", rdev_get_name(rdev),
+ __func__, val);
+
+ return val;
+}
+
+static int twl6032_ldo_enable(struct regulator_dev *rdev)
+{
+ struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+ struct twl6032_regulator_info *info = twl6032_reg->info;
+ int ret;
+
+ dev_dbg(&rdev->dev, "%s %s\n", rdev_get_name(rdev), __func__);
+
+ ret = regmap_write(rdev->regmap, info->base + TWL6032_VREG_STATE,
+ TWL6032_CFG_STATE_ON);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "%s %s: regmap_write: %d\n",
+ rdev_get_name(rdev), __func__, ret);
+ return ret;
+ }
+
+ ret = twl6032_set_trans_state(rdev, TWL6032_CFG_TRANS_SLEEP_SHIFT,
+ TWL6032_CFG_TRANS_STATE_AUTO);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "%s %s: twl6032_set_trans_state: %d\n",
+ rdev_get_name(rdev), __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int twl6032_ldo_disable(struct regulator_dev *rdev)
+{
+ struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+ struct twl6032_regulator_info *info = twl6032_reg->info;
+ int ret;
+
+ dev_dbg(&rdev->dev, "%s %s\n", rdev_get_name(rdev), __func__);
+
+ ret = regmap_write(rdev->regmap, info->base + TWL6032_VREG_STATE,
+ TWL6032_CFG_STATE_OFF);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "%s %s: regmap_write: %d\n",
+ rdev_get_name(rdev), __func__, ret);
+ return ret;
+ }
+
+ ret = twl6032_set_trans_state(rdev, TWL6032_CFG_TRANS_SLEEP_SHIFT,
+ TWL6032_CFG_TRANS_STATE_OFF);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "%s %s: twl6032_set_trans_state: %d\n",
+ rdev_get_name(rdev), __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int twl6032_ldo_is_enabled(struct regulator_dev *rdev)
+{
+ struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+ struct twl6032_regulator_info *info = twl6032_reg->info;
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(rdev->regmap, info->base + TWL6032_VREG_STATE, &val);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "%s regmap_read: %d\n", __func__, ret);
+ return ret;
+ }
+
+ dev_dbg(&rdev->dev, "%s %s: val: 0x%02X, val-masked: 0x%02X, ret: %d\n",
+ rdev_get_name(rdev), __func__,
+ val, val & TWL6032_CFG_STATE_MASK,
+ (val & TWL6032_CFG_STATE_MASK) == TWL6032_CFG_STATE_ON);
+
+ val &= TWL6032_CFG_STATE_MASK;
+
+ return val == TWL6032_CFG_STATE_ON;
+}
+
+static int twl6032_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+ struct twl6032_regulator_info *info = twl6032_reg->info;
+ unsigned int val = 0;
+ int ret;
+
+ dev_dbg(&rdev->dev, "%s %s: mode: 0x%02X\n", rdev_get_name(rdev),
+ __func__, mode);
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ val |= TWL6032_CFG_STATE_ON;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ val |= TWL6032_CFG_STATE_SLEEP;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_write(rdev->regmap, info->base + TWL6032_VREG_STATE, val);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "%s %s: regmap_write: %d\n",
+ rdev_get_name(rdev), __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int twl6032_ldo_get_status(struct regulator_dev *rdev)
+{
+ struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+ struct twl6032_regulator_info *info = twl6032_reg->info;
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(rdev->regmap, info->base + TWL6032_VREG_STATE, &val);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "%s %s: regmap_read: %d\n",
+ rdev_get_name(rdev), __func__, ret);
+ return ret;
+ }
+
+ dev_dbg(&rdev->dev, "%s %s: val: 0x%02X, val-with-mask: 0x%02X\n",
+ rdev_get_name(rdev), __func__,
+ val, val & TWL6032_CFG_STATE_MASK);
+
+ val &= TWL6032_CFG_STATE_MASK;
+
+ switch (val) {
+ case TWL6032_CFG_STATE_ON:
+ return REGULATOR_STATUS_NORMAL;
+
+ case TWL6032_CFG_STATE_SLEEP:
+ return REGULATOR_STATUS_STANDBY;
+
+ case TWL6032_CFG_STATE_OFF:
+ case TWL6032_CFG_STATE_OFF2:
+ default:
+ break;
+ }
+
+ return REGULATOR_STATUS_OFF;
+}
+
+static int twl6032_ldo_suspend_enable(struct regulator_dev *rdev)
+{
+ return twl6032_set_trans_state(rdev, TWL6032_CFG_TRANS_SLEEP_SHIFT,
+ TWL6032_CFG_TRANS_STATE_AUTO);
+}
+
+static int twl6032_ldo_suspend_disable(struct regulator_dev *rdev)
+{
+ return twl6032_set_trans_state(rdev, TWL6032_CFG_TRANS_SLEEP_SHIFT,
+ TWL6032_CFG_TRANS_STATE_OFF);
+}
+
+static int
+twl6032_fixed_list_voltage(struct regulator_dev *rdev, unsigned int sel)
+{
+ struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+ struct twl6032_regulator_info *info = twl6032_reg->info;
+
+ return info->min_mV * 1000; /* mV to V */
+}
+
+static int twl6032_fixed_get_voltage(struct regulator_dev *rdev)
+{
+ struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+ struct twl6032_regulator_info *info = twl6032_reg->info;
+
+ return info->min_mV * 1000; /* mV to V */
+}
+
+static const struct regulator_ops twl6032_ldo_ops = {
+ .list_voltage = twl6032_ldo_list_voltage,
+ .set_voltage_sel = twl6032_ldo_set_voltage_sel,
+ .get_voltage_sel = twl6032_ldo_get_voltage_sel,
+ .enable = twl6032_ldo_enable,
+ .disable = twl6032_ldo_disable,
+ .is_enabled = twl6032_ldo_is_enabled,
+ .set_mode = twl6032_ldo_set_mode,
+ .get_status = twl6032_ldo_get_status,
+ .set_suspend_enable = twl6032_ldo_suspend_enable,
+ .set_suspend_disable = twl6032_ldo_suspend_disable,
+};
+
+static const struct regulator_ops twl6032_fixed_ops = {
+ .list_voltage = twl6032_fixed_list_voltage,
+ .get_voltage = twl6032_fixed_get_voltage,
+ .enable = twl6032_ldo_enable,
+ .disable = twl6032_ldo_disable,
+ .is_enabled = twl6032_ldo_is_enabled,
+ .set_mode = twl6032_ldo_set_mode,
+ .get_status = twl6032_ldo_get_status,
+ .set_suspend_enable = twl6032_ldo_suspend_enable,
+ .set_suspend_disable = twl6032_ldo_suspend_disable,
+};
+
+#define TWL6032_LDO_REG_VOLTAGES \
+ ((TWL6032_LDO_MAX_MV - TWL6032_LDO_MIN_MV) / 100 + 1)
+#define TWL6032_LDO_REG(_id, _reg) \
+{ \
+ .base = _reg, \
+ .desc = { \
+ .name = "twl6032-reg-" # _id, \
+ .n_voltages = TWL6032_LDO_REG_VOLTAGES, \
+ .ops = &twl6032_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+}
+
+#define TWL6032_FIXED_REG(_id, _reg, _min_mV) \
+{ \
+ .base = _reg, \
+ .min_mV = _min_mV, \
+ .desc = { \
+ .name = "twl6032-reg-" # _id, \
+ .n_voltages = 1, \
+ .ops = &twl6032_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+}
+
+#define TWL6032_RESOURCE_REG(_id, _reg) \
+{ \
+ .base = _reg, \
+ .desc = { \
+ .name = "twl6032-reg-" # _id, \
+ .ops = &twl6032_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+}
+
+static struct twl6032_regulator_info twl6032_ldo_reg_info[] = {
+ TWL6032_LDO_REG(LDO1, 0x9C),
+ TWL6032_LDO_REG(LDO2, 0x84),
+ TWL6032_LDO_REG(LDO3, 0x8C),
+ TWL6032_LDO_REG(LDO4, 0x88),
+ TWL6032_LDO_REG(LDO5, 0x98),
+ TWL6032_LDO_REG(LDO6, 0x90),
+ TWL6032_LDO_REG(LDO7, 0xA4),
+ TWL6032_LDO_REG(LDOLN, 0x94),
+ TWL6032_LDO_REG(LDOUSB, 0xA0),
+};
+
+static struct twl6032_regulator_info twl6032_fixed_reg_info[] = {
+ TWL6032_FIXED_REG(VANA, 0x80, 2100),
+};
+
+static struct of_regulator_match
+twl6032_ldo_reg_matches[] = {
+ { .name = "LDO1", },
+ { .name = "LDO2", },
+ { .name = "LDO3", },
+ { .name = "LDO4", },
+ { .name = "LDO5", },
+ { .name = "LDO6", },
+ { .name = "LDO7", },
+ { .name = "LDOLN" },
+ { .name = "LDOUSB" }
+};
+
+static struct of_regulator_match
+twl6032_fixed_reg_matches[] = {
+ { .name = "VANA", },
+};
+
+#define TWL6032_LDO_REG_NUM ARRAY_SIZE(twl6032_ldo_reg_matches)
+#define TWL6032_FIXED_REG_NUM ARRAY_SIZE(twl6032_fixed_reg_matches)
+
+struct twl6032_regulator_priv {
+ struct twl6032_regulator ldo_regulators[TWL6032_LDO_REG_NUM];
+ struct twl6032_regulator fixed_regulators[TWL6032_FIXED_REG_NUM];
+};
+
+static int twl6032_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *regulators;
+ struct of_regulator_match *match;
+ struct twlcore *twl = dev_get_drvdata(pdev->dev.parent);
+ struct twl6032_regulator_priv *priv;
+ struct regulator_config config = {
+ .dev = &pdev->dev,
+ };
+ struct regulator_dev *rdev;
+ int ret, i;
+
+ if (!dev->of_node) {
+ dev_err(&pdev->dev, "no DT info\n");
+ return -EINVAL;
+ }
+
+ regulators = of_get_child_by_name(dev->of_node, "regulators");
+ if (!regulators) {
+ dev_err(dev, "regulator node not found\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ /* LDO regulators parsing */
+ ret = of_regulator_match(dev, regulators, twl6032_ldo_reg_matches,
+ TWL6032_LDO_REG_NUM);
+ of_node_put(regulators);
+ if (ret < 0) {
+ dev_err(dev, "error parsing LDO reg init data: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < TWL6032_LDO_REG_NUM; i++) {
+ struct twl6032_regulator *twl6032_reg;
+
+ match = &twl6032_ldo_reg_matches[i];
+ if (!match->of_node)
+ continue;
+
+ twl6032_reg = &priv->ldo_regulators[i];
+ twl6032_reg->info = &twl6032_ldo_reg_info[i];
+
+ config.init_data = match->init_data;
+ config.driver_data = &priv->ldo_regulators[i];
+ config.regmap = twl->twl_modules[0].regmap;
+ config.of_node = match->of_node;
+
+ rdev = devm_regulator_register(dev, &twl6032_reg->info->desc,
+ &config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(dev, "failed to register regulator %s: %d\n",
+ twl6032_reg->info->desc.name, ret);
+ return ret;
+ }
+ }
+
+ /* Fixed regulators parsing */
+ ret = of_regulator_match(dev, regulators, twl6032_fixed_reg_matches,
+ TWL6032_FIXED_REG_NUM);
+ of_node_put(regulators);
+ if (ret < 0) {
+ dev_err(dev, "error parsing fixed reg init data: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < TWL6032_FIXED_REG_NUM; i++) {
+ struct twl6032_regulator *twl6032_reg;
+
+ match = &twl6032_fixed_reg_matches[i];
+ if (!match->of_node)
+ continue;
+
+ twl6032_reg = &priv->fixed_regulators[i];
+ twl6032_reg->info = &twl6032_fixed_reg_info[i];
+
+ config.init_data = match->init_data;
+ config.driver_data = &priv->fixed_regulators[i];
+ config.regmap = twl->twl_modules[0].regmap;
+ config.of_node = match->of_node;
+
+ rdev = devm_regulator_register(dev, &twl6032_reg->info->desc,
+ &config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(dev, "failed to register regulator %s: %d\n",
+ twl6032_reg->info->desc.name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int twl6032_regulator_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id twl6032_dt_match[] = {
+ { .compatible = "ti,twl6032-regulator" },
+ { /* last entry */ }
+};
+
+MODULE_DEVICE_TABLE(platform, twl6032_regulator_driver_ids);
+
+static struct platform_driver twl6032_regulator_driver = {
+ .driver = {
+ .name = "twl6032-regulator",
+ .of_match_table = twl6032_dt_match,
+ },
+ .probe = twl6032_regulator_probe,
+ .remove = twl6032_regulator_remove,
+};
+
+static int __init twl6032_regulator_init(void)
+{
+ return platform_driver_register(&twl6032_regulator_driver);
+}
+subsys_initcall(twl6032_regulator_init);
+
+static void __exit twl6032_regulator_exit(void)
+{
+ platform_driver_unregister(&twl6032_regulator_driver);
+}
+module_exit(twl6032_regulator_exit);
+
+MODULE_AUTHOR("Nicolae Rosia <nicolae.rosia@gmail.com>");
+MODULE_DESCRIPTION("TI TWL6032 Regulator Driver");
+MODULE_LICENSE("GPL v2");
--
2.9.3
^ permalink raw reply related
* [PATCH 3/5] mfd: twl: move structure definitions to a public header
From: Nicolae Rosia @ 2016-11-26 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126181326.14951-1-Nicolae_Rosia@mentor.com>
We want to get rid of exported symbols and have
the child devices use structure members directly.
Move the structure definitions to header and set
drvdata so child devices can access it.
Signed-off-by: Nicolae Rosia <Nicolae_Rosia@mentor.com>
---
drivers/mfd/twl-core.c | 27 ++++-----------------------
include/linux/mfd/twl-core.h | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 39 insertions(+), 23 deletions(-)
create mode 100644 include/linux/mfd/twl-core.h
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index e16084e..409b836 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -48,6 +48,7 @@
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
+#include <linux/mfd/twl-core.h>
/* Register descriptions for audio */
#include <linux/mfd/twl4030-audio.h>
@@ -154,28 +155,7 @@ int twl4030_init_irq(struct device *dev, int irq_num);
int twl4030_exit_irq(void);
int twl4030_init_chip_irq(const char *chip);
-/* Structure for each TWL4030/TWL6030 Slave */
-struct twl_client {
- struct i2c_client *client;
- struct regmap *regmap;
-};
-
-/* mapping the module id to slave id and base address */
-struct twl_mapping {
- unsigned char sid; /* Slave ID */
- unsigned char base; /* base address */
-};
-
-struct twl_private {
- bool ready; /* The core driver is ready to be used */
- u32 twl_idcode; /* TWL IDCODE Register value */
- unsigned int twl_id;
-
- struct twl_mapping *twl_map;
- struct twl_client *twl_modules;
-};
-
-static struct twl_private *twl_priv;
+static struct twlcore *twl_priv;
static struct twl_mapping twl4030_map[] = {
/*
@@ -745,7 +725,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
goto free;
}
- twl_priv = devm_kzalloc(&client->dev, sizeof(struct twl_private),
+ twl_priv = devm_kzalloc(&client->dev, sizeof(struct twlcore),
GFP_KERNEL);
if (!twl_priv) {
status = -ENOMEM;
@@ -803,6 +783,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
twl_priv->ready = true;
+ dev_set_drvdata(&client->dev, twl_priv);
/* setup clock framework */
clocks_init(&pdev->dev);
diff --git a/include/linux/mfd/twl-core.h b/include/linux/mfd/twl-core.h
new file mode 100644
index 0000000..d1c01b3
--- /dev/null
+++ b/include/linux/mfd/twl-core.h
@@ -0,0 +1,35 @@
+/*
+ * MFD core driver for the Texas Instruments TWL PMIC family
+ *
+ * Copyright (C) 2016 Nicolae Rosia <nicolae.rosia@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __TWL_CORE_H__
+#define __TWL_CORE_H__
+
+/* Structure for each TWL4030/TWL6030 Slave */
+struct twl_client {
+ struct i2c_client *client;
+ struct regmap *regmap;
+};
+
+/* mapping the module id to slave id and base address */
+struct twl_mapping {
+ unsigned char sid; /* Slave ID */
+ unsigned char base; /* base address */
+};
+
+struct twlcore {
+ bool ready; /* The core driver is ready to be used */
+ u32 twl_idcode; /* TWL IDCODE Register value */
+ unsigned int twl_id;
+
+ struct twl_mapping *twl_map;
+ struct twl_client *twl_modules;
+};
+
+#endif
--
2.9.3
^ permalink raw reply related
* [PATCH 2/5] mfd: twl: remove useless header
From: Nicolae Rosia @ 2016-11-26 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126181326.14951-1-Nicolae_Rosia@mentor.com>
This header has one user, twl-core.c .
Remove it before it gets more users.
Signed-off-by: Nicolae Rosia <Nicolae_Rosia@mentor.com>
---
drivers/mfd/twl-core.c | 8 ++++++--
drivers/mfd/twl-core.h | 10 ----------
drivers/mfd/twl4030-irq.c | 2 --
drivers/mfd/twl6030-irq.c | 2 --
4 files changed, 6 insertions(+), 16 deletions(-)
delete mode 100644 drivers/mfd/twl-core.h
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 48b0668..e16084e 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -52,8 +52,6 @@
/* Register descriptions for audio */
#include <linux/mfd/twl4030-audio.h>
-#include "twl-core.h"
-
/*
* The TWL4030 "Triton 2" is one of a family of a multi-function "Power
* Management and System Companion Device" chips originally designed for
@@ -150,6 +148,12 @@
/*----------------------------------------------------------------------*/
+int twl6030_init_irq(struct device *dev, int irq_num);
+int twl6030_exit_irq(void);
+int twl4030_init_irq(struct device *dev, int irq_num);
+int twl4030_exit_irq(void);
+int twl4030_init_chip_irq(const char *chip);
+
/* Structure for each TWL4030/TWL6030 Slave */
struct twl_client {
struct i2c_client *client;
diff --git a/drivers/mfd/twl-core.h b/drivers/mfd/twl-core.h
deleted file mode 100644
index 6ff99dc..0000000
--- a/drivers/mfd/twl-core.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __TWL_CORE_H__
-#define __TWL_CORE_H__
-
-extern int twl6030_init_irq(struct device *dev, int irq_num);
-extern int twl6030_exit_irq(void);
-extern int twl4030_init_irq(struct device *dev, int irq_num);
-extern int twl4030_exit_irq(void);
-extern int twl4030_init_chip_irq(const char *chip);
-
-#endif /* __TWL_CORE_H__ */
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index b46c0cf..000c231 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -35,8 +35,6 @@
#include <linux/irqdomain.h>
#include <linux/i2c/twl.h>
-#include "twl-core.h"
-
/*
* TWL4030 IRQ handling has two stages in hardware, and thus in software.
* The Primary Interrupt Handler (PIH) stage exposes status bits saying
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 5357450..63eca76 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -42,8 +42,6 @@
#include <linux/irqdomain.h>
#include <linux/of_device.h>
-#include "twl-core.h"
-
/*
* TWL6030 (unlike its predecessors, which had two level interrupt handling)
* three interrupt registers INT_STS_A, INT_STS_B and INT_STS_C.
--
2.9.3
^ permalink raw reply related
* [PATCH 1/5] mfd: twl-core: make driver DT only
From: Nicolae Rosia @ 2016-11-26 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126181326.14951-1-Nicolae_Rosia@mentor.com>
All users are DT-only and it makes no sense to keep
unused code
Signed-off-by: Nicolae Rosia <Nicolae_Rosia@mentor.com>
---
drivers/mfd/Kconfig | 1 +
drivers/mfd/twl-core.c | 399 +------------------------------------------------
2 files changed, 8 insertions(+), 392 deletions(-)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c6df644..c180f8b 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1333,6 +1333,7 @@ config MFD_TPS80031
config TWL4030_CORE
bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 Support"
depends on I2C=y
+ depends on OF
select IRQ_DOMAIN
select REGMAP_I2C
help
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index c64615d..48b0668 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -13,6 +13,9 @@
* Code cleanup and modifications to IRQ handler.
* by syed khasim <x0khasim@ti.com>
*
+ * Code cleanup and modifications:
+ * Copyright (C) 2016 Nicolae Rosia <nicolae.rosia@gmail.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -604,376 +607,6 @@ int twl_get_hfclk_rate(void)
}
EXPORT_SYMBOL_GPL(twl_get_hfclk_rate);
-static struct device *
-add_numbered_child(unsigned mod_no, const char *name, int num,
- void *pdata, unsigned pdata_len,
- bool can_wakeup, int irq0, int irq1)
-{
- struct platform_device *pdev;
- struct twl_client *twl;
- int status, sid;
-
- if (unlikely(mod_no >= twl_get_last_module())) {
- pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
- return ERR_PTR(-EPERM);
- }
- sid = twl_priv->twl_map[mod_no].sid;
- twl = &twl_priv->twl_modules[sid];
-
- pdev = platform_device_alloc(name, num);
- if (!pdev)
- return ERR_PTR(-ENOMEM);
-
- pdev->dev.parent = &twl->client->dev;
-
- if (pdata) {
- status = platform_device_add_data(pdev, pdata, pdata_len);
- if (status < 0) {
- dev_dbg(&pdev->dev, "can't add platform_data\n");
- goto put_device;
- }
- }
-
- if (irq0) {
- struct resource r[2] = {
- { .start = irq0, .flags = IORESOURCE_IRQ, },
- { .start = irq1, .flags = IORESOURCE_IRQ, },
- };
-
- status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1);
- if (status < 0) {
- dev_dbg(&pdev->dev, "can't add irqs\n");
- goto put_device;
- }
- }
-
- status = platform_device_add(pdev);
- if (status)
- goto put_device;
-
- device_init_wakeup(&pdev->dev, can_wakeup);
-
- return &pdev->dev;
-
-put_device:
- platform_device_put(pdev);
- dev_err(&twl->client->dev, "failed to add device %s\n", name);
- return ERR_PTR(status);
-}
-
-static inline struct device *add_child(unsigned mod_no, const char *name,
- void *pdata, unsigned pdata_len,
- bool can_wakeup, int irq0, int irq1)
-{
- return add_numbered_child(mod_no, name, -1, pdata, pdata_len,
- can_wakeup, irq0, irq1);
-}
-
-static struct device *
-add_regulator_linked(int num, struct regulator_init_data *pdata,
- struct regulator_consumer_supply *consumers,
- unsigned num_consumers, unsigned long features)
-{
- struct twl_regulator_driver_data drv_data;
-
- /* regulator framework demands init_data ... */
- if (!pdata)
- return NULL;
-
- if (consumers) {
- pdata->consumer_supplies = consumers;
- pdata->num_consumer_supplies = num_consumers;
- }
-
- if (pdata->driver_data) {
- /* If we have existing drv_data, just add the flags */
- struct twl_regulator_driver_data *tmp;
- tmp = pdata->driver_data;
- tmp->features |= features;
- } else {
- /* add new driver data struct, used only during init */
- drv_data.features = features;
- drv_data.set_voltage = NULL;
- drv_data.get_voltage = NULL;
- drv_data.data = NULL;
- pdata->driver_data = &drv_data;
- }
-
- /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */
- return add_numbered_child(TWL_MODULE_PM_MASTER, "twl_reg", num,
- pdata, sizeof(*pdata), false, 0, 0);
-}
-
-static struct device *
-add_regulator(int num, struct regulator_init_data *pdata,
- unsigned long features)
-{
- return add_regulator_linked(num, pdata, NULL, 0, features);
-}
-
-/*
- * NOTE: We know the first 8 IRQs after pdata->base_irq are
- * for the PIH, and the next are for the PWR_INT SIH, since
- * that's how twl_init_irq() sets things up.
- */
-
-static int
-add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
- unsigned long features)
-{
- struct device *child;
-
- if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) {
- child = add_child(TWL4030_MODULE_GPIO, "twl4030_gpio",
- pdata->gpio, sizeof(*pdata->gpio),
- false, irq_base + GPIO_INTR_OFFSET, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) {
- child = add_child(TWL4030_MODULE_KEYPAD, "twl4030_keypad",
- pdata->keypad, sizeof(*pdata->keypad),
- true, irq_base + KEYPAD_INTR_OFFSET, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc &&
- twl_class_is_4030()) {
- child = add_child(TWL4030_MODULE_MADC, "twl4030_madc",
- pdata->madc, sizeof(*pdata->madc),
- true, irq_base + MADC_INTR_OFFSET, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) {
- /*
- * REVISIT platform_data here currently might expose the
- * "msecure" line ... but for now we just expect board
- * setup to tell the chip "it's always ok to SET_TIME".
- * Eventually, Linux might become more aware of such
- * HW security concerns, and "least privilege".
- */
- child = add_child(TWL_MODULE_RTC, "twl_rtc", NULL, 0,
- true, irq_base + RTC_INTR_OFFSET, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_PWM_TWL)) {
- child = add_child(TWL_MODULE_PWM, "twl-pwm", NULL, 0,
- false, 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_PWM_TWL_LED)) {
- child = add_child(TWL_MODULE_LED, "twl-pwmled", NULL, 0,
- false, 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb &&
- twl_class_is_4030()) {
-
- static struct regulator_consumer_supply usb1v5 = {
- .supply = "usb1v5",
- };
- static struct regulator_consumer_supply usb1v8 = {
- .supply = "usb1v8",
- };
- static struct regulator_consumer_supply usb3v1 = {
- .supply = "usb3v1",
- };
-
- /* First add the regulators so that they can be used by transceiver */
- if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) {
- /* this is a template that gets copied */
- struct regulator_init_data usb_fixed = {
- .constraints.valid_modes_mask =
- REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .constraints.valid_ops_mask =
- REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- };
-
- child = add_regulator_linked(TWL4030_REG_VUSB1V5,
- &usb_fixed, &usb1v5, 1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator_linked(TWL4030_REG_VUSB1V8,
- &usb_fixed, &usb1v8, 1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator_linked(TWL4030_REG_VUSB3V1,
- &usb_fixed, &usb3v1, 1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- }
-
- child = add_child(TWL_MODULE_USB, "twl4030_usb",
- pdata->usb, sizeof(*pdata->usb), true,
- /* irq0 = USB_PRES, irq1 = USB */
- irq_base + USB_PRES_INTR_OFFSET,
- irq_base + USB_INTR_OFFSET);
-
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- /* we need to connect regulators to this transceiver */
- if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) {
- usb1v5.dev_name = dev_name(child);
- usb1v8.dev_name = dev_name(child);
- usb3v1.dev_name = dev_name(child);
- }
- }
-
- if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) {
- child = add_child(TWL_MODULE_PM_RECEIVER, "twl4030_wdt", NULL,
- 0, false, 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) {
- child = add_child(TWL_MODULE_PM_MASTER, "twl4030_pwrbutton",
- NULL, 0, true, irq_base + 8 + 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio &&
- twl_class_is_4030()) {
- child = add_child(TWL4030_MODULE_AUDIO_VOICE, "twl4030-audio",
- pdata->audio, sizeof(*pdata->audio),
- false, 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- /* twl4030 regulators */
- if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) {
- child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VIO, pdata->vio,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VDAC, pdata->vdac,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator((features & TWL4030_VAUX2)
- ? TWL4030_REG_VAUX2_4030
- : TWL4030_REG_VAUX2,
- pdata->vaux2, features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- /* maybe add LDOs that are omitted on cost-reduced parts */
- if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET)
- && twl_class_is_4030()) {
- child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VSIM, pdata->vsim,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci &&
- !(features & (TPS_SUBSET | TWL5031))) {
- child = add_child(TWL_MODULE_MAIN_CHARGE, "twl4030_bci",
- pdata->bci, sizeof(*pdata->bci), false,
- /* irq0 = CHG_PRES, irq1 = BCI */
- irq_base + BCI_PRES_INTR_OFFSET,
- irq_base + BCI_INTR_OFFSET);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) {
- child = add_child(TWL_MODULE_PM_MASTER, "twl4030_power",
- pdata->power, sizeof(*pdata->power), false,
- 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- return 0;
-}
-
-/*----------------------------------------------------------------------*/
-
/*
* These three functions initialize the on-chip clock framework,
* letting it generate the right frequencies for USB, MADC, and
@@ -1000,8 +633,7 @@ static inline int __init unprotect_pm_master(void)
return e;
}
-static void clocks_init(struct device *dev,
- struct twl4030_clock_init_data *clock)
+static void clocks_init(struct device *dev)
{
int e = 0;
struct clk *osc;
@@ -1031,8 +663,6 @@ static void clocks_init(struct device *dev,
}
ctrl |= HIGH_PERF_SQ;
- if (clock && clock->ck32k_lowpwr_enable)
- ctrl |= CK32K_LOWPWR_EN;
e |= unprotect_pm_master();
/* effect->MADC+USB ck en */
@@ -1071,16 +701,10 @@ static int twl_remove(struct i2c_client *client)
return 0;
}
-static struct of_dev_auxdata twl_auxdata_lookup[] = {
- OF_DEV_AUXDATA("ti,twl4030-gpio", 0, "twl4030-gpio", NULL),
- { /* sentinel */ },
-};
-
/* NOTE: This driver only handles a single twl4030/tps659x0 chip */
static int
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
- struct twl4030_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *node = client->dev.of_node;
struct platform_device *pdev;
const struct regmap_config *twl_regmap_config;
@@ -1088,8 +712,8 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
int status;
unsigned i, num_slaves;
- if (!node && !pdata) {
- dev_err(&client->dev, "no platform data\n");
+ if (!node) {
+ dev_err(&client->dev, "no DT info\n");
return -EINVAL;
}
@@ -1177,7 +801,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_priv->ready = true;
/* setup clock framework */
- clocks_init(&pdev->dev, pdata ? pdata->clock : NULL);
+ clocks_init(&pdev->dev);
/* read TWL IDCODE Register */
if (twl_class_is_4030()) {
@@ -1225,15 +849,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
TWL4030_DCDC_GLOBAL_CFG);
}
- if (node) {
- if (pdata)
- twl_auxdata_lookup[0].platform_data = pdata->gpio;
- status = of_platform_populate(node, NULL, twl_auxdata_lookup,
- &client->dev);
- } else {
- status = add_children(pdata, irq_base, id->driver_data);
- }
-
fail:
if (status < 0)
twl_remove(client);
--
2.9.3
^ permalink raw reply related
* [PATCH 0/5] mfd: twl: improvements and new regulator driver
From: Nicolae Rosia @ 2016-11-26 18:13 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
The current TWL MFD driver has a number of problems which are
very well described by Russell King [0].
This series attemps to fix this by making the driver's private
structure available to child nodes.
A regulator driver for TWL6032 which makes use of the private
drvdata is introduced.
A driver for TWL6032 PMIC already exists in mainline,
twl-regulator, but it has the following drawbacks:
* has no mainline users
* it does not follow the recommended regulators binding since
it uses a compatible string for every regulator;
* it is broken
** the features flag is not set, hence the TWL6032
support is broken since it depends on TWL6032_SUBCLASS flag;
** even with that fixed, bit manipulations are wrong
If this receives positive feedback, I could convert all TWL drivers
to use drvdata, then get rid of the exported symbols.
[0] https://www.spinics.net/lists/linux-omap/msg133387.html
Nicolae Rosia (5):
mfd: twl-core: make driver DT only
mfd: twl: remove useless header
mfd: twl: move structure definitions to a public header
regulator: Add support for TI TWL6032
mfd: twl: use mfd_add_devices for TWL6032 regulator
.../bindings/regulator/twl6032-regulator.txt | 109 ++++
drivers/mfd/Kconfig | 1 +
drivers/mfd/twl-core.c | 444 ++--------------
drivers/mfd/twl-core.h | 10 -
drivers/mfd/twl4030-irq.c | 2 -
drivers/mfd/twl6030-irq.c | 2 -
drivers/regulator/Kconfig | 7 +
drivers/regulator/Makefile | 1 +
drivers/regulator/twl6032-regulator.c | 582 +++++++++++++++++++++
include/linux/mfd/twl-core.h | 35 ++
10 files changed, 768 insertions(+), 425 deletions(-)
create mode 100644 Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
delete mode 100644 drivers/mfd/twl-core.h
create mode 100644 drivers/regulator/twl6032-regulator.c
create mode 100644 include/linux/mfd/twl-core.h
--
2.9.3
^ permalink raw reply
* [PATCH] arm64: dts: uniphier: add SD-ctrl node for LD11 SoC
From: Masahiro Yamada @ 2016-11-26 18:10 UTC (permalink / raw)
To: linux-arm-kernel
The LD11 SoC is equipped with SD-ctrl (0x59810000) as well as
MIO-ctrl (0x5b3e0000). The SD-ctrl block on this SoC has just
one register for controlling RST_n pin of the eMMC device.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---
arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
index 0e5c58f..7a62fb9 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
@@ -273,6 +273,17 @@
reg = <0x59801000 0x400>;
};
+ sdctrl at 59810000 {
+ compatible = "socionext,uniphier-ld11-sdctrl",
+ "simple-mfd", "syscon";
+ reg = <0x59810000 0x400>;
+
+ sd_rst: reset {
+ compatible = "socionext,uniphier-ld11-sd-reset";
+ #reset-cells = <1>;
+ };
+ };
+
perictrl at 59820000 {
compatible = "socionext,uniphier-perictrl",
"simple-mfd", "syscon";
--
2.7.4
^ permalink raw reply related
* [GIT PULL] Amlogic 64-bit DT changes for v4.10, round 2
From: Martin Blumenstingl @ 2016-11-26 15:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <m2k2btx2c9.fsf@baylibre.com>
Hi Kevin,
On Wed, Nov 23, 2016 at 11:23 PM, Kevin Hilman <khilman@baylibre.com> wrote:
> Arnd, Olof,
>
> Here's a final round of arm64 DT changes for Amlogic family SoCs.
please note that SCPI is not working due to a change in Sudeep's
repository which has not made it into the Amlogic tree yet:
Sudeep's latest pull request indicates that we should use
"arm,scpi-pre-1.0", while currently we are only using
"amlogic,meson-gxbb-scpi": [0]
I fixed that in the Amlogic .dts files in [1] but this patch has not
been applied yet.
No pressure on this one - I just want to save your time (so you don't
have to search why SCPI is not working anymore)
Regards,
Martin
[0] http://lists.infradead.org/pipermail/linux-amlogic/2016-November/001632.html
[1] http://lists.infradead.org/pipermail/linux-amlogic/2016-November/001665.html
^ permalink raw reply
* [PATCH 5/5] ARM64: dts: meson-gx-p23x-q20x: enable USB on P23x and Q20x boards
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126145635.24488-1-martin.blumenstingl@googlemail.com>
All four devices are only using the dwc3 controller. The actual ports
are provided by dwc3's internal USB hub.
The implementation on P230, P231 and Q201 seems identical: the USB VBUS
supply seems to be hard-wired, while on Q200 the USB VBUS is provided
by GPIOAO_5.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 12 ++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts | 17 +++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
index 7a078be..360c91d 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
@@ -188,3 +188,15 @@
ðmac {
status = "okay";
};
+
+&usb2_phys {
+ status = "okay";
+};
+
+&usb3_phy0 {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts
index 5dbc660..6c28e87 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts
@@ -49,6 +49,19 @@
/ {
compatible = "amlogic,q200", "amlogic,s912", "amlogic,meson-gxm";
model = "Amlogic Meson GXM (S912) Q200 Development Board";
+
+ usb_pwr: regulator-usb-pwrs {
+ compatible = "regulator-fixed";
+
+ regulator-name = "USB_PWR";
+
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+
+ /* signal name in schematic: USB_PWR_EN */
+ gpio = <&gpio GPIODV_24 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
};
/* Q200 has exclusive choice between internal or external PHY */
@@ -75,3 +88,7 @@
max-speed = <1000>;
};
};
+
+&usb3_phy0 {
+ phy-supply = <&usb_pwr>;
+};
--
2.10.2
^ permalink raw reply related
* [PATCH 4/5] ARM64: dts: meson-gxm: add GXM specific USB configuration
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126145635.24488-1-martin.blumenstingl@googlemail.com>
The USB configuration on GXM is slightly different than on GXL. On GXM
the dwc2 controller is limited (via GHWCFG2_OP_MODE_MASK) to "device
mode".
The dwc3 controller's internal hub has 3 ports (instead of 2 on GXL)
enabled. It's hardware configuration limits it (via DWC3_GHWPARAMS0)
to host mode only.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
index 2b1d276e..0a6b224 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
@@ -121,3 +121,13 @@
clock-indices = <0 1>;
clock-output-names = "vbig", "vlittle";
};
+
+&usb3_phy0 {
+ /* dwc3 on GXM enables 3 USB ports on the internal hub */
+ phys = <&usb2_phys 0>, <&usb2_phys 1>, <&usb2_phys 2>;
+};
+
+&usb1 {
+ /* the dwc2 hardware configuration on GXM only allows device mode */
+ dr_mode = "device";
+};
--
2.10.2
^ permalink raw reply related
* [PATCH 3/5] arm64: dts: meson-gxl: add USB support
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126145635.24488-1-martin.blumenstingl@googlemail.com>
This adds USB support the the Meson GXL SoC. On most devices only the
dwc3 controller is used. It has an internal USB hub which provides two
ports. The PHYs for these ports are defined through the USB3 PHY, which
is ensures that all PHYs are using the same mode (because all of them
are used by the same controller).
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 49 ++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index 3af54dc..99ac900 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -44,9 +44,58 @@
#include "meson-gx.dtsi"
#include <dt-bindings/clock/gxbb-clkc.h>
#include <dt-bindings/gpio/meson-gxl-gpio.h>
+#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
/ {
compatible = "amlogic,meson-gxl";
+
+ soc {
+
+ usb0: usb at c9000000 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0xc9000000 0x0 0x100000>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb3_phy0>;
+ phy-names = "usb3-phy";
+ dr_mode = "host";
+ maximum-speed = "high-speed";
+ snps,dis_u2_susphy_quirk;
+ };
+
+ usb1: usb at c9100000 {
+ compatible = "snps,dwc2";
+ reg = <0x0 0xc9100000 0x0 0x40000>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clkc CLKID_USB>;
+ clock-names = "otg";
+ dr_mode = "host";
+ status = "disabled";
+ };
+ };
+};
+
+&apb {
+ usb2_phys: phy at 78000 {
+ compatible = "amlogic,meson-gxl-usb2-phy";
+ #phy-cells = <1>;
+ reg = <0x0 0x78000 0x0 0x80>;
+ clocks = <&clkc CLKID_USB1>, <&clkc CLKID_USB1_DDR_BRIDGE>;
+ clock-names = "usb", "usb_ddr";
+ resets = <&reset RESET_USB_OTG>;
+ status = "disabled";
+ };
+
+ usb3_phy0: phy at 78080 {
+ compatible = "amlogic,meson-gxl-usb3-phy";
+ #phy-cells = <0>;
+ reg = <0x0 0x78080 0x0 0x20>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+
+ /* dwc3 on GXL enables 2 USB ports on the internal hub */
+ phys = <&usb2_phys 0>, <&usb2_phys 1>;
+
+ status = "disabled";
+ };
};
ðmac {
--
2.10.2
^ permalink raw reply related
* [PATCH 2/5] phy: meson: add USB2 and USB3 PHY support for Meson GXL
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126145635.24488-1-martin.blumenstingl@googlemail.com>
This adds two new USB PHY drivers found on Meson GXL and GXM SoCs.
The registers for the USB2 PHY block handle a maximum of 4 ports (newer
SoCs may allow more ports, the driver handles this as long as the
register length is adjusted in the .dts). The PHY block theoretically
allows powering down each PHY port separately (by putting it into
"reset" state). Unfortunately this does not work (my board has 2 USB
ports, connected to port 1 and 2 of the dwc3's internal hub. When
leaving the third USB PHY disabled then the hub sees that a device is
plugged in, but it does not work: "usb usb1-port2: connect-debounce
failed").
The USB3 PHY will take care of enabling/disabling all available ports,
because the USB3 PHY also manages the mode of the USB2 PHYs.
The USB3 PHY actually has three purposes:
- it provides the USB3 PHY
- it handles the OTG device/host mode detection interrupt
- it notifies the corresponding USB2 PHYs of the OTG mode changes
On GXL and GXM SoCs one references all available USB2 PHY ports in the
USB3 PHY because all are connected to the same USB controller (thus the
mode will always match). This behavior is configurable via devicetree,
by passing (or not passing) a list of other ("child") PHYs which should
be configured by the USB3 PHY.
Unfortunately there are no datasheets available for any of these PHYs.
Both drivers were written by reading the reference drivers provided by
Amlogic and analyzing the registers on the kernel that was shipped with
my board.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/phy/Kconfig | 13 ++
drivers/phy/Makefile | 2 +
drivers/phy/phy-meson-gxl-usb2.c | 374 ++++++++++++++++++++++++++++++++++++++
drivers/phy/phy-meson-gxl-usb3.c | 377 +++++++++++++++++++++++++++++++++++++++
4 files changed, 766 insertions(+)
create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
create mode 100644 drivers/phy/phy-meson-gxl-usb3.c
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 728e03f..ea74843 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -502,4 +502,17 @@ config PHY_MESON8B_USB2
and GXBB SoCs.
If unsure, say N.
+config PHY_MESON_GXL_USB
+ tristate "Meson GXL USB2 and USB3 PHY drivers"
+ default ARCH_MESON
+ depends on OF && (ARCH_MESON || COMPILE_TEST)
+ depends on USB_SUPPORT
+ select USB_COMMON
+ select GENERIC_PHY
+ select REGMAP_MMIO
+ help
+ Enable this to support the Meson USB2 and USB3 PHYs found in
+ Meson GXL SoCs.
+ If unsure, say N.
+
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 0c7fdae..960a96e 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -61,3 +61,5 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
+obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb2.o
+obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb3.o
diff --git a/drivers/phy/phy-meson-gxl-usb2.c b/drivers/phy/phy-meson-gxl-usb2.c
new file mode 100644
index 0000000..c081ce3
--- /dev/null
+++ b/drivers/phy/phy-meson-gxl-usb2.c
@@ -0,0 +1,374 @@
+/*
+ * Meson GXL USB2 PHY driver
+ *
+ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/usb/of.h>
+
+/* bits [31:27] are read-only */
+#define U2P_R0 0x0
+ #define U2P_R0_BYPASS_SEL BIT(0)
+ #define U2P_R0_BYPASS_DM_EN BIT(1)
+ #define U2P_R0_BYPASS_DP_EN BIT(2)
+ #define U2P_R0_TXBITSTUFF_ENH BIT(3)
+ #define U2P_R0_TXBITSTUFF_EN BIT(4)
+ #define U2P_R0_DM_PULLDOWN BIT(5)
+ #define U2P_R0_DP_PULLDOWN BIT(6)
+ #define U2P_R0_DP_VBUS_VLD_EXT_SEL BIT(7)
+ #define U2P_R0_DP_VBUS_VLD_EXT BIT(8)
+ #define U2P_R0_ADP_PRB_EN BIT(9)
+ #define U2P_R0_ADP_DISCHARGE BIT(10)
+ #define U2P_R0_ADP_CHARGE BIT(11)
+ #define U2P_R0_DRV_VBUS BIT(12)
+ #define U2P_R0_ID_PULLUP BIT(13)
+ #define U2P_R0_LOOPBACK_EN_B BIT(14)
+ #define U2P_R0_OTG_DISABLE BIT(15)
+ #define U2P_R0_COMMON_ONN BIT(16)
+ #define U2P_R0_FSEL_SHIFT 17
+ #define U2P_R0_FSEL_MASK GENMASK(19, 17)
+ #define U2P_R0_REF_CLK_SEL_SHIFT 20
+ #define U2P_R0_REF_CLK_SEL_MASK GENMASK(21, 20)
+ #define U2P_R0_POWER_ON_RESET BIT(22)
+ #define U2P_R0_V_ATE_TEST_EN_B_SHIFT 23
+ #define U2P_R0_V_ATE_TEST_EN_B_MASK GENMASK(24, 23)
+ #define U2P_R0_ID_SET_ID_DQ BIT(25)
+ #define U2P_R0_ATE_RESET BIT(26)
+ #define U2P_R0_FSV_MINUS BIT(27)
+ #define U2P_R0_FSV_PLUS BIT(28)
+ #define U2P_R0_BYPASS_DM_DATA BIT(29)
+ #define U2P_R0_BYPASS_DP_DATA BIT(30)
+
+#define U2P_R1 0x4
+ #define U2P_R1_BURN_IN_TEST BIT(0)
+ #define U2P_R1_ACA_ENABLE BIT(1)
+ #define U2P_R1_DCD_ENABLE BIT(2)
+ #define U2P_R1_VDAT_SRC_EN_B BIT(3)
+ #define U2P_R1_VDAT_DET_EN_B BIT(4)
+ #define U2P_R1_CHARGES_SEL BIT(5)
+ #define U2P_R1_TX_PREEMP_PULSE_TUNE BIT(6)
+ #define U2P_R1_TX_PREEMP_AMP_TUNE_SHIFT 7
+ #define U2P_R1_TX_PREEMP_AMP_TUNE_MASK GENMASK(8, 7)
+ #define U2P_R1_TX_RES_TUNE_SHIFT 9
+ #define U2P_R1_TX_RES_TUNE_MASK GENMASK(10, 9)
+ #define U2P_R1_TX_RISE_TUNE_SHIFT 11
+ #define U2P_R1_TX_RISE_TUNE_MASK GENMASK(12, 11)
+ #define U2P_R1_TX_VREF_TUNE_SHIFT 13
+ #define U2P_R1_TX_VREF_TUNE_MASK GENMASK(16, 13)
+ #define U2P_R1_TX_FSLS_TUNE_SHIFT 17
+ #define U2P_R1_TX_FSLS_TUNE_MASK GENMASK(20, 17)
+ #define U2P_R1_TX_HSXV_TUNE_SHIFT 21
+ #define U2P_R1_TX_HSXV_TUNE_MASK GENMASK(22, 21)
+ #define U2P_R1_OTG_TUNE_SHIFT 23
+ #define U2P_R1_OTG_TUNE_MASK GENMASK(25, 23)
+ #define U2P_R1_SQRX_TUNE_SHIFT 26
+ #define U2P_R1_SQRX_TUNE_MASK GENMASK(28, 26)
+ #define U2P_R1_COMP_DIS_TUNE_SHIFT 29
+ #define U2P_R1_COMP_DIS_TUNE_MASK GENMASK(31, 29)
+
+/* bits [31:14] are read-only */
+#define U2P_R2 0x8
+ #define U2P_R2_DATA_IN_SHIFT 0
+ #define U2P_R2_DATA_IN_MASK GENMASK(3, 0)
+ #define U2P_R2_DATA_IN_EN_SHIFT 4
+ #define U2P_R2_DATA_IN_EN_MASK GENMASK(7, 4)
+ #define U2P_R2_ADDR_SHIFT 8
+ #define U2P_R2_ADDR_MASK GENMASK(11, 8)
+ #define U2P_R2_DATA_OUT_SEL BIT(12)
+ #define U2P_R2_CLK BIT(13)
+ #define U2P_R2_DATA_OUT_SHIFT 14
+ #define U2P_R2_DATA_OUT_MASK GENMASK(17, 14)
+ #define U2P_R2_ACA_PIN_RANGE_C BIT(18)
+ #define U2P_R2_ACA_PIN_RANGE_B BIT(19)
+ #define U2P_R2_ACA_PIN_RANGE_A BIT(20)
+ #define U2P_R2_ACA_PIN_GND BIT(21)
+ #define U2P_R2_ACA_PIN_FLOAT BIT(22)
+ #define U2P_R2_CHARGE_DETECT BIT(23)
+ #define U2P_R2_DEVICE_SESSION_VALID BIT(24)
+ #define U2P_R2_ADP_PROBE BIT(25)
+ #define U2P_R2_ADP_SENSE BIT(26)
+ #define U2P_R2_SESSION_END BIT(27)
+ #define U2P_R2_VBUS_VALID BIT(28)
+ #define U2P_R2_B_VALID BIT(29)
+ #define U2P_R2_A_VALID BIT(30)
+ #define U2P_R2_ID_DIG BIT(31)
+
+#define U2P_R3 0xc
+
+#define PHY_PORT_RESOURCE_SIZE 0x20
+
+#define RESET_COMPLETE_TIME 500
+
+struct phy_meson_gxl_usb2_priv {
+ struct regmap *regmap;
+ enum phy_mode mode;
+};
+
+struct phy_meson_gxl_usb2_drv {
+ void __iomem *base;
+ int num_ports;
+ struct phy **ports;
+ struct clk *clk_usb;
+ struct clk *clk_usb_ddr;
+};
+
+static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = U2P_R3,
+};
+
+static int phy_meson_gxl_usb2_set_mode(struct phy *phy, enum phy_mode mode)
+{
+ struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
+
+ switch (mode) {
+ case PHY_MODE_USB_HOST:
+ case PHY_MODE_USB_OTG:
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
+ U2P_R0_DM_PULLDOWN);
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
+ U2P_R0_DP_PULLDOWN);
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP, 0);
+ break;
+
+ case PHY_MODE_USB_DEVICE:
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
+ 0);
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
+ 0);
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP,
+ U2P_R0_ID_PULLUP);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* reset the PHY and wait until settings are stabilized */
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
+ U2P_R0_POWER_ON_RESET);
+ udelay(RESET_COMPLETE_TIME);
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
+ udelay(RESET_COMPLETE_TIME);
+
+ priv->mode = mode;
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb2_power_off(struct phy *phy)
+{
+ struct phy_meson_gxl_usb2_drv *drv_priv =
+ dev_get_drvdata(phy->dev.parent);
+ struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
+
+ /* power off the PHY by putting it into reset mode */
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
+ U2P_R0_POWER_ON_RESET);
+
+ clk_disable_unprepare(drv_priv->clk_usb_ddr);
+ clk_disable_unprepare(drv_priv->clk_usb);
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb2_power_on(struct phy *phy)
+{
+ struct phy_meson_gxl_usb2_drv *drv_priv =
+ dev_get_drvdata(phy->dev.parent);
+ struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
+ int ret;
+
+ ret = clk_prepare_enable(drv_priv->clk_usb);
+ if (ret) {
+ dev_err(&phy->dev, "Failed to enable USB clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(drv_priv->clk_usb_ddr);
+ if (ret) {
+ clk_disable_unprepare(drv_priv->clk_usb);
+
+ dev_err(&phy->dev, "Failed to enable USB DDR clock\n");
+ return ret;
+ }
+
+ /* power on the PHY by taking it out of reset mode */
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
+
+ ret = phy_meson_gxl_usb2_set_mode(phy, priv->mode);
+ if (ret) {
+ phy_meson_gxl_usb2_power_off(phy);
+
+ dev_err(&phy->dev, "Failed to initialize PHY with mode %d\n",
+ priv->mode);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct phy_ops phy_meson_gxl_usb2_ops = {
+ .power_on = phy_meson_gxl_usb2_power_on,
+ .power_off = phy_meson_gxl_usb2_power_off,
+ .set_mode = phy_meson_gxl_usb2_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *phy_meson_gxl_usb2_of_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct phy_meson_gxl_usb2_drv *priv = dev_get_drvdata(dev);
+ int port;
+
+ if (args->args_count != 1) {
+ dev_err(dev, "Invalid number of cells in 'phy' property\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ port = args->args[0];
+ if (WARN_ON(port >= priv->num_ports))
+ return ERR_PTR(-ENODEV);
+
+ return priv->ports[port];
+}
+
+static int phy_meson_gxl_usb2_probe_port(struct device *dev, int port)
+{
+ struct phy_meson_gxl_usb2_drv *drv_priv = dev_get_drvdata(dev);
+ struct phy_meson_gxl_usb2_priv *phy_priv;
+ struct phy *phy;
+ void __iomem *port_base;
+
+ phy_priv = devm_kzalloc(dev, sizeof(*phy_priv), GFP_KERNEL);
+ if (!phy_priv)
+ return -ENOMEM;
+
+ switch (of_usb_get_dr_mode_by_phy(dev->of_node, port)) {
+ case USB_DR_MODE_PERIPHERAL:
+ phy_priv->mode = PHY_MODE_USB_DEVICE;
+ break;
+ case USB_DR_MODE_OTG:
+ phy_priv->mode = PHY_MODE_USB_OTG;
+ break;
+ case USB_DR_MODE_HOST:
+ default:
+ phy_priv->mode = PHY_MODE_USB_HOST;
+ break;
+ }
+
+ phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create PHY port %d\n", port);
+ return PTR_ERR(phy);
+ }
+
+ port_base = drv_priv->base + (port * PHY_PORT_RESOURCE_SIZE);
+ phy_priv->regmap = devm_regmap_init_mmio(&phy->dev, port_base,
+ &phy_meson_gxl_usb2_regmap_conf);
+ if (IS_ERR(phy_priv->regmap))
+ return PTR_ERR(phy_priv->regmap);
+
+ phy_set_drvdata(phy, phy_priv);
+
+ drv_priv->ports[port] = phy;
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy_meson_gxl_usb2_drv *priv;
+ struct phy_provider *phy_provider;
+ struct resource *res;
+ int i, ret;
+
+ ret = device_reset(dev);
+ if (ret) {
+ dev_err(dev, "failed to reset device\n");
+ return ret;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->num_ports = resource_size(res) / PHY_PORT_RESOURCE_SIZE;
+ if (priv->num_ports < 1) {
+ dev_err(dev, "specified memory range is too small\n");
+ return -EINVAL;
+ }
+
+ priv->ports = devm_kcalloc(dev, priv->num_ports, sizeof(*priv->ports),
+ GFP_KERNEL);
+ if (!priv->ports)
+ return -ENOMEM;
+
+ priv->clk_usb = devm_clk_get(dev, "usb");
+ if (IS_ERR(priv->clk_usb)) {
+ dev_err(dev, "failed to get USB clock\n");
+ return PTR_ERR(priv->clk_usb);
+ }
+
+ priv->clk_usb_ddr = devm_clk_get(dev, "usb_ddr");
+ if (IS_ERR(priv->clk_usb_ddr)) {
+ dev_err(dev, "failed to get USB DDR clock\n");
+ return PTR_ERR(priv->clk_usb_ddr);
+ }
+
+ for (i = 0; i < priv->num_ports; i++) {
+ ret = phy_meson_gxl_usb2_probe_port(dev, i);
+ if (ret)
+ return ret;
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev,
+ phy_meson_gxl_usb2_of_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id phy_meson_gxl_usb2_of_match[] = {
+ { .compatible = "amlogic,meson-gxl-usb2-phy", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb2_of_match);
+
+static struct platform_driver phy_meson_gxl_usb2_driver = {
+ .probe = phy_meson_gxl_usb2_probe,
+ .driver = {
+ .name = "phy-meson-gxl-usb2",
+ .of_match_table = phy_meson_gxl_usb2_of_match,
+ },
+};
+module_platform_driver(phy_meson_gxl_usb2_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_DESCRIPTION("Meson GXL USB2 PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/phy-meson-gxl-usb3.c b/drivers/phy/phy-meson-gxl-usb3.c
new file mode 100644
index 0000000..90a4028
--- /dev/null
+++ b/drivers/phy/phy-meson-gxl-usb3.c
@@ -0,0 +1,377 @@
+/*
+ * Meson GXL USB3 PHY driver
+ *
+ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/usb/of.h>
+#include <linux/workqueue.h>
+
+#define USB_R0 0x00
+ #define USB_R0_P30_FSEL_SHIFT 0
+ #define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
+ #define USB_R0_P30_PHY_RESET BIT(6)
+ #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
+ #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
+ #define USB_R0_P30_ACJT_LEVEL_SHIFT 9
+ #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
+ #define USB_R0_P30_TX_BOOST_LEVEL_SHIFT 14
+ #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
+ #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
+ #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
+ #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_SHIFT 19
+ #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
+ #define USB_R0_U2D_SS_SCALEDOWN_MODE_SHIFT 29
+ #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
+ #define USB_R0_U2D_ACT BIT(31)
+
+#define USB_R1 0x04
+ #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
+ #define USB_R1_U3H_PME_ENABLE BIT(1)
+ #define USB_R1_U3H_HUB_PORT_OVERCURRENT_SHIFT 2
+ #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
+ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_SHIFT 7
+ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
+ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_SHIFT 12
+ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
+ #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
+ #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
+ #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
+ #define USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT 19
+ #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
+ #define USB_R1_P30_PCS_TX_SWING_FULL_SHIFT 25
+ #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
+
+#define USB_R2 0x08
+ #define USB_R2_P30_CR_DATA_IN_SHIFT 0
+ #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
+ #define USB_R2_P30_CR_READ BIT(16)
+ #define USB_R2_P30_CR_WRITE BIT(17)
+ #define USB_R2_P30_CR_CAP_ADDR BIT(18)
+ #define USB_R2_P30_CR_CAP_DATA BIT(19)
+ #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT 20
+ #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
+ #define USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT 26
+ #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
+
+#define USB_R3 0x0c
+ #define USB_R3_P30_SSC_ENABLE BIT(0)
+ #define USB_R3_P30_SSC_RANGE_SHIFT 1
+ #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
+ #define USB_R3_P30_SSC_REF_CLK_SEL_SHIFT 4
+ #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
+ #define USB_R3_P30_REF_SSP_EN BIT(13)
+ #define USB_R3_P30_LOS_BIAS_SHIFT 16
+ #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
+ #define USB_R3_P30_LOS_LEVEL_SHIFT 19
+ #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
+ #define USB_R3_P30_MPLL_MULTIPLIER_SHIFT 24
+ #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
+
+#define USB_R4 0x10
+ #define USB_R4_P21_PORT_RESET_0 BIT(0)
+ #define USB_R4_P21_SLEEP_M0 BIT(1)
+ #define USB_R4_MEM_PD_SHIFT 2
+ #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
+ #define USB_R4_P21_ONLY BIT(4)
+
+#define USB_R5 0x14
+ #define USB_R5_ID_DIG_SYNC BIT(0)
+ #define USB_R5_ID_DIG_REG BIT(1)
+ #define USB_R5_ID_DIG_CFG_SHIFT 2
+ #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
+ #define USB_R5_ID_DIG_EN_0 BIT(4)
+ #define USB_R5_ID_DIG_EN_1 BIT(5)
+ #define USB_R5_ID_DIG_CURR BIT(6)
+ #define USB_R5_ID_DIG_IRQ BIT(7)
+ #define USB_R5_ID_DIG_TH_SHIFT 8
+ #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
+ #define USB_R5_ID_DIG_CNT_SHIFT 16
+ #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
+
+/* read-only register */
+#define USB_R6 0x18
+ #define USB_R6_P30_CR_DATA_OUT_SHIFT 0
+ #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
+ #define USB_R6_P30_CR_ACK BIT(16)
+
+#define RESET_COMPLETE_TIME 500
+
+struct phy_meson_gxl_usb3_priv {
+ struct regmap *regmap;
+ struct delayed_work otg_work;
+ struct phy *this_phy;
+ int num_usb2_phys;
+ struct phy **usb2_phys;
+};
+
+static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = USB_R6,
+};
+
+static int phy_meson_gxl_usb3_update_mode(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ u32 val;
+ enum phy_mode mode;
+ int i, ret;
+
+ ret = regmap_read(priv->regmap, USB_R5, &val);
+ if (ret)
+ return ret;
+
+ if (val & USB_R5_ID_DIG_CURR) {
+ mode = PHY_MODE_USB_DEVICE;
+
+ regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT,
+ USB_R0_U2D_ACT);
+ regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
+ USB_R4_P21_SLEEP_M0);
+ } else {
+ mode = PHY_MODE_USB_HOST;
+
+ regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT, 0);
+ regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
+ 0);
+ }
+
+ /* inform the USB2 PHY that we have changed the mode */
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ ret = phy_set_mode(priv->usb2_phys[i], mode);
+ if (ret) {
+ dev_err(&phy->dev,
+ "Failed to update usb2-phy #%d mode to %d\n",
+ i, mode);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static void phy_meson_gxl_usb3_work(struct work_struct *data)
+{
+ struct phy_meson_gxl_usb3_priv *priv =
+ container_of(data, struct phy_meson_gxl_usb3_priv,
+ otg_work.work);
+
+ phy_meson_gxl_usb3_update_mode(priv->this_phy);
+
+ /* unmask IRQs which may have arrived in the meantime */
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
+}
+
+static int phy_meson_gxl_usb3_init(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ int i, ret;
+
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ ret = phy_init(priv->usb2_phys[i]);
+ if (ret) {
+ dev_err(&phy->dev,
+ "Failed to initialize related usb2-phy #%d\n",
+ i);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb3_exit(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ int i, ret;
+
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ ret = phy_exit(priv->usb2_phys[i]);
+ if (ret) {
+ dev_err(&phy->dev,
+ "Failed to exit related usb2-phy #%d\n", i);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb3_power_on(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ int i, ret;
+
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ ret = phy_power_on(priv->usb2_phys[i]);
+ if (ret) {
+ dev_err(&phy->dev,
+ "Failed to power on related usb2-phy #%d\n",
+ i);
+ return ret;
+ }
+ }
+
+ regmap_update_bits(priv->regmap, USB_R1,
+ USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
+ 0x20 << USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT);
+
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
+ USB_R5_ID_DIG_EN_0);
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1,
+ USB_R5_ID_DIG_EN_1);
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_TH_MASK,
+ 0xff << USB_R5_ID_DIG_TH_SHIFT);
+
+ return phy_meson_gxl_usb3_update_mode(phy);
+}
+
+static int phy_meson_gxl_usb3_power_off(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ int i, ret;
+
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ ret = phy_power_off(priv->usb2_phys[i]);
+ if (ret) {
+ dev_err(&phy->dev,
+ "Failed to power off related usb2-phy #%d\n",
+ i);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static irqreturn_t phy_meson_gxl_usb3_irq(int irq, void *data)
+{
+ u32 val;
+ struct phy_meson_gxl_usb3_priv *priv = data;
+
+ regmap_read(priv->regmap, USB_R5, &val);
+ if (!(val & USB_R5_ID_DIG_IRQ)) {
+ dev_err(&priv->this_phy->dev, "spurious interrupt\n");
+ return IRQ_NONE;
+ }
+
+ schedule_delayed_work(&priv->otg_work, msecs_to_jiffies(10));
+
+ /* acknowledge the IRQ */
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
+
+ return IRQ_HANDLED;
+}
+
+static const struct phy_ops phy_meson_gxl_usb3_ops = {
+ .init = phy_meson_gxl_usb3_init,
+ .exit = phy_meson_gxl_usb3_exit,
+ .power_on = phy_meson_gxl_usb3_power_on,
+ .power_off = phy_meson_gxl_usb3_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct phy_meson_gxl_usb3_priv *priv;
+ struct resource *res;
+ struct phy *phy;
+ struct phy_provider *phy_provider;
+ void __iomem *base;
+ int i, irq;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(dev, base,
+ &phy_meson_gxl_usb3_regmap_conf);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0) {
+ INIT_DELAYED_WORK(&priv->otg_work, phy_meson_gxl_usb3_work);
+
+ irq = devm_request_irq(dev, irq, phy_meson_gxl_usb3_irq,
+ IRQF_SHARED, dev_name(dev),
+ priv);
+ if (irq < 0) {
+ dev_err(dev, "could not register IRQ handler (%d)\n",
+ irq);
+ return -EINVAL;
+ }
+ }
+
+ priv->num_usb2_phys = of_count_phandle_with_args(np, "phys",
+ "#phy-cells");
+
+ priv->usb2_phys = devm_kcalloc(dev, priv->num_usb2_phys,
+ sizeof(*priv->usb2_phys), GFP_KERNEL);
+ if (!priv->usb2_phys)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ priv->usb2_phys[i] = devm_of_phy_get_by_index(dev, np, i);
+ if (IS_ERR(priv->usb2_phys[i])) {
+ dev_err(dev, "failed to get related usb2-phy #%d", i);
+ return PTR_ERR(priv->usb2_phys[i]);
+ }
+ }
+
+ phy = devm_phy_create(dev, np, &phy_meson_gxl_usb3_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(phy);
+ }
+
+ phy_set_drvdata(phy, priv);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id phy_meson_gxl_usb3_of_match[] = {
+ { .compatible = "amlogic,meson-gxl-usb3-phy", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb3_of_match);
+
+static struct platform_driver phy_meson_gxl_usb3_driver = {
+ .probe = phy_meson_gxl_usb3_probe,
+ .driver = {
+ .name = "phy-meson-gxl-usb3",
+ .of_match_table = phy_meson_gxl_usb3_of_match,
+ },
+};
+module_platform_driver(phy_meson_gxl_usb3_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_DESCRIPTION("Meson GXL USB3 PHY driver");
+MODULE_LICENSE("GPL");
--
2.10.2
^ permalink raw reply related
* [PATCH 1/5] Documentation: dt-bindings: Add documentation for Meson GXL USB2/3 PHYs
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126145635.24488-1-martin.blumenstingl@googlemail.com>
This adds the DT binding documentation for the USB2 and USB3 PHYs found
in the Meson GXL and GXM SoCs.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../devicetree/bindings/phy/meson-gxl-usb2-phy.txt | 25 ++++++++++++++++++++
.../devicetree/bindings/phy/meson-gxl-usb3-phy.txt | 27 ++++++++++++++++++++++
2 files changed, 52 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
diff --git a/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
new file mode 100644
index 0000000..e7828ca
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
@@ -0,0 +1,25 @@
+* Amlogic Meson GXL and GXM USB2 PHY binding
+
+This describes the USB2 PHY block which provides multiple USB2 PHY ports.
+
+Required properties:
+- compatible: Should be "amlogic,meson-gxl-usb2-phy"
+- reg: The base address and length of the registers
+- #phys-cells: should be 1 (see phy-bindings.txt in this directory)
+- clocks: phandle and clock identifier for the phy clocks
+- clock-names: "usb" and "usb_ddr"
+- resets: reference to the reset controller
+
+Optional properties:
+- phy-supply: see phy-bindings.txt in this directory
+
+
+Example:
+ usb2_phys: phy at 78000 {
+ compatible = "amlogic,meson-gxl-usb2-phy";
+ #phy-cells = <1>;
+ reg = <0x0 0x78000 0x0 0x80>;
+ clocks = <&clkc CLKID_USB1>, <&clkc CLKID_USB1_DDR_BRIDGE>;
+ clock-names = "usb", "usb_ddr";
+ resets = <&reset RESET_USB_OTG>;
+ };
diff --git a/Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt b/Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
new file mode 100644
index 0000000..be779e8
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
@@ -0,0 +1,27 @@
+* Amlogic Meson GXL and GXM USB3 PHY binding
+
+Required properties:
+- compatible: Should be "amlogic,meson-gxl-usb3-phy"
+- reg: The base address and length of the registers
+- #phys-cells: should be 0 (see phy-bindings.txt in this directory)
+- interrupts: describes the OTG device/host mode detection interrupt
+- phys: a list of related PHYs (typically the USB2 PHYs, see
+ meson-gxl-usb2-phy.txt in this directory). The mode of
+ the listed PHYs will be managed by the USB3 PHY (which
+ is required for OTG device/host detection to work).
+ The number of PHYs listed typically matches the number
+ of ports which are enabled in the USB controller which
+ uses this PHY.
+
+Optional properties:
+- phy-supply: see phy-bindings.txt in this directory
+
+
+Example:
+ usb3_phy0: phy at 78080 {
+ compatible = "amlogic,meson-gxl-usb3-phy";
+ #phy-cells = <0>;
+ reg = <0x0 0x78080 0x0 0x20>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb2_phys 0>, <&usb2_phys 1>;
+ };
--
2.10.2
^ permalink raw reply related
* [PATCH 0/5] Meson GXL and GXM USB support
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-arm-kernel
USB support on GXL and GXM differs a lot from Meson8b and GXBB:
The most obvious change is that GXL and GXM now have one dwc3
controller and one dwc2 controller (instead of two dwc2 controllers).
With that there are also new USB PHYs.
Due to lack of hardware I was only able to test this on a board with
GXM, but as far as I understand the hardware my preparations should be
correct (so it should also work on GXL).
dwc2 will probably stay unused on most GXM devices since it's limited
to device mode via some dwc2 hardware configuration register.
dwc3 is probably used on all devices, even if there is more than just
one USB port. dwc3 has a built-in USB2 hub - on GXL this hub has two
ports enabled, while on GXM there are three ports enabled (see below
for lsusb output). There are no USB3 ports enabled in the dwc3 hardware
configuration, meaning that the SoC is limited to high-speed mode.
On my GXM device the dwc3 hardware configuration forces it into "host
only" mode.
The SoCs contain two PHY blocks: one USB3 PHY and up to four USB2 PHYs
(on GXM there are only three enabled, but the registers should support
up to four).
The USB3 PHY also handles the OTG interrupts, but since dwc3's hardware
configuration enforces "host only" mode I was not able to test this. It
simply takes care of an interrupt and then notifies all related PHYs
about the new mode.
The USB2 PHY block is a bit different: I created one PHY driver which
spans all "PHY ports" because the handling is a bit tricky. It turns
out that for each available USB port in dwc3's hub the corresponding
PHY must be enabled (even if there is no physical port - in my case
port 3 is not connected to anything, but disabling the PHY breaks
ports 1 and 2 as well).
I decided not not pass the USB2 PHYs directly to dwc3 due to three
reasons: 1. the USB3 PHY (which holds a reference to all relevant
USB2 PHY ports) controls the mode of the USB2 PHY ports (since both
are used with the same controller and thus it makes sense to keep the
mode consistent across all ports) 2. the dwc3 driver does not support
passing multiple USB2 PHYs (only one USB2 and one USB3 PHY can be
passed to it) 3. it is similar to how the vendor reference driver
manages the PHYs. Please note that this coupling is not a fixed, this
is all configurable via devicetree (so if the third USB2 PHY has to
be passed two the dwc2 controller then this is still possible by
just moving on PHY reference in the .dts).
The coupling of the USB2 and USB3 PHYs is the reason why I sent the
two drivers in one patch, even though they are handling different IP
blocks (different registers, etc.).
Unfortunately there are no datasheets available for any of these PHYs.
Both drivers were written by reading the reference drivers provided by
Amlogic and analyzing the registers on the kernel that was shipped with
my board.
As a last note: the dwc3 driver currently only explicitly enables the
first USB port "DWC3_GUSB2PHYCFG(0)" in the internal hub. The hardware
seems to enable the other two (DWC3_GUSB2PHYCFG(1) and
DWC3_GUSB2PHYCFG(2)) automatically. I will ask the dwc3 maintainers if
changes to dwc3 are desired any how these should look like, but for now
it's working fine even without changes there.
lsusb output on GXM for the dwc3 hub:
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
...
Hub Port Status:
Port 1: 0000.0100 power
Port 2: 0000.0100 power
Port 3: 0000.0100 power
NOTE: The devicetree changes depend on my previous series:
"[PATCH 0/2] minor GXL and GXM improvements" - see [0]
NOTE2: This series depends on an upstream dwc3/xhci-plat DMA fix
(special thanks to Arnd Bergmann and Sriram Dash for fixing that):
"[PATCH v5 0/6] inherit dma configuration from parent dev" - see [1]
I have a tree with all dependencies applied available at [2] if
someone wants a quick way to test this (I don't take any responsibility
if anything explodes though).
[0] http://lists.infradead.org/pipermail/linux-amlogic/2016-November/001665.html
[1] http://marc.info/?l=linux-usb&m=147938307209685&w=2
[2] https://github.com/xdarklight/linux/commits/meson-gx-integration-4.10-20161126
Martin Blumenstingl (5):
Documentation: dt-bindings: Add documentation for Meson GXL USB2/3
PHYs
phy: meson: add USB2 and USB3 PHY support for Meson GXL
arm64: dts: meson-gxl: add USB support
ARM64: dts: meson-gxm: add GXM specific USB configuration
ARM64: dts: meson-gx-p23x-q20x: enable USB on P23x and Q20x boards
.../devicetree/bindings/phy/meson-gxl-usb2-phy.txt | 25 ++
.../devicetree/bindings/phy/meson-gxl-usb3-phy.txt | 27 ++
.../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 12 +
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 49 +++
.../arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts | 17 +
arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 10 +
drivers/phy/Kconfig | 13 +
drivers/phy/Makefile | 2 +
drivers/phy/phy-meson-gxl-usb2.c | 374 ++++++++++++++++++++
drivers/phy/phy-meson-gxl-usb3.c | 377 +++++++++++++++++++++
10 files changed, 906 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
create mode 100644 drivers/phy/phy-meson-gxl-usb3.c
--
2.10.2
^ permalink raw reply
* [PATCH v3 00/12] Initial Tegra186 support
From: Pavel Machek @ 2016-11-26 13:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160819173233.13260-1-thierry.reding@gmail.com>
Hi!
> From: Thierry Reding <treding@nvidia.com>
>
> Hi everyone,
>
> This is a set of patches to add initial support for Tegra186. It is
> based on Joseph's patches but I rewrote some of the drivers to be a
> little easier to comprehend and maintain (hopefully). I've also
> included clock and reset drivers as a proof of concept.
Is there any phone/tablet on the market with this chipset?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
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