* [PATCH v3 1/2] dt-bindings: mfd: mxs-lradc: Fix interrupt order
@ 2026-11-13 1:32 Fabio Estevam
2026-11-13 1:32 ` [PATCH v3 2/2] mfd: mxs-lradc: Pass parent IRQs to child drivers Fabio Estevam
0 siblings, 1 reply; 3+ messages in thread
From: Fabio Estevam @ 2026-11-13 1:32 UTC (permalink / raw)
To: lee
Cc: maz, andy, jic23, dmitry.torokhov, linux-input, mfd, linux-iio,
robh, krzk+dt, conor+dt, devicetree, imx, Fabio Estevam,
Krzysztof Kozlowski
The interrupt descriptions added during the conversion to YAML do not
match the ICOLL source numbers used by the existing DTS files.
For i.MX23, Table 5-1 of the reference manual maps source 36 to touch
detection and sources 37 through 44 to channels 0 through 7. imx23.dtsi
lists these sources in that order.
For i.MX28, Table 5-1 maps source 10 to touch detection, sources 14 and
15 to the threshold interrupts, sources 16 through 23 to channels 0
through 7, and sources 24 and 25 to buttons 0 and 1. imx28.dtsi also
lists these sources in that order.
Reorder the schema descriptions to match the hardware documentation and
the existing DT ABI.
Fixes: 009528b5aa13 ("dt-bindings: mfd: convert mxs-lradc bindings to json-schema")
Signed-off-by: Fabio Estevam <festevam@gmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Changes since v2:
- None. Only collected Krzysztof's tag.
Documentation/devicetree/bindings/mfd/mxs-lradc.yaml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/mfd/mxs-lradc.yaml b/Documentation/devicetree/bindings/mfd/mxs-lradc.yaml
index 782b2f4005a0..755029880677 100644
--- a/Documentation/devicetree/bindings/mfd/mxs-lradc.yaml
+++ b/Documentation/devicetree/bindings/mfd/mxs-lradc.yaml
@@ -87,13 +87,13 @@ then:
properties:
interrupts:
items:
+ - description: touchscreen
- description: channel 0
- description: channel 1
- description: channel 2
- description: channel 3
- description: channel 4
- description: channel 5
- - description: touchscreen
- description: channel 6
- description: channel 7
fsl,lradc-touchscreen-wires:
@@ -102,6 +102,7 @@ else:
properties:
interrupts:
items:
+ - description: touchscreen
- description: threshold 0
- description: threshold 1
- description: channel 0
@@ -110,11 +111,10 @@ else:
- description: channel 3
- description: channel 4
- description: channel 5
- - description: button 0
- - description: button 1
- - description: touchscreen
- description: channel 6
- description: channel 7
+ - description: button 0
+ - description: button 1
additionalProperties: false
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v3 2/2] mfd: mxs-lradc: Pass parent IRQs to child drivers
2026-11-13 1:32 [PATCH v3 1/2] dt-bindings: mfd: mxs-lradc: Fix interrupt order Fabio Estevam
@ 2026-11-13 1:32 ` Fabio Estevam
2026-11-13 1:56 ` sashiko-bot
0 siblings, 1 reply; 3+ messages in thread
From: Fabio Estevam @ 2026-11-13 1:32 UTC (permalink / raw)
To: lee
Cc: maz, andy, jic23, dmitry.torokhov, linux-input, mfd, linux-iio,
robh, krzk+dt, conor+dt, devicetree, imx, Fabio Estevam, stable
The MFD driver stores raw DT interrupt indices in IRQ resources but
registers its child devices without an IRQ domain or IRQ base. The child
drivers consequently receive the indices as if they were mapped Linux
IRQ numbers. IRQ index 0 triggers the platform_get_irq_byname() warning:
0 is an invalid IRQ number
The children then try to recover the indices from their resources and
map them against the parent OF node. Besides duplicating IRQ names in
the parent and children, this relies on invalid platform IRQ resources
and fails when IRQ 0 is rejected.
Resolve the interrupts with platform_get_irq() in the MFD parent and
store the mapped IRQs in the shared LRADC data. Drop the child IRQ
resources and duplicated name arrays, and have both child drivers
request the mapped IRQs directly. Use the MFD memory base support to
translate a single relative memory resource shared by both cells.
Tested on an i.MX28 EVK. The mxs-lradc-ts driver probes successfully,
touch events are reported, and the touch-detect and LRADC channel 7
interrupt counters increase as expected.
Cc: stable@vger.kernel.org
Suggested-by: Lee Jones <lee@kernel.org>
Closes: https://lore.kernel.org/linux-input/CAOMZO5CgTzo6GuXptD4mFTN=UsJJqpkixDW1Q64gqZGrij8+uQ@mail.gmail.com/
Fixes: a85a6c86c25b ("driver core: platform: Clarify that IRQ 0 is invalid")
Signed-off-by: Fabio Estevam <festevam@gmail.com>
---
Changes since v2:
- Use reversed Christmas tree. (Andy)
- Check the return value of device_get_match_data() (Andy)
This is a long-standing bug that I reported in 2020:
https://lore.kernel.org/linux-input/CAOMZO5CgTzo6GuXptD4mFTN=UsJJqpkixDW1Q64gqZGrij8+uQ@mail.gmail.com/
This patch touches MFD, IIO, and Input. Since the IRQ mapping is moved
into the MFD parent, I suggest merging it through the MFD tree, with
acks from the IIO and Input maintainers.
The full backtrace:
[ 10.540505] WARNING: drivers/base/platform.c:492 at __platform_get_irq_byname+0xb4/0xcc, CPU#0: swapper/0/1
[ 10.555516] 0 is an invalid IRQ number
[ 10.559627] Modules linked in:
[ 10.562849] CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 7.3.0-rc7-next-20261016-00003-g36062817a968 #17 VOLUNTARY
[ 10.573732] Hardware name: Freescale MXS (Device Tree)
[ 10.578934] Call trace:
[ 10.578992] unwind_backtrace from show_stack+0x10/0x14
[ 10.586955] show_stack from dump_stack_lvl+0x48/0x64
[ 10.592170] dump_stack_lvl from __warn+0x8c/0x190
[ 10.597114] __warn from warn_slowpath_fmt+0x94/0xcc
[ 10.602232] warn_slowpath_fmt from __platform_get_irq_byname+0xb4/0xcc
[ 10.609027] __platform_get_irq_byname from platform_get_irq_byname+0x10/0x30
[ 10.616337] platform_get_irq_byname from mxs_lradc_ts_probe+0x18c/0x378
[ 10.623247] mxs_lradc_ts_probe from platform_probe+0x58/0x90
[ 10.629174] platform_probe from really_probe+0xc4/0x2cc
[ 10.634649] really_probe from __driver_probe_device+0xa0/0x1e0
[ 10.640721] __driver_probe_device from driver_probe_device+0x30/0xc0
[ 10.647315] driver_probe_device from __driver_attach+0x94/0x158
[ 10.653466] __driver_attach from bus_for_each_dev+0x7c/0xd0
[ 10.659280] bus_for_each_dev from bus_add_driver+0x158/0x1fc
[ 10.665169] bus_add_driver from driver_register+0x7c/0x114
[ 10.670901] driver_register from do_one_initcall+0x60/0x294
[ 10.676721] do_one_initcall from kernel_init_freeable+0x19c/0x24c
[ 10.683073] kernel_init_freeable from kernel_init+0x14/0x10c
[ 10.688997] kernel_init from ret_from_fork+0x14/0x38
[ 10.694200] Exception stack(0xc8819fb0 to 0xc8819ff8)
[ 10.699335] 9fa0: 00000000 00000000 00000000 00000000
[ 10.707591] 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 10.715843] 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
[ 10.723117] irq event stamp: 146363
[ 10.726729] hardirqs last enabled at (146367): [<c00adbd8>] __nbcon_atomic_flush_pending_con+0x120/0x1c0
[ 10.736770] hardirqs last disabled at (146372): [<c0008f38>] __irq_svc+0x58/0xb0
[ 10.744618] softirqs last enabled at (146362): [<c0032c20>] __irq_exit_rcu+0x148/0x1d4
[ 10.753153] softirqs last disabled at (146385): [<c0032c20>] __irq_exit_rcu+0x148/0x1d4
[ 10.761603] ---[ end trace 0000000000000000 ]---
[ 10.766374] mxs-lradc-ts mxs-lradc-ts: error -EINVAL: IRQ mxs-lradc-touchscreen not found
[ 10.766456] mxs-lradc-ts mxs-lradc-ts: probe with driver mxs-lradc-ts failed with error -22
drivers/iio/adc/mxs-lradc-adc.c | 43 +-----
drivers/input/touchscreen/mxs-lradc-ts.c | 30 ++--
drivers/mfd/mxs-lradc.c | 175 ++++++++++++-----------
include/linux/mfd/mxs-lradc.h | 10 ++
4 files changed, 113 insertions(+), 145 deletions(-)
diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c
index dda5182a5076..1222997649f4 100644
--- a/drivers/iio/adc/mxs-lradc-adc.c
+++ b/drivers/iio/adc/mxs-lradc-adc.c
@@ -17,7 +17,6 @@
#include <linux/mfd/core.h>
#include <linux/mfd/mxs-lradc.h>
#include <linux/module.h>
-#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/sysfs.h>
@@ -39,28 +38,6 @@
#define VREF_MV_BASE 1850
-static const char *mx23_lradc_adc_irq_names[] = {
- "mxs-lradc-channel0",
- "mxs-lradc-channel1",
- "mxs-lradc-channel2",
- "mxs-lradc-channel3",
- "mxs-lradc-channel4",
- "mxs-lradc-channel5",
-};
-
-static const char *mx28_lradc_adc_irq_names[] = {
- "mxs-lradc-thresh0",
- "mxs-lradc-thresh1",
- "mxs-lradc-channel0",
- "mxs-lradc-channel1",
- "mxs-lradc-channel2",
- "mxs-lradc-channel3",
- "mxs-lradc-channel4",
- "mxs-lradc-channel5",
- "mxs-lradc-button0",
- "mxs-lradc-button1",
-};
-
static const u32 mxs_lradc_adc_vref_mv[][LRADC_MAX_TOTAL_CHANS] = {
[IMX23_LRADC] = {
VREF_MV_BASE, /* CH0 */
@@ -691,9 +668,8 @@ static int mxs_lradc_adc_probe(struct platform_device *pdev)
struct mxs_lradc_adc *adc;
struct iio_dev *iio;
struct resource *iores;
- int ret, irq, virq, i, s, n;
+ int ret, i, s;
u64 scale_uv;
- const char **irq_name;
/* Allocate the IIO device. */
iio = devm_iio_device_alloc(dev, sizeof(*adc));
@@ -725,28 +701,19 @@ static int mxs_lradc_adc_probe(struct platform_device *pdev)
if (lradc->soc == IMX23_LRADC) {
iio->channels = mx23_lradc_chan_spec;
iio->num_channels = ARRAY_SIZE(mx23_lradc_chan_spec);
- irq_name = mx23_lradc_adc_irq_names;
- n = ARRAY_SIZE(mx23_lradc_adc_irq_names);
} else {
iio->channels = mx28_lradc_chan_spec;
iio->num_channels = ARRAY_SIZE(mx28_lradc_chan_spec);
- irq_name = mx28_lradc_adc_irq_names;
- n = ARRAY_SIZE(mx28_lradc_adc_irq_names);
}
ret = stmp_reset_block(adc->base);
if (ret)
return ret;
- for (i = 0; i < n; i++) {
- irq = platform_get_irq_byname(pdev, irq_name[i]);
- if (irq < 0)
- return irq;
-
- virq = irq_of_parse_and_map(dev->parent->of_node, irq);
-
- ret = devm_request_irq(dev, virq, mxs_lradc_adc_handle_irq,
- 0, irq_name[i], iio);
+ for (i = 0; i < lradc->num_adc_irqs; i++) {
+ ret = devm_request_irq(dev, lradc->adc_irq[i],
+ mxs_lradc_adc_handle_irq, 0,
+ dev_name(dev), iio);
if (ret)
return ret;
}
diff --git a/drivers/input/touchscreen/mxs-lradc-ts.c b/drivers/input/touchscreen/mxs-lradc-ts.c
index 2970d9eb9c2b..c89aaed9eb8d 100644
--- a/drivers/input/touchscreen/mxs-lradc-ts.c
+++ b/drivers/input/touchscreen/mxs-lradc-ts.c
@@ -18,15 +18,8 @@
#include <linux/mfd/core.h>
#include <linux/mfd/mxs-lradc.h>
#include <linux/of.h>
-#include <linux/of_irq.h>
#include <linux/platform_device.h>
-static const char * const mxs_lradc_ts_irq_names[] = {
- "mxs-lradc-touchscreen",
- "mxs-lradc-channel6",
- "mxs-lradc-channel7",
-};
-
/*
* Touchscreen handling
*/
@@ -601,12 +594,12 @@ static int mxs_lradc_ts_register(struct mxs_lradc_ts *ts)
static int mxs_lradc_ts_probe(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct device_node *node = dev->parent->of_node;
- struct mxs_lradc *lradc = dev_get_drvdata(dev->parent);
struct mxs_lradc_ts *ts;
- int ret, irq, virq, i;
+ struct device_node *node = pdev->dev.parent->of_node;
+ struct mxs_lradc *lradc = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
u32 ts_wires = 0, adapt;
+ int ret, i;
ts = devm_kzalloc_obj(dev, *ts);
if (!ts)
@@ -668,19 +661,12 @@ static int mxs_lradc_ts_probe(struct platform_device *pdev)
return ret;
mxs_lradc_ts_hw_init(ts);
+ mxs_lradc_ts_stop(ts);
- for (i = 0; i < 3; i++) {
- irq = platform_get_irq_byname(pdev, mxs_lradc_ts_irq_names[i]);
- if (irq < 0)
- return irq;
-
- virq = irq_of_parse_and_map(node, irq);
-
- mxs_lradc_ts_stop(ts);
-
- ret = devm_request_irq(dev, virq,
+ for (i = 0; i < ARRAY_SIZE(lradc->ts_irq); i++) {
+ ret = devm_request_irq(dev, lradc->ts_irq[i],
mxs_lradc_ts_handle_irq,
- 0, mxs_lradc_ts_irq_names[i], ts);
+ 0, dev_name(dev), ts);
if (ret)
return ret;
}
diff --git a/drivers/mfd/mxs-lradc.c b/drivers/mfd/mxs-lradc.c
index 30a66e268169..d16dfea89207 100644
--- a/drivers/mfd/mxs-lradc.c
+++ b/drivers/mfd/mxs-lradc.c
@@ -18,12 +18,9 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
+#include <linux/sizes.h>
#include <linux/slab.h>
-#define ADC_CELL 0
-#define TSC_CELL 1
-#define RES_MEM 0
-
enum mx23_lradc_irqs {
MX23_LRADC_TS_IRQ = 0,
MX23_LRADC_CH0_IRQ,
@@ -52,84 +49,111 @@ enum mx28_lradc_irqs {
MX28_LRADC_BUTTON1_IRQ,
};
-static struct resource mx23_adc_resources[] = {
- DEFINE_RES_MEM(0x0, 0x0),
- DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH0_IRQ, "mxs-lradc-channel0"),
- DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH1_IRQ, "mxs-lradc-channel1"),
- DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH2_IRQ, "mxs-lradc-channel2"),
- DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH3_IRQ, "mxs-lradc-channel3"),
- DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH4_IRQ, "mxs-lradc-channel4"),
- DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH5_IRQ, "mxs-lradc-channel5"),
+struct mxs_lradc_soc_data {
+ enum mxs_lradc_id soc;
+ unsigned int num_adc_irqs;
+ u8 adc_irq[MXS_LRADC_MAX_ADC_IRQS];
+ u8 ts_irq[MXS_LRADC_NUM_TS_IRQS];
};
-static struct resource mx23_touchscreen_resources[] = {
- DEFINE_RES_MEM(0x0, 0x0),
- DEFINE_RES_IRQ_NAMED(MX23_LRADC_TS_IRQ, "mxs-lradc-touchscreen"),
- DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH6_IRQ, "mxs-lradc-channel6"),
- DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH7_IRQ, "mxs-lradc-channel7"),
+static const struct mxs_lradc_soc_data mx23_lradc_data = {
+ .soc = IMX23_LRADC,
+ .num_adc_irqs = 6,
+ .adc_irq = {
+ MX23_LRADC_CH0_IRQ,
+ MX23_LRADC_CH1_IRQ,
+ MX23_LRADC_CH2_IRQ,
+ MX23_LRADC_CH3_IRQ,
+ MX23_LRADC_CH4_IRQ,
+ MX23_LRADC_CH5_IRQ,
+ },
+ .ts_irq = {
+ MX23_LRADC_TS_IRQ,
+ MX23_LRADC_CH6_IRQ,
+ MX23_LRADC_CH7_IRQ,
+ },
};
-static struct resource mx28_adc_resources[] = {
- DEFINE_RES_MEM(0x0, 0x0),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_TRESH0_IRQ, "mxs-lradc-thresh0"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_TRESH1_IRQ, "mxs-lradc-thresh1"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH0_IRQ, "mxs-lradc-channel0"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH1_IRQ, "mxs-lradc-channel1"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH2_IRQ, "mxs-lradc-channel2"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH3_IRQ, "mxs-lradc-channel3"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH4_IRQ, "mxs-lradc-channel4"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH5_IRQ, "mxs-lradc-channel5"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_BUTTON0_IRQ, "mxs-lradc-button0"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_BUTTON1_IRQ, "mxs-lradc-button1"),
+static const struct mxs_lradc_soc_data mx28_lradc_data = {
+ .soc = IMX28_LRADC,
+ .num_adc_irqs = 10,
+ .adc_irq = {
+ MX28_LRADC_TRESH0_IRQ,
+ MX28_LRADC_TRESH1_IRQ,
+ MX28_LRADC_CH0_IRQ,
+ MX28_LRADC_CH1_IRQ,
+ MX28_LRADC_CH2_IRQ,
+ MX28_LRADC_CH3_IRQ,
+ MX28_LRADC_CH4_IRQ,
+ MX28_LRADC_CH5_IRQ,
+ MX28_LRADC_BUTTON0_IRQ,
+ MX28_LRADC_BUTTON1_IRQ,
+ },
+ .ts_irq = {
+ MX28_LRADC_TS_IRQ,
+ MX28_LRADC_CH6_IRQ,
+ MX28_LRADC_CH7_IRQ,
+ },
};
-static struct resource mx28_touchscreen_resources[] = {
- DEFINE_RES_MEM(0x0, 0x0),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_TS_IRQ, "mxs-lradc-touchscreen"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH6_IRQ, "mxs-lradc-channel6"),
- DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH7_IRQ, "mxs-lradc-channel7"),
+static const struct resource mxs_lradc_resources[] = {
+ DEFINE_RES_MEM(0, SZ_8K),
};
-static struct mfd_cell mx23_cells[] = {
+static const struct mfd_cell mxs_lradc_cells[] = {
{
.name = "mxs-lradc-adc",
- .resources = mx23_adc_resources,
- .num_resources = ARRAY_SIZE(mx23_adc_resources),
+ .resources = mxs_lradc_resources,
+ .num_resources = ARRAY_SIZE(mxs_lradc_resources),
},
{
.name = "mxs-lradc-ts",
- .resources = mx23_touchscreen_resources,
- .num_resources = ARRAY_SIZE(mx23_touchscreen_resources),
- },
-};
-
-static struct mfd_cell mx28_cells[] = {
- {
- .name = "mxs-lradc-adc",
- .resources = mx28_adc_resources,
- .num_resources = ARRAY_SIZE(mx28_adc_resources),
+ .resources = mxs_lradc_resources,
+ .num_resources = ARRAY_SIZE(mxs_lradc_resources),
},
- {
- .name = "mxs-lradc-ts",
- .resources = mx28_touchscreen_resources,
- .num_resources = ARRAY_SIZE(mx28_touchscreen_resources),
- }
};
static const struct of_device_id mxs_lradc_dt_ids[] = {
- { .compatible = "fsl,imx23-lradc", .data = (void *)IMX23_LRADC, },
- { .compatible = "fsl,imx28-lradc", .data = (void *)IMX28_LRADC, },
+ { .compatible = "fsl,imx23-lradc", .data = &mx23_lradc_data, },
+ { .compatible = "fsl,imx28-lradc", .data = &mx28_lradc_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids);
+static int mxs_lradc_get_irqs(struct platform_device *pdev,
+ struct mxs_lradc *lradc,
+ const struct mxs_lradc_soc_data *data)
+{
+ int i, irq;
+
+ for (i = 0; i < data->num_adc_irqs; i++) {
+ irq = platform_get_irq(pdev, data->adc_irq[i]);
+ if (irq < 0)
+ return irq;
+
+ lradc->adc_irq[i] = irq;
+ }
+ lradc->num_adc_irqs = data->num_adc_irqs;
+
+ for (i = 0; i < ARRAY_SIZE(data->ts_irq); i++) {
+ irq = platform_get_irq(pdev, data->ts_irq[i]);
+ if (irq < 0)
+ return irq;
+
+ lradc->ts_irq[i] = irq;
+ }
+
+ return 0;
+}
+
static int mxs_lradc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
+ const struct mxs_lradc_soc_data *data;
struct mxs_lradc *lradc;
- struct mfd_cell *cells = NULL;
struct resource *res;
+ unsigned int num_cells;
int ret = 0;
u32 ts_wires = 0;
@@ -137,7 +161,11 @@ static int mxs_lradc_probe(struct platform_device *pdev)
if (!lradc)
return -ENOMEM;
- lradc->soc = (kernel_ulong_t)device_get_match_data(&pdev->dev);
+ data = device_get_match_data(dev);
+ if (!data)
+ return -ENODATA;
+
+ lradc->soc = data->soc;
lradc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(lradc->clk)) {
@@ -187,38 +215,15 @@ static int mxs_lradc_probe(struct platform_device *pdev)
goto err_clk;
}
- switch (lradc->soc) {
- case IMX23_LRADC:
- mx23_adc_resources[RES_MEM] = *res;
- mx23_touchscreen_resources[RES_MEM] = *res;
- cells = mx23_cells;
- break;
- case IMX28_LRADC:
- mx28_adc_resources[RES_MEM] = *res;
- mx28_touchscreen_resources[RES_MEM] = *res;
- cells = mx28_cells;
- break;
- default:
- dev_err(dev, "Unsupported SoC\n");
- ret = -ENODEV;
+ ret = mxs_lradc_get_irqs(pdev, lradc, data);
+ if (ret)
goto err_clk;
- }
-
- ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
- &cells[ADC_CELL], 1, NULL, 0, NULL);
- if (ret) {
- dev_err(&pdev->dev, "Failed to add the ADC subdevice\n");
- goto err_clk;
- }
-
- if (!lradc->touchscreen_wire)
- return 0;
- ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
- &cells[TSC_CELL], 1, NULL, 0, NULL);
+ num_cells = lradc->touchscreen_wire ? ARRAY_SIZE(mxs_lradc_cells) : 1;
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+ mxs_lradc_cells, num_cells, res, 0, NULL);
if (ret) {
- dev_err(&pdev->dev,
- "Failed to add the touchscreen subdevice\n");
+ dev_err(dev, "Failed to add subdevices\n");
goto err_clk;
}
diff --git a/include/linux/mfd/mxs-lradc.h b/include/linux/mfd/mxs-lradc.h
index ada3d81ee277..d36951f03da2 100644
--- a/include/linux/mfd/mxs-lradc.h
+++ b/include/linux/mfd/mxs-lradc.h
@@ -19,6 +19,9 @@
#define LRADC_MAX_MAPPED_CHANS 8
#define LRADC_MAX_TOTAL_CHANS 16
+#define MXS_LRADC_MAX_ADC_IRQS 10
+#define MXS_LRADC_NUM_TS_IRQS 3
+
#define LRADC_DELAY_TIMER_HZ 2000
#define LRADC_CTRL0 0x00
@@ -153,6 +156,9 @@ enum mxs_lradc_ts_wires {
* @buffer_vchans: channels that can be used during buffered capture
* @touchscreen_wire: touchscreen type (4-wire or 5-wire)
* @use_touchbutton: button state (on or off)
+ * @num_adc_irqs: number of ADC interrupts
+ * @adc_irq: ADC interrupts
+ * @ts_irq: touchscreen interrupts
*/
struct mxs_lradc {
enum mxs_lradc_id soc;
@@ -161,6 +167,10 @@ struct mxs_lradc {
enum mxs_lradc_ts_wires touchscreen_wire;
bool use_touchbutton;
+
+ unsigned int num_adc_irqs;
+ int adc_irq[MXS_LRADC_MAX_ADC_IRQS];
+ int ts_irq[MXS_LRADC_NUM_TS_IRQS];
};
static inline u32 mxs_lradc_irq_mask(struct mxs_lradc *lradc)
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v3 2/2] mfd: mxs-lradc: Pass parent IRQs to child drivers
2026-11-13 1:32 ` [PATCH v3 2/2] mfd: mxs-lradc: Pass parent IRQs to child drivers Fabio Estevam
@ 2026-11-13 1:56 ` sashiko-bot
0 siblings, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-11-13 1:56 UTC (permalink / raw)
To: Fabio Estevam
Cc: linux-input, mfd, devicetree, imx, robh, conor+dt, Frank.Li,
dmitry.torokhov, lee
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [High] mfd: mxs-lradc: use-after-free in release_resource() on shared
mem resource
--
commit 976bbc1082d0f14834e0c7850fdccd2c40f13cb4
Author: Fabio Estevam <festevam@gmail.com>
mfd: mxs-lradc: Pass parent IRQs to child drivers
This commit moves IRQ resolution from the mxs-lradc child drivers into
the MFD parent and shares a single relative memory resource across both
MFD cells via devm_mfd_add_devices().
> diff --git a/drivers/mfd/mxs-lradc.c b/drivers/mfd/mxs-lradc.c
> index 30a66e2681699..d16dfea892076 100644
> --- a/drivers/mfd/mxs-lradc.c
> +++ b/drivers/mfd/mxs-lradc.c
[ ... ]
> +static const struct resource mxs_lradc_resources[] = {
> + DEFINE_RES_MEM(0, SZ_8K),
> };
>
> -static struct mfd_cell mx23_cells[] = {
> +static const struct mfd_cell mxs_lradc_cells[] = {
> {
> .name = "mxs-lradc-adc",
> - .resources = mx23_adc_resources,
> - .num_resources = ARRAY_SIZE(mx23_adc_resources),
> + .resources = mxs_lradc_resources,
> + .num_resources = ARRAY_SIZE(mxs_lradc_resources),
> },
> {
> .name = "mxs-lradc-ts",
> - .resources = mx23_touchscreen_resources,
> - .num_resources = ARRAY_SIZE(mx23_touchscreen_resources),
> + .resources = mxs_lradc_resources,
> + .num_resources = ARRAY_SIZE(mxs_lradc_resources),
> },
> };
[ ... ]
> @@ -187,38 +215,15 @@ static int mxs_lradc_probe(struct platform_device *pdev)
> goto err_clk;
> }
>
> - switch (lradc->soc) {
> - case IMX23_LRADC:
> - mx23_adc_resources[RES_MEM] = *res;
> - mx23_touchscreen_resources[RES_MEM] = *res;
> - cells = mx23_cells;
> - break;
> - case IMX28_LRADC:
> - mx28_adc_resources[RES_MEM] = *res;
> - mx28_touchscreen_resources[RES_MEM] = *res;
> - cells = mx28_cells;
> - break;
> - default:
> - dev_err(dev, "Unsupported SoC\n");
> - ret = -ENODEV;
> + ret = mxs_lradc_get_irqs(pdev, lradc, data);
> + if (ret)
> goto err_clk;
> - }
> -
> - ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
> - &cells[ADC_CELL], 1, NULL, 0, NULL);
> - if (ret) {
> - dev_err(&pdev->dev, "Failed to add the ADC subdevice\n");
> - goto err_clk;
> - }
> -
> - if (!lradc->touchscreen_wire)
> - return 0;
>
> - ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
> - &cells[TSC_CELL], 1, NULL, 0, NULL);
> + num_cells = lradc->touchscreen_wire ? ARRAY_SIZE(mxs_lradc_cells) : 1;
> + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
> + mxs_lradc_cells, num_cells, res, 0, NULL);
[Severity: High]
Does passing the same relative IORESOURCE_MEM range in mxs_lradc_cells[]
with mem_base = res cause a use-after-free in __release_resource() when
the driver is unbound with a touchscreen enabled?
When num_cells is 2, mfd_add_device() gives both mxs-lradc-adc and
mxs-lradc-ts an IORESOURCE_MEM resource with parent = res and identical
bounds [res->start, res->start + SZ_8K - 1]. In platform_device_add(),
insert_resource() inserts the ADC resource (r_adc) as a child of res, and
then __insert_resource() places the identical touchscreen resource (r_ts)
between res and r_adc, setting r_adc->parent = r_ts.
On driver unbind, mfd_remove_devices() unregisters the children in
reverse order:
1. platform_device_unregister(pdev_ts) calls release_resource(r_ts) ->
__release_resource(r_ts, true), which unlinks r_ts from res->child
without reparenting r_ts->child (r_adc), and platform_device_release()
frees r_ts while r_adc->parent still points to it.
2. platform_device_unregister(pdev_adc) then calls
release_resource(r_adc) -> __release_resource(r_adc, true), which
walks r_adc->parent->child and writes to the freed r_ts.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113013212.470981-1-festevam@gmail.com?part=2
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-13 1:56 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-13 1:32 [PATCH v3 1/2] dt-bindings: mfd: mxs-lradc: Fix interrupt order Fabio Estevam
2026-11-13 1:32 ` [PATCH v3 2/2] mfd: mxs-lradc: Pass parent IRQs to child drivers Fabio Estevam
2026-11-13 1:56 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox