Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions docs/07_UPSTREAM_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,22 @@ Small PRs beat one giant PR.
counter), so the upstream value is an approximate gauge, consistent with the
silicon limit above.

5. **ES8311 audio codec PR (task #21)**
- The in-repo `drivers/audio/es8311.c` is a standalone driver against the
Zephyr audio codec API (native_sim ztest 9/9). It is **board-independent**
and is the natural first audio upstream contribution — propose it as its own
PR (codec driver + `everest,es8311` binding + the ztest), separate from the
board port. Hardware-validated on the StickS3 (HW-006).
5. **ES8311 audio codec (issue #7) — engage upstream, do NOT open a competing PR**
- The in-repo `drivers/audio/es8311.c` is a standalone, **board-independent**
driver against the Zephyr audio codec API: playback HW-verified on the StickS3
(HW-006, 440 Hz beep), an ADC/capture route added and HW-verified (HW-016d),
native_sim ztest **11/11** (includes `test_configure_capture_sequence` /
`test_configure_capture_only`).
- **Superseded framing**: the original "propose it as its own PR" plan is
replaced by **ADR 0004** (`docs/adr/0004-es8311-upstream-engage-pr107660.md`).
Upstream already has a live ES8311 effort (PR #107660), so opening a competing
driver would duplicate/fragment it. Decision: **engage #107660**, and
contribute our differentiator — the HW-verified **capture/ADC route**, which
#107660 omits — as a clean follow-up once the playback codec lands.
- **Current action (per ADR 0004 Update): HOLD.** Engage only after (a) the base
board PR #107655 lands and (b) the ES8311 work resumes on a live PR. Until
then this driver stays repo-local. See ADR 0004 for the trigger conditions and
the parked, trimmed engagement comment.

6. **IR (NEC) — in-repo on stock PWM drivers; an RMT driver is a separate big PR**
- Zephyr 4.4 has no ESP32 RMT driver and no consumer-IR subsystem (verified
Expand Down
58 changes: 58 additions & 0 deletions docs/drafts/es8311-upstream-comments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# ES8311 upstream — parked comment drafts (issue #7)

Status: **DRAFTS — not posted.** Hold per ADR 0004 Update (2026-06-05).
Last live-tracker check: 2026-06-11 — #107660 still DIRTY/CONFLICTING (no movement
since 2026-06-05); #107655 base board OPEN/BLOCKED (moving, not merged); no named
successor ES8311 PR. Hold conditions still hold.

Trigger to post Draft B: (a) base board #107655 merges AND (b) ES8311 work resumes
on a live PR (#107660 de-conflicts, or a named successor appears).

---

## Draft A — framing note for issue #7 (thc1006/zephyr-m5stack-sticks3)

Post when convenient (low sensitivity; our own tracker). Aligns the issue with ADR 0004.

> Updating the plan to match ADR 0004. Upstream already has a live ES8311 effort
> (zephyrproject-rtos/zephyr#107660), so instead of opening a competing driver we'll
> engage that PR and contribute our differentiator — the hardware-verified
> capture/ADC route, which #107660 currently omits — as a clean follow-up once the
> playback codec lands. Holding until the base board PR #107655 merges and the
> ES8311 work resumes on a live PR. The in-repo driver stays repo-local meanwhile
> (native_sim ztest 11/11; playback HW-006 and capture HW-016d verified on a real
> StickS3).

---

## Draft B — engagement comment for the live upstream ES8311 PR

Post ONLY after the trigger above. Leads with the mute-register confirmation and a
hardware-check offer; deliberately drops any "we have more code to contribute".

> We're running an Everest ES8311 on a physical M5Stack StickS3 (ESP32-S3) under a
> Zephyr port, and can confirm one load-bearing detail from real hardware: muting
> the DAC at register 0x31 needs both DSMMUTE and DEMMUTE (bits [6:5]) — mask 0x9F,
> set 0x60 — to go cleanly silent. That matches what this PR does and agrees with
> the Everest datasheet, ESP-ADF, and the Linux `sound/soc/codecs/es8311` path.
> Playback at 16 kHz / 16-bit is audible on our board.
>
> If it helps review confidence, we're happy to run a hardware smoke-test of this
> driver on a real StickS3 (chip-id probe + playback) and report back — a second
> physical board besides the S3-BOX-3. Let us know.

---

## Submission-time work (gated)

The full "ready to fire" checklist lives in
`docs/issues/0007-es8311-upstream-readiness.md` — see it for the genericize list,
the split-PR scope, and the submission mechanics. Verified 2026-06-11:

- checkpatch under Zephyr's `.checkpatch.conf` (the CI config) → **0 errors,
0 warnings** on driver, emul, binding, Kconfig and test. (A bare `--no-tree`
run reports SPDX-line / extern nits, but those are Linux-kernel checks Zephyr
disables, so they are not real findings.)
- twister native_sim → 11/11 pass.
- The only real pre-submission task is genericizing the M5Stack/HW-ID references
in comments (logic is already board-independent) — itemized in the readiness doc.
76 changes: 76 additions & 0 deletions docs/issues/0007-es8311-upstream-readiness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Issue #7 — ES8311 upstream readiness checklist

Tracks the prep for contributing `drivers/audio/es8311.c` (+ binding + ztest)
to Zephyr upstream. **Strategy is set by ADR 0004: do NOT open a competing PR;
engage the existing effort and HOLD until the gate opens.** This file is the
"ready to fire" checklist so the actual submission is fast once the gate lifts.

## Gate status (live, re-checked 2026-06-11)

| Upstream PR | What | State | Gates us? |
|---|---|---|---|
| zephyr#110205 | `boards: m5stack: add M5Stack StickS3` (our maintainer thc1006) | **OPEN, APPROVED**, not merged | once merged → clean board-driven path for our codec |
| zephyr#107655 | `boards: espressif: ESP32-S3-BOX-3` (base board) | OPEN, CHANGES_REQUESTED, active (upd 6/10) | ADR gate: ES8311 work resumes after this lands |
| zephyr#107660 | `drivers: audio: ES8311 + BOX-3 speaker sample` (nnSiD) | OPEN, CHANGES_REQUESTED, **stalled since 6/5**, playback-only (ADC disabled) | the existing effort to coordinate with |
Comment on lines +10 to +14

**Hold conditions still in force**: neither #107655 nor #110205 has merged, and
no live successor ES8311 PR exists. Do not post upstream yet (ADR 0004 update
2026-06-05).

## Readiness — verified 2026-06-11 (all GREEN)

- [x] **checkpatch clean** — `es8311.c`, `emul_es8311.c`, `Kconfig.es8311`,
`everest,es8311.yaml`, test `main.c` all return 0 errors / 0 warnings under
Zephyr's `.checkpatch.conf` (the earlier SPDX/EXTERN/CONFIG_DESCRIPTION
hits were Linux-kernel checks Zephyr disables).
- [x] **Unit tests pass** — `tests/drivers/audio/es8311` → twister native_sim
11/11 cases pass.
- [x] **DCO ready** — existing commits already carry
`Signed-off-by: Hsiu-Chi Tsai <hctsai@linux.com>`.
- [x] **No AI footers** — no `Co-Authored-By` / `Generated with` / Claude/
Anthropic tells in the commit history of these files.
- [x] **Driver code is board-independent** — `DT_DRV_COMPAT everest_es8311`,
generic `audio_codec_api` registration, no `#ifdef`/hardcoded M5Stack logic.
- [x] **Capture/ADC route present** — the differentiator vs #107660 (which
disables ADC). Zephyr's codec API already models capture
(`route_input`/direction-aware start/stop).
- [x] **Tree layout matches upstream** — `drivers/audio/`, `dts/bindings/audio/`,
`tests/drivers/audio/es8311/` mirror the Zephyr structure.

## TODO at submission time (gated — do when the window opens)

### 1. Genericize board/project-specific references (the only code cleanup)
The driver *logic* is generic, but comments/description name our board and
internal HW-IDs. For the upstream copy, rephrase to keep the technical content
and drop project-internal tells. Keep Espressif/ESP-ADF/esp-bsp provenance
(those strengthen the contribution).

- `drivers/audio/es8311.c`: lines ~10, 14–15, 73, 100–101, 136, 154, 160, 172,
323, 422 — replace "M5Stack StickS3 / this project's bring-up / HW-016/HW-016d"
with generic phrasing ("a 16 kHz / 16-bit MCLK-from-BCLK configuration",
"hardware-validated").
- `dts/bindings/audio/everest,es8311.yaml`: lines 9, 13 — drop the StickS3
sentence from `description`.
- `drivers/audio/Kconfig.es8311`: help text — drop "Used on the M5Stack StickS3".

### 2. Split into a focused PR (reviewer norm on #107660)
Codec driver + binding + ztest only. No board, no sample in the same PR.

### 3. Submission mechanics
- Branch off current `zephyrproject-rtos/zephyr` main.
- Re-author commits with DCO sign-off, no AI footers, Zephyr commit-message
style (`drivers: audio: add ES8311 ...`).
- Run `scripts/ci/check_compliance.py` (Kconfig, DTS, Gitlint, Identity) in
addition to checkpatch.
- Consider a `MAINTAINERS.yml` entry (or let the maintainer add one).
- Lead with the **capture route** as the value-add over #107660; offer a
real-hardware StickS3 data point.

### 4. Coordinate, don't duplicate
Per ADR 0004: engage #107660 / its successor with a trimmed comment (mute-reg
0x31 confirmation + offer a hardware check). Do not take over the PR uninvited.

## References
- ADR 0004 — `docs/adr/0004-es8311-upstream-engage-pr107660.md`
- Upstream plan item 5 — `docs/07_UPSTREAM_PLAN.md`
- Driver / binding / test — `drivers/audio/es8311.c`, `dts/bindings/audio/everest,es8311.yaml`, `tests/drivers/audio/es8311/`
86 changes: 86 additions & 0 deletions scripts/check_es8311_upstream_gate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env bash
# Copyright (c) 2026 Hsiu-Chi Tsai
# SPDX-License-Identifier: Apache-2.0
#
# Issue #7 monitor: report whether the gate to upstream the ES8311 codec driver
# has opened. Per ADR 0004 the gate is BOTH of, not either of:
# (1) the base board PR #107655 has MERGED, AND
# (2) the ES8311 work has resumed on a *live successor* PR — an open es8311
# PR that is neither the stalled original (#107660) nor one of ours.
# Only when both hold do we print GATE OPEN. Our own board PR (#110205) merging
# on its own is NOT the gate (that was the old, too-loose trigger). Needs `gh`
# authenticated.
#
# Usage: bash scripts/check_es8311_upstream_gate.sh
set -euo pipefail

Z=zephyrproject-rtos/zephyr
BASE_PR=107655 # ADR 0004 gate (1): base board lands first
STALLED_PR=107660 # known-stalled original ES8311 PR; not a successor
OUR_PRS=(110205) # our own board PR(s) — never a successor
OUR_AUTHORS=(thc1006 junnncct1106) # our authors — their es8311 PRs are not a successor

# field PR JSON_FIELD -> value, or "" on ANY gh error.
# Returns empty (not "?") on failure so a gh outage / auth gap / rate-limit can
# never be mistaken for a real value such as a false "merged" timestamp.
field() { gh pr view "$1" --repo "$Z" --json "$2" -q ".$2" 2>/dev/null || true; }

# is_merged PR -> success only if the PR is *actually* merged.
# Authoritative signal is state==MERGED (verified against the live GitHub API);
# mergedAt must also be a real ISO-8601 timestamp. "", "null" and "?" all fail.
is_merged() {
local state merged
state=$(field "$1" state)
merged=$(field "$1" mergedAt)
[ "$state" = "MERGED" ] && [[ "$merged" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T ]]
}

# in_list NEEDLE ITEM... -> success if NEEDLE equals one of ITEM.
in_list() {
local needle="$1"; shift
local x
for x in "$@"; do [ "$x" = "$needle" ] && return 0; done
return 1
}

echo "ES8311 upstream gate — $(date -u '+%Y-%m-%d %H:%MZ')"
echo "----------------------------------------------------"

for pr in "$BASE_PR" "$STALLED_PR" "${OUR_PRS[@]}"; do
state=$(field "$pr" state)
merged=$(field "$pr" mergedAt)
review=$(field "$pr" reviewDecision)
title=$(field "$pr" title)
printf '#%-7s %-6s merged=%-21s review=%-18s %s\n' \
"$pr" "${state:-?}" "${merged:-no}" "${review:-none}" "${title:0:48}"
done

# Gate (1): base board must be MERGED.
base_merged=0
if is_merged "$BASE_PR"; then base_merged=1; fi

# Gate (2): a live successor — any OPEN es8311 PR that is neither the stalled
# original nor one of ours. Reuses the upstream search; "*" marks a candidate.
echo "--- live ES8311 PRs upstream ---"
successor=0
while IFS=$'\t' read -r num author updated title; do
[ -z "$num" ] && continue
mark=' '
if ! in_list "$num" "$STALLED_PR" "${OUR_PRS[@]}" \
&& ! in_list "$author" "${OUR_AUTHORS[@]}"; then
mark='*'; successor=1
fi
printf ' %s #%-7s %-14s %s — %s\n' "$mark" "$num" "$author" "$updated" "${title:0:50}"
done < <(gh search prs --repo "$Z" es8311 --state open \
--json number,author,updatedAt,title \
-q '.[] | "\(.number)\t\(.author.login)\t\(.updatedAt[0:10])\t\(.title[0:50])"' 2>/dev/null || true)
[ "$successor" = 1 ] && echo " (* = candidate live successor PR)"

echo "----------------------------------------------------"
printf 'gate(1) base #%s merged : %s\n' "$BASE_PR" "$([ "$base_merged" = 1 ] && echo yes || echo no)"
printf 'gate(2) live successor PR : %s\n' "$([ "$successor" = 1 ] && echo yes || echo no)"
if [ "$base_merged" = 1 ] && [ "$successor" = 1 ]; then
echo "VERDICT: GATE OPEN — base board landed AND ES8311 resumed on a live PR. Proceed per docs/issues/0007-es8311-upstream-readiness.md (genericize → split PR → coordinate the successor)."
else
echo "VERDICT: STILL HOLDING — ADR 0004 gate not met (need BOTH base #$BASE_PR merged AND a live successor PR). Keep waiting."
fi
74 changes: 74 additions & 0 deletions scripts/test_check_es8311_gate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env bash
# Copyright (c) 2026 Hsiu-Chi Tsai
# SPDX-License-Identifier: Apache-2.0
#
# Offline integration test for scripts/check_es8311_upstream_gate.sh.
# Puts a mock `gh` on PATH (no network, no auth) and asserts the gate VERDICT
# across the four scenarios that the maintainer review on PR #16 called out:
# 1. base #107655 MERGED + a live successor PR -> GATE OPEN
# 2. base #107655 MERGED but NO successor -> STILL HOLDING (AND, not OR)
# 3. only our own board #110205 MERGED (old bug) -> STILL HOLDING
# 4. gh failing entirely (old "?" false-merge bug) -> STILL HOLDING (never false-open)
#
# Usage: bash scripts/test_check_es8311_gate.sh
set -euo pipefail

here=$(cd "$(dirname "$0")" && pwd)
gate="$here/check_es8311_upstream_gate.sh"
td=$(mktemp -d)
trap 'rm -rf "$td"' EXIT
mkdir -p "$td/bin"

cat > "$td/bin/gh" <<'MOCK'
#!/usr/bin/env bash
# Fake gh; $SCEN selects the scenario. Mirrors the shape the real gh returns.
get_json_field() { local p=""; while [ $# -gt 0 ]; do [ "$1" = "--json" ] && p="$2"; shift; done; echo "$p"; }
prview() {
local pr="$1"; shift; local f; f=$(get_json_field "$@")
[ "$SCEN" = "fail" ] && return 1
local state="OPEN" merged="null"
case "$SCEN:$pr" in
open_succ:107655|base_only:107655) state="MERGED"; merged="2026-06-09T10:00:00Z" ;;
ourboard:110205) state="MERGED"; merged="2026-06-09T10:00:00Z" ;;
esac
case "$f" in
state) echo "$state" ;;
mergedAt) echo "$merged" ;;
reviewDecision) echo "APPROVED" ;;
title) echo "fake title for $pr" ;;
esac
}
search() {
[ "$SCEN" = "fail" ] && return 1
printf '107660\tnnSiD\t2026-06-05\tES8311 codec driver\n'
printf '110205\tthc1006\t2026-06-03\tM5Stack StickS3\n'
[ "$SCEN" = "open_succ" ] && printf '109999\tnnSiD\t2026-06-10\tES8311 v2 split codec PR\n'
}
case "$1 $2" in
"pr view") shift 2; prview "$@" ;;
"search prs") search ;;
*) exit 0 ;;
esac
MOCK
chmod +x "$td/bin/gh"

pass=0 fail=0
check() { # SCEN EXPECT_REGEX label
local out verdict
out=$(SCEN="$1" PATH="$td/bin:$PATH" bash "$gate")
verdict=$(echo "$out" | grep VERDICT)
if echo "$verdict" | grep -qE "$2"; then
printf 'PASS %-12s %s\n' "$1" "$3"; pass=$((pass+1))
else
printf 'FAIL %-12s %s\n got: %s\n' "$1" "$3" "$verdict"; fail=$((fail+1))
fi
}

check open_succ 'GATE OPEN' 'base merged + live successor -> open'
check base_only 'STILL HOLDING' 'base merged, no successor -> hold (AND)'
check ourboard 'STILL HOLDING' 'only our #110205 merged -> hold (old false-open)'
check fail 'STILL HOLDING' 'gh down -> hold (old "?" false-merge)'

echo "----------------------------------------"
echo "PASS=$pass FAIL=$fail"
[ "$fail" -eq 0 ]
Loading