From 8e54033b4250cecadd653817e7d3497e98af9a09 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 29 Jan 2025 16:49:39 +0200 Subject: [PATCH 01/20] pinctrl: baytrail: Use dedicated helpers for chained IRQ handlers Instead of relying on the fact that the parent IRQ chip supports fasteoi mode and calling the respective callback at the end of the interrupt handler, surround it with enter and exit helpers for chained IRQ handlers which will consider all possible cases. This in particular unifies how GPIO drivers handle IRQ. Reviewed-by: Hans de Goede Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-baytrail.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 7340dc20349c..c4458ac539ff 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -1355,6 +1355,8 @@ static void byt_gpio_irq_handler(struct irq_desc *desc) void __iomem *reg; unsigned long pending; + chained_irq_enter(chip, desc); + /* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < vg->chip.ngpio; base += 32) { reg = byt_gpio_reg(vg, base, BYT_INT_STAT_REG); @@ -1369,7 +1371,8 @@ static void byt_gpio_irq_handler(struct irq_desc *desc) for_each_set_bit(pin, &pending, 32) generic_handle_domain_irq(vg->chip.irq.domain, base + pin); } - chip->irq_eoi(data); + + chained_irq_exit(chip, desc); } static bool byt_direct_irq_sanity_check(struct intel_pinctrl *vg, int pin, u32 conf0) From 5feac4d72d9f0aa80ff76690d56522e6106b3c7b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 29 Jan 2025 16:49:40 +0200 Subject: [PATCH 02/20] pinctrl: lynxpoint: Use dedicated helpers for chained IRQ handlers Instead of relying on the fact that the parent IRQ chip supports fasteoi mode and calling the respective callback at the end of the interrupt handler, surround it with enter and exit helpers for chained IRQ handlers which will consider all possible cases. This in particular unifies how GPIO drivers handle IRQ. Reviewed-by: Hans de Goede Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-lynxpoint.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/intel/pinctrl-lynxpoint.c b/drivers/pinctrl/intel/pinctrl-lynxpoint.c index cc5ede17c383..ac5459a4c63e 100644 --- a/drivers/pinctrl/intel/pinctrl-lynxpoint.c +++ b/drivers/pinctrl/intel/pinctrl-lynxpoint.c @@ -549,6 +549,8 @@ static void lp_gpio_irq_handler(struct irq_desc *desc) unsigned long pending; u32 base, pin; + chained_irq_enter(chip, desc); + /* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < lg->chip.ngpio; base += 32) { reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); @@ -560,7 +562,8 @@ static void lp_gpio_irq_handler(struct irq_desc *desc) for_each_set_bit(pin, &pending, 32) generic_handle_domain_irq(lg->chip.irq.domain, base + pin); } - chip->irq_eoi(data); + + chained_irq_exit(chip, desc); } static void lp_irq_ack(struct irq_data *d) From c42a407beeb91dd5e8cf1d537a7291a5d6415192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 23 Jan 2025 11:11:10 +0100 Subject: [PATCH 03/20] pinctrl: intel: Import PWM_LPSS namespace for devm_pwm_lpss_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Intel pinctrl driver can provide a PWM device and for that needs to call the function devm_pwm_lpss_probe(). That function is provided by the pwm-lpss driver which intends to export it in the "PWM_LPSS" namespace. To prepare fixing the pwm-lpss driver to indeed use the "PWM_LPSS" namespace, import that namespace when used. Signed-off-by: Uwe Kleine-König Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-intel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 527e4b87ae52..d593ad03f949 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1941,3 +1941,4 @@ MODULE_AUTHOR("Mathias Nyman "); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel pinctrl/GPIO core driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("PWM_LPSS"); From 112f5e0917cff2af35ada29e7db0b4d05bca7941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 23 Jan 2025 11:11:11 +0100 Subject: [PATCH 04/20] pwm: lpss: Actually use a module namespace by defining the namespace earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DEFAULT_SYMBOL_NAMESPACE must be already defined when is included. So move the define above the include block. With the DEFAULT_SYMBOL_NAMESPACE being defined too late, the exported symbols end up in the default namespace. So the respective modules can use the symbols defined in pwm-lpss.c just fine and up to now just imported the PWM_LPSS namespace without any gain. Signed-off-by: Uwe Kleine-König Signed-off-by: Andy Shevchenko --- drivers/pwm/pwm-lpss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 3b99feb3bb49..e3c72ed7fff1 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -10,6 +10,8 @@ * Author: Alan Cox */ +#define DEFAULT_SYMBOL_NAMESPACE "PWM_LPSS" + #include #include #include @@ -19,8 +21,6 @@ #include #include -#define DEFAULT_SYMBOL_NAMESPACE "PWM_LPSS" - #include "pwm-lpss.h" #define PWM 0x00000000 From a1e062ab4a1f19bb0e94093ef90ab9a74f1f7744 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Feb 2025 19:01:00 +0200 Subject: [PATCH 05/20] MAINTAINERS: Add pin control and GPIO to the Intel MID record Intel MID record is not listed all related files. Add to there pin control and GPIO drivers along with HSU (High Speed UART) and HSU DMA. Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 896a307fa065..f6b806993b4f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11846,12 +11846,19 @@ S: Supported F: arch/x86/include/asm/intel-mid.h F: arch/x86/pci/intel_mid_pci.c F: arch/x86/platform/intel-mid/ +F: drivers/dma/hsu/ F: drivers/extcon/extcon-intel-mrfld.c +F: drivers/gpio/gpio-merrifield.c +F: drivers/gpio/gpio-tangier.* F: drivers/iio/adc/intel_mrfld_adc.c F: drivers/mfd/intel_soc_pmic_mrfld.c +F: drivers/pinctrl/intel/pinctrl-merrifield.c +F: drivers/pinctrl/intel/pinctrl-moorefield.c +F: drivers/pinctrl/intel/pinctrl-tangier.* F: drivers/platform/x86/intel/mrfld_pwrbtn.c F: drivers/platform/x86/intel_scu_* F: drivers/staging/media/atomisp/ +F: drivers/tty/serial/8250/8250_mid.c F: drivers/watchdog/intel-mid_wdt.c F: include/linux/mfd/intel_soc_pmic_mrfld.h F: include/linux/platform_data/x86/intel-mid_wdt.h From 6edf3152bd4c2bc58e3705872642e282d8b3eeb9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Feb 2025 21:44:50 +0200 Subject: [PATCH 06/20] pwm: lpss: Clarify the bypass member semantics in struct pwm_lpss_boardinfo Instead of an odd comment, cite the documentation, which says more clearly what's going on with the programming flow on some of the Intel SoCs. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg --- include/linux/platform_data/x86/pwm-lpss.h | 33 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/include/linux/platform_data/x86/pwm-lpss.h b/include/linux/platform_data/x86/pwm-lpss.h index 752c06b47cc8..f0349edb47f4 100644 --- a/include/linux/platform_data/x86/pwm-lpss.h +++ b/include/linux/platform_data/x86/pwm-lpss.h @@ -15,9 +15,36 @@ struct pwm_lpss_boardinfo { unsigned int npwm; unsigned long base_unit_bits; /* - * Some versions of the IP may stuck in the state machine if enable - * bit is not set, and hence update bit will show busy status till - * the reset. For the rest it may be otherwise. + * NOTE: + * Intel Broxton, Apollo Lake, and Gemini Lake have different programming flow. + * + * Initial Enable or First Activation + * 1. Program the base unit and on time divisor values. + * 2. Set the software update bit. + * 3. Poll in a loop on the PWMCTRL bit until software update bit is cleared.+ + * 4. Enable the PWM output by setting PWM Enable. + * 5. Repeat the above steps for the next PWM Module. + * + * Dynamic update while PWM is Enabled + * 1. Program the base unit and on-time divisor values. + * 2. Set the software update bit. + * 3. Repeat the above steps for the next PWM module. + * + * + After setting PWMCTRL register's SW update bit, hardware automatically + * deasserts the SW update bit after a brief delay. It was observed that + * setting of PWM enable is typically done via read-modify-write of the PWMCTRL + * register. If there is no/little delay between setting software update bit + * and setting enable bit via read-modify-write, it is possible that the read + * could return with software enable as 1. In that case, the last write to set + * enable to 1 could also set sw_update to 1. If this happens, sw_update gets + * stuck and the driver code can hang as it explicitly waits for sw_update bit + * to be 0 after setting the enable bit to 1. To avoid this race condition, + * SW should poll on the software update bit to make sure that it is 0 before + * doing the read-modify-write to set the enable bit to 1. + * + * Also, we noted that if sw_update bit was set in step #1 above then when it + * is set again in step #2, sw_update bit never gets cleared and the flow hangs. + * As such, we need to make sure that sw_update bit is 0 when doing step #1. */ bool bypass; /* From 0eee258cdf172763502f142d85e967f27a573be0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Feb 2025 21:44:51 +0200 Subject: [PATCH 07/20] pinctrl: intel: Fix wrong bypass assignment in intel_pinctrl_probe_pwm() When instantiating PWM, the bypass should be set to false. The field is used for the selected Intel SoCs that do not have PWM feature enabled in their pin control IPs. Fixes: eb78d3604d6b ("pinctrl: intel: Enumerate PWM device when community has a capability") Reported-by: Alexis GUILLEMET Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Tested-by: Alexis GUILLEMET --- drivers/pinctrl/intel/pinctrl-intel.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index d593ad03f949..e4de88e10d68 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1543,7 +1543,6 @@ static int intel_pinctrl_probe_pwm(struct intel_pinctrl *pctrl, .clk_rate = 19200000, .npwm = 1, .base_unit_bits = 22, - .bypass = true, }; struct pwm_chip *chip; From 18311a766c587fc69b1806f1d5943305903b7e6e Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:02 +0530 Subject: [PATCH 08/20] err.h: move IOMEM_ERR_PTR() to err.h Since IOMEM_ERR_PTR() macro deals with an error pointer, a better place for it is err.h. This helps avoid dependency on io.h for the users that don't need it. Suggested-by: Andy Shevchenko Signed-off-by: Raag Jadav Acked-by: Arnd Bergmann Signed-off-by: Andy Shevchenko --- include/linux/err.h | 3 +++ include/linux/io.h | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/err.h b/include/linux/err.h index a4dacd745fcf..1d60aa86db53 100644 --- a/include/linux/err.h +++ b/include/linux/err.h @@ -44,6 +44,9 @@ static inline void * __must_check ERR_PTR(long error) /* Return the pointer in the percpu address space. */ #define ERR_PTR_PCPU(error) ((void __percpu *)(unsigned long)ERR_PTR(error)) +/* Cast an error pointer to __iomem. */ +#define IOMEM_ERR_PTR(error) (__force void __iomem *)ERR_PTR(error) + /** * PTR_ERR - Extract the error code from an error pointer. * @ptr: An error pointer. diff --git a/include/linux/io.h b/include/linux/io.h index 59ec5eea696c..40cb2de73f5e 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -65,8 +65,6 @@ static inline void devm_ioport_unmap(struct device *dev, void __iomem *addr) } #endif -#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err) - void __iomem *devm_ioremap(struct device *dev, resource_size_t offset, resource_size_t size); void __iomem *devm_ioremap_uc(struct device *dev, resource_size_t offset, From a21cad9312767d26b5257ce0662699bb202cdda1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 12 Feb 2025 11:55:03 +0530 Subject: [PATCH 09/20] driver core: Split devres APIs to device/devres.h device.h is a huge header which is hard to follow and easy to miss something. Improve that by splitting devres APIs to device/devres.h. In particular this helps to speedup the build of the code that includes device.h solely for a devres APIs. While at it, cast the error pointers to __iomem using IOMEM_ERR_PTR() and fix sparse warnings. Signed-off-by: Raag Jadav Acked-by: Arnd Bergmann Reviewed-by: Greg Kroah-Hartman Signed-off-by: Andy Shevchenko --- include/linux/device.h | 119 +------------------------------- include/linux/device/devres.h | 124 ++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 118 deletions(-) create mode 100644 include/linux/device/devres.h diff --git a/include/linux/device.h b/include/linux/device.h index 80a5b3268986..78ca7fd0e625 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -26,9 +26,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -281,123 +281,6 @@ int __must_check device_create_bin_file(struct device *dev, void device_remove_bin_file(struct device *dev, const struct bin_attribute *attr); -/* device resource management */ -typedef void (*dr_release_t)(struct device *dev, void *res); -typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data); - -void *__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, - int nid, const char *name) __malloc; -#define devres_alloc(release, size, gfp) \ - __devres_alloc_node(release, size, gfp, NUMA_NO_NODE, #release) -#define devres_alloc_node(release, size, gfp, nid) \ - __devres_alloc_node(release, size, gfp, nid, #release) - -void devres_for_each_res(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data, - void (*fn)(struct device *, void *, void *), - void *data); -void devres_free(void *res); -void devres_add(struct device *dev, void *res); -void *devres_find(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); -void *devres_get(struct device *dev, void *new_res, - dr_match_t match, void *match_data); -void *devres_remove(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); -int devres_destroy(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); -int devres_release(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); - -/* devres group */ -void * __must_check devres_open_group(struct device *dev, void *id, gfp_t gfp); -void devres_close_group(struct device *dev, void *id); -void devres_remove_group(struct device *dev, void *id); -int devres_release_group(struct device *dev, void *id); - -/* managed devm_k.alloc/kfree for device drivers */ -void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) __alloc_size(2); -void *devm_krealloc(struct device *dev, void *ptr, size_t size, - gfp_t gfp) __must_check __realloc_size(3); -__printf(3, 0) char *devm_kvasprintf(struct device *dev, gfp_t gfp, - const char *fmt, va_list ap) __malloc; -__printf(3, 4) char *devm_kasprintf(struct device *dev, gfp_t gfp, - const char *fmt, ...) __malloc; -static inline void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) -{ - return devm_kmalloc(dev, size, gfp | __GFP_ZERO); -} -static inline void *devm_kmalloc_array(struct device *dev, - size_t n, size_t size, gfp_t flags) -{ - size_t bytes; - - if (unlikely(check_mul_overflow(n, size, &bytes))) - return NULL; - - return devm_kmalloc(dev, bytes, flags); -} -static inline void *devm_kcalloc(struct device *dev, - size_t n, size_t size, gfp_t flags) -{ - return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO); -} -static inline __realloc_size(3, 4) void * __must_check -devm_krealloc_array(struct device *dev, void *p, size_t new_n, size_t new_size, gfp_t flags) -{ - size_t bytes; - - if (unlikely(check_mul_overflow(new_n, new_size, &bytes))) - return NULL; - - return devm_krealloc(dev, p, bytes, flags); -} - -void devm_kfree(struct device *dev, const void *p); -char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc; -const char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp); -void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp) - __realloc_size(3); - -unsigned long devm_get_free_pages(struct device *dev, - gfp_t gfp_mask, unsigned int order); -void devm_free_pages(struct device *dev, unsigned long addr); - -#ifdef CONFIG_HAS_IOMEM -void __iomem *devm_ioremap_resource(struct device *dev, - const struct resource *res); -void __iomem *devm_ioremap_resource_wc(struct device *dev, - const struct resource *res); - -void __iomem *devm_of_iomap(struct device *dev, - struct device_node *node, int index, - resource_size_t *size); -#else - -static inline -void __iomem *devm_ioremap_resource(struct device *dev, - const struct resource *res) -{ - return ERR_PTR(-EINVAL); -} - -static inline -void __iomem *devm_ioremap_resource_wc(struct device *dev, - const struct resource *res) -{ - return ERR_PTR(-EINVAL); -} - -static inline -void __iomem *devm_of_iomap(struct device *dev, - struct device_node *node, int index, - resource_size_t *size) -{ - return ERR_PTR(-EINVAL); -} - -#endif - /* allows to add/remove a custom action to devres stack */ int devm_remove_action_nowarn(struct device *dev, void (*action)(void *), void *data); diff --git a/include/linux/device/devres.h b/include/linux/device/devres.h new file mode 100644 index 000000000000..6b0b265058bc --- /dev/null +++ b/include/linux/device/devres.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _DEVICE_DEVRES_H_ +#define _DEVICE_DEVRES_H_ + +#include +#include +#include +#include +#include +#include + +struct device; +struct device_node; +struct resource; + +/* device resource management */ +typedef void (*dr_release_t)(struct device *dev, void *res); +typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data); + +void * __malloc +__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid, const char *name); +#define devres_alloc(release, size, gfp) \ + __devres_alloc_node(release, size, gfp, NUMA_NO_NODE, #release) +#define devres_alloc_node(release, size, gfp, nid) \ + __devres_alloc_node(release, size, gfp, nid, #release) + +void devres_for_each_res(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data, + void (*fn)(struct device *, void *, void *), + void *data); +void devres_free(void *res); +void devres_add(struct device *dev, void *res); +void *devres_find(struct device *dev, dr_release_t release, dr_match_t match, void *match_data); +void *devres_get(struct device *dev, void *new_res, dr_match_t match, void *match_data); +void *devres_remove(struct device *dev, dr_release_t release, dr_match_t match, void *match_data); +int devres_destroy(struct device *dev, dr_release_t release, dr_match_t match, void *match_data); +int devres_release(struct device *dev, dr_release_t release, dr_match_t match, void *match_data); + +/* devres group */ +void * __must_check devres_open_group(struct device *dev, void *id, gfp_t gfp); +void devres_close_group(struct device *dev, void *id); +void devres_remove_group(struct device *dev, void *id); +int devres_release_group(struct device *dev, void *id); + +/* managed devm_k.alloc/kfree for device drivers */ +void * __alloc_size(2) +devm_kmalloc(struct device *dev, size_t size, gfp_t gfp); +void * __must_check __realloc_size(3) +devm_krealloc(struct device *dev, void *ptr, size_t size, gfp_t gfp); +static inline void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) +{ + return devm_kmalloc(dev, size, gfp | __GFP_ZERO); +} +static inline void *devm_kmalloc_array(struct device *dev, size_t n, size_t size, gfp_t flags) +{ + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) + return NULL; + + return devm_kmalloc(dev, bytes, flags); +} +static inline void *devm_kcalloc(struct device *dev, size_t n, size_t size, gfp_t flags) +{ + return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO); +} +static inline __realloc_size(3, 4) void * __must_check +devm_krealloc_array(struct device *dev, void *p, size_t new_n, size_t new_size, gfp_t flags) +{ + size_t bytes; + + if (unlikely(check_mul_overflow(new_n, new_size, &bytes))) + return NULL; + + return devm_krealloc(dev, p, bytes, flags); +} + +void devm_kfree(struct device *dev, const void *p); + +void * __realloc_size(3) +devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp); + +char * __malloc +devm_kstrdup(struct device *dev, const char *s, gfp_t gfp); +const char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp); +char * __printf(3, 0) __malloc +devm_kvasprintf(struct device *dev, gfp_t gfp, const char *fmt, va_list ap); +char * __printf(3, 4) __malloc +devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...); + +unsigned long devm_get_free_pages(struct device *dev, gfp_t gfp_mask, unsigned int order); +void devm_free_pages(struct device *dev, unsigned long addr); + +#ifdef CONFIG_HAS_IOMEM + +void __iomem *devm_ioremap_resource(struct device *dev, const struct resource *res); +void __iomem *devm_ioremap_resource_wc(struct device *dev, const struct resource *res); + +void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index, + resource_size_t *size); +#else + +static inline +void __iomem *devm_ioremap_resource(struct device *dev, const struct resource *res) +{ + return IOMEM_ERR_PTR(-EINVAL); +} + +static inline +void __iomem *devm_ioremap_resource_wc(struct device *dev, const struct resource *res) +{ + return IOMEM_ERR_PTR(-EINVAL); +} + +static inline +void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index, + resource_size_t *size) +{ + return IOMEM_ERR_PTR(-EINVAL); +} + +#endif + +#endif /* _DEVICE_DEVRES_H_ */ From 99e297cdd338b8a18c986ed4e088676579b7fe96 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 12 Feb 2025 11:55:04 +0530 Subject: [PATCH 10/20] iio: imu: st_lsm9ds0: Replace device.h with what is needed Instead of including a huge device.h with tons of dependencies include only what driver actually uses. Acked-by: Jonathan Cameron Signed-off-by: Andy Shevchenko --- drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c | 2 +- drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c index 0732cfa258c4..8cc071463249 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -7,7 +7,7 @@ * Author: Andy Shevchenko */ -#include +#include #include #include #include diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c index 43ec57c1e604..806e55f75f65 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -7,7 +7,7 @@ * Author: Andy Shevchenko */ -#include +#include #include #include #include From a103b833ac3806b816bc993cba77d0b17cf801f1 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:05 +0530 Subject: [PATCH 11/20] devres: Introduce devm_kmemdup_array() Introduce '_array' variant of devm_kmemdup() which is more robust and consistent with alloc family of helpers. Suggested-by: Andy Shevchenko Signed-off-by: Raag Jadav Reviewed-by: Dmitry Torokhov Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- include/linux/device/devres.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/device/devres.h b/include/linux/device/devres.h index 6b0b265058bc..9b49f9915850 100644 --- a/include/linux/device/devres.h +++ b/include/linux/device/devres.h @@ -79,6 +79,11 @@ void devm_kfree(struct device *dev, const void *p); void * __realloc_size(3) devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp); +static inline void *devm_kmemdup_array(struct device *dev, const void *src, + size_t n, size_t size, gfp_t flags) +{ + return devm_kmemdup(dev, src, size_mul(size, n), flags); +} char * __malloc devm_kstrdup(struct device *dev, const char *s, gfp_t gfp); From 753764aa8eb52f54d8d1f42158595bfc16f0e748 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:06 +0530 Subject: [PATCH 12/20] pinctrl: intel: copy communities using devm_kmemdup_array() Copy communities using devm_kmemdup_array() instead of doing it manually. Signed-off-by: Raag Jadav Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-intel.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 527e4b87ae52..33cb918ed806 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1577,8 +1577,8 @@ int intel_pinctrl_probe(struct platform_device *pdev, * to the registers. */ pctrl->ncommunities = pctrl->soc->ncommunities; - pctrl->communities = devm_kcalloc(dev, pctrl->ncommunities, - sizeof(*pctrl->communities), GFP_KERNEL); + pctrl->communities = devm_kmemdup_array(dev, pctrl->soc->communities, pctrl->ncommunities, + sizeof(*pctrl->soc->communities), GFP_KERNEL); if (!pctrl->communities) return -ENOMEM; @@ -1588,8 +1588,6 @@ int intel_pinctrl_probe(struct platform_device *pdev, u32 offset; u32 value; - *community = pctrl->soc->communities[i]; - regs = devm_platform_ioremap_resource(pdev, community->barno); if (IS_ERR(regs)) return PTR_ERR(regs); From f192c8447f4ea0d6d35e17c599348f24ab264372 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:07 +0530 Subject: [PATCH 13/20] pinctrl: baytrail: copy communities using devm_kmemdup_array() Copy communities using devm_kmemdup_array() instead of doing it manually. Signed-off-by: Raag Jadav Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-baytrail.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 7340dc20349c..c856a2065a1f 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -1557,16 +1557,14 @@ static int byt_set_soc_data(struct intel_pinctrl *vg, vg->soc = soc; vg->ncommunities = vg->soc->ncommunities; - vg->communities = devm_kcalloc(vg->dev, vg->ncommunities, - sizeof(*vg->communities), GFP_KERNEL); + vg->communities = devm_kmemdup_array(vg->dev, vg->soc->communities, vg->ncommunities, + sizeof(*vg->soc->communities), GFP_KERNEL); if (!vg->communities) return -ENOMEM; for (i = 0; i < vg->soc->ncommunities; i++) { struct intel_community *comm = vg->communities + i; - *comm = vg->soc->communities[i]; - comm->pad_regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(comm->pad_regs)) return PTR_ERR(comm->pad_regs); From d795fb90d6c63ef3182b49c766a6fef75b4f790d Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:08 +0530 Subject: [PATCH 14/20] pinctrl: cherryview: use devm_kmemdup_array() Convert to use devm_kmemdup_array() and while at it, use source size instead of destination. Signed-off-by: Raag Jadav Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-cherryview.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index c673e262e1db..69b18ce0f685 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1631,9 +1631,8 @@ static int chv_pinctrl_probe(struct platform_device *pdev) pctrl->soc = soc_data; pctrl->ncommunities = pctrl->soc->ncommunities; - pctrl->communities = devm_kmemdup(dev, pctrl->soc->communities, - pctrl->ncommunities * sizeof(*pctrl->communities), - GFP_KERNEL); + pctrl->communities = devm_kmemdup_array(dev, pctrl->soc->communities, pctrl->ncommunities, + sizeof(*pctrl->soc->communities), GFP_KERNEL); if (!pctrl->communities) return -ENOMEM; From 91bfcc7a2fdb5f7833fa8f2a1919eaef0e6a98dd Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:09 +0530 Subject: [PATCH 15/20] pinctrl: tangier: use devm_kmemdup_array() Convert to use devm_kmemdup_array() and while at it, use source size instead of destination. Signed-off-by: Raag Jadav Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-tangier.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-tangier.c b/drivers/pinctrl/intel/pinctrl-tangier.c index d3baf0f4eea0..ac61e632b487 100644 --- a/drivers/pinctrl/intel/pinctrl-tangier.c +++ b/drivers/pinctrl/intel/pinctrl-tangier.c @@ -524,7 +524,6 @@ static int tng_pinctrl_probe(struct platform_device *pdev, struct device *dev = &pdev->dev; struct tng_family *families; struct tng_pinctrl *tp; - size_t families_len; void __iomem *regs; unsigned int i; @@ -543,8 +542,8 @@ static int tng_pinctrl_probe(struct platform_device *pdev, * Make a copy of the families which we can use to hold pointers * to the registers. */ - families_len = size_mul(sizeof(*families), tp->nfamilies); - families = devm_kmemdup(dev, tp->families, families_len, GFP_KERNEL); + families = devm_kmemdup_array(dev, tp->families, tp->nfamilies, + sizeof(*tp->families), GFP_KERNEL); if (!families) return -ENOMEM; From 86068aca754880715960a218410749b929c037bd Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:10 +0530 Subject: [PATCH 16/20] pinctrl: pxa2xx: use devm_kmemdup_array() Convert to use devm_kmemdup_array() which is more robust. Signed-off-by: Raag Jadav Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/pinctrl/pxa/pinctrl-pxa2xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c index 9e34b92ff5f2..9fd7a8fb2bc4 100644 --- a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c +++ b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c @@ -281,9 +281,8 @@ static int pxa2xx_build_functions(struct pxa_pinctrl *pctl) for (df = pctl->ppins[i].functions; df->name; df++) if (!pxa2xx_find_function(pctl, df->name, functions)) (functions + pctl->nfuncs++)->name = df->name; - pctl->functions = devm_kmemdup(pctl->dev, functions, - pctl->nfuncs * sizeof(*functions), - GFP_KERNEL); + pctl->functions = devm_kmemdup_array(pctl->dev, functions, pctl->nfuncs, + sizeof(*functions), GFP_KERNEL); if (!pctl->functions) return -ENOMEM; @@ -314,7 +313,8 @@ static int pxa2xx_build_groups(struct pxa_pinctrl *pctl) pctl->ppins[j].pin.name; func = pctl->functions + i; func->ngroups = ngroups; - func->groups = devm_kmemdup(pctl->dev, gtmp, ngroups * sizeof(*gtmp), GFP_KERNEL); + func->groups = devm_kmemdup_array(pctl->dev, gtmp, ngroups, + sizeof(*gtmp), GFP_KERNEL); if (!func->groups) return -ENOMEM; } From a0d78eec88395e67117a3453f55a4fc3c7265cf2 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:11 +0530 Subject: [PATCH 17/20] iio: adc: xilinx-xadc-core: use devm_kmemdup_array() Convert to use devm_kmemdup_array() and while at it, use source size instead of destination. Signed-off-by: Raag Jadav Acked-by: Jonathan Cameron Signed-off-by: Andy Shevchenko --- drivers/iio/adc/xilinx-xadc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index cfbfcaefec0f..e1f8740ae688 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1245,8 +1245,8 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, unsigned int *conf, int irq) channel_templates = xadc_us_channels; max_channels = ARRAY_SIZE(xadc_us_channels); } - channels = devm_kmemdup(dev, channel_templates, - sizeof(channels[0]) * max_channels, GFP_KERNEL); + channels = devm_kmemdup_array(dev, channel_templates, max_channels, + sizeof(*channel_templates), GFP_KERNEL); if (!channels) return -ENOMEM; From cdcc09a495a4fa60f1c612db207d78b82b6c4531 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:12 +0530 Subject: [PATCH 18/20] input: sparse-keymap: use devm_kmemdup_array() Convert to use devm_kmemdup_array() and while at it, use source size instead of destination. Signed-off-by: Raag Jadav Acked-by: Dmitry Torokhov Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/input/sparse-keymap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 25bf8be6e711..96f23ae57d5a 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -176,8 +176,7 @@ int sparse_keymap_setup(struct input_dev *dev, for (e = keymap; e->type != KE_END; e++) map_size++; - map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map), - GFP_KERNEL); + map = devm_kmemdup_array(&dev->dev, keymap, map_size, sizeof(*keymap), GFP_KERNEL); if (!map) return -ENOMEM; From b8c38ccb2ca52b9a38cfeb9f89abab5d6e713221 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:13 +0530 Subject: [PATCH 19/20] input: ipaq-micro-keys: use devm_kmemdup_array() Convert to use devm_kmemdup_array() which is more robust. Signed-off-by: Raag Jadav Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/input/keyboard/ipaq-micro-keys.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c index 58631bf7ce55..ca7ec054b1ce 100644 --- a/drivers/input/keyboard/ipaq-micro-keys.c +++ b/drivers/input/keyboard/ipaq-micro-keys.c @@ -102,9 +102,8 @@ static int micro_key_probe(struct platform_device *pdev) keys->input->keycodesize = sizeof(micro_keycodes[0]); keys->input->keycodemax = ARRAY_SIZE(micro_keycodes); - keys->codes = devm_kmemdup(&pdev->dev, micro_keycodes, - keys->input->keycodesize * keys->input->keycodemax, - GFP_KERNEL); + keys->codes = devm_kmemdup_array(&pdev->dev, micro_keycodes, keys->input->keycodemax, + keys->input->keycodesize, GFP_KERNEL); if (!keys->codes) return -ENOMEM; From 0ee2261d08aa21a7327f145cbf1bfb6ac2205c7d Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Mon, 3 Mar 2025 19:25:06 +0530 Subject: [PATCH 20/20] pinctrl: intel: drop repeated config dependency We already have ACPI dependency for Intel pinctrl menu. No need to repeat it. Signed-off-by: Raag Jadav Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig index 14c26c023590..248c2e558ff3 100644 --- a/drivers/pinctrl/intel/Kconfig +++ b/drivers/pinctrl/intel/Kconfig @@ -39,7 +39,6 @@ config PINCTRL_INTEL config PINCTRL_INTEL_PLATFORM tristate "Intel pinctrl and GPIO platform driver" - depends on ACPI select PINCTRL_INTEL help This pinctrl driver provides an interface that allows configuring @@ -141,7 +140,6 @@ config PINCTRL_METEORLAKE config PINCTRL_METEORPOINT tristate "Intel Meteor Point pinctrl and GPIO driver" - depends on ACPI select PINCTRL_INTEL help Meteor Point is the PCH of Intel Meteor Lake. This pinctrl driver