* [PATCH v3 05/11 6.1.y] minmax.h: add whitespace around operators and after commas
From: Eliav Farber @ 2025-10-02 18:00 UTC (permalink / raw)
To: gregkh, kenneth.feng, alexander.deucher, christian.koenig,
airlied, simona, linus.walleij, dmitry.torokhov, tglx, wens,
jernej.skrabec, samuel, agk, snitzer, mpatocka, clm, dsterba,
luc.vanoostenryck, pmladek, rostedt, andriy.shevchenko, linux,
senozhatsky, akpm, lijo.lazar, asad.kamal, kevinyang.wang,
David.Laight, amd-gfx, dri-devel, linux-kernel, linux-input,
linux-arm-kernel, linux-sunxi, dm-devel, linux-btrfs,
linux-sparse, stable, farbere
Cc: Arnd Bergmann, Christoph Hellwig, Dan Carpenter,
Jason A. Donenfeld, Jens Axboe, Lorenzo Stoakes, Mateusz Guzik,
Matthew Wilcox, Pedro Falcato
In-Reply-To: <20251002180036.33738-1-farbere@amazon.com>
From: David Laight <David.Laight@ACULAB.COM>
[ Upstream commit 71ee9b16251ea4bf7c1fe222517c82bdb3220acc ]
Patch series "minmax.h: Cleanups and minor optimisations".
Some tidyups and minor changes to minmax.h.
This patch (of 7):
Link: https://lkml.kernel.org/r/c50365d214e04f9ba256d417c8bebbc0@AcuMS.aculab.com
Link: https://lkml.kernel.org/r/f04b2e1310244f62826267346fde0553@AcuMS.aculab.com
Signed-off-by: David Laight <david.laight@aculab.com>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@kernel.org>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dan Carpenter <dan.carpenter@linaro.org>
Cc: Jason A. Donenfeld <Jason@zx2c4.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Mateusz Guzik <mjguzik@gmail.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Pedro Falcato <pedro.falcato@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
include/linux/minmax.h | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/include/linux/minmax.h b/include/linux/minmax.h
index 98008dd92153..51b0d988e322 100644
--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -51,10 +51,10 @@
* only need to be careful to not cause warnings for
* pointer use.
*/
-#define __signed_type_use(x,ux) (2+__is_nonneg(x,ux))
-#define __unsigned_type_use(x,ux) (1+2*(sizeof(ux)<4))
-#define __sign_use(x,ux) (is_signed_type(typeof(ux))? \
- __signed_type_use(x,ux):__unsigned_type_use(x,ux))
+#define __signed_type_use(x, ux) (2 + __is_nonneg(x, ux))
+#define __unsigned_type_use(x, ux) (1 + 2 * (sizeof(ux) < 4))
+#define __sign_use(x, ux) (is_signed_type(typeof(ux)) ? \
+ __signed_type_use(x, ux) : __unsigned_type_use(x, ux))
/*
* To avoid warnings about casting pointers to integers
@@ -74,15 +74,15 @@
#ifdef CONFIG_64BIT
#define __signed_type(ux) long
#else
- #define __signed_type(ux) typeof(__builtin_choose_expr(sizeof(ux)>4,1LL,1L))
+ #define __signed_type(ux) typeof(__builtin_choose_expr(sizeof(ux) > 4, 1LL, 1L))
#endif
-#define __is_nonneg(x,ux) statically_true((__signed_type(ux))(x)>=0)
+#define __is_nonneg(x, ux) statically_true((__signed_type(ux))(x) >= 0)
-#define __types_ok(x,y,ux,uy) \
- (__sign_use(x,ux) & __sign_use(y,uy))
+#define __types_ok(x, y, ux, uy) \
+ (__sign_use(x, ux) & __sign_use(y, uy))
-#define __types_ok3(x,y,z,ux,uy,uz) \
- (__sign_use(x,ux) & __sign_use(y,uy) & __sign_use(z,uz))
+#define __types_ok3(x, y, z, ux, uy, uz) \
+ (__sign_use(x, ux) & __sign_use(y, uy) & __sign_use(z, uz))
#define __cmp_op_min <
#define __cmp_op_max >
@@ -97,7 +97,7 @@
#define __careful_cmp_once(op, x, y, ux, uy) ({ \
__auto_type ux = (x); __auto_type uy = (y); \
- BUILD_BUG_ON_MSG(!__types_ok(x,y,ux,uy), \
+ BUILD_BUG_ON_MSG(!__types_ok(x, y, ux, uy), \
#op"("#x", "#y") signedness error"); \
__cmp(op, ux, uy); })
@@ -114,7 +114,7 @@
static_assert(__builtin_choose_expr(__is_constexpr((lo) > (hi)), \
(lo) <= (hi), true), \
"clamp() low limit " #lo " greater than high limit " #hi); \
- BUILD_BUG_ON_MSG(!__types_ok3(val,lo,hi,uval,ulo,uhi), \
+ BUILD_BUG_ON_MSG(!__types_ok3(val, lo, hi, uval, ulo, uhi), \
"clamp("#val", "#lo", "#hi") signedness error"); \
__clamp(uval, ulo, uhi); })
@@ -154,7 +154,7 @@
#define __careful_op3(op, x, y, z, ux, uy, uz) ({ \
__auto_type ux = (x); __auto_type uy = (y);__auto_type uz = (z);\
- BUILD_BUG_ON_MSG(!__types_ok3(x,y,z,ux,uy,uz), \
+ BUILD_BUG_ON_MSG(!__types_ok3(x, y, z, ux, uy, uz), \
#op"3("#x", "#y", "#z") signedness error"); \
__cmp(op, ux, __cmp(op, uy, uz)); })
@@ -326,9 +326,9 @@ static inline bool in_range32(u32 val, u32 start, u32 len)
* Use these carefully: no type checking, and uses the arguments
* multiple times. Use for obvious constants only.
*/
-#define MIN(a,b) __cmp(min,a,b)
-#define MAX(a,b) __cmp(max,a,b)
-#define MIN_T(type,a,b) __cmp(min,(type)(a),(type)(b))
-#define MAX_T(type,a,b) __cmp(max,(type)(a),(type)(b))
+#define MIN(a, b) __cmp(min, a, b)
+#define MAX(a, b) __cmp(max, a, b)
+#define MIN_T(type, a, b) __cmp(min, (type)(a), (type)(b))
+#define MAX_T(type, a, b) __cmp(max, (type)(a), (type)(b))
#endif /* _LINUX_MINMAX_H */
--
2.47.3
^ permalink raw reply related
* [PATCH v3 06/11 6.1.y] minmax.h: update some comments
From: Eliav Farber @ 2025-10-02 18:00 UTC (permalink / raw)
To: gregkh, kenneth.feng, alexander.deucher, christian.koenig,
airlied, simona, linus.walleij, dmitry.torokhov, tglx, wens,
jernej.skrabec, samuel, agk, snitzer, mpatocka, clm, dsterba,
luc.vanoostenryck, pmladek, rostedt, andriy.shevchenko, linux,
senozhatsky, akpm, lijo.lazar, asad.kamal, kevinyang.wang,
David.Laight, amd-gfx, dri-devel, linux-kernel, linux-input,
linux-arm-kernel, linux-sunxi, dm-devel, linux-btrfs,
linux-sparse, stable, farbere
Cc: Arnd Bergmann, Christoph Hellwig, Dan Carpenter,
Jason A. Donenfeld, Jens Axboe, Lorenzo Stoakes, Mateusz Guzik,
Matthew Wilcox, Pedro Falcato
In-Reply-To: <20251002180036.33738-1-farbere@amazon.com>
From: David Laight <David.Laight@ACULAB.COM>
[ Upstream commit 10666e99204818ef45c702469488353b5bb09ec7 ]
- Change three to several.
- Remove the comment about retaining constant expressions, no longer true.
- Realign to nearer 80 columns and break on major punctiation.
- Add a leading comment to the block before __signed_type() and __is_nonneg()
Otherwise the block explaining the cast is a bit 'floating'.
Reword the rest of that comment to improve readability.
Link: https://lkml.kernel.org/r/85b050c81c1d4076aeb91a6cded45fee@AcuMS.aculab.com
Signed-off-by: David Laight <david.laight@aculab.com>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@kernel.org>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dan Carpenter <dan.carpenter@linaro.org>
Cc: Jason A. Donenfeld <Jason@zx2c4.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Mateusz Guzik <mjguzik@gmail.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Pedro Falcato <pedro.falcato@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
include/linux/minmax.h | 53 +++++++++++++++++++-----------------------
1 file changed, 24 insertions(+), 29 deletions(-)
diff --git a/include/linux/minmax.h b/include/linux/minmax.h
index 51b0d988e322..24e4b372649a 100644
--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -8,13 +8,10 @@
#include <linux/types.h>
/*
- * min()/max()/clamp() macros must accomplish three things:
+ * min()/max()/clamp() macros must accomplish several things:
*
* - Avoid multiple evaluations of the arguments (so side-effects like
* "x++" happen only once) when non-constant.
- * - Retain result as a constant expressions when called with only
- * constant expressions (to avoid tripping VLA warnings in stack
- * allocation usage).
* - Perform signed v unsigned type-checking (to generate compile
* errors instead of nasty runtime surprises).
* - Unsigned char/short are always promoted to signed int and can be
@@ -31,25 +28,23 @@
* bit #0 set if ok for unsigned comparisons
* bit #1 set if ok for signed comparisons
*
- * In particular, statically non-negative signed integer
- * expressions are ok for both.
+ * In particular, statically non-negative signed integer expressions
+ * are ok for both.
*
- * NOTE! Unsigned types smaller than 'int' are implicitly
- * converted to 'int' in expressions, and are accepted for
- * signed conversions for now. This is debatable.
+ * NOTE! Unsigned types smaller than 'int' are implicitly converted to 'int'
+ * in expressions, and are accepted for signed conversions for now.
+ * This is debatable.
*
- * Note that 'x' is the original expression, and 'ux' is
- * the unique variable that contains the value.
+ * Note that 'x' is the original expression, and 'ux' is the unique variable
+ * that contains the value.
*
- * We use 'ux' for pure type checking, and 'x' for when
- * we need to look at the value (but without evaluating
- * it for side effects! Careful to only ever evaluate it
- * with sizeof() or __builtin_constant_p() etc).
+ * We use 'ux' for pure type checking, and 'x' for when we need to look at the
+ * value (but without evaluating it for side effects!
+ * Careful to only ever evaluate it with sizeof() or __builtin_constant_p() etc).
*
- * Pointers end up being checked by the normal C type
- * rules at the actual comparison, and these expressions
- * only need to be careful to not cause warnings for
- * pointer use.
+ * Pointers end up being checked by the normal C type rules at the actual
+ * comparison, and these expressions only need to be careful to not cause
+ * warnings for pointer use.
*/
#define __signed_type_use(x, ux) (2 + __is_nonneg(x, ux))
#define __unsigned_type_use(x, ux) (1 + 2 * (sizeof(ux) < 4))
@@ -57,19 +52,19 @@
__signed_type_use(x, ux) : __unsigned_type_use(x, ux))
/*
- * To avoid warnings about casting pointers to integers
- * of different sizes, we need that special sign type.
+ * Check whether a signed value is always non-negative.
*
- * On 64-bit we can just always use 'long', since any
- * integer or pointer type can just be cast to that.
+ * A cast is needed to avoid any warnings from values that aren't signed
+ * integer types (in which case the result doesn't matter).
*
- * This does not work for 128-bit signed integers since
- * the cast would truncate them, but we do not use s128
- * types in the kernel (we do use 'u128', but they will
- * be handled by the !is_signed_type() case).
+ * On 64-bit any integer or pointer type can safely be cast to 'long'.
+ * But on 32-bit we need to avoid warnings about casting pointers to integers
+ * of different sizes without truncating 64-bit values so 'long' or 'long long'
+ * must be used depending on the size of the value.
*
- * NOTE! The cast is there only to avoid any warnings
- * from when values that aren't signed integer types.
+ * This does not work for 128-bit signed integers since the cast would truncate
+ * them, but we do not use s128 types in the kernel (we do use 'u128',
+ * but they are handled by the !is_signed_type() case).
*/
#ifdef CONFIG_64BIT
#define __signed_type(ux) long
--
2.47.3
^ permalink raw reply related
* [PATCH v3 04/11 6.1.y] minmax: fix up min3() and max3() too
From: Eliav Farber @ 2025-10-02 18:00 UTC (permalink / raw)
To: gregkh, kenneth.feng, alexander.deucher, christian.koenig,
airlied, simona, linus.walleij, dmitry.torokhov, tglx, wens,
jernej.skrabec, samuel, agk, snitzer, mpatocka, clm, dsterba,
luc.vanoostenryck, pmladek, rostedt, andriy.shevchenko, linux,
senozhatsky, akpm, lijo.lazar, asad.kamal, kevinyang.wang,
David.Laight, amd-gfx, dri-devel, linux-kernel, linux-input,
linux-arm-kernel, linux-sunxi, dm-devel, linux-btrfs,
linux-sparse, stable, farbere
Cc: Linus Torvalds, David Laight, Arnd Bergmann
In-Reply-To: <20251002180036.33738-1-farbere@amazon.com>
From: Linus Torvalds <torvalds@linux-foundation.org>
[ Upstream commit 21b136cc63d2a9ddd60d4699552b69c214b32964 ]
David Laight pointed out that we should deal with the min3() and max3()
mess too, which still does excessive expansion.
And our current macros are actually rather broken.
In particular, the macros did this:
#define min3(x, y, z) min((typeof(x))min(x, y), z)
#define max3(x, y, z) max((typeof(x))max(x, y), z)
and that not only is a nested expansion of possibly very complex
arguments with all that involves, the typing with that "typeof()" cast
is completely wrong.
For example, imagine what happens in max3() if 'x' happens to be a
'unsigned char', but 'y' and 'z' are 'unsigned long'. The types are
compatible, and there's no warning - but the result is just random
garbage.
No, I don't think we've ever hit that issue in practice, but since we
now have sane infrastructure for doing this right, let's just use it.
It fixes any excessive expansion, and also avoids these kinds of broken
type issues.
Requested-by: David Laight <David.Laight@aculab.com>
Acked-by: Arnd Bergmann <arnd@kernel.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
include/linux/minmax.h | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/include/linux/minmax.h b/include/linux/minmax.h
index 41da6f85a407..98008dd92153 100644
--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -152,13 +152,20 @@
#define umax(x, y) \
__careful_cmp(max, (x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull)
+#define __careful_op3(op, x, y, z, ux, uy, uz) ({ \
+ __auto_type ux = (x); __auto_type uy = (y);__auto_type uz = (z);\
+ BUILD_BUG_ON_MSG(!__types_ok3(x,y,z,ux,uy,uz), \
+ #op"3("#x", "#y", "#z") signedness error"); \
+ __cmp(op, ux, __cmp(op, uy, uz)); })
+
/**
* min3 - return minimum of three values
* @x: first value
* @y: second value
* @z: third value
*/
-#define min3(x, y, z) min((typeof(x))min(x, y), z)
+#define min3(x, y, z) \
+ __careful_op3(min, x, y, z, __UNIQUE_ID(x_), __UNIQUE_ID(y_), __UNIQUE_ID(z_))
/**
* max3 - return maximum of three values
@@ -166,7 +173,8 @@
* @y: second value
* @z: third value
*/
-#define max3(x, y, z) max((typeof(x))max(x, y), z)
+#define max3(x, y, z) \
+ __careful_op3(max, x, y, z, __UNIQUE_ID(x_), __UNIQUE_ID(y_), __UNIQUE_ID(z_))
/**
* min_not_zero - return the minimum that is _not_ zero, unless both are zero
--
2.47.3
^ permalink raw reply related
* [PATCH v3 03/11 6.1.y] minmax: improve macro expansion and type checking
From: Eliav Farber @ 2025-10-02 18:00 UTC (permalink / raw)
To: gregkh, kenneth.feng, alexander.deucher, christian.koenig,
airlied, simona, linus.walleij, dmitry.torokhov, tglx, wens,
jernej.skrabec, samuel, agk, snitzer, mpatocka, clm, dsterba,
luc.vanoostenryck, pmladek, rostedt, andriy.shevchenko, linux,
senozhatsky, akpm, lijo.lazar, asad.kamal, kevinyang.wang,
David.Laight, amd-gfx, dri-devel, linux-kernel, linux-input,
linux-arm-kernel, linux-sunxi, dm-devel, linux-btrfs,
linux-sparse, stable, farbere
Cc: Linus Torvalds, Arnd Bergmann, David Laight, Lorenzo Stoakes
In-Reply-To: <20251002180036.33738-1-farbere@amazon.com>
From: Linus Torvalds <torvalds@linux-foundation.org>
[ Upstream commit 22f5468731491e53356ba7c028f0fdea20b18e2c ]
This clarifies the rules for min()/max()/clamp() type checking and makes
them a much more efficient macro expansion.
In particular, we now look at the type and range of the inputs to see
whether they work together, generating a mask of acceptable comparisons,
and then just verifying that the inputs have a shared case:
- an expression with a signed type can be used for
(1) signed comparisons
(2) unsigned comparisons if it is statically known to have a
non-negative value
- an expression with an unsigned type can be used for
(3) unsigned comparison
(4) signed comparisons if the type is smaller than 'int' and thus
the C integer promotion rules will make it signed anyway
Here rule (1) and (3) are obvious, and rule (2) is important in order to
allow obvious trivial constants to be used together with unsigned
values.
Rule (4) is not necessarily a good idea, but matches what we used to do,
and we have extant cases of this situation in the kernel. Notably with
bcachefs having an expression like
min(bch2_bucket_sectors_dirty(a), ca->mi.bucket_size)
where bch2_bucket_sectors_dirty() returns an 's64', and
'ca->mi.bucket_size' is of type 'u16'.
Technically that bcachefs comparison is clearly sensible on a C type
level, because the 'u16' will go through the normal C integer promotion,
and become 'int', and then we're comparing two signed values and
everything looks sane.
However, it's not entirely clear that a 'min(s64,u16)' operation makes a
lot of conceptual sense, and it's possible that we will remove rule (4).
After all, the _reason_ we have these complicated type checks is exactly
that the C type promotion rules are not very intuitive.
But at least for now the rule is in place for backwards compatibility.
Also note that rule (2) existed before, but is hugely relaxed by this
commit. It used to be true only for the simplest compile-time
non-negative integer constants. The new macro model will allow cases
where the compiler can trivially see that an expression is non-negative
even if it isn't necessarily a constant.
For example, the amdgpu driver does
min_t(size_t, sizeof(fru_info->serial), pia[addr] & 0x3F));
because our old 'min()' macro would see that 'pia[addr] & 0x3F' is of
type 'int' and clearly not a C constant expression, so doing a 'min()'
with a 'size_t' is a signedness violation.
Our new 'min()' macro still sees that 'pia[addr] & 0x3F' is of type
'int', but is smart enough to also see that it is clearly non-negative,
and thus would allow that case without any complaints.
Cc: Arnd Bergmann <arnd@kernel.org>
Cc: David Laight <David.Laight@aculab.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
include/linux/compiler.h | 9 +++++
include/linux/minmax.h | 74 ++++++++++++++++++++++++++++++++--------
2 files changed, 68 insertions(+), 15 deletions(-)
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index f6ea15821cea..a6a7be83fae6 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -244,6 +244,15 @@ static inline void *offset_to_ptr(const int *off)
*/
#define is_signed_type(type) (((type)(-1)) < (__force type)1)
+/*
+ * Useful shorthand for "is this condition known at compile-time?"
+ *
+ * Note that the condition may involve non-constant values,
+ * but the compiler may know enough about the details of the
+ * values to determine that the condition is statically true.
+ */
+#define statically_true(x) (__builtin_constant_p(x) && (x))
+
/*
* This is needed in functions which generate the stack canary, see
* arch/x86/kernel/smpboot.c::start_secondary() for an example.
diff --git a/include/linux/minmax.h b/include/linux/minmax.h
index e3e4353df983..41da6f85a407 100644
--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -26,19 +26,63 @@
#define __typecheck(x, y) \
(!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
-/* is_signed_type() isn't a constexpr for pointer types */
-#define __is_signed(x) \
- __builtin_choose_expr(__is_constexpr(is_signed_type(typeof(x))), \
- is_signed_type(typeof(x)), 0)
+/*
+ * __sign_use for integer expressions:
+ * bit #0 set if ok for unsigned comparisons
+ * bit #1 set if ok for signed comparisons
+ *
+ * In particular, statically non-negative signed integer
+ * expressions are ok for both.
+ *
+ * NOTE! Unsigned types smaller than 'int' are implicitly
+ * converted to 'int' in expressions, and are accepted for
+ * signed conversions for now. This is debatable.
+ *
+ * Note that 'x' is the original expression, and 'ux' is
+ * the unique variable that contains the value.
+ *
+ * We use 'ux' for pure type checking, and 'x' for when
+ * we need to look at the value (but without evaluating
+ * it for side effects! Careful to only ever evaluate it
+ * with sizeof() or __builtin_constant_p() etc).
+ *
+ * Pointers end up being checked by the normal C type
+ * rules at the actual comparison, and these expressions
+ * only need to be careful to not cause warnings for
+ * pointer use.
+ */
+#define __signed_type_use(x,ux) (2+__is_nonneg(x,ux))
+#define __unsigned_type_use(x,ux) (1+2*(sizeof(ux)<4))
+#define __sign_use(x,ux) (is_signed_type(typeof(ux))? \
+ __signed_type_use(x,ux):__unsigned_type_use(x,ux))
+
+/*
+ * To avoid warnings about casting pointers to integers
+ * of different sizes, we need that special sign type.
+ *
+ * On 64-bit we can just always use 'long', since any
+ * integer or pointer type can just be cast to that.
+ *
+ * This does not work for 128-bit signed integers since
+ * the cast would truncate them, but we do not use s128
+ * types in the kernel (we do use 'u128', but they will
+ * be handled by the !is_signed_type() case).
+ *
+ * NOTE! The cast is there only to avoid any warnings
+ * from when values that aren't signed integer types.
+ */
+#ifdef CONFIG_64BIT
+ #define __signed_type(ux) long
+#else
+ #define __signed_type(ux) typeof(__builtin_choose_expr(sizeof(ux)>4,1LL,1L))
+#endif
+#define __is_nonneg(x,ux) statically_true((__signed_type(ux))(x)>=0)
-/* True for a non-negative signed int constant */
-#define __is_noneg_int(x) \
- (__builtin_choose_expr(__is_constexpr(x) && __is_signed(x), x, -1) >= 0)
+#define __types_ok(x,y,ux,uy) \
+ (__sign_use(x,ux) & __sign_use(y,uy))
-#define __types_ok(x, y, ux, uy) \
- (__is_signed(ux) == __is_signed(uy) || \
- __is_signed((ux) + 0) == __is_signed((uy) + 0) || \
- __is_noneg_int(x) || __is_noneg_int(y))
+#define __types_ok3(x,y,z,ux,uy,uz) \
+ (__sign_use(x,ux) & __sign_use(y,uy) & __sign_use(z,uz))
#define __cmp_op_min <
#define __cmp_op_max >
@@ -53,8 +97,8 @@
#define __careful_cmp_once(op, x, y, ux, uy) ({ \
__auto_type ux = (x); __auto_type uy = (y); \
- static_assert(__types_ok(x, y, ux, uy), \
- #op "(" #x ", " #y ") signedness error, fix types or consider u" #op "() before " #op "_t()"); \
+ BUILD_BUG_ON_MSG(!__types_ok(x,y,ux,uy), \
+ #op"("#x", "#y") signedness error"); \
__cmp(op, ux, uy); })
#define __careful_cmp(op, x, y) \
@@ -70,8 +114,8 @@
static_assert(__builtin_choose_expr(__is_constexpr((lo) > (hi)), \
(lo) <= (hi), true), \
"clamp() low limit " #lo " greater than high limit " #hi); \
- static_assert(__types_ok(uval, lo, uval, ulo), "clamp() 'lo' signedness error"); \
- static_assert(__types_ok(uval, hi, uval, uhi), "clamp() 'hi' signedness error"); \
+ BUILD_BUG_ON_MSG(!__types_ok3(val,lo,hi,uval,ulo,uhi), \
+ "clamp("#val", "#lo", "#hi") signedness error"); \
__clamp(uval, ulo, uhi); })
#define __careful_clamp(val, lo, hi) \
--
2.47.3
^ permalink raw reply related
* [PATCH v3 02/11 6.1.y] minmax: don't use max() in situations that want a C constant expression
From: Eliav Farber @ 2025-10-02 18:00 UTC (permalink / raw)
To: gregkh, kenneth.feng, alexander.deucher, christian.koenig,
airlied, simona, linus.walleij, dmitry.torokhov, tglx, wens,
jernej.skrabec, samuel, agk, snitzer, mpatocka, clm, dsterba,
luc.vanoostenryck, pmladek, rostedt, andriy.shevchenko, linux,
senozhatsky, akpm, lijo.lazar, asad.kamal, kevinyang.wang,
David.Laight, amd-gfx, dri-devel, linux-kernel, linux-input,
linux-arm-kernel, linux-sunxi, dm-devel, linux-btrfs,
linux-sparse, stable, farbere
Cc: Linus Torvalds, David Laight, Lorenzo Stoakes
In-Reply-To: <20251002180036.33738-1-farbere@amazon.com>
From: Linus Torvalds <torvalds@linux-foundation.org>
[ Upstream commit cb04e8b1d2f24c4c2c92f7b7529031fc35a16fed ]
We only had a couple of array[] declarations, and changing them to just
use 'MAX()' instead of 'max()' fixes the issue.
This will allow us to simplify our min/max macros enormously, since they
can now unconditionally use temporary variables to avoid using the
argument values multiple times.
Cc: David Laight <David.Laight@aculab.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
V2 -> V3:
- Fix build failure in drivers/md/dm-integrity.c: In function
‘integrity_metadata’.
The fix uses MAX() instead of max() in the checksums_onstack[] array
declarations.
Note: In the mainline branch, checksums_onstack[] used max_t(), so it
was fixed to use MAX_T() in commit 4477b39c32fd ("minmax: add a few
more MIN_T/MAX_T users").
In 6.1.y, checksums_onstack[] used max(), so it was fixed to use MAX
in the backport of commit cb04e8b1d2f2 ("minmax: don't use max() in
situations that want a C constant expression").
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 2 +-
drivers/input/touchscreen/cyttsp4_core.c | 2 +-
drivers/irqchip/irq-sun6i-r.c | 2 +-
drivers/md/dm-integrity.c | 2 +-
fs/btrfs/tree-checker.c | 2 +-
lib/vsprintf.c | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index 768b6e7dbd77..fd1faa840ec0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -700,7 +700,7 @@ static const char *smu_get_feature_name(struct smu_context *smu,
size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu,
char *buf)
{
- int8_t sort_feature[max(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)];
+ int8_t sort_feature[MAX(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)];
uint64_t feature_mask;
int i, feature_index;
uint32_t count = 0;
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
index dccbcb942fe5..936d69da3bda 100644
--- a/drivers/input/touchscreen/cyttsp4_core.c
+++ b/drivers/input/touchscreen/cyttsp4_core.c
@@ -871,7 +871,7 @@ static void cyttsp4_get_mt_touches(struct cyttsp4_mt_data *md, int num_cur_tch)
struct cyttsp4_touch tch;
int sig;
int i, j, t = 0;
- int ids[max(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)];
+ int ids[MAX(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)];
memset(ids, 0, si->si_ofs.tch_abs[CY_TCH_T].max * sizeof(int));
for (i = 0; i < num_cur_tch; i++) {
diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
index a01e44049415..99958d470d62 100644
--- a/drivers/irqchip/irq-sun6i-r.c
+++ b/drivers/irqchip/irq-sun6i-r.c
@@ -270,7 +270,7 @@ static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
static int sun6i_r_intc_suspend(void)
{
- u32 buf[BITS_TO_U32(max(SUN6I_NR_TOP_LEVEL_IRQS, SUN6I_NR_MUX_BITS))];
+ u32 buf[BITS_TO_U32(MAX(SUN6I_NR_TOP_LEVEL_IRQS, SUN6I_NR_MUX_BITS))];
int i;
/* Wake IRQs are enabled during system sleep and shutdown. */
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index a201019babe4..fc9cb626ca91 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -1794,7 +1794,7 @@ static void integrity_metadata(struct work_struct *w)
struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
char *checksums;
unsigned int extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
- char checksums_onstack[max((size_t)HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
+ char checksums_onstack[MAX(HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
sector_t sector;
unsigned int sectors_to_process;
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index d3e5429ee03d..6108cfab1ba5 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -608,7 +608,7 @@ static int check_dir_item(struct extent_buffer *leaf,
*/
if (key->type == BTRFS_DIR_ITEM_KEY ||
key->type == BTRFS_XATTR_ITEM_KEY) {
- char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
+ char namebuf[MAX(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
read_extent_buffer(leaf, namebuf,
(unsigned long)(di + 1), name_len);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index fa1c19701855..2b0b5f08b8fc 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1082,7 +1082,7 @@ char *resource_string(char *buf, char *end, struct resource *res,
#define FLAG_BUF_SIZE (2 * sizeof(res->flags))
#define DECODED_BUF_SIZE sizeof("[mem - 64bit pref window disabled]")
#define RAW_BUF_SIZE sizeof("[mem - flags 0x]")
- char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE,
+ char sym[MAX(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE,
2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)];
char *p = sym, *pend = sym + sizeof(sym);
--
2.47.3
^ permalink raw reply related
* [PATCH v3 01/11 6.1.y] minmax: simplify min()/max()/clamp() implementation
From: Eliav Farber @ 2025-10-02 18:00 UTC (permalink / raw)
To: gregkh, kenneth.feng, alexander.deucher, christian.koenig,
airlied, simona, linus.walleij, dmitry.torokhov, tglx, wens,
jernej.skrabec, samuel, agk, snitzer, mpatocka, clm, dsterba,
luc.vanoostenryck, pmladek, rostedt, andriy.shevchenko, linux,
senozhatsky, akpm, lijo.lazar, asad.kamal, kevinyang.wang,
David.Laight, amd-gfx, dri-devel, linux-kernel, linux-input,
linux-arm-kernel, linux-sunxi, dm-devel, linux-btrfs,
linux-sparse, stable, farbere
Cc: Linus Torvalds, David Laight, Lorenzo Stoakes
In-Reply-To: <20251002180036.33738-1-farbere@amazon.com>
From: Linus Torvalds <torvalds@linux-foundation.org>
[ Upstream commit dc1c8034e31b14a2e5e212104ec508aec44ce1b9 ]
Now that we no longer have any C constant expression contexts (ie array
size declarations or static initializers) that use min() or max(), we
can simpify the implementation by not having to worry about the result
staying as a C constant expression.
So now we can unconditionally just use temporary variables of the right
type, and get rid of the excessive expansion that used to come from the
use of
__builtin_choose_expr(__is_constexpr(...), ..
to pick the specialized code for constant expressions.
Another expansion simplification is to pass the temporary variables (in
addition to the original expression) to our __types_ok() macro. That
may superficially look like it complicates the macro, but when we only
want the type of the expression, expanding the temporary variable names
is much simpler and smaller than expanding the potentially complicated
original expression.
As a result, on my machine, doing a
$ time make drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.i
goes from
real 0m16.621s
user 0m15.360s
sys 0m1.221s
to
real 0m2.532s
user 0m2.091s
sys 0m0.452s
because the token expansion goes down dramatically.
In particular, the longest line expansion (which was line 71 of that
'ia_css_ynr.host.c' file) shrinks from 23,338kB (yes, 23MB for one
single line) to "just" 1,444kB (now "only" 1.4MB).
And yes, that line is still the line from hell, because it's doing
multiple levels of "min()/max()" expansion thanks to some of them being
hidden inside the uDIGIT_FITTING() macro.
Lorenzo has a nice cleanup patch that makes that driver use inline
functions instead of macros for sDIGIT_FITTING() and uDIGIT_FITTING(),
which will fix that line once and for all, but the 16-fold reduction in
this case does show why we need to simplify these helpers.
Cc: David Laight <David.Laight@aculab.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
include/linux/minmax.h | 43 ++++++++++++++++++++----------------------
1 file changed, 20 insertions(+), 23 deletions(-)
diff --git a/include/linux/minmax.h b/include/linux/minmax.h
index fc384714da45..e3e4353df983 100644
--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -35,10 +35,10 @@
#define __is_noneg_int(x) \
(__builtin_choose_expr(__is_constexpr(x) && __is_signed(x), x, -1) >= 0)
-#define __types_ok(x, y) \
- (__is_signed(x) == __is_signed(y) || \
- __is_signed((x) + 0) == __is_signed((y) + 0) || \
- __is_noneg_int(x) || __is_noneg_int(y))
+#define __types_ok(x, y, ux, uy) \
+ (__is_signed(ux) == __is_signed(uy) || \
+ __is_signed((ux) + 0) == __is_signed((uy) + 0) || \
+ __is_noneg_int(x) || __is_noneg_int(y))
#define __cmp_op_min <
#define __cmp_op_max >
@@ -51,34 +51,31 @@
#define __cmp_once(op, type, x, y) \
__cmp_once_unique(op, type, x, y, __UNIQUE_ID(x_), __UNIQUE_ID(y_))
-#define __careful_cmp_once(op, x, y) ({ \
- static_assert(__types_ok(x, y), \
+#define __careful_cmp_once(op, x, y, ux, uy) ({ \
+ __auto_type ux = (x); __auto_type uy = (y); \
+ static_assert(__types_ok(x, y, ux, uy), \
#op "(" #x ", " #y ") signedness error, fix types or consider u" #op "() before " #op "_t()"); \
- __cmp_once(op, __auto_type, x, y); })
+ __cmp(op, ux, uy); })
-#define __careful_cmp(op, x, y) \
- __builtin_choose_expr(__is_constexpr((x) - (y)), \
- __cmp(op, x, y), __careful_cmp_once(op, x, y))
+#define __careful_cmp(op, x, y) \
+ __careful_cmp_once(op, x, y, __UNIQUE_ID(x_), __UNIQUE_ID(y_))
#define __clamp(val, lo, hi) \
((val) >= (hi) ? (hi) : ((val) <= (lo) ? (lo) : (val)))
-#define __clamp_once(val, lo, hi, unique_val, unique_lo, unique_hi) ({ \
- typeof(val) unique_val = (val); \
- typeof(lo) unique_lo = (lo); \
- typeof(hi) unique_hi = (hi); \
+#define __clamp_once(val, lo, hi, uval, ulo, uhi) ({ \
+ __auto_type uval = (val); \
+ __auto_type ulo = (lo); \
+ __auto_type uhi = (hi); \
static_assert(__builtin_choose_expr(__is_constexpr((lo) > (hi)), \
(lo) <= (hi), true), \
"clamp() low limit " #lo " greater than high limit " #hi); \
- static_assert(__types_ok(val, lo), "clamp() 'lo' signedness error"); \
- static_assert(__types_ok(val, hi), "clamp() 'hi' signedness error"); \
- __clamp(unique_val, unique_lo, unique_hi); })
-
-#define __careful_clamp(val, lo, hi) ({ \
- __builtin_choose_expr(__is_constexpr((val) - (lo) + (hi)), \
- __clamp(val, lo, hi), \
- __clamp_once(val, lo, hi, __UNIQUE_ID(__val), \
- __UNIQUE_ID(__lo), __UNIQUE_ID(__hi))); })
+ static_assert(__types_ok(uval, lo, uval, ulo), "clamp() 'lo' signedness error"); \
+ static_assert(__types_ok(uval, hi, uval, uhi), "clamp() 'hi' signedness error"); \
+ __clamp(uval, ulo, uhi); })
+
+#define __careful_clamp(val, lo, hi) \
+ __clamp_once(val, lo, hi, __UNIQUE_ID(v_), __UNIQUE_ID(l_), __UNIQUE_ID(h_))
/**
* min - return minimum of two values of the same or compatible types
--
2.47.3
^ permalink raw reply related
* [PATCH v3 00/11 6.1.y] Backport minmax.h updates from v6.17-rc7
From: Eliav Farber @ 2025-10-02 18:00 UTC (permalink / raw)
To: gregkh, kenneth.feng, alexander.deucher, christian.koenig,
airlied, simona, linus.walleij, dmitry.torokhov, tglx, wens,
jernej.skrabec, samuel, agk, snitzer, mpatocka, clm, dsterba,
luc.vanoostenryck, pmladek, rostedt, andriy.shevchenko, linux,
senozhatsky, akpm, lijo.lazar, asad.kamal, kevinyang.wang,
David.Laight, amd-gfx, dri-devel, linux-kernel, linux-input,
linux-arm-kernel, linux-sunxi, dm-devel, linux-btrfs,
linux-sparse, stable, farbere
This series backports 13 patches to update minmax.h in the 6.1.y branch,
aligning it with v6.17-rc7.
The ultimate goal is to synchronize all longterm branches so that they
include the full set of minmax.h changes (6.12.y and 6.6.y were already
backported by me and are now ligned).
The key motivation is to bring in commit d03eba99f5bf ("minmax: allow
min()/max()/clamp() if the arguments have the same signedness"), which
is missing in older kernels.
In mainline, this change enables min()/max()/clamp() to accept mixed
argument types, provided both have the same signedness. Without it,
backported patches that use these forms may trigger compiler warnings,
which escalate to build failures when -Werror is enabled.
Changes in v3:
- v2 included 13 patches:
https://lore.kernel.org/stable/20250929183358.18982-1-farbere@amazon.com/
- First 2 were accepted and are part of 6.1.155.
- 3rd caused build in drivers/md/ to fail:
In file included from ./include/linux/container_of.h:5,
from ./include/linux/list.h:5,
from ./include/linux/wait.h:7,
from ./include/linux/mempool.h:8,
from ./include/linux/bio.h:8,
from drivers/md/dm-bio-record.h:10,
from drivers/md/dm-integrity.c:9:
drivers/md/dm-integrity.c: In function ‘integrity_metadata’:
drivers/md/dm-integrity.c:131:105: error: ISO C90 forbids variable length array ‘checksums_onstack’ [-Werror=vla]
131 | #define MAX_TAG_SIZE (JOURNAL_SECTOR_DATA - JOURNAL_MAC_PER_SECTOR - offsetof(struct journal_entry, last_bytes[MAX_SECTORS_PER_BLOCK]))
| ^~~~~~~~~~~~~
./include/linux/build_bug.h:78:56: note: in definition of macro ‘__static_assert’
78 | #define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
| ^~~~
./include/linux/minmax.h:56:9: note: in expansion of macro ‘static_assert’
56 | static_assert(__types_ok(x, y, ux, uy), \
| ^~~~~~~~~~~~~
./include/linux/minmax.h:41:31: note: in expansion of macro ‘__is_noneg_int’
41 | __is_noneg_int(x) || __is_noneg_int(y))
| ^~~~~~~~~~~~~~
./include/linux/minmax.h:56:23: note: in expansion of macro ‘__types_ok’
56 | static_assert(__types_ok(x, y, ux, uy), \
| ^~~~~~~~~~
./include/linux/minmax.h:61:9: note: in expansion of macro ‘__careful_cmp_once’
61 | __careful_cmp_once(op, x, y, __UNIQUE_ID(x_), __UNIQUE_ID(y_))
| ^~~~~~~~~~~~~~~~~~
./include/linux/minmax.h:92:25: note: in expansion of macro ‘__careful_cmp’
92 | #define max(x, y) __careful_cmp(max, x, y)
| ^~~~~~~~~~~~~
drivers/md/dm-integrity.c:1797:40: note: in expansion of macro ‘max’
1797 | char checksums_onstack[max((size_t)HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
| ^~~
drivers/md/dm-integrity.c:131:89: note: in expansion of macro ‘offsetof’
131 | #define MAX_TAG_SIZE (JOURNAL_SECTOR_DATA - JOURNAL_MAC_PER_SECTOR - offsetof(struct journal_entry, last_bytes[MAX_SECTORS_PER_BLOCK]))
| ^~~~~~~~
drivers/md/dm-integrity.c:1797:73: note: in expansion of macro ‘MAX_TAG_SIZE’
1797 | char checksums_onstack[max((size_t)HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
| ^~~~~~~~~~~~
- The build was fixed in the second patch of this series.
Changes in v2:
- v1 included 19 patches:
https://lore.kernel.org/stable/20250924202320.32333-1-farbere@amazon.com/
- First 6 were pushed to the stable-tree.
- 7th cauded amd driver's build to fail.
- This change fixes it.
- Modified files:
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
David Laight (7):
minmax.h: add whitespace around operators and after commas
minmax.h: update some comments
minmax.h: reduce the #define expansion of min(), max() and clamp()
minmax.h: use BUILD_BUG_ON_MSG() for the lo < hi test in clamp()
minmax.h: move all the clamp() definitions after the min/max() ones
minmax.h: simplify the variants of clamp()
minmax.h: remove some #defines that are only expanded once
Linus Torvalds (4):
minmax: simplify min()/max()/clamp() implementation
minmax: don't use max() in situations that want a C constant
expression
minmax: improve macro expansion and type checking
minmax: fix up min3() and max3() too
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 2 +-
drivers/input/touchscreen/cyttsp4_core.c | 2 +-
drivers/irqchip/irq-sun6i-r.c | 2 +-
drivers/md/dm-integrity.c | 2 +-
fs/btrfs/tree-checker.c | 2 +-
include/linux/compiler.h | 9 +
include/linux/minmax.h | 222 +++++++++++++----------
lib/vsprintf.c | 2 +-
8 files changed, 143 insertions(+), 100 deletions(-)
--
2.47.3
^ permalink raw reply
* [PATCH v3 2/2] dt-bindings: touchscreen: consolidate simple touch controller to trivial-touch.yaml
From: Frank Li @ 2025-10-02 16:44 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Job Noorman,
open list:INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN)...,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list
Cc: imx
In-Reply-To: <20251002164413.1112136-1-Frank.Li@nxp.com>
Move ar1021.txt, azoteq,iqs5xx.yaml, himax,hx83112b.yaml,
hynitron,cstxxx.yaml, ilitek_ts_i2c.yaml, semtech,sx8654.yaml, ar1021.txt
to trivial-touch.yaml to consolidate simple touch yaml binding to one file.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v3
move more files into trivial-touch.yaml
don't add rob's review by because big change
prevous discussion at
https://lore.kernel.org/imx/175937443731.2982292.3723741722041625819.robh@kernel.org/T/#m35cfaaee8239b7a9aad3354b80de5f44d267c2e9
change in v2
move to trivial-touch.yaml
previous discussion
https://lore.kernel.org/imx/20250925-swimming-overspend-ddf7ab4a252c@spud/T/#t
---
.../bindings/input/touchscreen/ar1021.txt | 15 ----
.../input/touchscreen/azoteq,iqs5xx.yaml | 75 ------------------
.../input/touchscreen/himax,hx83112b.yaml | 64 ----------------
.../input/touchscreen/hynitron,cstxxx.yaml | 65 ----------------
.../input/touchscreen/ilitek_ts_i2c.yaml | 76 -------------------
.../input/touchscreen/semtech,sx8654.yaml | 52 -------------
.../input/touchscreen/trivial-touch.yaml | 31 ++++++++
7 files changed, 31 insertions(+), 347 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/ar1021.txt
delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml
delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml
delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml
delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml
delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt b/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt
deleted file mode 100644
index 82019bd6094ee..0000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-* Microchip AR1020 and AR1021 touchscreen interface (I2C)
-
-Required properties:
-- compatible : "microchip,ar1021-i2c"
-- reg : I2C slave address
-- interrupts : touch controller interrupt
-
-Example:
-
- touchscreen@4d {
- compatible = "microchip,ar1021-i2c";
- reg = <0x4d>;
- interrupt-parent = <&gpio3>;
- interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
- };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml b/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml
deleted file mode 100644
index b5f377215c098..0000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml
+++ /dev/null
@@ -1,75 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/azoteq,iqs5xx.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
-
-maintainers:
- - Jeff LaBundy <jeff@labundy.com>
-
-description: |
- The Azoteq IQS550, IQS572 and IQS525 trackpad and touchscreen controllers
- employ projected-capacitance sensing and can track up to five independent
- contacts.
-
- Link to datasheet: https://www.azoteq.com/
-
-allOf:
- - $ref: touchscreen.yaml#
-
-properties:
- compatible:
- enum:
- - azoteq,iqs550
- - azoteq,iqs572
- - azoteq,iqs525
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- reset-gpios:
- maxItems: 1
-
- wakeup-source: true
-
- touchscreen-size-x: true
- touchscreen-size-y: true
- touchscreen-inverted-x: true
- touchscreen-inverted-y: true
- touchscreen-swapped-x-y: true
-
-required:
- - compatible
- - reg
- - interrupts
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/gpio/gpio.h>
- #include <dt-bindings/interrupt-controller/irq.h>
-
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
-
- touchscreen@74 {
- compatible = "azoteq,iqs550";
- reg = <0x74>;
- interrupt-parent = <&gpio>;
- interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
- reset-gpios = <&gpio 22 (GPIO_ACTIVE_LOW |
- GPIO_PUSH_PULL)>;
-
- touchscreen-size-x = <800>;
- touchscreen-size-y = <480>;
- };
- };
-
-...
diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml b/Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml
deleted file mode 100644
index f5cfacb5e966d..0000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml
+++ /dev/null
@@ -1,64 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/himax,hx83112b.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Himax hx83112b touchscreen controller
-
-maintainers:
- - Job Noorman <job@noorman.info>
-
-allOf:
- - $ref: touchscreen.yaml#
-
-properties:
- compatible:
- enum:
- - himax,hx83100a
- - himax,hx83112b
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- reset-gpios:
- maxItems: 1
-
- touchscreen-inverted-x: true
- touchscreen-inverted-y: true
- touchscreen-size-x: true
- touchscreen-size-y: true
- touchscreen-swapped-x-y: true
-
-additionalProperties: false
-
-required:
- - compatible
- - reg
- - interrupts
- - reset-gpios
- - touchscreen-size-x
- - touchscreen-size-y
-
-examples:
- - |
- #include <dt-bindings/interrupt-controller/irq.h>
- #include <dt-bindings/gpio/gpio.h>
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
- touchscreen@48 {
- compatible = "himax,hx83112b";
- reg = <0x48>;
- interrupt-parent = <&tlmm>;
- interrupts = <65 IRQ_TYPE_LEVEL_LOW>;
- touchscreen-size-x = <1080>;
- touchscreen-size-y = <2160>;
- reset-gpios = <&tlmm 64 GPIO_ACTIVE_LOW>;
- };
- };
-
-...
diff --git a/Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml b/Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml
deleted file mode 100644
index 9cb5d4af00f75..0000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml
+++ /dev/null
@@ -1,65 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/hynitron,cstxxx.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Hynitron cstxxx series touchscreen controller
-
-description: |
- Bindings for Hynitron cstxxx series multi-touch touchscreen
- controllers.
-
-maintainers:
- - Chris Morgan <macromorgan@hotmail.com>
-
-allOf:
- - $ref: touchscreen.yaml#
-
-properties:
- compatible:
- enum:
- - hynitron,cst340
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- reset-gpios:
- maxItems: 1
-
- touchscreen-size-x: true
- touchscreen-size-y: true
- touchscreen-inverted-x: true
- touchscreen-inverted-y: true
- touchscreen-swapped-x-y: true
-
-additionalProperties: false
-
-required:
- - compatible
- - reg
- - interrupts
- - reset-gpios
-
-examples:
- - |
- #include <dt-bindings/gpio/gpio.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
- touchscreen@1a {
- compatible = "hynitron,cst340";
- reg = <0x1a>;
- interrupt-parent = <&gpio4>;
- interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
- reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>;
- touchscreen-size-x = <640>;
- touchscreen-size-y = <480>;
- };
- };
-
-...
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml b/Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml
deleted file mode 100644
index 9f73289997568..0000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml
+++ /dev/null
@@ -1,76 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/ilitek_ts_i2c.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Ilitek I2C Touchscreen Controller
-
-maintainers:
- - Dmitry Torokhov <dmitry.torokhov@gmail.com>
-
-allOf:
- - $ref: touchscreen.yaml#
-
-properties:
- compatible:
- enum:
- - ilitek,ili210x
- - ilitek,ili2117
- - ilitek,ili2120
- - ilitek,ili2130
- - ilitek,ili2131
- - ilitek,ili2132
- - ilitek,ili2316
- - ilitek,ili2322
- - ilitek,ili2323
- - ilitek,ili2326
- - ilitek,ili251x
- - ilitek,ili2520
- - ilitek,ili2521
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- reset-gpios:
- maxItems: 1
-
- wakeup-source:
- type: boolean
- description: touchscreen can be used as a wakeup source.
-
- touchscreen-size-x: true
- touchscreen-size-y: true
- touchscreen-inverted-x: true
- touchscreen-inverted-y: true
- touchscreen-swapped-x-y: true
-
-additionalProperties: false
-
-required:
- - compatible
- - reg
- - interrupts
-
-examples:
- - |
- #include <dt-bindings/interrupt-controller/irq.h>
- #include <dt-bindings/gpio/gpio.h>
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
-
- touchscreen@41 {
- compatible = "ilitek,ili2520";
- reg = <0x41>;
-
- interrupt-parent = <&gpio1>;
- interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
- reset-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
- touchscreen-inverted-y;
- wakeup-source;
- };
- };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml b/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml
deleted file mode 100644
index b2554064b6888..0000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml
+++ /dev/null
@@ -1,52 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/semtech,sx8654.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Semtech SX8654 I2C Touchscreen Controller
-
-maintainers:
- - Frank Li <Frank.Li@nxp.com>
-
-properties:
- compatible:
- enum:
- - semtech,sx8650
- - semtech,sx8654
- - semtech,sx8655
- - semtech,sx8656
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- reset-gpios:
- maxItems: 1
-
-required:
- - compatible
- - reg
- - interrupts
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/gpio/gpio.h>
- #include <dt-bindings/interrupt-controller/irq.h>
-
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
-
- touchscreen@48 {
- compatible = "semtech,sx8654";
- reg = <0x48>;
- interrupt-parent = <&gpio6>;
- interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
- reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
- };
- };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
index 349d1a6687a05..fa27c6754ca4e 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
@@ -12,8 +12,39 @@ maintainers:
properties:
compatible:
enum:
+ # The Azoteq IQS550, IQS572 and IQS525 trackpad and touchscreen controllers
+ - azoteq,iqs550
+ - azoteq,iqs572
+ - azoteq,iqs525
+ # Himax hx83100a touchscreen controller
+ - himax,hx83100a
+ # Himax hx83112b touchscreen controller
+ - himax,hx83112b
+ # Hynitron cstxxx series touchscreen controller
+ - hynitron,cst340
+ # Ilitek I2C Touchscreen Controller
+ - ilitek,ili210x
+ - ilitek,ili2117
+ - ilitek,ili2120
+ - ilitek,ili2130
+ - ilitek,ili2131
+ - ilitek,ili2132
+ - ilitek,ili2316
+ - ilitek,ili2322
+ - ilitek,ili2323
+ - ilitek,ili2326
+ - ilitek,ili251x
+ - ilitek,ili2520
+ - ilitek,ili2521
# MAXI MAX11801 Resistive touch screen controller with i2c interface
- maxim,max11801
+ # Microchip AR1020 and AR1021 touchscreen interface (I2C)
+ - microchip,ar1021-i2c
+ # Trivial touch screen controller with i2c interface
+ - semtech,sx8650
+ - semtech,sx8654
+ - semtech,sx8655
+ - semtech,sx8656
reg:
maxItems: 1
--
2.34.1
^ permalink raw reply related
* [PATCH v3 1/2] dt-bindings: touchscreen: rename maxim,max11801.yaml to trivial-touch.yaml
From: Frank Li @ 2025-10-02 16:44 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
open list:INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN)...,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list
Cc: imx
Rename maxim,max11801.yaml to trivial-touch.yaml for simple i2c touch
controller with one interrupt and common touch properties.
Add optional reset-gpios and wakeup-source properties.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v3
- add wakeup-source and reset-gpios optional properties
change in v2
new patch
previous discussion
https://lore.kernel.org/imx/20250925-swimming-overspend-ddf7ab4a252c@spud/T/#t
---
.../{maxim,max11801.yaml => trivial-touch.yaml} | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
rename Documentation/devicetree/bindings/input/touchscreen/{maxim,max11801.yaml => trivial-touch.yaml} (70%)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
similarity index 70%
rename from Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml
rename to Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
index 4f528d2201992..349d1a6687a05 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
@@ -1,17 +1,19 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: http://devicetree.org/schemas/input/touchscreen/maxim,max11801.yaml#
+$id: http://devicetree.org/schemas/input/touchscreen/trivial-touch.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: MAXI MAX11801 Resistive touch screen controller with i2c interface
+title: Trivial touch screen controller with i2c interface
maintainers:
- Frank Li <Frank.Li@nxp.com>
properties:
compatible:
- const: maxim,max11801
+ enum:
+ # MAXI MAX11801 Resistive touch screen controller with i2c interface
+ - maxim,max11801
reg:
maxItems: 1
@@ -19,6 +21,11 @@ properties:
interrupts:
maxItems: 1
+ reset-gpios:
+ maxItems: 1
+
+ wakeup-source: true
+
allOf:
- $ref: touchscreen.yaml
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v2 1/2] dt-bindings: touchscreen: rename maxim,max11801.yaml to trivial-touch.yaml
From: Rob Herring (Arm) @ 2025-10-02 3:07 UTC (permalink / raw)
To: Frank Li
Cc: Conor Dooley, linux-kernel, devicetree, linux-input, imx,
Dmitry Torokhov, Krzysztof Kozlowski
In-Reply-To: <20250926184720.391335-1-Frank.Li@nxp.com>
On Fri, 26 Sep 2025 14:47:11 -0400, Frank Li wrote:
> Rename maxim,max11801.yaml to trivial-touch.yaml for simple i2c touch
> controller with one interrupt and common touch properties.
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> change in v2
> new patch
>
> previous discussion
> https://lore.kernel.org/imx/20250925-swimming-overspend-ddf7ab4a252c@spud/T/#t
> ---
> .../{maxim,max11801.yaml => trivial-touch.yaml} | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
> rename Documentation/devicetree/bindings/input/touchscreen/{maxim,max11801.yaml => trivial-touch.yaml} (74%)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v2 2/2] dt-bindings: touchscreen: move ar1021.txt to trivial-touch.yaml
From: Rob Herring @ 2025-10-02 3:06 UTC (permalink / raw)
To: Frank Li
Cc: Conor Dooley, Dmitry Torokhov, Krzysztof Kozlowski, Conor Dooley,
open list:INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN)...,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list, imx
In-Reply-To: <aN2eWrTWsonkchJT@lizhi-Precision-Tower-5810>
On Wed, Oct 01, 2025 at 05:34:18PM -0400, Frank Li wrote:
> On Tue, Sep 30, 2025 at 08:05:56PM +0100, Conor Dooley wrote:
> > On Fri, Sep 26, 2025 at 02:47:12PM -0400, Frank Li wrote:
> > > ar1021 have only reg and interrupts property beside touch common
> > > properties. So move context of ar1021.txt into trivial-touch.yaml.
> > >
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > > change in v2
> > > move to trivial-touch.yaml
> > >
> > > previous discussion
> > > https://lore.kernel.org/imx/20250925-swimming-overspend-ddf7ab4a252c@spud/T/#t
> >
> > You mentioned there were a load of other devices using just these 3
> > properties. Do you intend moving those too?
>
> I go through other yaml, I have not found more. But there are somes, which
> have one additonal properties reset-gpios.
>
> If add 'reset-gpios' as optional property here, I can move more these into
> this files. But I am not sure if it is good idea to lose restriction or
> use if branch in trivial-touch.yaml.
That seems fine. Unless reset-gpios is required, I don't think you need
an if/then schema. Even required probably doesn't make sense. Any board
design could tie off the reset or make it not s/w controlled.
Rob
^ permalink raw reply
* Re: [PATCH v2 2/2] dt-bindings: touchscreen: move ar1021.txt to trivial-touch.yaml
From: Frank Li @ 2025-10-01 21:34 UTC (permalink / raw)
To: Conor Dooley
Cc: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
open list:INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN)...,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list, imx
In-Reply-To: <20250930-venomous-tracing-669be2e1163b@spud>
On Tue, Sep 30, 2025 at 08:05:56PM +0100, Conor Dooley wrote:
> On Fri, Sep 26, 2025 at 02:47:12PM -0400, Frank Li wrote:
> > ar1021 have only reg and interrupts property beside touch common
> > properties. So move context of ar1021.txt into trivial-touch.yaml.
> >
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
> > change in v2
> > move to trivial-touch.yaml
> >
> > previous discussion
> > https://lore.kernel.org/imx/20250925-swimming-overspend-ddf7ab4a252c@spud/T/#t
>
> You mentioned there were a load of other devices using just these 3
> properties. Do you intend moving those too?
I go through other yaml, I have not found more. But there are somes, which
have one additonal properties reset-gpios.
If add 'reset-gpios' as optional property here, I can move more these into
this files. But I am not sure if it is good idea to lose restriction or
use if branch in trivial-touch.yaml.
In other trivial-*.yaml, there are one reset-gpios and one power-supply.
Frank
>
> > ---
> > .../bindings/input/touchscreen/ar1021.txt | 15 ---------------
> > .../bindings/input/touchscreen/trivial-touch.yaml | 2 ++
> > 2 files changed, 2 insertions(+), 15 deletions(-)
> > delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/ar1021.txt
> >
> > diff --git a/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt b/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt
> > deleted file mode 100644
> > index 82019bd6094ee..0000000000000
> > --- a/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt
> > +++ /dev/null
> > @@ -1,15 +0,0 @@
> > -* Microchip AR1020 and AR1021 touchscreen interface (I2C)
> > -
> > -Required properties:
> > -- compatible : "microchip,ar1021-i2c"
> > -- reg : I2C slave address
> > -- interrupts : touch controller interrupt
> > -
> > -Example:
> > -
> > - touchscreen@4d {
> > - compatible = "microchip,ar1021-i2c";
> > - reg = <0x4d>;
> > - interrupt-parent = <&gpio3>;
> > - interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
> > - };
> > diff --git a/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
> > index c393cce273c5b..d6aed3afd4acb 100644
> > --- a/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
> > +++ b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
> > @@ -14,6 +14,8 @@ properties:
> > enum:
> > # MAXI MAX11801 Resistive touch screen controller with i2c interface
> > - maxim,max11801
> > + # Microchip AR1020 and AR1021 touchscreen interface (I2C)
> > + - microchip,ar1021-i2c
> >
> > reg:
> > maxItems: 1
> > --
> > 2.34.1
> >
^ permalink raw reply
* [PATCH] HID: hid-lg-g15: Add hw_brightness_changed support for the G510 keyboard
From: Hans de Goede @ 2025-10-01 21:19 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires; +Cc: Hans de Goede, linux-input
Add hw_brightness_changed support for the G510 keyboard, so that e.g.
GNOME will show an OSD notification when toggling the backlight on/off
with the button the keyboard.
Note that it is not possible to turn the backlight back on by writing
/sys/class/leds/.../brightness it can only be turned on by pressing
the button on the keyboard. To reflect this /sys/class/leds/.../brightness
will always report the last brightness value independent of the on/off
toggle built into the keyboard.
Signed-off-by: Hans de Goede <hansg@kernel.org>
---
This patch applies on top of "HID: lg-g15 - Add support for Logitech G13."
---
drivers/hid/hid-lg-g15.c | 35 ++++++++++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/hid-lg-g15.c b/drivers/hid/hid-lg-g15.c
index 7b8df2d5b57f..1a88bc44ada4 100644
--- a/drivers/hid/hid-lg-g15.c
+++ b/drivers/hid/hid-lg-g15.c
@@ -26,6 +26,9 @@
#define LG_G510_FEATURE_BACKLIGHT_RGB 0x05
#define LG_G510_FEATURE_POWER_ON_RGB 0x06
+#define LG_G510_INPUT_MACRO_KEYS 0x03
+#define LG_G510_INPUT_KBD_BACKLIGHT 0x04
+
#define LG_G13_INPUT_REPORT 0x01
#define LG_G13_FEATURE_M_KEYS_LEDS 0x05
#define LG_G13_FEATURE_BACKLIGHT_RGB 0x07
@@ -423,6 +426,20 @@ static int lg_g510_get_initial_led_brightness(struct lg_g15_data *g15, int i)
g15->leds[i].brightness = 0;
}
+ if (i)
+ return 0;
+
+ ret = hid_hw_raw_request(g15->hdev, LG_G510_INPUT_KBD_BACKLIGHT,
+ g15->transfer_buf, 2,
+ HID_INPUT_REPORT, HID_REQ_GET_REPORT);
+ if (ret != 2) {
+ /* This can happen when a KVM switch is used, so only warn. */
+ hid_warn(g15->hdev, "Error getting backlight state: %d\n", ret);
+ return 0;
+ }
+
+ g15->backlight_disabled = g15->transfer_buf[1] & 0x04;
+
return 0;
}
@@ -849,14 +866,24 @@ static int lg_g510_event(struct lg_g15_data *g15, u8 *data)
static int lg_g510_leds_event(struct lg_g15_data *g15, u8 *data)
{
+ struct lg_g15_led *g15_led = &g15->leds[LG_G15_KBD_BRIGHTNESS];
bool backlight_disabled;
+ backlight_disabled = data[1] & 0x04;
+ if (backlight_disabled == g15->backlight_disabled)
+ return 0;
+
+ led_classdev_notify_brightness_hw_changed(
+ &g15_led->mcdev.led_cdev,
+ backlight_disabled ? 0 : g15_led->brightness);
+
+ g15->backlight_disabled = backlight_disabled;
+
/*
* The G510 ignores backlight updates when the backlight is turned off
* through the light toggle button on the keyboard, to work around this
* we queue a workitem to sync values when the backlight is turned on.
*/
- backlight_disabled = data[1] & 0x04;
if (!backlight_disabled)
schedule_work(&g15->work);
@@ -892,9 +919,9 @@ static int lg_g15_raw_event(struct hid_device *hdev, struct hid_report *report,
break;
case LG_G510:
case LG_G510_USB_AUDIO:
- if (data[0] == 0x03 && size == 5)
+ if (data[0] == LG_G510_INPUT_MACRO_KEYS && size == 5)
return lg_g510_event(g15, data);
- if (data[0] == 0x04 && size == 2)
+ if (data[0] == LG_G510_INPUT_KBD_BACKLIGHT && size == 2)
return lg_g510_leds_event(g15, data);
break;
}
@@ -933,6 +960,8 @@ static void lg_g15_setup_led_rgb(struct lg_g15_data *g15, int index)
lg_g510_kbd_led_set;
gled->mcdev.led_cdev.brightness_get =
lg_g510_kbd_led_get;
+ if (index == LG_G15_KBD_BRIGHTNESS)
+ g15->leds[index].mcdev.led_cdev.flags = LED_BRIGHT_HW_CHANGED;
}
gled->mcdev.led_cdev.max_brightness = 255;
gled->mcdev.num_colors = 3;
--
2.51.0
^ permalink raw reply related
* [dtor-input:next] BUILD SUCCESS d655a684c24dde9e9f3f98f3dbae5a4f592117d4
From: kernel test robot @ 2025-10-01 19:18 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
branch HEAD: d655a684c24dde9e9f3f98f3dbae5a4f592117d4 Input: aw86927 - fix error code in probe()
elapsed time: 1274m
configs tested: 130
configs skipped: 4
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-15.1.0
alpha allyesconfig gcc-15.1.0
arc allmodconfig gcc-15.1.0
arc allnoconfig gcc-15.1.0
arc allyesconfig gcc-15.1.0
arc haps_hs_defconfig gcc-15.1.0
arc randconfig-001-20251001 gcc-8.5.0
arc randconfig-002-20251001 gcc-8.5.0
arm allmodconfig gcc-15.1.0
arm allnoconfig clang-22
arm allyesconfig gcc-15.1.0
arm orion5x_defconfig clang-22
arm randconfig-001-20251001 gcc-14.3.0
arm randconfig-002-20251001 clang-22
arm randconfig-003-20251001 gcc-12.5.0
arm randconfig-004-20251001 gcc-8.5.0
arm sama5_defconfig gcc-15.1.0
arm stm32_defconfig gcc-15.1.0
arm64 alldefconfig gcc-15.1.0
arm64 allmodconfig clang-19
arm64 allnoconfig gcc-15.1.0
arm64 randconfig-001-20251001 clang-22
arm64 randconfig-002-20251001 gcc-9.5.0
arm64 randconfig-003-20251001 gcc-8.5.0
arm64 randconfig-004-20251001 gcc-8.5.0
csky allnoconfig gcc-15.1.0
csky randconfig-001-20251001 gcc-13.4.0
csky randconfig-002-20251001 gcc-15.1.0
hexagon allmodconfig clang-17
hexagon allnoconfig clang-22
hexagon allyesconfig clang-22
hexagon randconfig-001-20251001 clang-22
hexagon randconfig-002-20251001 clang-22
i386 allmodconfig gcc-14
i386 allnoconfig gcc-14
i386 allyesconfig gcc-14
i386 buildonly-randconfig-001-20251001 clang-20
i386 buildonly-randconfig-002-20251001 clang-20
i386 buildonly-randconfig-003-20251001 gcc-14
i386 buildonly-randconfig-004-20251001 clang-20
i386 buildonly-randconfig-005-20251001 clang-20
i386 buildonly-randconfig-006-20251001 clang-20
i386 defconfig clang-20
loongarch allmodconfig clang-19
loongarch allnoconfig clang-22
loongarch randconfig-001-20251001 gcc-13.4.0
loongarch randconfig-002-20251001 gcc-15.1.0
m68k allmodconfig gcc-15.1.0
m68k allnoconfig gcc-15.1.0
m68k allyesconfig gcc-15.1.0
microblaze allmodconfig gcc-15.1.0
microblaze allnoconfig gcc-15.1.0
microblaze allyesconfig gcc-15.1.0
microblaze defconfig gcc-15.1.0
mips allnoconfig gcc-15.1.0
mips ip32_defconfig clang-22
mips omega2p_defconfig clang-22
nios2 allnoconfig gcc-11.5.0
nios2 defconfig gcc-11.5.0
nios2 randconfig-001-20251001 gcc-11.5.0
nios2 randconfig-002-20251001 gcc-11.5.0
openrisc allnoconfig gcc-15.1.0
openrisc allyesconfig gcc-15.1.0
openrisc defconfig gcc-15.1.0
parisc allmodconfig gcc-15.1.0
parisc allnoconfig gcc-15.1.0
parisc allyesconfig gcc-15.1.0
parisc defconfig gcc-15.1.0
parisc randconfig-001-20251001 gcc-8.5.0
parisc randconfig-002-20251001 gcc-8.5.0
parisc64 defconfig gcc-15.1.0
powerpc allmodconfig gcc-15.1.0
powerpc allnoconfig gcc-15.1.0
powerpc allyesconfig clang-22
powerpc randconfig-001-20251001 gcc-8.5.0
powerpc randconfig-002-20251001 clang-22
powerpc randconfig-003-20251001 clang-22
powerpc64 randconfig-001-20251001 gcc-8.5.0
powerpc64 randconfig-002-20251001 clang-22
powerpc64 randconfig-003-20251001 gcc-13.4.0
riscv allmodconfig clang-22
riscv allnoconfig gcc-15.1.0
riscv allyesconfig clang-16
riscv defconfig clang-22
riscv randconfig-001-20251001 clang-22
riscv randconfig-002-20251001 gcc-8.5.0
s390 allmodconfig clang-18
s390 allnoconfig clang-22
s390 allyesconfig gcc-15.1.0
s390 defconfig clang-22
s390 randconfig-001-20251001 clang-22
s390 randconfig-002-20251001 gcc-12.5.0
sh allmodconfig gcc-15.1.0
sh allnoconfig gcc-15.1.0
sh allyesconfig gcc-15.1.0
sh defconfig gcc-15.1.0
sh r7785rp_defconfig gcc-15.1.0
sh randconfig-001-20251001 gcc-13.4.0
sh randconfig-002-20251001 gcc-11.5.0
sh rts7751r2dplus_defconfig gcc-15.1.0
sparc allmodconfig gcc-15.1.0
sparc allnoconfig gcc-15.1.0
sparc defconfig gcc-15.1.0
sparc randconfig-001-20251001 gcc-15.1.0
sparc randconfig-002-20251001 gcc-8.5.0
sparc sparc64_defconfig gcc-15.1.0
sparc64 defconfig clang-20
sparc64 randconfig-001-20251001 gcc-8.5.0
sparc64 randconfig-002-20251001 clang-20
um allmodconfig clang-19
um allnoconfig clang-22
um allyesconfig gcc-14
um defconfig clang-22
um i386_defconfig gcc-14
um randconfig-001-20251001 gcc-14
um randconfig-002-20251001 gcc-14
um x86_64_defconfig clang-22
x86_64 allnoconfig clang-20
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20251001 clang-20
x86_64 buildonly-randconfig-002-20251001 clang-20
x86_64 buildonly-randconfig-003-20251001 clang-20
x86_64 buildonly-randconfig-004-20251001 clang-20
x86_64 buildonly-randconfig-005-20251001 clang-20
x86_64 buildonly-randconfig-006-20251001 clang-20
x86_64 defconfig gcc-14
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig gcc-15.1.0
xtensa randconfig-001-20251001 gcc-15.1.0
xtensa randconfig-002-20251001 gcc-10.5.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH v3] dt-bindings: input: Convert MELFAS MIP4 Touchscreen to DT schema
From: Ariel D'Alessandro @ 2025-10-01 18:38 UTC (permalink / raw)
To: angelogioacchino.delregno, ariel.dalessandro, conor+dt,
dmitry.torokhov, krzk+dt, robh
Cc: devicetree, kernel, linux-input, linux-kernel
Convert the existing text-based DT bindings for MELFAS MIP4 Touchscreen
controller to a DT schema.
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../input/touchscreen/melfas,mip4_ts.yaml | 56 +++++++++++++++++++
.../input/touchscreen/melfas_mip4.txt | 20 -------
2 files changed, 56 insertions(+), 20 deletions(-)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml
delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
diff --git a/Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml b/Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml
new file mode 100644
index 0000000000000..314be65c56caa
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/touchscreen/melfas,mip4_ts.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MELFAS MIP4 Touchscreen
+
+maintainers:
+ - Ariel D'Alessandro <ariel.dalessandro@collabora.com>
+
+properties:
+ compatible:
+ const: melfas,mip4_ts
+
+ reg:
+ description: I2C address of the chip (0x48 or 0x34)
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ ce-gpios:
+ description:
+ GPIO connected to the CE (chip enable) pin of the chip (active high)
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ touchscreen@34 {
+ compatible = "melfas,mip4_ts";
+ reg = <0x34>;
+
+ interrupts-extended = <&tlmm 13 IRQ_TYPE_EDGE_FALLING>;
+ ce-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
+
+ pinctrl-0 = <&touchscreen_default>;
+ pinctrl-names = "default";
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt b/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
deleted file mode 100644
index b2ab5498e5190..0000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-* MELFAS MIP4 Touchscreen
-
-Required properties:
-- compatible: must be "melfas,mip4_ts"
-- reg: I2C slave address of the chip (0x48 or 0x34)
-- interrupts: interrupt to which the chip is connected
-
-Optional properties:
-- ce-gpios: GPIO connected to the CE (chip enable) pin of the chip
-
-Example:
- i2c@00000000 {
- touchscreen: melfas_mip4@48 {
- compatible = "melfas,mip4_ts";
- reg = <0x48>;
- interrupt-parent = <&gpio>;
- interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
- ce-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
- };
- };
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v2 09/12] dt-bindings: regulator: Convert Dialog DA9211 Regulators to DT schema
From: Ariel D'Alessandro @ 2025-10-01 17:43 UTC (permalink / raw)
To: AngeloGioacchino Del Regno, airlied, amergnat, andrew+netdev,
andrew-ct.chen, broonie, chunkuang.hu, conor+dt, davem,
dmitry.torokhov, edumazet, flora.fu, heiko, houlong.wei, jeesw,
kernel, krzk+dt, kuba, lgirdwood, linus.walleij,
louisalexis.eyraud, luiz.dentz, maarten.lankhorst, marcel,
matthias.bgg, mchehab, minghsiu.tsai, mripard, p.zabel, pabeni,
robh, sean.wang, simona, support.opensource, tiffany.lin,
tzimmermann, yunfei.dong
Cc: devicetree, dri-devel, linux-arm-kernel, linux-bluetooth,
linux-gpio, linux-input, linux-kernel, linux-media,
linux-mediatek, linux-rockchip, linux-sound, netdev
In-Reply-To: <990cc068-adc9-473a-b4c7-9113583cb83c@collabora.com>
Angelo,
On 9/12/25 5:11 AM, AngeloGioacchino Del Regno wrote:
> Il 11/09/25 17:09, Ariel D'Alessandro ha scritto:
>> Convert the existing text-based DT bindings for Dialog Semiconductor
>> DA9211
>> Voltage Regulators family to a DT schema. Examples are simplified, as
>> these
>> are all equal.
>>
>> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
>> ---
>> .../devicetree/bindings/regulator/da9211.txt | 205 ------------------
>> .../bindings/regulator/dlg,da9211.yaml | 104 +++++++++
>> 2 files changed, 104 insertions(+), 205 deletions(-)
>> delete mode 100644 Documentation/devicetree/bindings/regulator/
>> da9211.txt
>> create mode 100644 Documentation/devicetree/bindings/regulator/
>> dlg,da9211.yaml
>>
>
> ..snip..
>
>> diff --git a/Documentation/devicetree/bindings/regulator/
>> dlg,da9211.yaml b/Documentation/devicetree/bindings/regulator/
>> dlg,da9211.yaml
>> new file mode 100644
>> index 0000000000000..9d5e25bc3872c
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/regulator/dlg,da9211.yaml
>> @@ -0,0 +1,104 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/regulator/dlg,da9211.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title:
>> + Dialog Semiconductor DA9211/DA9212/DA9213/DA9223/DA9214/DA9224/
>> DA9215/DA9225
>> + Voltage Regulator
>
> Dialog Semiconductor DA9211-9215, DA9223-9225 Voltage Regulators
>
> Better? :-)
Much better, thanks! Will fix in v3.
>
>> +
>> +maintainers:
>> + - Ariel D'Alessandro <ariel.dalessandro@collabora.com>
>> +
>> +properties:
>> + compatible:
>> + enum:
>> + - dlg,da9211
>> + - dlg,da9212
>> + - dlg,da9213
>> + - dlg,da9214
>> + - dlg,da9215
>> + - dlg,da9223
>> + - dlg,da9224
>> + - dlg,da9225
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + interrupts:
>> + maxItems: 1
>> +
>> + regulators:
>> + type: object
>> + additionalProperties: false
>> + description:
>> + List of regulators provided by the device
>> +
>> + patternProperties:
>> + "^BUCK([AB])$":
>> + type: object
>> + $ref: regulator.yaml#
>> + unevaluatedProperties: false
>> + description: |
>
> Please drop the vertical bar | from all descriptions
Ack. Fixed in v3.
>
> after which,
>
> Reviewed-by: AngeloGioacchino Del Regno
> <angelogioacchino.delregno@collabora.com>
Thanks a lot!
Regards,
--
Ariel D'Alessandro
Software Engineer
Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK
Registered in England & Wales, no. 5513718
^ permalink raw reply
* Re: [PATCH v2 03/12] dt-bindings: net: Convert Marvell 8897/8997 bindings to DT schema
From: Ariel D'Alessandro @ 2025-10-01 17:27 UTC (permalink / raw)
To: Rob Herring
Cc: airlied, amergnat, andrew+netdev, andrew-ct.chen,
angelogioacchino.delregno, broonie, chunkuang.hu, conor+dt, davem,
dmitry.torokhov, edumazet, flora.fu, heiko, houlong.wei, jeesw,
kernel, krzk+dt, kuba, lgirdwood, linus.walleij,
louisalexis.eyraud, luiz.dentz, maarten.lankhorst, marcel,
matthias.bgg, mchehab, minghsiu.tsai, mripard, p.zabel, pabeni,
sean.wang, simona, support.opensource, tiffany.lin, tzimmermann,
yunfei.dong, devicetree, dri-devel, linux-arm-kernel,
linux-bluetooth, linux-gpio, linux-input, linux-kernel,
linux-media, linux-mediatek, linux-rockchip, linux-sound, netdev
In-Reply-To: <20250912140619.GA1293647-robh@kernel.org>
Rob,
On 9/12/25 11:06 AM, Rob Herring wrote:
> On Thu, Sep 11, 2025 at 12:09:52PM -0300, Ariel D'Alessandro wrote:
>> Convert the existing text-based DT bindings for Marvell 8897/8997
>> (sd8897/sd8997) bluetooth devices controller to a DT schema.
>>
>> While here:
>>
>> * bindings for "usb1286,204e" (USB interface) are dropped from the DT
>> schema definition as these are currently documented in file [0].
>> * DT binding users are updated to use bluetooth generic name
>> recommendation.
>>
>> [0] Documentation/devicetree/bindings/net/btusb.txt
>>
>> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
>> ---
>> .../net/bluetooth/marvell,sd8897-bt.yaml | 79 ++++++++++++++++++
>> .../devicetree/bindings/net/btusb.txt | 2 +-
>> .../bindings/net/marvell-bt-8xxx.txt | 83 -------------------
>
>> .../dts/rockchip/rk3288-veyron-fievel.dts | 2 +-
>> .../boot/dts/rockchip/rk3288-veyron-jaq.dts | 2 +-
>> arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi | 2 +-
>
> .dts files should be separate patches. Please send the bindings patches
> separately per subsystem so subsystem maintainers can apply them. All
> the Mediatek dts changes can be 1 series.
Ack, will fix in v3.
>
> The schema looks good.
Great, thanks!
--
Ariel D'Alessandro
Software Engineer
Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK
Registered in England & Wales, no. 5513718
^ permalink raw reply
* Re: [PATCH v2 00/12] MediaTek dt-bindings sanitization (MT8173)
From: Ariel D'Alessandro @ 2025-10-01 17:17 UTC (permalink / raw)
To: Rob Herring
Cc: airlied, amergnat, andrew+netdev, andrew-ct.chen,
angelogioacchino.delregno, broonie, chunkuang.hu, conor+dt, davem,
dmitry.torokhov, edumazet, flora.fu, heiko, houlong.wei, jeesw,
kernel, krzk+dt, kuba, lgirdwood, linus.walleij,
louisalexis.eyraud, luiz.dentz, maarten.lankhorst, marcel,
matthias.bgg, mchehab, minghsiu.tsai, mripard, p.zabel, pabeni,
sean.wang, simona, support.opensource, tiffany.lin, tzimmermann,
yunfei.dong, devicetree, dri-devel, linux-arm-kernel,
linux-bluetooth, linux-gpio, linux-input, linux-kernel,
linux-media, linux-mediatek, linux-rockchip, linux-sound, netdev
In-Reply-To: <20250923214834.GC91441-robh@kernel.org>
Rob,
On 9/23/25 6:48 PM, Rob Herring wrote:
> On Thu, Sep 11, 2025 at 12:09:49PM -0300, Ariel D'Alessandro wrote:
>> This patch series continues the effort to address Device Tree validation
>> warnings for MediaTek platforms, with a focus on MT8173. It follows the
>> initial cleanup series by Angelo [0].
>>
>> Similarly to the ongoing MT8183 work done by Julien Massot, this patchset
>> eliminates several of the remaining warnings by improving or converting DT
>> bindings to YAML, adding missing properties, and updating device tree files
>> accordingly.
>>
>> [0] https://www.spinics.net/lists/kernel/msg5780177.html
>>
>> Changes in v2:
>> * Wrapped commit messages to 75 columns line wrap.
>> * Replaced "YAML" by "DT schema" in patches subject and content.
>> * mt8173-mdp: Fixed properties: compatible, clocks, iommus and
>> mediatek,vpu.
>> * mt8173-vpu: Fixed line wrap. Dropped memory-region property description.
>> * mediatek,mmsys: Dropped patch as it's not a binding issue.
>> * mediatek,od: Rewrote commit log with details on DT schema users missing
>> the related property. Rewrote mediatek,gce-client-reg property.
>> * mediatek,ufoe: Rewrote commit log with details on DT schema users missing
>> the related property. Rewrote mediatek,gce-client-reg property.
>> * marvell,sd8897-bt: Moved to net/bluetooth/. Added missing ref to
>> bluetooth-controller.yaml. Dropped example. Updated reference in another
>> file. Minor fixes in properties.
>> * mediatek,mt8173-rt5650: Dropped unnecessary quotes and unused label.
>> * dlg,da9211: Dropped enable-gpios description. Rewrote generic example
>> node names. Minor fixes in properties.
>> * melfas,mip4_ts: Dropped unnecessary quotes. Added "active high" to
>> ce-gpios property description.
>> * mediatek,jpeg: Dropped patch as it doesn't apply.
>>
>> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
>>
>> Ariel D'Alessandro (12):
>> dt-bindings: media: Convert MediaTek mt8173-mdp bindings to DT schema
>> dt-bindings: media: Convert MediaTek mt8173-vpu bindings to DT schema
>> dt-bindings: net: Convert Marvell 8897/8997 bindings to DT schema
>> dt-bindings: ASoC: Convert MediaTek RT5650 codecs bindings to DT
>> schema
>> dt-bindings: display: mediatek,od: Add mediatek,gce-client-reg
>> property
>> dt-bindings: display: mediatek,ufoe: Add mediatek,gce-client-reg
>> property
>> arm64: dts: mediatek: mt8173: Fix mt8173-pinctrl node names
>> dt-bindings: pinctrl: mt65xx: Allow gpio-line-names
>> dt-bindings: regulator: Convert Dialog DA9211 Regulators to DT schema
>> arm64: dts: mediatek: mt8173-elm: Drop unused bank supply
>> dt-bindings: soc: mediatek: pwrap: Add power-domains property
>> dt-bindings: input: Convert MELFAS MIP4 Touchscreen to DT schema
>
> As we're close to the merge window, I applied patches 2, 8, and 11.
Great, I can see that patches 5 and 6 were also applied (with small
modifications).
Thanks!
--
Ariel D'Alessandro
Software Engineer
Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK
Registered in England & Wales, no. 5513718
^ permalink raw reply
* [PATCH v12 5/6] power: supply: pf1550: add battery charger support
From: Samuel Kayode via B4 Relay @ 2025-10-01 15:42 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Sebastian Reichel, Frank Li
In-Reply-To: <20251001-pf1550-v12-0-a3302aa41687@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add support for the battery charger for pf1550 PMIC.
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v11:
- Seperate the battery properties from the charger properties
v9:
- Fix thermal regulation temperature ranges
- Fix default thermal regulation temperature
- Drop unused `data` variable in reg_init
- Select charger operation mode based on application - suggested by Sean
v8:
- Drop PF1550_CHARGER_NAME
- Drop unnecessary POWER_SUPPLY_STATUS_CHARGING s
- Replace POWER_SUPPLY_HEALTH_DEAD with POWER_SUPPLY_HEALTH_NO_BATTERY
- Drop check for charger in delayed_work s
- Use dev_warn when battery is over-voltage
- Define two power supplies: charger and battery
- Use devm_delayed_work_autocancel to automate cleanup and fix race
condition
v7:
- Use reverse christmas tree order
- Drop unecessary 0 in id table's driver data field
- Store virqs to avoid reinvoking platform_get_irq in the interrupt
service routine
- Drop manufacturer and model global variables
v6:
- Drop lock entirely
- Reverse christmas tree order for variables defined in probe as
suggested by Frank
- return pf1550_reg_init
v5:
- Drop lock for battery and charger delayed_work
- More conservative locking in vbus delayed_work
- Apply lock when setting power supply type during register initialization
v4:
- Finish handling of some interrupts in threaded irq handler
- Use platform_get_irq
v3:
- Use struct power_supply_get_battery_info to get constant charge
voltage if specified
- Use virqs mapped in MFD driver
v2:
- Address feedback from Enric Balletbo Serra
---
drivers/power/supply/Kconfig | 11 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/pf1550-charger.c | 641 ++++++++++++++++++++++++++++++++++
3 files changed, 653 insertions(+)
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 79ddb006e2dad6bf96b71ed570a37c006b5f9433..6d0c872edac1f45da314632e671af1aeda4c87b8 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -471,6 +471,17 @@ config CHARGER_88PM860X
help
Say Y here to enable charger for Marvell 88PM860x chip.
+config CHARGER_PF1550
+ tristate "NXP PF1550 battery charger driver"
+ depends on MFD_PF1550
+ help
+ Say Y to enable support for the NXP PF1550 battery charger.
+ The device is a single cell Li-Ion/Li-Polymer battery charger for
+ portable application.
+
+ This driver can also be built as a module. If so, the module will be
+ called pf1550-charger.
+
config BATTERY_RX51
tristate "Nokia RX-51 (N900) battery driver"
depends on TWL4030_MADC
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index f943c9150b326d41ff241f82610f70298635eb08..5a177f4884deb79f059cfbfa95466932630a48de 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_CHARGER_RT9467) += rt9467-charger.o
obj-$(CONFIG_CHARGER_RT9471) += rt9471.o
obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
+obj-$(CONFIG_CHARGER_PF1550) += pf1550-charger.o
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o ab8500_chargalg.o
obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o
diff --git a/drivers/power/supply/pf1550-charger.c b/drivers/power/supply/pf1550-charger.c
new file mode 100644
index 0000000000000000000000000000000000000000..98f1ee8eca3bc8dff2c3a697d157b9e3da204fe2
--- /dev/null
+++ b/drivers/power/supply/pf1550-charger.c
@@ -0,0 +1,641 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * charger driver for the PF1550
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+ * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+ */
+
+#include <linux/devm-helpers.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#define PF1550_DEFAULT_CONSTANT_VOLT 4200000
+#define PF1550_DEFAULT_MIN_SYSTEM_VOLT 3500000
+#define PF1550_DEFAULT_THERMAL_TEMP 95
+#define PF1550_CHARGER_IRQ_NR 5
+
+struct pf1550_charger {
+ struct device *dev;
+ const struct pf1550_ddata *pf1550;
+ struct power_supply *charger;
+ struct power_supply *battery;
+ struct delayed_work vbus_sense_work;
+ struct delayed_work chg_sense_work;
+ struct delayed_work bat_sense_work;
+ int virqs[PF1550_CHARGER_IRQ_NR];
+
+ u32 constant_volt;
+ u32 min_system_volt;
+ u32 thermal_regulation_temp;
+};
+
+static int pf1550_get_charger_state(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_CHG_SNS_MASK;
+
+ switch (data) {
+ case PF1550_CHG_PRECHARGE:
+ case PF1550_CHG_CONSTANT_CURRENT:
+ case PF1550_CHG_CONSTANT_VOL:
+ case PF1550_CHG_EOC:
+ *val = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case PF1550_CHG_DONE:
+ *val = POWER_SUPPLY_STATUS_FULL;
+ break;
+ case PF1550_CHG_TIMER_FAULT:
+ case PF1550_CHG_SUSPEND:
+ *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case PF1550_CHG_OFF_INV:
+ case PF1550_CHG_OFF_TEMP:
+ case PF1550_CHG_LINEAR_ONLY:
+ *val = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ default:
+ *val = POWER_SUPPLY_STATUS_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static int pf1550_get_charge_type(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_CHG_SNS_MASK;
+
+ switch (data) {
+ case PF1550_CHG_SNS_MASK:
+ *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ case PF1550_CHG_CONSTANT_CURRENT:
+ case PF1550_CHG_CONSTANT_VOL:
+ case PF1550_CHG_EOC:
+ *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ case PF1550_CHG_DONE:
+ case PF1550_CHG_TIMER_FAULT:
+ case PF1550_CHG_SUSPEND:
+ case PF1550_CHG_OFF_INV:
+ case PF1550_CHG_BAT_OVER:
+ case PF1550_CHG_OFF_TEMP:
+ case PF1550_CHG_LINEAR_ONLY:
+ *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ default:
+ *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ }
+
+ return 0;
+}
+
+/*
+ * Supported health statuses:
+ * - POWER_SUPPLY_HEALTH_DEAD
+ * - POWER_SUPPLY_HEALTH_GOOD
+ * - POWER_SUPPLY_HEALTH_OVERVOLTAGE
+ * - POWER_SUPPLY_HEALTH_UNKNOWN
+ */
+static int pf1550_get_battery_health(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_BAT_SNS_MASK;
+
+ switch (data) {
+ case PF1550_BAT_NO_DETECT:
+ *val = POWER_SUPPLY_HEALTH_NO_BATTERY;
+ break;
+ case PF1550_BAT_NO_VBUS:
+ case PF1550_BAT_LOW_THAN_PRECHARG:
+ case PF1550_BAT_CHARG_FAIL:
+ case PF1550_BAT_HIGH_THAN_PRECHARG:
+ *val = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case PF1550_BAT_OVER_VOL:
+ *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ break;
+ default:
+ *val = POWER_SUPPLY_HEALTH_UNKNOWN;
+ break;
+ }
+
+ return 0;
+}
+
+static int pf1550_get_present(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_BAT_SNS_MASK;
+ *val = (data == PF1550_BAT_NO_DETECT) ? 0 : 1;
+
+ return 0;
+}
+
+static int pf1550_get_online(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_VBUS_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ *val = (data & PF1550_VBUS_VALID) ? 1 : 0;
+
+ return 0;
+}
+
+static void pf1550_chg_bat_work(struct work_struct *work)
+{
+ struct pf1550_charger *chg = container_of(to_delayed_work(work),
+ struct pf1550_charger,
+ bat_sense_work);
+ unsigned int data;
+
+ if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_BATT_SNS, &data)) {
+ dev_err(chg->dev, "Read BATT_SNS error.\n");
+ return;
+ }
+
+ switch (data & PF1550_BAT_SNS_MASK) {
+ case PF1550_BAT_NO_VBUS:
+ dev_dbg(chg->dev, "No valid VBUS input.\n");
+ break;
+ case PF1550_BAT_LOW_THAN_PRECHARG:
+ dev_dbg(chg->dev, "VBAT < VPRECHG.LB.\n");
+ break;
+ case PF1550_BAT_CHARG_FAIL:
+ dev_dbg(chg->dev, "Battery charging failed.\n");
+ break;
+ case PF1550_BAT_HIGH_THAN_PRECHARG:
+ dev_dbg(chg->dev, "VBAT > VPRECHG.LB.\n");
+ break;
+ case PF1550_BAT_OVER_VOL:
+ dev_dbg(chg->dev, "VBAT > VBATOV.\n");
+ break;
+ case PF1550_BAT_NO_DETECT:
+ dev_dbg(chg->dev, "Battery not detected.\n");
+ break;
+ default:
+ dev_err(chg->dev, "Unknown value read:%x\n",
+ data & PF1550_CHG_SNS_MASK);
+ }
+}
+
+static void pf1550_chg_chg_work(struct work_struct *work)
+{
+ struct pf1550_charger *chg = container_of(to_delayed_work(work),
+ struct pf1550_charger,
+ chg_sense_work);
+ unsigned int data;
+
+ if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_SNS, &data)) {
+ dev_err(chg->dev, "Read CHG_SNS error.\n");
+ return;
+ }
+
+ switch (data & PF1550_CHG_SNS_MASK) {
+ case PF1550_CHG_PRECHARGE:
+ dev_dbg(chg->dev, "In pre-charger mode.\n");
+ break;
+ case PF1550_CHG_CONSTANT_CURRENT:
+ dev_dbg(chg->dev, "In fast-charge constant current mode.\n");
+ break;
+ case PF1550_CHG_CONSTANT_VOL:
+ dev_dbg(chg->dev, "In fast-charge constant voltage mode.\n");
+ break;
+ case PF1550_CHG_EOC:
+ dev_dbg(chg->dev, "In EOC mode.\n");
+ break;
+ case PF1550_CHG_DONE:
+ dev_dbg(chg->dev, "In DONE mode.\n");
+ break;
+ case PF1550_CHG_TIMER_FAULT:
+ dev_info(chg->dev, "In timer fault mode.\n");
+ break;
+ case PF1550_CHG_SUSPEND:
+ dev_info(chg->dev, "In thermistor suspend mode.\n");
+ break;
+ case PF1550_CHG_OFF_INV:
+ dev_info(chg->dev, "Input invalid, charger off.\n");
+ break;
+ case PF1550_CHG_BAT_OVER:
+ dev_warn(chg->dev, "Battery over-voltage.\n");
+ break;
+ case PF1550_CHG_OFF_TEMP:
+ dev_info(chg->dev, "Temp high, charger off.\n");
+ break;
+ case PF1550_CHG_LINEAR_ONLY:
+ dev_dbg(chg->dev, "In Linear mode, not charging.\n");
+ break;
+ default:
+ dev_err(chg->dev, "Unknown value read:%x\n",
+ data & PF1550_CHG_SNS_MASK);
+ }
+}
+
+static void pf1550_chg_vbus_work(struct work_struct *work)
+{
+ struct pf1550_charger *chg = container_of(to_delayed_work(work),
+ struct pf1550_charger,
+ vbus_sense_work);
+ unsigned int data;
+
+ if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_VBUS_SNS, &data)) {
+ dev_err(chg->dev, "Read VBUS_SNS error.\n");
+ return;
+ }
+
+ if (data & PF1550_VBUS_UVLO) {
+ dev_dbg(chg->dev, "VBUS detached.\n");
+ power_supply_changed(chg->battery);
+ }
+ if (data & PF1550_VBUS_IN2SYS)
+ dev_dbg(chg->dev, "VBUS_IN2SYS_SNS.\n");
+ if (data & PF1550_VBUS_OVLO)
+ dev_dbg(chg->dev, "VBUS_OVLO_SNS.\n");
+ if (data & PF1550_VBUS_VALID) {
+ dev_dbg(chg->dev, "VBUS attached.\n");
+ power_supply_changed(chg->charger);
+ }
+}
+
+static irqreturn_t pf1550_charger_irq_handler(int irq, void *data)
+{
+ struct pf1550_charger *chg = data;
+ struct device *dev = chg->dev;
+ int i, irq_type = -1;
+
+ for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++)
+ if (irq == chg->virqs[i])
+ irq_type = i;
+
+ switch (irq_type) {
+ case PF1550_CHARG_IRQ_BAT2SOCI:
+ dev_info(dev, "BAT to SYS Overcurrent interrupt.\n");
+ break;
+ case PF1550_CHARG_IRQ_BATI:
+ schedule_delayed_work(&chg->bat_sense_work,
+ msecs_to_jiffies(10));
+ break;
+ case PF1550_CHARG_IRQ_CHGI:
+ schedule_delayed_work(&chg->chg_sense_work,
+ msecs_to_jiffies(10));
+ break;
+ case PF1550_CHARG_IRQ_VBUSI:
+ schedule_delayed_work(&chg->vbus_sense_work,
+ msecs_to_jiffies(10));
+ break;
+ case PF1550_CHARG_IRQ_THMI:
+ dev_info(dev, "Thermal interrupt.\n");
+ break;
+ default:
+ dev_err(dev, "unknown interrupt occurred.\n");
+ }
+
+ return IRQ_HANDLED;
+}
+
+static enum power_supply_property pf1550_charger_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static enum power_supply_property pf1550_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static int pf1550_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pf1550_charger *chg = power_supply_get_drvdata(psy);
+ struct regmap *regmap = chg->pf1550->regmap;
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = pf1550_get_charger_state(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ ret = pf1550_get_charge_type(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = pf1550_get_battery_health(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ ret = pf1550_get_present(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = pf1550_get_online(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = "PF1550";
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = "NXP";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct power_supply_desc pf1550_charger_desc = {
+ .name = "pf1550-charger",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .properties = pf1550_charger_props,
+ .num_properties = ARRAY_SIZE(pf1550_charger_props),
+ .get_property = pf1550_charger_get_property,
+};
+
+static const struct power_supply_desc pf1550_battery_desc = {
+ .name = "pf1550-battery",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = pf1550_battery_props,
+ .num_properties = ARRAY_SIZE(pf1550_battery_props),
+ .get_property = pf1550_charger_get_property,
+};
+
+static int pf1550_set_constant_volt(struct pf1550_charger *chg,
+ unsigned int uvolt)
+{
+ unsigned int data;
+
+ if (uvolt >= 3500000 && uvolt <= 4440000)
+ data = 8 + (uvolt - 3500000) / 20000;
+ else
+ return dev_err_probe(chg->dev, -EINVAL,
+ "Wrong value for constant voltage\n");
+
+ dev_dbg(chg->dev, "Charging constant voltage: %u (0x%x)\n", uvolt,
+ data);
+
+ return regmap_update_bits(chg->pf1550->regmap,
+ PF1550_CHARG_REG_BATT_REG,
+ PF1550_CHARG_REG_BATT_REG_CHGCV_MASK, data);
+}
+
+static int pf1550_set_min_system_volt(struct pf1550_charger *chg,
+ unsigned int uvolt)
+{
+ unsigned int data;
+
+ switch (uvolt) {
+ case 3500000:
+ data = 0x0;
+ break;
+ case 3700000:
+ data = 0x1;
+ break;
+ case 4300000:
+ data = 0x2;
+ break;
+ default:
+ return dev_err_probe(chg->dev, -EINVAL,
+ "Wrong value for minimum system voltage\n");
+ }
+
+ data <<= PF1550_CHARG_REG_BATT_REG_VMINSYS_SHIFT;
+
+ dev_dbg(chg->dev, "Minimum system regulation voltage: %u (0x%x)\n",
+ uvolt, data);
+
+ return regmap_update_bits(chg->pf1550->regmap,
+ PF1550_CHARG_REG_BATT_REG,
+ PF1550_CHARG_REG_BATT_REG_VMINSYS_MASK, data);
+}
+
+static int pf1550_set_thermal_regulation_temp(struct pf1550_charger *chg,
+ unsigned int cells)
+{
+ unsigned int data;
+
+ switch (cells) {
+ case 80:
+ data = 0x0;
+ break;
+ case 95:
+ data = 0x1;
+ break;
+ case 110:
+ data = 0x2;
+ break;
+ case 125:
+ data = 0x3;
+ break;
+ default:
+ return dev_err_probe(chg->dev, -EINVAL,
+ "Wrong value for thermal temperature\n");
+ }
+
+ data <<= PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_SHIFT;
+
+ dev_dbg(chg->dev, "Thermal regulation loop temperature: %u (0x%x)\n",
+ cells, data);
+
+ return regmap_update_bits(chg->pf1550->regmap,
+ PF1550_CHARG_REG_THM_REG_CNFG,
+ PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_MASK,
+ data);
+}
+
+/*
+ * Sets charger registers to proper and safe default values.
+ */
+static int pf1550_reg_init(struct pf1550_charger *chg)
+{
+ struct power_supply_battery_info *info;
+ struct device *dev = chg->dev;
+ int ret;
+
+ /* Unmask charger interrupt, mask DPMI and reserved bit */
+ ret = regmap_write(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_INT_MASK,
+ PF1550_CHG_INT_MASK);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Error unmask charger interrupt\n");
+
+ ret = pf1550_set_constant_volt(chg, chg->constant_volt);
+ if (ret)
+ return ret;
+
+ ret = pf1550_set_min_system_volt(chg, chg->min_system_volt);
+ if (ret)
+ return ret;
+
+ ret = pf1550_set_thermal_regulation_temp(chg,
+ chg->thermal_regulation_temp);
+ if (ret)
+ return ret;
+
+ /*
+ * The PF1550 charger has 3 modes of operation. By default, the charger
+ * is in mode 1; it remains off. Appropriate for applications not using
+ * a battery. The other supported mode is mode 2, the charger is turned
+ * on to charge a battery when present.
+ */
+ if (power_supply_get_battery_info(chg->charger, &info)) {
+ ret = regmap_write(chg->pf1550->regmap,
+ PF1550_CHARG_REG_CHG_OPER,
+ PF1550_CHG_BAT_ON);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Error turn on charger\n");
+ }
+
+ return 0;
+}
+
+static void pf1550_dt_parse_dev_info(struct pf1550_charger *chg)
+{
+ struct power_supply_battery_info *info;
+ struct device *dev = chg->dev;
+
+ if (device_property_read_u32(dev->parent, "nxp,min-system-microvolt",
+ &chg->min_system_volt))
+ chg->min_system_volt = PF1550_DEFAULT_MIN_SYSTEM_VOLT;
+
+ if (device_property_read_u32(dev->parent,
+ "nxp,thermal-regulation-celsius",
+ &chg->thermal_regulation_temp))
+ chg->thermal_regulation_temp = PF1550_DEFAULT_THERMAL_TEMP;
+
+ if (power_supply_get_battery_info(chg->charger, &info))
+ chg->constant_volt = PF1550_DEFAULT_CONSTANT_VOLT;
+ else
+ chg->constant_volt = info->constant_charge_voltage_max_uv;
+}
+
+static int pf1550_charger_probe(struct platform_device *pdev)
+{
+ const struct pf1550_ddata *pf1550 = dev_get_drvdata(pdev->dev.parent);
+ struct power_supply_config psy_cfg = {};
+ struct pf1550_charger *chg;
+ int i, irq, ret;
+
+ chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
+ if (!chg)
+ return -ENOMEM;
+
+ chg->dev = &pdev->dev;
+ chg->pf1550 = pf1550;
+
+ if (!chg->pf1550->regmap)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "failed to get regmap\n");
+
+ platform_set_drvdata(pdev, chg);
+
+ ret = devm_delayed_work_autocancel(chg->dev, &chg->vbus_sense_work,
+ pf1550_chg_vbus_work);
+ if (ret)
+ return dev_err_probe(chg->dev, ret,
+ "failed to add vbus sense work\n");
+
+ ret = devm_delayed_work_autocancel(chg->dev, &chg->chg_sense_work,
+ pf1550_chg_chg_work);
+ if (ret)
+ return dev_err_probe(chg->dev, ret,
+ "failed to add charger sense work\n");
+
+ ret = devm_delayed_work_autocancel(chg->dev, &chg->bat_sense_work,
+ pf1550_chg_bat_work);
+ if (ret)
+ return dev_err_probe(chg->dev, ret,
+ "failed to add battery sense work\n");
+
+ for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ chg->virqs[i] = irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ pf1550_charger_irq_handler,
+ IRQF_NO_SUSPEND,
+ "pf1550-charger", chg);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed irq request\n");
+ }
+
+ psy_cfg.drv_data = chg;
+
+ chg->charger = devm_power_supply_register(&pdev->dev,
+ &pf1550_charger_desc,
+ &psy_cfg);
+ if (IS_ERR(chg->charger))
+ return dev_err_probe(&pdev->dev, PTR_ERR(chg->charger),
+ "failed: power supply register\n");
+
+ chg->battery = devm_power_supply_register(&pdev->dev,
+ &pf1550_battery_desc,
+ &psy_cfg);
+ if (IS_ERR(chg->battery))
+ return dev_err_probe(&pdev->dev, PTR_ERR(chg->battery),
+ "failed: power supply register\n");
+
+ pf1550_dt_parse_dev_info(chg);
+
+ return pf1550_reg_init(chg);
+}
+
+static const struct platform_device_id pf1550_charger_id[] = {
+ { "pf1550-charger", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, pf1550_charger_id);
+
+static struct platform_driver pf1550_charger_driver = {
+ .driver = {
+ .name = "pf1550-charger",
+ },
+ .probe = pf1550_charger_probe,
+ .id_table = pf1550_charger_id,
+};
+module_platform_driver(pf1550_charger_driver);
+
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_DESCRIPTION("PF1550 charger driver");
+MODULE_LICENSE("GPL");
--
2.50.1
^ permalink raw reply related
* [PATCH v12 6/6] MAINTAINERS: add an entry for pf1550 mfd driver
From: Samuel Kayode via B4 Relay @ 2025-10-01 15:42 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Frank Li, Krzysztof Kozlowski
In-Reply-To: <20251001-pf1550-v12-0-a3302aa41687@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add MAINTAINERS entry for pf1550 PMIC.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v9:
- Pick up Frank's `Reviewed-by` tag
v6:
- Add imx mailing list
---
MAINTAINERS | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 97d958c945e4ffa3031590823f7a2867f577ebf3..5cc042b7ffe31a79bbbcbfd1fec7831b3546054d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18293,6 +18293,17 @@ F: Documentation/devicetree/bindings/clock/*imx*
F: drivers/clk/imx/
F: include/dt-bindings/clock/*imx*
+NXP PF1550 PMIC MFD DRIVER
+M: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+L: imx@lists.linux.dev
+S: Maintained
+F: Documentation/devicetree/bindings/mfd/nxp,pf1550.yaml
+F: drivers/input/misc/pf1550-onkey.c
+F: drivers/mfd/pf1550.c
+F: drivers/power/supply/pf1550-charger.c
+F: drivers/regulator/pf1550-regulator.c
+F: include/linux/mfd/pfd1550.h
+
NXP PF8100/PF8121A/PF8200 PMIC REGULATOR DEVICE DRIVER
M: Jagan Teki <jagan@amarulasolutions.com>
S: Maintained
--
2.50.1
^ permalink raw reply related
* [PATCH v12 3/6] regulator: pf1550: add support for regulator
From: Samuel Kayode via B4 Relay @ 2025-10-01 15:42 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Frank Li
In-Reply-To: <20251001-pf1550-v12-0-a3302aa41687@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add regulator support for the pf1550 PMIC.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v10:
- Change dvsX_enb to dvsX_enable
v9:
- Requested by Sean:
- Add support for SW1 DVS enable/disable
- Add support for standby voltages
- Add map_voltage for all configurable regulators
- Add regulator enable/disable for all regulators
- Fix for DVS activation when meant to be disabled
v7:
- Use reverese christmas tree style
- Drop unecessary 0 in id table's driver data
v6:
- Use dvs_enb variable in pf1550_dev as suggested by Frank Li
v5:
- Address Mark's feedback:
- Add comments to clarify difference in interrupts
- Issue warn event for _LS(low side) interrupt
- Validate maximum ramp_delay
v4:
- Address Mark's feedback:
- Use C++ comments for SPDX license
- Add portions copyright to reflect my update
- Validate ramp_delay
- Report overcurrent and temperature events
- Use platform_get_irq
v3:
- Drop duplicate include
- Drop unnecessary includes
- Accept lower case regulator names from devicetree
- Use virqs mapped in core MFD driver
v2:
- Add driver for regulator
---
drivers/regulator/Kconfig | 9 +
drivers/regulator/Makefile | 1 +
drivers/regulator/pf1550-regulator.c | 429 +++++++++++++++++++++++++++++++++++
3 files changed, 439 insertions(+)
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index eaa6df1c9f806652a21942bcb48084ba63f942d9..b7dd374134382c30b282eaf71c9045aa31179291 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1049,6 +1049,15 @@ config REGULATOR_PV88090
Say y here to support the voltage regulators and convertors
on PV88090
+config REGULATOR_PF1550
+ tristate "NXP PF1550 regulator"
+ depends on MFD_PF1550
+ help
+ Say y here to select this option to enable the regulators on
+ the PF1550 PMICs.
+ This driver controls the PF1550 regulators via I2C bus.
+ The regulators include three bucks and three ldos.
+
config REGULATOR_PWM
tristate "PWM voltage regulator"
depends on PWM
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index be98b29d6675d8be1ca984c2d137bdfc4ba2de87..1e2e58874123ecb3e2694eff357fc011d53014e8 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -125,6 +125,7 @@ obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o
obj-$(CONFIG_REGULATOR_PF9453) += pf9453-regulator.o
+obj-$(CONFIG_REGULATOR_PF1550) += pf1550-regulator.o
obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
diff --git a/drivers/regulator/pf1550-regulator.c b/drivers/regulator/pf1550-regulator.c
new file mode 100644
index 0000000000000000000000000000000000000000..90492609773886343151c2ba40d2d4bf84c37c5e
--- /dev/null
+++ b/drivers/regulator/pf1550-regulator.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// regulator driver for the PF1550
+//
+// Copyright (C) 2016 Freescale Semiconductor, Inc.
+// Robin Gong <yibin.gong@freescale.com>
+//
+// Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+// Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+//
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define PF1550_REGULATOR_IRQ_NR 11
+#define PF1550_MAX_REGULATOR 7
+
+struct pf1550_desc {
+ struct regulator_desc desc;
+ unsigned char stby_reg;
+ unsigned char stby_mask;
+ unsigned char stby_enable_reg;
+ unsigned char stby_enable_mask;
+};
+
+struct pf1550_regulator_info {
+ struct device *dev;
+ const struct pf1550_ddata *pf1550;
+ struct pf1550_desc regulator_descs[PF1550_MAX_REGULATOR];
+ struct regulator_dev *rdevs[PF1550_MAX_REGULATOR];
+};
+
+static const int pf1550_sw12_volts[] = {
+ 1100000, 1200000, 1350000, 1500000, 1800000, 2500000, 3000000, 3300000,
+};
+
+static const int pf1550_ldo13_volts[] = {
+ 750000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000,
+ 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+ 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+ 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
+};
+
+static int pf1550_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ int id = rdev_get_id(rdev);
+ unsigned int ramp_bits = 0;
+ int ret;
+
+ if (id > PF1550_VREFDDR)
+ return -EACCES;
+
+ if (ramp_delay < 0 || ramp_delay > 6250)
+ return -EINVAL;
+
+ ramp_delay = 6250 / ramp_delay;
+ ramp_bits = ramp_delay >> 1;
+
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg + 4, 0x10,
+ ramp_bits << 4);
+ if (ret < 0)
+ dev_err(&rdev->dev, "ramp failed, err %d\n", ret);
+
+ return ret;
+}
+
+static int pf1550_set_suspend_enable(struct regulator_dev *rdev)
+{
+ const struct pf1550_desc *desc = container_of(rdev->desc,
+ struct pf1550_desc,
+ desc);
+ unsigned int val = desc->stby_enable_mask;
+
+ return regmap_update_bits(rdev->regmap, desc->stby_enable_reg,
+ desc->stby_enable_mask, val);
+}
+
+static int pf1550_set_suspend_disable(struct regulator_dev *rdev)
+{
+ const struct pf1550_desc *desc = container_of(rdev->desc,
+ struct pf1550_desc,
+ desc);
+
+ return regmap_update_bits(rdev->regmap, desc->stby_enable_reg,
+ desc->stby_enable_mask, 0);
+}
+
+static int pf1550_buck_set_table_suspend_voltage(struct regulator_dev *rdev,
+ int uV)
+{
+ const struct pf1550_desc *desc = container_of(rdev->desc,
+ struct pf1550_desc,
+ desc);
+ int ret;
+
+ ret = regulator_map_voltage_ascend(rdev, uV, uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
+ return ret;
+ }
+
+ return regmap_update_bits(rdev->regmap, desc->stby_reg,
+ desc->stby_mask, ret);
+}
+
+static int pf1550_buck_set_linear_suspend_voltage(struct regulator_dev *rdev,
+ int uV)
+{
+ const struct pf1550_desc *desc = container_of(rdev->desc,
+ struct pf1550_desc,
+ desc);
+ int ret;
+
+ ret = regulator_map_voltage_linear(rdev, uV, uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
+ return ret;
+ }
+
+ return regmap_update_bits(rdev->regmap, desc->stby_reg,
+ desc->stby_mask, ret);
+}
+
+static const struct regulator_ops pf1550_sw1_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_voltage = pf1550_buck_set_table_suspend_voltage,
+ .map_voltage = regulator_map_voltage_ascend,
+ .set_ramp_delay = pf1550_set_ramp_delay,
+};
+
+static const struct regulator_ops pf1550_sw2_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_voltage = pf1550_buck_set_linear_suspend_voltage,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_ramp_delay = pf1550_set_ramp_delay,
+};
+
+static const struct regulator_ops pf1550_ldo1_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static const struct regulator_ops pf1550_ldo2_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .map_voltage = regulator_map_voltage_linear,
+};
+
+static const struct regulator_ops pf1550_fixed_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+#define PF_VREF(_chip, match, _name, voltage) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = 1, \
+ .ops = &pf1550_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (voltage), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+#define PF_SW(_chip, match, _name, min, max, mask, step) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pf1550_sw2_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .linear_min_sel = 0, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_reg = _chip ## _PMIC_REG_ ## _name ## _STBY_VOLT, \
+ .stby_mask = (mask), \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+#define PF_LDO1(_chip, match, _name, mask, voltages) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ARRAY_SIZE(voltages), \
+ .ops = &pf1550_ldo1_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .volt_table = voltages, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+#define PF_LDO2(_chip, match, _name, mask, min, max, step) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pf1550_ldo2_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .linear_min_sel = 0, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+static struct pf1550_desc pf1550_regulators[] = {
+ PF_SW(PF1550, "sw1", SW1, 600000, 1387500, 0x3f, 12500),
+ PF_SW(PF1550, "sw2", SW2, 600000, 1387500, 0x3f, 12500),
+ PF_SW(PF1550, "sw3", SW3, 1800000, 3300000, 0xf, 100000),
+ PF_VREF(PF1550, "vrefddr", VREFDDR, 1200000),
+ PF_LDO1(PF1550, "ldo1", LDO1, 0x1f, pf1550_ldo13_volts),
+ PF_LDO2(PF1550, "ldo2", LDO2, 0xf, 1800000, 3300000, 100000),
+ PF_LDO1(PF1550, "ldo3", LDO3, 0x1f, pf1550_ldo13_volts),
+};
+
+static irqreturn_t pf1550_regulator_irq_handler(int irq, void *data)
+{
+ struct pf1550_regulator_info *info = data;
+ struct device *dev = info->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ int i, irq_type = -1;
+ unsigned int event;
+
+ for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++)
+ if (irq == platform_get_irq(pdev, i))
+ irq_type = i;
+
+ switch (irq_type) {
+ /* The _LS interrupts indicate over-current event. The _HS interrupts
+ * which are more accurate and can detect catastrophic faults, issue
+ * an error event. The current limit FAULT interrupt is similar to the
+ * _HS'
+ */
+ case PF1550_PMIC_IRQ_SW1_LS:
+ case PF1550_PMIC_IRQ_SW2_LS:
+ case PF1550_PMIC_IRQ_SW3_LS:
+ event = REGULATOR_EVENT_OVER_CURRENT_WARN;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ if (!strcmp(rdev_get_name(info->rdevs[i]), "SW3"))
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ case PF1550_PMIC_IRQ_SW1_HS:
+ case PF1550_PMIC_IRQ_SW2_HS:
+ case PF1550_PMIC_IRQ_SW3_HS:
+ event = REGULATOR_EVENT_OVER_CURRENT;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ if (!strcmp(rdev_get_name(info->rdevs[i]), "SW3"))
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ case PF1550_PMIC_IRQ_LDO1_FAULT:
+ case PF1550_PMIC_IRQ_LDO2_FAULT:
+ case PF1550_PMIC_IRQ_LDO3_FAULT:
+ event = REGULATOR_EVENT_OVER_CURRENT;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ if (!strcmp(rdev_get_name(info->rdevs[i]), "LDO3"))
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ case PF1550_PMIC_IRQ_TEMP_110:
+ case PF1550_PMIC_IRQ_TEMP_125:
+ event = REGULATOR_EVENT_OVER_TEMP;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ default:
+ dev_err(dev, "regulator interrupt: irq %d occurred\n",
+ irq_type);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int pf1550_regulator_probe(struct platform_device *pdev)
+{
+ const struct pf1550_ddata *pf1550 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct pf1550_regulator_info *info;
+ int i, irq = -1, ret = 0;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ config.regmap = dev_get_regmap(pf1550->dev, NULL);
+ if (!config.regmap)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "failed to get parent regmap\n");
+
+ config.dev = pf1550->dev;
+ config.regmap = pf1550->regmap;
+ info->dev = &pdev->dev;
+ info->pf1550 = pf1550;
+
+ memcpy(info->regulator_descs, pf1550_regulators,
+ sizeof(info->regulator_descs));
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_regulators); i++) {
+ struct regulator_desc *desc;
+
+ desc = &info->regulator_descs[i].desc;
+
+ if ((desc->id == PF1550_SW2 && !pf1550->dvs2_enable) ||
+ (desc->id == PF1550_SW1 && !pf1550->dvs1_enable)) {
+ /* OTP_SW2_DVS_ENB == 1? or OTP_SW1_DVS_ENB == 1? */
+ desc->volt_table = pf1550_sw12_volts;
+ desc->n_voltages = ARRAY_SIZE(pf1550_sw12_volts);
+ desc->ops = &pf1550_sw1_ops;
+ }
+
+ info->rdevs[i] = devm_regulator_register(&pdev->dev, desc,
+ &config);
+ if (IS_ERR(info->rdevs[i]))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(info->rdevs[i]),
+ "failed to initialize regulator-%d\n",
+ i);
+ }
+
+ platform_set_drvdata(pdev, info);
+
+ for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ pf1550_regulator_irq_handler,
+ IRQF_NO_SUSPEND,
+ "pf1550-regulator", info);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed: irq request (IRQ: %d)\n",
+ i);
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id pf1550_regulator_id[] = {
+ { "pf1550-regulator", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, pf1550_regulator_id);
+
+static struct platform_driver pf1550_regulator_driver = {
+ .driver = {
+ .name = "pf1550-regulator",
+ },
+ .probe = pf1550_regulator_probe,
+ .id_table = pf1550_regulator_id,
+};
+module_platform_driver(pf1550_regulator_driver);
+
+MODULE_DESCRIPTION("NXP PF1550 regulator driver");
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_LICENSE("GPL");
--
2.50.1
^ permalink raw reply related
* [PATCH v12 4/6] input: pf1550: add onkey support
From: Samuel Kayode via B4 Relay @ 2025-10-01 15:42 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Frank Li
In-Reply-To: <20251001-pf1550-v12-0-a3302aa41687@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add support for the onkey of the pf1550 PMIC.
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v10:
- Use regmap_clear_bits instead of regmap_write
v9:
- Requested by Sean:
- Add support for disabling power down of system by onkey
v8:
- Pick up `Acked-by` tag from Dmitry
- Use C++ for SPDX license header comment and C type for rest of license
comment
v7:
- Use reverese christmas tree style
- Drop unecessary 0 in id table's driver data
v4:
- Address Dmitry's feedback
- Drop irq variable in onkey_drv_data
- Drop keycode variable in onkey_drv_data
- Define wakeup as type bool
- Use platform_get_irq
- Use type const for struct pf1550_dev in onkey_drv_data
- Replace (error < 0) with (error) in if statement when applicable
- No need to define driver_data in table id
- Define driver.pm with pm_sleep_ptr
v3:
- Address Dmitry's feedback
- Drop compatible string
- Remove dependency on OF
- Use generic device properties
- Drop unnecessary includes
- Drop unnecessary initializations in probe
- Always use the KEY_POWER property for onkey->keycode
- Do mapping of irqs in MFD driver
- Define onkey->input before interrupts are active
- Drop unnecessary input_free_device since devm
- Manage onkey irqs instead of the main interrupt line.
- Fix integer overflow when unmasking onkey irqs in onkey_resume.
v2:
- Add driver for onkey
---
drivers/input/misc/Kconfig | 11 +++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/pf1550-onkey.c | 197 ++++++++++++++++++++++++++++++++++++++
3 files changed, 209 insertions(+)
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 0fb21c99a5e3d1230d7f40f99e0c2d360bbe80e8..4312a1f533e370b4bbef439bceae8f0969712249 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -179,6 +179,17 @@ config INPUT_PCSPKR
To compile this driver as a module, choose M here: the
module will be called pcspkr.
+config INPUT_PF1550_ONKEY
+ tristate "NXP PF1550 Onkey support"
+ depends on MFD_PF1550
+ help
+ Say Y here if you want support for PF1550 PMIC. Onkey can trigger
+ release and 1s(push hold), 2s, 3s, 4s, 8s interrupt for long press
+ detect.
+
+ To compile this driver as a module, choose M here. The module will be
+ called pf1550-onkey.
+
config INPUT_PM8941_PWRKEY
tristate "Qualcomm PM8941 power key support"
depends on MFD_SPMI_PMIC
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index d468c8140b93da5bb537e8a3baea2b90e7bb4229..bbf1aa7bec4f10274af5ffcb5a5651bf7c776dc6 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
+obj-$(CONFIG_INPUT_PF1550_ONKEY) += pf1550-onkey.o
obj-$(CONFIG_INPUT_PM8941_PWRKEY) += pm8941-pwrkey.o
obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
diff --git a/drivers/input/misc/pf1550-onkey.c b/drivers/input/misc/pf1550-onkey.c
new file mode 100644
index 0000000000000000000000000000000000000000..9be6377151cb3be824ab34ff37f983196b909324
--- /dev/null
+++ b/drivers/input/misc/pf1550-onkey.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the PF1550 ONKEY
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+ * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+ */
+
+#include <linux/err.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/platform_device.h>
+
+#define PF1550_ONKEY_IRQ_NR 6
+
+struct onkey_drv_data {
+ struct device *dev;
+ const struct pf1550_ddata *pf1550;
+ bool wakeup;
+ struct input_dev *input;
+};
+
+static irqreturn_t pf1550_onkey_irq_handler(int irq, void *data)
+{
+ struct onkey_drv_data *onkey = data;
+ struct platform_device *pdev = to_platform_device(onkey->dev);
+ int i, state, irq_type = -1;
+
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++)
+ if (irq == platform_get_irq(pdev, i))
+ irq_type = i;
+
+ switch (irq_type) {
+ case PF1550_ONKEY_IRQ_PUSHI:
+ state = 0;
+ break;
+ case PF1550_ONKEY_IRQ_1SI:
+ case PF1550_ONKEY_IRQ_2SI:
+ case PF1550_ONKEY_IRQ_3SI:
+ case PF1550_ONKEY_IRQ_4SI:
+ case PF1550_ONKEY_IRQ_8SI:
+ state = 1;
+ break;
+ default:
+ dev_err(onkey->dev, "onkey interrupt: irq %d occurred\n",
+ irq_type);
+ return IRQ_HANDLED;
+ }
+
+ input_event(onkey->input, EV_KEY, KEY_POWER, state);
+ input_sync(onkey->input);
+
+ return IRQ_HANDLED;
+}
+
+static int pf1550_onkey_probe(struct platform_device *pdev)
+{
+ struct onkey_drv_data *onkey;
+ struct input_dev *input;
+ bool key_power = false;
+ int i, irq, error;
+
+ onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
+ if (!onkey)
+ return -ENOMEM;
+
+ onkey->dev = &pdev->dev;
+
+ onkey->pf1550 = dev_get_drvdata(pdev->dev.parent);
+ if (!onkey->pf1550->regmap)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "failed to get regmap\n");
+
+ onkey->wakeup = device_property_read_bool(pdev->dev.parent,
+ "wakeup-source");
+
+ if (device_property_read_bool(pdev->dev.parent,
+ "nxp,disable-key-power")) {
+ error = regmap_clear_bits(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_PWRCTRL1,
+ PF1550_ONKEY_RST_EN);
+ if (error)
+ return dev_err_probe(&pdev->dev, error,
+ "failed: disable turn system off");
+ } else {
+ key_power = true;
+ }
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input)
+ return dev_err_probe(&pdev->dev, -ENOMEM,
+ "failed to allocate the input device\n");
+
+ input->name = pdev->name;
+ input->phys = "pf1550-onkey/input0";
+ input->id.bustype = BUS_HOST;
+
+ if (key_power)
+ input_set_capability(input, EV_KEY, KEY_POWER);
+
+ onkey->input = input;
+ platform_set_drvdata(pdev, onkey);
+
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ error = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ pf1550_onkey_irq_handler,
+ IRQF_NO_SUSPEND,
+ "pf1550-onkey", onkey);
+ if (error)
+ return dev_err_probe(&pdev->dev, error,
+ "failed: irq request (IRQ: %d)\n",
+ i);
+ }
+
+ error = input_register_device(input);
+ if (error)
+ return dev_err_probe(&pdev->dev, error,
+ "failed to register input device\n");
+
+ device_init_wakeup(&pdev->dev, onkey->wakeup);
+
+ return 0;
+}
+
+static int pf1550_onkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct onkey_drv_data *onkey = platform_get_drvdata(pdev);
+ int i, irq;
+
+ if (!device_may_wakeup(&pdev->dev))
+ regmap_write(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI |
+ ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI);
+ else
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq > 0)
+ enable_irq_wake(irq);
+ }
+
+ return 0;
+}
+
+static int pf1550_onkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct onkey_drv_data *onkey = platform_get_drvdata(pdev);
+ int i, irq;
+
+ if (!device_may_wakeup(&pdev->dev))
+ regmap_write(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ ~((u8)(ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI |
+ ONKEY_IRQ_2SI | ONKEY_IRQ_3SI | ONKEY_IRQ_4SI |
+ ONKEY_IRQ_8SI)));
+ else
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq > 0)
+ disable_irq_wake(irq);
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend,
+ pf1550_onkey_resume);
+
+static const struct platform_device_id pf1550_onkey_id[] = {
+ { "pf1550-onkey", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, pf1550_onkey_id);
+
+static struct platform_driver pf1550_onkey_driver = {
+ .driver = {
+ .name = "pf1550-onkey",
+ .pm = pm_sleep_ptr(&pf1550_onkey_pm_ops),
+ },
+ .probe = pf1550_onkey_probe,
+ .id_table = pf1550_onkey_id,
+};
+module_platform_driver(pf1550_onkey_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION("PF1550 onkey Driver");
+MODULE_LICENSE("GPL");
--
2.50.1
^ permalink raw reply related
* [PATCH v12 2/6] mfd: pf1550: add core driver
From: Samuel Kayode via B4 Relay @ 2025-10-01 15:42 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Frank Li
In-Reply-To: <20251001-pf1550-v12-0-a3302aa41687@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add the core driver for pf1550 PMIC. There are 3 subdevices for which the
drivers will be added in subsequent patches.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v11:
- Add Tested-by tag from Sean
v10:
- Address Lee's feedback:
- Change dvsX_enb to dvsX_enable
- Add new line where necessary
- Can use 100 chars in a line
- Begin comments with uppercase
- Rearrange members of struct pf1550_ddata
- Add support for disabling onkey shutting down system
v9:
- Requested by Sean:
- Add support for SW1 DVS enable/disable
- Use consistent whitespace
- Adjust commenting and log messages of the read_otp function
v8:
- Address Lee's feedback:
- Drop `mfd` from driver description and comments
- Add module name in Kconfig
- Fix license commenting
- Drop filenames from comments
- Drop unnecessary tabbing
- Alphabetical ordering of includes
- Remove magic numbers
- Add comments for pf1550_read_otp function
- Fix log error message in pf1550_read_otp
- Drop pf1550_add_child_device function
- Start comments with upper case
- Rename pf1550_dev to pf1550_ddata
- Drop i2c member in struct pf1550_ddata/pf1550_dev
- Use more helpful log message when device id not recognized
- Fix dvs_enb: when bit is set the DVS is disabled and when bit is clear the
DVS is enabled
- Verified the PM_OPS suspend and resume do act as expected
v7:
- Address Frank's feedback:
- Ensure reverse christmas tree order for local variable definitions
- Drop unnecessary driver data definition in id table
v6:
- Address Frank's feedback:
- Ensure lowercase when defining register addresses
- Use GENMASK macro for masking
- Hardcode IRQ flags in pf1550_add_child_device
- Add dvs_enb variable for SW2 regulator
- Drop chip type variable
v5:
- Use top level interrupt to manage interrupts for the sub-drivers as
recommended by Mark Brown. The regmap_irq_sub_irq_map would have been used
if not for the irregular charger irq address. For all children, the mask
register is directly after the irq register (i.e., 0x08, 0x09) except
for the charger: 0x80, 0x82. Meaning .mask_base would be applicable
for all but the charger
- Fix bad offset for temperature interrupts of regulator
v4:
- Use struct resource to define irq so platform_get_irq can be used in
children as suggested by Dmitry
- Let mfd_add_devices create the mappings for the interrupts
- ack_base and init_ack_masked defined for charger and regulator irq
chips
- No need to define driver_data in table id
v3:
- Address Dmitry's feedback:
- Place Table IDs next to each other
- Drop of_match_ptr
- Replace dev_err with dev_err_probe in probe method
- Drop useless log in probe
- Map all irqs instead of doing it in the sub-devices as recommended by
Dmitry.
v2:
- Address feedback from Enric Balletbo Serra
---
drivers/mfd/Kconfig | 16 ++
drivers/mfd/Makefile | 2 +
drivers/mfd/pf1550.c | 367 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/pf1550.h | 273 +++++++++++++++++++++++++++++++++
4 files changed, 658 insertions(+)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 425c5fba6cb1e7848dcea05bd77c729a71d48e2c..e48c471f572cf4fbfe4de82eae6eeae5fa3bfbfc 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -604,6 +604,22 @@ config MFD_MX25_TSADC
i.MX25 processors. They consist of a conversion queue for general
purpose ADC and a queue for Touchscreens.
+config MFD_PF1550
+ tristate "NXP PF1550 PMIC Support"
+ depends on I2C=y && OF
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ help
+ Say yes here to add support for NXP PF1550. This is a companion Power
+ Management IC with regulators, onkey, and charger control on chip.
+ This driver provides common support for accessing the device;
+ additional drivers must be enabled in order to use the functionality
+ of the device.
+
+ This driver can also be built as a module and if so will be called
+ pf1550.
+
config MFD_HI6421_PMIC
tristate "HiSilicon Hi6421 PMU/Codec IC"
depends on OF
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f7bdedd5a66d16bf8ccee0da1236a441e6f085b0..987e8c2ba5bf7b449ea636f62f103c933f0ac3d0 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -121,6 +121,8 @@ obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o
obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
+obj-$(CONFIG_MFD_PF1550) += pf1550.o
+
obj-$(CONFIG_MFD_CORE) += mfd-core.o
ocelot-soc-objs := ocelot-core.o ocelot-spi.o
diff --git a/drivers/mfd/pf1550.c b/drivers/mfd/pf1550.c
new file mode 100644
index 0000000000000000000000000000000000000000..c4f567c055640662cc2db742917cc87cf9cabb5f
--- /dev/null
+++ b/drivers/mfd/pf1550.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Core driver for the PF1550
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+ * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+static const struct regmap_config pf1550_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PF1550_PMIC_REG_END,
+};
+
+static const struct regmap_irq pf1550_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_IRQ_CHG, 0, IRQ_CHG),
+ REGMAP_IRQ_REG(PF1550_IRQ_REGULATOR, 0, IRQ_REGULATOR),
+ REGMAP_IRQ_REG(PF1550_IRQ_ONKEY, 0, IRQ_ONKEY),
+};
+
+static const struct regmap_irq_chip pf1550_irq_chip = {
+ .name = "pf1550",
+ .status_base = PF1550_PMIC_REG_INT_CATEGORY,
+ .init_ack_masked = 1,
+ .num_regs = 1,
+ .irqs = pf1550_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_irqs),
+};
+
+static const struct regmap_irq pf1550_regulator_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW1_LS, 0, PMIC_IRQ_SW1_LS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW2_LS, 0, PMIC_IRQ_SW2_LS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW3_LS, 0, PMIC_IRQ_SW3_LS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW1_HS, 3, PMIC_IRQ_SW1_HS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW2_HS, 3, PMIC_IRQ_SW2_HS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW3_HS, 3, PMIC_IRQ_SW3_HS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO1_FAULT, 16, PMIC_IRQ_LDO1_FAULT),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO2_FAULT, 16, PMIC_IRQ_LDO2_FAULT),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO3_FAULT, 16, PMIC_IRQ_LDO3_FAULT),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_TEMP_110, 24, PMIC_IRQ_TEMP_110),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_TEMP_125, 24, PMIC_IRQ_TEMP_125),
+};
+
+static const struct regmap_irq_chip pf1550_regulator_irq_chip = {
+ .name = "pf1550-regulator",
+ .status_base = PF1550_PMIC_REG_SW_INT_STAT0,
+ .ack_base = PF1550_PMIC_REG_SW_INT_STAT0,
+ .mask_base = PF1550_PMIC_REG_SW_INT_MASK0,
+ .use_ack = 1,
+ .init_ack_masked = 1,
+ .num_regs = 25,
+ .irqs = pf1550_regulator_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_regulator_irqs),
+};
+
+static const struct resource regulator_resources[] = {
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW1_LS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW2_LS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW3_LS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW1_HS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW2_HS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW3_HS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO1_FAULT),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO2_FAULT),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO3_FAULT),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_TEMP_110),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_TEMP_125),
+};
+
+static const struct regmap_irq pf1550_onkey_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_PUSHI, 0, ONKEY_IRQ_PUSHI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_1SI, 0, ONKEY_IRQ_1SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_2SI, 0, ONKEY_IRQ_2SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_3SI, 0, ONKEY_IRQ_3SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_4SI, 0, ONKEY_IRQ_4SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_8SI, 0, ONKEY_IRQ_8SI),
+};
+
+static const struct regmap_irq_chip pf1550_onkey_irq_chip = {
+ .name = "pf1550-onkey",
+ .status_base = PF1550_PMIC_REG_ONKEY_INT_STAT0,
+ .ack_base = PF1550_PMIC_REG_ONKEY_INT_STAT0,
+ .mask_base = PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ .use_ack = 1,
+ .init_ack_masked = 1,
+ .num_regs = 1,
+ .irqs = pf1550_onkey_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_onkey_irqs),
+};
+
+static const struct resource onkey_resources[] = {
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_PUSHI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_1SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_2SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_3SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_4SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_8SI),
+};
+
+static const struct regmap_irq pf1550_charger_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_BAT2SOCI, 0, CHARG_IRQ_BAT2SOCI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_BATI, 0, CHARG_IRQ_BATI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_CHGI, 0, CHARG_IRQ_CHGI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_VBUSI, 0, CHARG_IRQ_VBUSI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_THMI, 0, CHARG_IRQ_THMI),
+};
+
+static const struct regmap_irq_chip pf1550_charger_irq_chip = {
+ .name = "pf1550-charger",
+ .status_base = PF1550_CHARG_REG_CHG_INT,
+ .ack_base = PF1550_CHARG_REG_CHG_INT,
+ .mask_base = PF1550_CHARG_REG_CHG_INT_MASK,
+ .use_ack = 1,
+ .init_ack_masked = 1,
+ .num_regs = 1,
+ .irqs = pf1550_charger_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_charger_irqs),
+};
+
+static const struct resource charger_resources[] = {
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_BAT2SOCI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_BATI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_CHGI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_VBUSI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_THMI),
+};
+
+static const struct mfd_cell pf1550_regulator_cell = {
+ .name = "pf1550-regulator",
+ .num_resources = ARRAY_SIZE(regulator_resources),
+ .resources = regulator_resources,
+};
+
+static const struct mfd_cell pf1550_onkey_cell = {
+ .name = "pf1550-onkey",
+ .num_resources = ARRAY_SIZE(onkey_resources),
+ .resources = onkey_resources,
+};
+
+static const struct mfd_cell pf1550_charger_cell = {
+ .name = "pf1550-charger",
+ .num_resources = ARRAY_SIZE(charger_resources),
+ .resources = charger_resources,
+};
+
+/*
+ * The PF1550 is shipped in variants of A0, A1,...A9. Each variant defines a
+ * configuration of the PMIC in a One-Time Programmable (OTP) memory.
+ * This memory is accessed indirectly by writing valid keys to specific
+ * registers of the PMIC. To read the OTP memory after writing the valid keys,
+ * the OTP register address to be read is written to pf1550 register 0xc4 and
+ * its value read from pf1550 register 0xc5.
+ */
+static int pf1550_read_otp(const struct pf1550_ddata *pf1550, unsigned int index,
+ unsigned int *val)
+{
+ int ret = 0;
+
+ ret = regmap_write(pf1550->regmap, PF1550_PMIC_REG_KEY, PF1550_OTP_PMIC_KEY);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_write(pf1550->regmap, PF1550_CHARG_REG_CHGR_KEY2, PF1550_OTP_CHGR_KEY);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_KEY3, PF1550_OTP_TEST_KEY);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_FMRADDR, index);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_read(pf1550->regmap, PF1550_TEST_REG_FMRDATA, val);
+ if (ret)
+ goto read_err;
+
+ return 0;
+
+read_err:
+ return dev_err_probe(pf1550->dev, ret, "OTP reg %x not found!\n", index);
+}
+
+static int pf1550_i2c_probe(struct i2c_client *i2c)
+{
+ const struct mfd_cell *regulator = &pf1550_regulator_cell;
+ const struct mfd_cell *charger = &pf1550_charger_cell;
+ const struct mfd_cell *onkey = &pf1550_onkey_cell;
+ unsigned int reg_data = 0, otp_data = 0;
+ struct pf1550_ddata *pf1550;
+ struct irq_domain *domain;
+ int irq, ret = 0;
+
+ pf1550 = devm_kzalloc(&i2c->dev, sizeof(*pf1550), GFP_KERNEL);
+ if (!pf1550)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, pf1550);
+ pf1550->dev = &i2c->dev;
+ pf1550->irq = i2c->irq;
+
+ pf1550->regmap = devm_regmap_init_i2c(i2c, &pf1550_regmap_config);
+ if (IS_ERR(pf1550->regmap))
+ return dev_err_probe(pf1550->dev, PTR_ERR(pf1550->regmap),
+ "failed to allocate register map\n");
+
+ ret = regmap_read(pf1550->regmap, PF1550_PMIC_REG_DEVICE_ID, ®_data);
+ if (ret < 0)
+ return dev_err_probe(pf1550->dev, ret, "cannot read chip ID\n");
+ if (reg_data != PF1550_DEVICE_ID)
+ return dev_err_probe(pf1550->dev, -ENODEV, "invalid device ID: 0x%02x\n", reg_data);
+
+ /* Regulator DVS for SW2 */
+ ret = pf1550_read_otp(pf1550, PF1550_OTP_SW2_SW3, &otp_data);
+ if (ret)
+ return ret;
+
+ /* When clear, DVS should be enabled */
+ if (!(otp_data & OTP_SW2_DVS_ENB))
+ pf1550->dvs2_enable = true;
+
+ /* Regulator DVS for SW1 */
+ ret = pf1550_read_otp(pf1550, PF1550_OTP_SW1_SW2, &otp_data);
+ if (ret)
+ return ret;
+
+ if (!(otp_data & OTP_SW1_DVS_ENB))
+ pf1550->dvs1_enable = true;
+
+ /* Add top level interrupts */
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, pf1550->irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING,
+ 0, &pf1550_irq_chip,
+ &pf1550->irq_data);
+ if (ret)
+ return ret;
+
+ /* Add regulator */
+ irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_REGULATOR);
+ if (irq < 0)
+ return dev_err_probe(pf1550->dev, irq,
+ "Failed to get parent vIRQ(%d) for chip %s\n",
+ PF1550_IRQ_REGULATOR, pf1550_irq_chip.name);
+
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_regulator_irq_chip,
+ &pf1550->irq_data_regulator);
+ if (ret)
+ return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
+ pf1550_regulator_irq_chip.name);
+
+ domain = regmap_irq_get_domain(pf1550->irq_data_regulator);
+
+ ret = devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, regulator, 1, NULL, 0, domain);
+ if (ret)
+ return ret;
+
+ /* Add onkey */
+ irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_ONKEY);
+ if (irq < 0)
+ return dev_err_probe(pf1550->dev, irq,
+ "Failed to get parent vIRQ(%d) for chip %s\n",
+ PF1550_IRQ_ONKEY, pf1550_irq_chip.name);
+
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_onkey_irq_chip,
+ &pf1550->irq_data_onkey);
+ if (ret)
+ return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
+ pf1550_onkey_irq_chip.name);
+
+ domain = regmap_irq_get_domain(pf1550->irq_data_onkey);
+
+ ret = devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, onkey, 1, NULL, 0, domain);
+ if (ret)
+ return ret;
+
+ /* Add battery charger */
+ irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_CHG);
+ if (irq < 0)
+ return dev_err_probe(pf1550->dev, irq,
+ "Failed to get parent vIRQ(%d) for chip %s\n",
+ PF1550_IRQ_CHG, pf1550_irq_chip.name);
+
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_charger_irq_chip,
+ &pf1550->irq_data_charger);
+ if (ret)
+ return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
+ pf1550_charger_irq_chip.name);
+
+ domain = regmap_irq_get_domain(pf1550->irq_data_charger);
+
+ return devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, charger, 1, NULL, 0, domain);
+}
+
+static int pf1550_suspend(struct device *dev)
+{
+ struct pf1550_ddata *pf1550 = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev)) {
+ enable_irq_wake(pf1550->irq);
+ disable_irq(pf1550->irq);
+ }
+
+ return 0;
+}
+
+static int pf1550_resume(struct device *dev)
+{
+ struct pf1550_ddata *pf1550 = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev)) {
+ disable_irq_wake(pf1550->irq);
+ enable_irq(pf1550->irq);
+ }
+
+ return 0;
+}
+static DEFINE_SIMPLE_DEV_PM_OPS(pf1550_pm, pf1550_suspend, pf1550_resume);
+
+static const struct i2c_device_id pf1550_i2c_id[] = {
+ { "pf1550" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, pf1550_i2c_id);
+
+static const struct of_device_id pf1550_dt_match[] = {
+ { .compatible = "nxp,pf1550" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pf1550_dt_match);
+
+static struct i2c_driver pf1550_i2c_driver = {
+ .driver = {
+ .name = "pf1550",
+ .pm = pm_sleep_ptr(&pf1550_pm),
+ .of_match_table = pf1550_dt_match,
+ },
+ .probe = pf1550_i2c_probe,
+ .id_table = pf1550_i2c_id,
+};
+module_i2c_driver(pf1550_i2c_driver);
+
+MODULE_DESCRIPTION("NXP PF1550 core driver");
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/pf1550.h b/include/linux/mfd/pf1550.h
new file mode 100644
index 0000000000000000000000000000000000000000..7cb2340ff2bd92883a709806da58601daaf98a88
--- /dev/null
+++ b/include/linux/mfd/pf1550.h
@@ -0,0 +1,273 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Declarations for the PF1550 PMIC
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+ * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+ */
+
+#ifndef __LINUX_MFD_PF1550_H
+#define __LINUX_MFD_PF1550_H
+
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+enum pf1550_pmic_reg {
+ /* PMIC regulator part */
+ PF1550_PMIC_REG_DEVICE_ID = 0x00,
+ PF1550_PMIC_REG_OTP_FLAVOR = 0x01,
+ PF1550_PMIC_REG_SILICON_REV = 0x02,
+
+ PF1550_PMIC_REG_INT_CATEGORY = 0x06,
+ PF1550_PMIC_REG_SW_INT_STAT0 = 0x08,
+ PF1550_PMIC_REG_SW_INT_MASK0 = 0x09,
+ PF1550_PMIC_REG_SW_INT_SENSE0 = 0x0a,
+ PF1550_PMIC_REG_SW_INT_STAT1 = 0x0b,
+ PF1550_PMIC_REG_SW_INT_MASK1 = 0x0c,
+ PF1550_PMIC_REG_SW_INT_SENSE1 = 0x0d,
+ PF1550_PMIC_REG_SW_INT_STAT2 = 0x0e,
+ PF1550_PMIC_REG_SW_INT_MASK2 = 0x0f,
+ PF1550_PMIC_REG_SW_INT_SENSE2 = 0x10,
+ PF1550_PMIC_REG_LDO_INT_STAT0 = 0x18,
+ PF1550_PMIC_REG_LDO_INT_MASK0 = 0x19,
+ PF1550_PMIC_REG_LDO_INT_SENSE0 = 0x1a,
+ PF1550_PMIC_REG_TEMP_INT_STAT0 = 0x20,
+ PF1550_PMIC_REG_TEMP_INT_MASK0 = 0x21,
+ PF1550_PMIC_REG_TEMP_INT_SENSE0 = 0x22,
+ PF1550_PMIC_REG_ONKEY_INT_STAT0 = 0x24,
+ PF1550_PMIC_REG_ONKEY_INT_MASK0 = 0x25,
+ PF1550_PMIC_REG_ONKEY_INT_SENSE0 = 0x26,
+ PF1550_PMIC_REG_MISC_INT_STAT0 = 0x28,
+ PF1550_PMIC_REG_MISC_INT_MASK0 = 0x29,
+ PF1550_PMIC_REG_MISC_INT_SENSE0 = 0x2a,
+
+ PF1550_PMIC_REG_COINCELL_CONTROL = 0x30,
+
+ PF1550_PMIC_REG_SW1_VOLT = 0x32,
+ PF1550_PMIC_REG_SW1_STBY_VOLT = 0x33,
+ PF1550_PMIC_REG_SW1_SLP_VOLT = 0x34,
+ PF1550_PMIC_REG_SW1_CTRL = 0x35,
+ PF1550_PMIC_REG_SW1_CTRL1 = 0x36,
+ PF1550_PMIC_REG_SW2_VOLT = 0x38,
+ PF1550_PMIC_REG_SW2_STBY_VOLT = 0x39,
+ PF1550_PMIC_REG_SW2_SLP_VOLT = 0x3a,
+ PF1550_PMIC_REG_SW2_CTRL = 0x3b,
+ PF1550_PMIC_REG_SW2_CTRL1 = 0x3c,
+ PF1550_PMIC_REG_SW3_VOLT = 0x3e,
+ PF1550_PMIC_REG_SW3_STBY_VOLT = 0x3f,
+ PF1550_PMIC_REG_SW3_SLP_VOLT = 0x40,
+ PF1550_PMIC_REG_SW3_CTRL = 0x41,
+ PF1550_PMIC_REG_SW3_CTRL1 = 0x42,
+ PF1550_PMIC_REG_VSNVS_CTRL = 0x48,
+ PF1550_PMIC_REG_VREFDDR_CTRL = 0x4a,
+ PF1550_PMIC_REG_LDO1_VOLT = 0x4c,
+ PF1550_PMIC_REG_LDO1_CTRL = 0x4d,
+ PF1550_PMIC_REG_LDO2_VOLT = 0x4f,
+ PF1550_PMIC_REG_LDO2_CTRL = 0x50,
+ PF1550_PMIC_REG_LDO3_VOLT = 0x52,
+ PF1550_PMIC_REG_LDO3_CTRL = 0x53,
+ PF1550_PMIC_REG_PWRCTRL0 = 0x58,
+ PF1550_PMIC_REG_PWRCTRL1 = 0x59,
+ PF1550_PMIC_REG_PWRCTRL2 = 0x5a,
+ PF1550_PMIC_REG_PWRCTRL3 = 0x5b,
+ PF1550_PMIC_REG_SW1_PWRDN_SEQ = 0x5f,
+ PF1550_PMIC_REG_SW2_PWRDN_SEQ = 0x60,
+ PF1550_PMIC_REG_SW3_PWRDN_SEQ = 0x61,
+ PF1550_PMIC_REG_LDO1_PWRDN_SEQ = 0x62,
+ PF1550_PMIC_REG_LDO2_PWRDN_SEQ = 0x63,
+ PF1550_PMIC_REG_LDO3_PWRDN_SEQ = 0x64,
+ PF1550_PMIC_REG_VREFDDR_PWRDN_SEQ = 0x65,
+
+ PF1550_PMIC_REG_STATE_INFO = 0x67,
+ PF1550_PMIC_REG_I2C_ADDR = 0x68,
+ PF1550_PMIC_REG_IO_DRV0 = 0x69,
+ PF1550_PMIC_REG_IO_DRV1 = 0x6a,
+ PF1550_PMIC_REG_RC_16MHZ = 0x6b,
+ PF1550_PMIC_REG_KEY = 0x6f,
+
+ /* Charger part */
+ PF1550_CHARG_REG_CHG_INT = 0x80,
+ PF1550_CHARG_REG_CHG_INT_MASK = 0x82,
+ PF1550_CHARG_REG_CHG_INT_OK = 0x84,
+ PF1550_CHARG_REG_VBUS_SNS = 0x86,
+ PF1550_CHARG_REG_CHG_SNS = 0x87,
+ PF1550_CHARG_REG_BATT_SNS = 0x88,
+ PF1550_CHARG_REG_CHG_OPER = 0x89,
+ PF1550_CHARG_REG_CHG_TMR = 0x8a,
+ PF1550_CHARG_REG_CHG_EOC_CNFG = 0x8d,
+ PF1550_CHARG_REG_CHG_CURR_CNFG = 0x8e,
+ PF1550_CHARG_REG_BATT_REG = 0x8f,
+ PF1550_CHARG_REG_BATFET_CNFG = 0x91,
+ PF1550_CHARG_REG_THM_REG_CNFG = 0x92,
+ PF1550_CHARG_REG_VBUS_INLIM_CNFG = 0x94,
+ PF1550_CHARG_REG_VBUS_LIN_DPM = 0x95,
+ PF1550_CHARG_REG_USB_PHY_LDO_CNFG = 0x96,
+ PF1550_CHARG_REG_DBNC_DELAY_TIME = 0x98,
+ PF1550_CHARG_REG_CHG_INT_CNFG = 0x99,
+ PF1550_CHARG_REG_THM_ADJ_SETTING = 0x9a,
+ PF1550_CHARG_REG_VBUS2SYS_CNFG = 0x9b,
+ PF1550_CHARG_REG_LED_PWM = 0x9c,
+ PF1550_CHARG_REG_FAULT_BATFET_CNFG = 0x9d,
+ PF1550_CHARG_REG_LED_CNFG = 0x9e,
+ PF1550_CHARG_REG_CHGR_KEY2 = 0x9f,
+
+ PF1550_TEST_REG_FMRADDR = 0xc4,
+ PF1550_TEST_REG_FMRDATA = 0xc5,
+ PF1550_TEST_REG_KEY3 = 0xdf,
+
+ PF1550_PMIC_REG_END = 0xff,
+};
+
+/* One-Time Programmable(OTP) memory */
+enum pf1550_otp_reg {
+ PF1550_OTP_SW1_SW2 = 0x1e,
+ PF1550_OTP_SW2_SW3 = 0x1f,
+};
+
+#define PF1550_DEVICE_ID 0x7c
+
+/* Keys for reading OTP */
+#define PF1550_OTP_PMIC_KEY 0x15
+#define PF1550_OTP_CHGR_KEY 0x50
+#define PF1550_OTP_TEST_KEY 0xab
+
+/* Supported charger modes */
+#define PF1550_CHG_BAT_OFF 1
+#define PF1550_CHG_BAT_ON 2
+
+#define PF1550_CHG_PRECHARGE 0
+#define PF1550_CHG_CONSTANT_CURRENT 1
+#define PF1550_CHG_CONSTANT_VOL 2
+#define PF1550_CHG_EOC 3
+#define PF1550_CHG_DONE 4
+#define PF1550_CHG_TIMER_FAULT 6
+#define PF1550_CHG_SUSPEND 7
+#define PF1550_CHG_OFF_INV 8
+#define PF1550_CHG_BAT_OVER 9
+#define PF1550_CHG_OFF_TEMP 10
+#define PF1550_CHG_LINEAR_ONLY 12
+#define PF1550_CHG_SNS_MASK 0xf
+#define PF1550_CHG_INT_MASK 0x51
+
+#define PF1550_BAT_NO_VBUS 0
+#define PF1550_BAT_LOW_THAN_PRECHARG 1
+#define PF1550_BAT_CHARG_FAIL 2
+#define PF1550_BAT_HIGH_THAN_PRECHARG 4
+#define PF1550_BAT_OVER_VOL 5
+#define PF1550_BAT_NO_DETECT 6
+#define PF1550_BAT_SNS_MASK 0x7
+
+#define PF1550_VBUS_UVLO BIT(2)
+#define PF1550_VBUS_IN2SYS BIT(3)
+#define PF1550_VBUS_OVLO BIT(4)
+#define PF1550_VBUS_VALID BIT(5)
+
+#define PF1550_CHARG_REG_BATT_REG_CHGCV_MASK 0x3f
+#define PF1550_CHARG_REG_BATT_REG_VMINSYS_SHIFT 6
+#define PF1550_CHARG_REG_BATT_REG_VMINSYS_MASK GENMASK(7, 6)
+#define PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_SHIFT 2
+#define PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_MASK GENMASK(3, 2)
+
+#define PF1550_ONKEY_RST_EN BIT(7)
+
+/* DVS enable masks */
+#define OTP_SW1_DVS_ENB BIT(1)
+#define OTP_SW2_DVS_ENB BIT(3)
+
+/* Top level interrupt masks */
+#define IRQ_REGULATOR (BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(6))
+#define IRQ_ONKEY BIT(5)
+#define IRQ_CHG BIT(0)
+
+/* Regulator interrupt masks */
+#define PMIC_IRQ_SW1_LS BIT(0)
+#define PMIC_IRQ_SW2_LS BIT(1)
+#define PMIC_IRQ_SW3_LS BIT(2)
+#define PMIC_IRQ_SW1_HS BIT(0)
+#define PMIC_IRQ_SW2_HS BIT(1)
+#define PMIC_IRQ_SW3_HS BIT(2)
+#define PMIC_IRQ_LDO1_FAULT BIT(0)
+#define PMIC_IRQ_LDO2_FAULT BIT(1)
+#define PMIC_IRQ_LDO3_FAULT BIT(2)
+#define PMIC_IRQ_TEMP_110 BIT(0)
+#define PMIC_IRQ_TEMP_125 BIT(1)
+
+/* Onkey interrupt masks */
+#define ONKEY_IRQ_PUSHI BIT(0)
+#define ONKEY_IRQ_1SI BIT(1)
+#define ONKEY_IRQ_2SI BIT(2)
+#define ONKEY_IRQ_3SI BIT(3)
+#define ONKEY_IRQ_4SI BIT(4)
+#define ONKEY_IRQ_8SI BIT(5)
+
+/* Charger interrupt masks */
+#define CHARG_IRQ_BAT2SOCI BIT(1)
+#define CHARG_IRQ_BATI BIT(2)
+#define CHARG_IRQ_CHGI BIT(3)
+#define CHARG_IRQ_VBUSI BIT(5)
+#define CHARG_IRQ_DPMI BIT(6)
+#define CHARG_IRQ_THMI BIT(7)
+
+enum pf1550_irq {
+ PF1550_IRQ_CHG,
+ PF1550_IRQ_REGULATOR,
+ PF1550_IRQ_ONKEY,
+};
+
+enum pf1550_pmic_irq {
+ PF1550_PMIC_IRQ_SW1_LS,
+ PF1550_PMIC_IRQ_SW2_LS,
+ PF1550_PMIC_IRQ_SW3_LS,
+ PF1550_PMIC_IRQ_SW1_HS,
+ PF1550_PMIC_IRQ_SW2_HS,
+ PF1550_PMIC_IRQ_SW3_HS,
+ PF1550_PMIC_IRQ_LDO1_FAULT,
+ PF1550_PMIC_IRQ_LDO2_FAULT,
+ PF1550_PMIC_IRQ_LDO3_FAULT,
+ PF1550_PMIC_IRQ_TEMP_110,
+ PF1550_PMIC_IRQ_TEMP_125,
+};
+
+enum pf1550_onkey_irq {
+ PF1550_ONKEY_IRQ_PUSHI,
+ PF1550_ONKEY_IRQ_1SI,
+ PF1550_ONKEY_IRQ_2SI,
+ PF1550_ONKEY_IRQ_3SI,
+ PF1550_ONKEY_IRQ_4SI,
+ PF1550_ONKEY_IRQ_8SI,
+};
+
+enum pf1550_charg_irq {
+ PF1550_CHARG_IRQ_BAT2SOCI,
+ PF1550_CHARG_IRQ_BATI,
+ PF1550_CHARG_IRQ_CHGI,
+ PF1550_CHARG_IRQ_VBUSI,
+ PF1550_CHARG_IRQ_THMI,
+};
+
+enum pf1550_regulators {
+ PF1550_SW1,
+ PF1550_SW2,
+ PF1550_SW3,
+ PF1550_VREFDDR,
+ PF1550_LDO1,
+ PF1550_LDO2,
+ PF1550_LDO3,
+};
+
+struct pf1550_ddata {
+ struct regmap_irq_chip_data *irq_data_regulator;
+ struct regmap_irq_chip_data *irq_data_charger;
+ struct regmap_irq_chip_data *irq_data_onkey;
+ struct regmap_irq_chip_data *irq_data;
+ struct regmap *regmap;
+ struct device *dev;
+ bool dvs1_enable;
+ bool dvs2_enable;
+ int irq;
+};
+
+#endif /* __LINUX_MFD_PF1550_H */
--
2.50.1
^ permalink raw reply related
* [PATCH v12 0/6] add support for pf1550 PMIC MFD-based drivers
From: Samuel Kayode via B4 Relay @ 2025-10-01 15:42 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Krzysztof Kozlowski, Frank Li, Sebastian Reichel
This series adds support for pf1550 PMIC. It provides the core driver and
sub-drivers for the regulator, power supply and input subsystems.
Patch 1 adds the DT binding document for the PMIC. Patches 2-5 adds the
pertinent drivers. Last patch adds a MAINTAINERS entry for the drivers.
The patches 3-5 depend on the core driver provided in patch 2.
Changes since v1:
- DT bindings for all devices included
- Add onkey driver
- Add driver for the regulators
- Ensure charger is activated as some variants have it off by default
- Update mfd and charger driver per feedback from eballetbo@gmail.com
- Add myself as maintainer for these drivers
- Link to v1: https://lore.kernel.org/1523974819-8711-1-git-send-email-abel.vesa@nxp.com/
Changes since v2:
- Rebase on recent mainline kernel v6.15
- Single yaml file containing dt bindings for all pf1550 devices
- irq mapping done in MFD driver as suggested by Dmitry Torokhov
- Drop unnecessary includes in drivers
- Replace dev_err with dev_err_probe in probe method of drivers
- Drop compatible string from drivers of the sub-devices
- Remove dependency on OF from drivers of the sub-devices
- onkey: move driver from input/keyboard into input/misc
- onkey: remove dependency on OF
- onkey: use onkey virqs instead of central irq
- onkey: fix integer overflow for regmap_write when unmasking
interrupts during pf1550_onkey_resume
- charger: add support for monitored-battery which is used in setting
a constant voltage for the charger.
- Address other feedback from Dmitry Torokhov and Krzysztof Kozlowski
- Link to v2: https://lore.kernel.org/cover.1747409892.git.samuel.kayode@savoirfairelinux.com/
Changes since v3:
- Update manufacturer from Freescale to NXP in compatible,
dt-binding and Kconfigs
- Use C++ style comments for SPDX license in .c code
- Add portions copyright to source code
- irqs are defined as struct resource in mfd cell such that
platform_get_irq is used in the sub-devices
- Make struct pf1550_dev of type const in sub-device driver
- irq variable dropped from sub-device driver struct
- EXPORT_SYMBOL of global pf1550_read_otp function for use in
regulator driver
- Drop unneeded info in driver_data when defining device table id
- regulator: validate ramp_delay
- regulator: report overcurrent and over temperature events
- onkey: drop unnecessary keycode variable
- onkey: change wakeup variable to type bool
- onkey: replace (error < 0) with error in if statement when possible
- onkey: use pm_sleep_ptr when defining driver.pm
- charger: finish handling of some interrupts in threaded irq handler
- Link to v3: https://lore.kernel.org/20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com/
Changes since v4:
- Use top level interrupt to minimize number of registers checked on
each interrupt
- Fix bad offset for temperature interrupts of regulator irq chip
- Address Krzysztof's comments for dt-binding
- regulator: add comments to clarify difference in its interrupts
- regulator: issue warn event for _LS interrupt and error event for
_HS interrupt
- regulator: validate maximum and minimum ramp_delay
- charger: drop lock in battery and charger delayed_work
- charger: more conservative locking for vbus delayed_work
- charger: apply lock when setting power_supply type during register
intialization
- Link to v4: https://lore.kernel.org/r/20250603-pf1550-v4-0-bfdf51ee59cc@savoirfairelinux.com
Changes since v5:
- Ensure lowercase when assigning hex values
- Add imx@lists.linux.dev to relevant mailing list in MAINTAINERS file
- Use GENMASK macro
- Drop unused chips variable
- Read the OTP in the mfd driver probe for new dvs_enb variable
- Hardcode IRQ flags in pf1550_add_child function
- charger: drop the mutex entirely
- charger: reverse christmas tree style local variable definition in
probe
- Link to v5: https://lore.kernel.org/r/20250610-pf1550-v5-0-ed0d9e3aaac7@savoirfairelinux.com
Changes since v6:
- Use reverse christmas tree order
- Drop 0 in table id's driver data
- charger: store virq to avoid reinvoking platform_get_irq in ISR
- Link to v6: https://lore.kernel.org/r/20250611-pf1550-v6-0-34f2ddfe045e@savoirfairelinux.com
Changes since v7:
- Thanks everyone for the reviews
- Use C++ comment only for SPDX license header in core, charger and
onkey drivers
- Drop filenames from comments
- Rename pf1550_dev to pf1550_ddata
- Define OTP register for accessing status of DVS
- core: rename from `mfd driver` to `core driver`
- core: add child devices in a cleaner manner
- charger: define two power supplies: battery and external power
- charger: use devm_delayed_work_autocancel
- Link to v7: https://lore.kernel.org/r/20250612-pf1550-v7-0-0e393b0f45d7@savoirfairelinux.com
Changes since v8:
- Collect Frank's `Reviewed-by` tags
- core: use consistent whitespace
- regulator: add standby support for regulators requested by Sean Nyekjaer
- regulator: add support for SW1 DVS enable/disable
- regulator: fix improper DVS activation
- regulator: add map_voltage for regulators
- regulator: add enable/disable for regulators
- charger: use datasheet thermal regulation temperature ranges
- charger: select charger operation mode based on the application
- onkey: add support for disabling system power down via onkey
- dt-bindings: changed temperature ranges
- dt-bindings: added `disable-key-power`
- Link to v8: https://lore.kernel.org/r/20250707-pf1550-v8-0-6b6eb67c03a0@savoirfairelinux.com
Changes since v9:
- add Sean's Tested-by tag
- core: style changes
- dt-bindings: add regulator-state-mem to examples
- onkey: use regmap_clear_bits to avoid overwriting all bits of the
PWRCTRL register
- Link to v9: https://lore.kernel.org/r/20250716-pf1550-v9-0-502a647f04ef@savoirfairelinux.com
Changes since v10:
- add Sean's Tested-by tag on mfd patch
- charger: separate battery properties from charger properties
- Link to v10: https://lore.kernel.org/r/20250820-pf1550-v10-0-4c0b6e4445e3@savoirfairelinux.com
Changes since v11:
- rebase on v6.17
- charger: add Sebastian's `Acked-by` tag
- Link to v11: https://lore.kernel.org/r/20250917-pf1550-v11-0-e0649822fcc9@savoirfairelinux.com
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
Samuel Kayode (6):
dt-bindings: mfd: add pf1550
mfd: pf1550: add core driver
regulator: pf1550: add support for regulator
input: pf1550: add onkey support
power: supply: pf1550: add battery charger support
MAINTAINERS: add an entry for pf1550 mfd driver
.../devicetree/bindings/mfd/nxp,pf1550.yaml | 161 ++++++
MAINTAINERS | 11 +
drivers/input/misc/Kconfig | 11 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/pf1550-onkey.c | 197 +++++++
drivers/mfd/Kconfig | 16 +
drivers/mfd/Makefile | 2 +
drivers/mfd/pf1550.c | 367 ++++++++++++
drivers/power/supply/Kconfig | 11 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/pf1550-charger.c | 641 +++++++++++++++++++++
drivers/regulator/Kconfig | 9 +
drivers/regulator/Makefile | 1 +
drivers/regulator/pf1550-regulator.c | 429 ++++++++++++++
include/linux/mfd/pf1550.h | 273 +++++++++
15 files changed, 2131 insertions(+)
---
base-commit: 6063257da111c7639d020c5f15bfb37fb839d8b6
change-id: 20250527-pf1550-d401f0d07b80
Best regards,
--
Samuel Kayode <samuel.kayode@savoirfairelinux.com>
^ permalink raw reply
* [PATCH v12 1/6] dt-bindings: mfd: add pf1550
From: Samuel Kayode via B4 Relay @ 2025-10-01 15:42 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Krzysztof Kozlowski
In-Reply-To: <20251001-pf1550-v12-0-a3302aa41687@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add a DT binding document for pf1550 PMIC. This describes the core mfd
device along with its children: regulators, charger and onkey.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v10:
- Add regulator-state-mem to examples
v9:
- Add regulator suspend bindings in example
- Add binding for disabling onkey power down
- Fix thermal regulation temperature range
v5:
- Address Krzystof's feedback:
- Drop monitored battery ref already included in power supply schema
- Move `additionalProperties` close to `type` for regulator
- Drop unneccessary |
- Change `additionalProperties` to `unevaluatedProperties` for the
PMIC
v4:
- Address Krzystof's feedback:
- Filename changed to nxp,pf1550.yaml
- Replace Freescale with NXP
- Define include before battery-cell
- Drop operating-range-celsius in example since
nxp,thermal-regulation-celsisus already exists
- Not sure if there is similar binding to thermal-regulation...
for regulating temperature on thermal-zones? @Sebastian and @Krzysztof
v3:
- Address Krzysztof's feedback:
- Fold charger and onkey objects
- Drop compatible for sub-devices: onkey, charger and regulator.
- Drop constant voltage property already included in
monitored-battery
- Fix whitespace warnings
- Fix license
v2:
- Add yamls for the PMIC and the sub-devices
---
.../devicetree/bindings/mfd/nxp,pf1550.yaml | 161 +++++++++++++++++++++
1 file changed, 161 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/nxp,pf1550.yaml b/Documentation/devicetree/bindings/mfd/nxp,pf1550.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e50dc44252c60063463295c5ec3e3c90d1592ec2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/nxp,pf1550.yaml
@@ -0,0 +1,161 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/nxp,pf1550.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP PF1550 Power Management IC
+
+maintainers:
+ - Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+
+description:
+ PF1550 PMIC provides battery charging and power supply for low power IoT and
+ wearable applications. This device consists of an i2c controlled MFD that
+ includes regulators, battery charging and an onkey/power button.
+
+$ref: /schemas/power/supply/power-supply.yaml
+
+properties:
+ compatible:
+ const: nxp,pf1550
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ wakeup-source: true
+
+ regulators:
+ type: object
+ additionalProperties: false
+
+ patternProperties:
+ "^(ldo[1-3]|sw[1-3]|vrefddr)$":
+ type: object
+ $ref: /schemas/regulator/regulator.yaml
+ description:
+ regulator configuration for ldo1-3, buck converters(sw1-3)
+ and DDR termination reference voltage (vrefddr)
+ unevaluatedProperties: false
+
+ monitored-battery:
+ description: |
+ A phandle to a monitored battery node that contains a valid value
+ for:
+ constant-charge-voltage-max-microvolt.
+
+ nxp,thermal-regulation-celsius:
+ description:
+ Temperature threshold for thermal regulation of charger in celsius.
+ enum: [ 80, 95, 110, 125 ]
+
+ nxp,min-system-microvolt:
+ description:
+ System specific lower limit voltage.
+ enum: [ 3500000, 3700000, 4300000 ]
+
+ nxp,disable-key-power:
+ type: boolean
+ description:
+ Disable power-down using a long key-press. The onkey driver will remove
+ support for the KEY_POWER key press when triggered using a long press of
+ the onkey.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/input/linux-event-codes.h>
+
+ battery: battery-cell {
+ compatible = "simple-battery";
+ constant-charge-voltage-max-microvolt = <4400000>;
+ };
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmic@8 {
+ compatible = "nxp,pf1550";
+ reg = <0x8>;
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+ wakeup-source;
+ monitored-battery = <&battery>;
+ nxp,min-system-microvolt = <4300000>;
+ nxp,thermal-regulation-celsius = <80>;
+
+ regulators {
+ sw1_reg: sw1 {
+ regulator-name = "sw1";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <1387500>;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-min-microvolt = <1270000>;
+ };
+ };
+
+ sw2_reg: sw2 {
+ regulator-name = "sw2";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <1387500>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ sw3_reg: sw3 {
+ regulator-name = "sw3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vldo1_reg: ldo1 {
+ regulator-name = "ldo1";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vldo2_reg: ldo2 {
+ regulator-name = "ldo2";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vldo3_reg: ldo3 {
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+ };
+ };
--
2.50.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox