All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "James Calligeros" <jcalligeros99@gmail.com>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v3 08/21] ASoC: apple: Add macaudio machine driver
Date: Sun, 18 Oct 2026 06:23:12 +0000	[thread overview]
Message-ID: <sashiko-outbox-175986@kernel.org> (raw)
In-Reply-To: <20261018-macaudio-v3-8-abdff7741dea@gmail.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [Critical] ASoC: apple: macaudio: wrong drvdata and teardown order in remove()
- [High] ASoC: apple: macaudio: ABBA deadlock in macaudio_vlimit_update()
- [High] ASoC: apple: macaudio: static macaudio_card mutated across probes
- [High] ASoC: apple: macaudio: atomic Primary FE fails with nonatomic speaker BE
- [Medium] ASoC: apple: macaudio: OF node reference leaks in macaudio_parse_of()
- [Medium] ASoC: apple: macaudio: TDM idle mode skipped in macaudio_be_assign_tdm()
- [Medium] ASoC: apple: macaudio: race with cancel_delayed_work() on timeout work
--

commit 56eeabc9bf8ef8e9b2a3eb1ec213300f3ed1ab23
Author: Martin Povišer <povik+lin@cutebit.org>

ASoC: apple: Add macaudio machine driver

This commit adds an ASoC machine driver for Apple Silicon Macs to manage
DPCM routing between MCA I2S frontends/backends, speaker arrays, speaker
sense capture, and headset jack codecs.

> diff --git a/sound/soc/apple/macaudio.c b/sound/soc/apple/macaudio.c
> new file mode 100644
> index 0000000000000..b8e58c9a676f8
> --- /dev/null
> +++ b/sound/soc/apple/macaudio.c
> @@ -0,0 +1,1715 @@

[ ... ]

> +static struct snd_soc_dai_link macaudio_fe_links[] = {
> +	{
> +		.name = "Primary",
> +		.stream_name = "Primary",
> +		.dynamic = 1,
> +		.dpcm_merged_rate = 1,
> +		.dpcm_merged_chan = 1,
> +		.dpcm_merged_format = 1,
> +		.dai_fmt = MACAUDIO_DAI_FMT,
> +		SND_SOC_DAILINK_REG(primary),
> +	},
> +	{
> +		.name = "Secondary",
> +		.stream_name = "Secondary",
> +		.dynamic = 1,
> +		.dpcm_merged_rate = 1,
> +		.dpcm_merged_chan = 1,
> +		.dpcm_merged_format = 1,
> +		.dai_fmt = MACAUDIO_DAI_FMT,
> +		.playback_only = 1,
> +		.nonatomic = 1,
> +		SND_SOC_DAILINK_REG(secondary),
> +	},

[Severity: High]
Should the Primary frontend link in macaudio_fe_links[] (and the headphone
backend links in macaudio_parse_of()) also set .nonatomic = 1?

In macaudio_dapm_routes[], both Primary and Secondary are routed to both
Speaker Playback Mux (where Primary is the default selection at index 0)
and Headphone Playback Mux. In macaudio_parse_of(), speaker backend links
set link->nonatomic = 1, while headphone backend links have
link->nonatomic = 0.

When Primary (atomic) is routed to a speaker backend (nonatomic),
dpcm_be_connect() in sound/soc/soc-pcm.c rejects the connection with
-EINVAL because an atomic frontend cannot connect to a nonatomic backend:

sound/soc/soc-pcm.c:dpcm_be_connect() {
	...
	if (be_substream->pcm->nonatomic && !fe_substream->pcm->nonatomic) {
		dev_err(be->dev, "FE is atomic but BE is nonatomic, invalid configuration\n");
		return -EINVAL;
	}
	if (!be_substream->pcm->nonatomic && fe_substream->pcm->nonatomic) {
		be_substream->pcm->nonatomic = 1;
	}
	...
}

Furthermore, if Secondary (nonatomic) is ever routed to Headphone Playback
Mux, dpcm_be_connect() mutates the headphone backend PCM to nonatomic = 1,
causing subsequent attempts to route Primary to headphones to also fail
with -EINVAL.

[ ... ]

> +static void macaudio_vlimit_update(struct macaudio_snd_data *ma, bool take_rwsem)
> +{
> +	bool unlock = true;
> +	const char *reason;
> +
> +	/* Do nothing if there is no safety configured */
> +	if (!ma->has_safety)
> +		return;
> +
> +	/* Check that the control has been pinged within the timeout */
> +	if (ma->speaker_lock_remain <= 0) {
> +		reason = "Lock timeout";
> +		unlock = false;
> +	}
> +
> +	/*
> +	 * If this has been called from either of the safety interlock
> +	 * workqueues, the core API has not taken controls_rwsem for us.
> +	 * Take the write semaphore since macaudio_vlimit_unlock writes
> +	 * to the kcontrols.
> +	 */
> +	if (take_rwsem)
> +		down_write(&ma->card->snd_card->controls_rwsem);

[Severity: High]
Can taking controls_rwsem here while holding ma->volume_lock_mutex cause an
AB-BA deadlock with macaudio_slk_put()?

When lock_update_work or lock_timeout_work runs,
macaudio_vlimit_enable_timeout(), macaudio_vlimit_disable_timeout(), and
macaudio_vlimit_timeout_work() first acquire ma->volume_lock_mutex via
guard(mutex)(&ma->volume_lock_mutex) and then call
macaudio_vlimit_update(ma, true), which calls
down_write(&ma->card->snd_card->controls_rwsem):

  volume_lock_mutex -> controls_rwsem

Conversely, when userspace writes to the Speaker Volume Unlock control,
snd_ctl_elem_write() in sound/core/control.c acquires
down_write(&card->controls_rwsem) before invoking macaudio_slk_put(), which
then acquires guard(mutex)(&ma->volume_lock_mutex):

  controls_rwsem -> volume_lock_mutex

If a userspace control write races with either work item, will the two
threads deadlock against each other?

> +
> +	if (unlock != ma->speaker_volume_unlocked) {
> +		if (unlock) {
> +			dev_info(ma->card->dev, "Speaker volumes unlocked\n");
> +		} else  {
> +			dev_info(ma->card->dev, "Speaker volumes locked: %s\n", reason);
> +			ma->speaker_volume_was_locked = true;
> +		}
> +
> +		macaudio_vlimit_unlock(ma, unlock);
> +		ma->speaker_volume_unlocked = unlock;
> +		snd_ctl_notify(ma->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE,
> +			       &ma->speaker_lock_kctl->id);
> +	}
> +
> +	if (take_rwsem)
> +		up_write(&ma->card->snd_card->controls_rwsem);
> +}
> +
> +static void macaudio_vlimit_enable_timeout(struct macaudio_snd_data *ma)
> +{
> +	guard(mutex)(&ma->volume_lock_mutex);
> +
> +	if (ma->speaker_lock_timeout_enabled) {
> +		return;
> +	}
> +
> +	if (ma->speaker_lock_remain > 0) {
> +		ma->speaker_lock_timeout = ktime_add(ktime_get(), ma->speaker_lock_remain);
> +		schedule_delayed_work(&ma->lock_timeout_work,
> +				      usecs_to_jiffies(ktime_to_us(ma->speaker_lock_remain)));
> +		dev_dbg(ma->card->dev, "Enabling volume limit timeout: %ld us left\n",
> +			(long)ktime_to_us(ma->speaker_lock_remain));
> +	}
> +
> +	macaudio_vlimit_update(ma, true);
> +
> +	ma->speaker_lock_timeout_enabled = true;
> +}
> +
> +static void macaudio_vlimit_disable_timeout(struct macaudio_snd_data *ma)
> +{
> +	ktime_t now;
> +
> +	guard(mutex)(&ma->volume_lock_mutex);
> +
> +	if (!ma->speaker_lock_timeout_enabled) {
> +		return;
> +	}
> +
> +	now = ktime_get();
> +
> +	cancel_delayed_work(&ma->lock_timeout_work);
> +
> +	if (ktime_after(now, ma->speaker_lock_timeout))
> +		ma->speaker_lock_remain = 0;
> +	else if (ma->speaker_lock_remain > 0)
> +		ma->speaker_lock_remain = ktime_sub(ma->speaker_lock_timeout, now);
> +
> +	dev_dbg(ma->card->dev, "Disabling volume limit timeout: %ld us left\n",
> +		(long)ktime_to_us(ma->speaker_lock_remain));
> +
> +	macaudio_vlimit_update(ma, true);
> +
> +	ma->speaker_lock_timeout_enabled = false;
> +}
> +
> +static void macaudio_vlimit_timeout_work(struct work_struct *wrk)
> +{
> +	struct macaudio_snd_data *ma = container_of(to_delayed_work(wrk),
> +						    struct macaudio_snd_data, lock_timeout_work);
> +
> +	guard(mutex)(&ma->volume_lock_mutex);
> +	ma->speaker_lock_remain = 0;
> +	macaudio_vlimit_update(ma, true);
> +}

[Severity: Medium]
What happens if lock_timeout_work fires and macaudio_vlimit_timeout_work()
blocks on ma->volume_lock_mutex just after macaudio_slk_put() or
macaudio_vlimit_disable_timeout() acquires ma->volume_lock_mutex?

Because macaudio_slk_put() and macaudio_vlimit_disable_timeout() use
non-synchronous cancel_delayed_work(&ma->lock_timeout_work) while holding
ma->volume_lock_mutex, cancel_delayed_work() cannot stop a
macaudio_vlimit_timeout_work() instance that has already been dispatched
and is waiting on ma->volume_lock_mutex.

Once macaudio_slk_put() refreshes ma->speaker_lock_remain to
ms_to_ktime(SPEAKER_LOCK_TIMEOUT), reschedules lock_timeout_work, and
releases ma->volume_lock_mutex (or macaudio_vlimit_disable_timeout()
disables the timeout and releases the mutex), the waiting
macaudio_vlimit_timeout_work() will acquire ma->volume_lock_mutex and
unconditionally zero ma->speaker_lock_remain and lock the speaker volumes.

Should macaudio_vlimit_timeout_work() verify that
ma->speaker_lock_timeout_enabled is still true and
ktime_after(ktime_get(), ma->speaker_lock_timeout) before zeroing
ma->speaker_lock_remain?

[ ... ]

> +static int macaudio_parse_of_component(struct device_node *node, int index,
> +				struct snd_soc_dai_link_component *comp)
> +{
> +	struct of_phandle_args args;
> +	int ret;
> +
> +	ret = of_parse_phandle_with_args(node, "sound-dai", "#sound-dai-cells",
> +						index, &args);
> +	if (ret)
> +		return ret;
> +	comp->of_node = args.np;
> +	return snd_soc_get_dai_name(&args, &comp->dai_name);
> +}

[ ... ]

> +static int macaudio_parse_of(struct macaudio_snd_data *ma, struct snd_soc_card *card)
> +{
> +	struct device_node *codec = NULL;
> +	struct device_node *cpu = NULL;
> +	struct device_node *np = NULL;
> +	struct device_node *platform = NULL;
> +	struct snd_soc_dai_link *link = NULL;
> +	struct device *dev = card->dev;
> +	struct macaudio_link_props *link_props;
> +	int ret, num_links, i;

[ ... ]

> +		for (be_index = 0; be_index < num_bes; be_index++) {
> +			/*
> +			 * Set initial link name to be overwritten by a BE-specific
> +			 * name later so that we can use at least use the provisional
> +			 * name in error messages.
> +			 */
> +			link->name = link_name;
> +
> +			ret = macaudio_parse_of_be_dai_link(card, link, be_index,
> +							    ncodecs_per_cpu, cpu, codec);
> +			if (ret)
> +				goto err_free;
> +
> +			link->nonatomic = link_props->is_speakers = speakers;
> +			link_props->is_headphones = !speakers;
> +
> +			link_props->codecs = devm_kcalloc(dev, ncodecs_per_cpu,
> +							  sizeof(struct ma_codec_idle), GFP_KERNEL);
> +			if (!link_props->codecs)
> +				return -ENOMEM;

[ ... ]

> +			/* Steal platform OF reference for use in FE links later */
> +			platform = link->cpus->of_node;
> +
> +			link++; link_props++;
> +		}
> +
> +		of_node_put(codec);
> +		of_node_put(cpu);
> +		cpu = codec = NULL;
> +
> +		num_links += num_bes;
> +	}

[ ... ]

> +err_free:
> +	of_node_put(codec);
> +	of_node_put(cpu);
> +	of_node_put(np);
> +
> +	if (!card->dai_link)
> +		return ret;
> +
> +	for (i = 0; i < num_links; i++) {
> +		/*
> +		 * TODO: If we don't go through this path are the references
> +		 * freed inside ASoC?
> +		 */
> +		snd_soc_of_put_dai_link_codecs(&card->dai_link[i]);
> +		snd_soc_of_put_dai_link_cpus(&card->dai_link[i]);
> +	}
> +
> +	return ret;
> +}

[Severity: Medium]
Does macaudio_parse_of() leak device_node references in several paths?

1. If devm_kcalloc() for link_props->codecs fails, macaudio_parse_of()
returns -ENOMEM directly from inside the for_each_available_child_of_node()
loop instead of jumping to err_free, leaking np, cpu, codec, and all
previously acquired DAI link component of_node references.

2. In macaudio_parse_of_component(), comp->of_node = args.np is assigned
before calling snd_soc_get_dai_name(&args, &comp->dai_name). In
macaudio_parse_of(), num_links is only incremented by num_bes after the
entire inner for (be_index = 0; be_index < num_bes; be_index++) loop
completes. If macaudio_parse_of_be_dai_link() fails (for example when
snd_soc_get_dai_name() returns -EPROBE_DEFER), execution jumps to err_free,
where the cleanup loop only iterates up to num_links and misses any
comp->of_node references already populated in the current child node's BE
links.

3. Regarding the TODO comment in err_free: ASoC core does not release
dai_link->codecs[].of_node or dai_link->cpus[].of_node. If
devm_snd_soc_register_card() fails or when the driver is removed, those
device_node references are never released.

[ ... ]

> +static int macaudio_be_assign_tdm(struct snd_soc_pcm_runtime *rtd)
> +{
> +	struct snd_soc_card *card = rtd->card;
> +	struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
> +	struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
> +	struct snd_soc_dai *dai;
> +	unsigned int mask;
> +	int nslots, ret, i;
> +
> +	if (!props->tdm_mask)
> +		return 0;
> +
> +	mask = props->tdm_mask;
> +	nslots = __fls(mask) + 1;
> +
> +	if (rtd->dai_link->num_codecs == 1) {
> +		ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 0), mask,
> +					       0, nslots, MACAUDIO_SLOTWIDTH);
> +
> +		/*
> +		 * Headphones get a pass on -ENOTSUPP (see the comment
> +		 * around bclk_ratio value for primary FE).
> +		 */
> +		if (ret == -ENOTSUPP && props->is_headphones)
> +			return 0;
> +
> +		return ret;
> +	}
> +
> +	for_each_rtd_codec_dais(rtd, i, dai) {
> +		int slot = __ffs(mask);
> +
> +		mask &= ~(1 << slot);
> +		ret = snd_soc_dai_set_tdm_slot(dai, 1 << slot, 0, nslots,
> +					       MACAUDIO_SLOTWIDTH);
> +		if (ret)
> +			return ret;
> +
> +		if (props->codecs[i].idle_mode) {
> +			ret = snd_soc_dai_set_tdm_idle(dai, props->codecs[i].idle_mask,
> +						       0, props->codecs[i].idle_mode, 0);
> +			if (ret) {
> +				dev_err(card->dev, "Failed to set idle props for codec %d\n", i);
> +				return ret;
> +			}
> +
> +		}
> +	}
> +
> +	return 0;
> +}

[Severity: Medium]
When rtd->dai_link->num_codecs == 1, macaudio_be_assign_tdm() returns early
after calling snd_soc_dai_set_tdm_slot() without checking
props->codecs[0].idle_mode or calling snd_soc_dai_set_tdm_idle().

On machines where each speaker backend DAI link has a single codec (such as
2 speaker codecs split across 2 CPU BEs), won't this skip applying the
dai-tdm-idle-mode-* and dai-tdm-slot-tx-idle-mask-* properties parsed by
macaudio_get_codec_idle_props()?

[ ... ]

> +static struct snd_soc_card macaudio_card = {
> +	.owner = THIS_MODULE,
> +	.driver_name = "macaudio",
> +	.dapm_widgets = macaudio_snd_widgets,
> +	.num_dapm_widgets = ARRAY_SIZE(macaudio_snd_widgets),
> +	.dapm_routes = macaudio_dapm_routes,
> +	.num_dapm_routes = ARRAY_SIZE(macaudio_dapm_routes),
> +	.controls = macaudio_controls,
> +	.num_controls = ARRAY_SIZE(macaudio_controls),
> +	.probe = macaudio_probe,
> +	.late_probe = macaudio_late_probe,
> +	.component_chaining = true,
> +	.fully_routed = true,
> +	.fixup_controls = macaudio_fixup_controls,
> +};

[ ... ]

> +static int macaudio_snd_platform_probe(struct platform_device *pdev)
> +{
> +	struct snd_soc_card *card;
> +	struct macaudio_snd_data *data;
> +	struct device *dev = &pdev->dev;
> +	struct snd_soc_dai_link *link;
> +	const struct of_device_id *of_id;
> +	int ret;
> +	int i;
> +
> +	of_id = of_match_device(macaudio_snd_device_id, dev);
> +	if (!of_id)
> +		return -EINVAL;
> +
> +	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +	card = &macaudio_card;
> +	data->card = card;
> +
> +	snd_soc_card_set_drvdata(card, data);
> +	dev_set_drvdata(&pdev->dev, data);
> +	mutex_init(&data->volume_lock_mutex);
> +	mutex_init(&data->be_link_mutex);
> +
> +	card->dev = dev;
> +
> +	if (of_id->data)
> +		data->cfg = of_id->data;
> +	else
> +		data->cfg = &macaudio_fallback_cfg;
> +
> +	ret = macaudio_parse_of(data, card);
> +	if (ret)
> +		return ret;
> +
> +	/* Remove useless controls */
> +	if (!data->has_speakers) /* No speakers, remove both */
> +		card->num_controls -= MACAUDIO_NUM_SPEAKER_CONTROLS;
> +	else if (!data->cfg->safe_vol) /* No safety, remove unlock */
> +		card->num_controls -= MACAUDIO_NUM_SPEAKER_LIMIT_CONTROLS;
> +	else /* Speakers with safety, mark us as such */
> +		data->has_safety = true;

[Severity: High]
Since macaudio_card is a static struct shared across probe attempts, what
happens if devm_snd_soc_register_card() defers probe (-EPROBE_DEFER) or the
device is unbound and re-probed?

In macaudio_snd_platform_probe(), card->num_controls is decremented in-place
with -= without being reset to ARRAY_SIZE(macaudio_controls). Across
repeated deferred probes, card->num_controls will be decremented multiple
times, dropping valid controls or underflowing. For example, on a machine
with speakers and !safe_vol, a second probe attempt will drop the Speaker
Sample Rate control, causing snd_soc_card_get_kcontrol(card, "Speaker Sample
Rate") in macaudio_late_probe() to return NULL and triggering a NULL pointer
dereference when macaudio_dpcm_hw_params() or macaudio_be_hw_free() accesses
&ma->speaker_sample_rate_kctl->id.

Similarly, macaudio_parse_of() assigns a devm-allocated array to
macaudio_card.dai_link; if probe fails after that allocation, devres frees
the array while leaving macaudio_card.dai_link pointing to freed memory if a
subsequent probe jumps to err_free before reallocating card->dai_link.
Embedding struct snd_soc_card inside struct macaudio_snd_data (and
initializing it from a const template on probe) would avoid mutating global
state across probes.

> +
> +	for_each_card_prelinks(card, i, link) {
> +		if (link->no_pcm) {
> +			link->ops = &macaudio_be_ops;
> +			link->init = macaudio_be_init;
> +			link->exit = macaudio_be_exit;
> +		} else {
> +			link->ops = &macaudio_fe_ops;
> +			link->init = macaudio_fe_init;
> +		}
> +	}
> +
> +	INIT_WORK(&data->lock_update_work, macaudio_vlimit_update_work);
> +	INIT_DELAYED_WORK(&data->lock_timeout_work, macaudio_vlimit_timeout_work);
> +
> +	return devm_snd_soc_register_card(dev, card);
> +}
> +
> +static void macaudio_snd_platform_remove(struct platform_device *pdev)
> +{
> +	struct macaudio_snd_data *ma = dev_get_drvdata(&pdev->dev);
> +
> +	cancel_work_sync(&ma->lock_update_work);
> +	cancel_delayed_work_sync(&ma->lock_timeout_work);
> +}

[Severity: Critical]
Does macaudio_snd_platform_remove() retrieve the wrong pointer from
dev_get_drvdata(&pdev->dev) and cancel the work items in the wrong order
relative to card unregistration?

1. In macaudio_snd_platform_probe(), dev_set_drvdata(&pdev->dev, data) sets
the platform device's drvdata to struct macaudio_snd_data *data, and then
calls devm_snd_soc_register_card(dev, card). Inside snd_soc_register_card()
in sound/soc/soc-core.c, ASoC unconditionally overwrites card->dev's drvdata
with card:

sound/soc/soc-core.c:snd_soc_register_card() {
	...
	dev_set_drvdata(card->dev, card);
	...
}

When macaudio_snd_platform_remove() later calls dev_get_drvdata(&pdev->dev),
it receives struct snd_soc_card * (instead of struct macaudio_snd_data *)
and passes offsets inside macaudio_card to cancel_work_sync() and
cancel_delayed_work_sync().

2. Because the card is registered with devm_snd_soc_register_card(), the
devres release callback that unregisters the card runs after
macaudio_snd_platform_remove() returns. While the card is still registered
(and during PCM teardown in snd_soc_unregister_card()), macaudio_be_trigger()
or macaudio_slk_put() can schedule lock_update_work and lock_timeout_work
again after macaudio_snd_platform_remove() has completed, leading to
use-after-free when devres frees struct macaudio_snd_data.

|}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261018-macaudio-v3-0-abdff7741dea@gmail.com?part=8

  reply	other threads:[~2026-10-18  6:23 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-18  5:53 [PATCH v3 00/21] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
2026-10-18  5:53 ` [PATCH v3 01/21] ASoC: dt-bindings: cs42l84: Document sound-name-prefix property James Calligeros
2026-10-18  5:53 ` [PATCH v3 02/21] ASoC: dt-bindings: cs42l42: Document additional dai-common properties James Calligeros
2026-10-18  6:04   ` sashiko-bot
2026-10-18  5:53 ` [PATCH v3 03/21] ASoC: dt-bindings: Add binding for Apple Silicon Mac audio James Calligeros
2026-10-18  6:07   ` sashiko-bot
2026-10-18  5:53 ` [PATCH v3 04/21] ASoC: ops: Introduce 'snd_soc_ctl_activate' James Calligeros
2026-10-18  5:53 ` [PATCH v3 05/21] ASoC: ops: Introduce 'soc_set_enum_kctl' James Calligeros
2026-10-18  5:54 ` [PATCH v3 06/21] ASoC: card: Let 'fixup_controls' return errors James Calligeros
2026-10-18  5:54 ` [PATCH v3 07/21] ASoC: tas2770: Add compatible for TAS5770L James Calligeros
2026-10-18  5:54 ` [PATCH v3 08/21] ASoC: apple: Add macaudio machine driver James Calligeros
2026-10-18  6:23   ` sashiko-bot [this message]
2026-10-18  5:54 ` [PATCH v3 09/21] arm64: dts: apple: t8103-jxxx: Add regulators for CS42L83 power supply James Calligeros
2026-10-18  6:04   ` sashiko-bot
2026-10-18  5:54 ` [PATCH v3 10/21] arm64: dts: apple: t8103-j274: Add speaker/headset jack nodes James Calligeros
2026-10-18  6:10   ` sashiko-bot
2026-10-18  5:54 ` [PATCH v3 11/21] arm64: dts: apple: t8103-j313: " James Calligeros
2026-10-18  6:15   ` sashiko-bot
2026-10-18  5:54 ` [PATCH v3 12/21] arm64: dts: apple: t8103-j293: " James Calligeros
2026-10-18  5:54 ` [PATCH v3 13/21] arm64: dts: apple: t8103-j45x: Add headset " James Calligeros
2026-10-18  5:54 ` [PATCH v3 14/21] arm64: dts: apple: t8112-j413: Add speaker/headset " James Calligeros
2026-10-18  5:54 ` [PATCH v3 15/21] arm64: dts: apple: t8112-j415: " James Calligeros
2026-10-18  5:54 ` [PATCH v3 16/21] arm64: dts: apple: t8112-j473: " James Calligeros
2026-10-18  5:54 ` [PATCH v3 17/21] arm64: dts: apple: t8112-j493: " James Calligeros
2026-10-18  5:54 ` [PATCH v3 18/21] arm64: dts: apple: t600x-j31x: " James Calligeros
2026-10-18  5:54 ` [PATCH v3 19/21] arm64: dts: apple: t600x-j375: " James Calligeros
2026-10-18  5:54 ` [PATCH v3 20/21] arm64: dts: apple: t602x-j41x: " James Calligeros
2026-10-18  5:54 ` [PATCH v3 21/21] arm64: dts: apple: t602x-j47x: " James Calligeros

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-175986@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=jcalligeros99@gmail.com \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.