Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d4d7ff5
dt-bindings: sound: describe Denali protected audio
geocausa Aug 23, 2026
492bd17
soundwire: add optional slave transport metadata
geocausa Aug 23, 2026
e675426
ASoC: qcom: x1e80100: prepare Denali feedback backends
geocausa Aug 23, 2026
6c414d2
soundwire: support opt-in SIMPLE transport extensions
geocausa Aug 23, 2026
76b5330
soundwire: qcom: expose Denali WSA feedback DAIs
geocausa Aug 23, 2026
ad09560
ASoC: wsa884x: add opt-in VI and CPS feedback DAIs
geocausa Aug 23, 2026
619c7e7
ASoC: lpass-wsa-macro: add Denali feedback endpoints
geocausa Aug 23, 2026
5b83bb8
ASoC: q6dsp: expose Denali WSA protection streams
ooaklee Aug 23, 2026
74d46b6
soc: qcom: apr: drain callbacks before freeing services
ooaklee Sep 1, 2026
3fa4043
ASoC: q6apm: correlate commands and memory mappings
ooaklee Sep 1, 2026
15251b7
ASoC: q6dsp: parse FullIO topology extensions
geocausa Aug 23, 2026
18914b9
ASoC: q6apm: add graph-scoped OOB configuration
geocausa Aug 23, 2026
bd0f254
ASoC: q6apm: run FullIO protection per graph
geocausa Aug 23, 2026
246b428
ASoC: qcom: wire Denali protection backends
ooaklee Aug 31, 2026
67f5afb
dt-bindings: sound: describe WSA884x speaker load
ooaklee Aug 31, 2026
3c70006
ASoC: wsa884x: add opt-in 2S 4-ohm profile
geocausa Jul 29, 2026
e448e5b
ASoC: codecs: order WSA protection clocks after both PAs
geocausa Aug 23, 2026
fafa6d9
arm64: dts: qcom: denali: describe VI and CPS audio paths
geocausa Aug 23, 2026
d6acd93
arm64: dts: qcom: denali: select 4-ohm speaker profile
ooaklee Aug 31, 2026
72dc28f
ASoC: q6dsp: allow modules with more than eight input ports
ooaklee Sep 2, 2026
76cde6d
ASoC: q6apm: restore SP11 protected pull geometry
ooaklee Aug 23, 2026
1af1e83
ASoC: q6apm: restore protected pull pause lifecycle
ooaklee Aug 23, 2026
160dc2a
ASoC: qcom: x1e80100: restore Denali PA gain range
ooaklee Aug 23, 2026
236e7d3
ASoC: q6apm: scope protected pull setup to graph client
ooaklee Aug 23, 2026
c75072e
ASoC: q6apm: restore SP11 pull position ownership
ooaklee Aug 23, 2026
e2aa84f
ASoC: q6apm: preserve SP11 pull run-state order
ooaklee Aug 23, 2026
8c5f8f2
ASoC: q6apm: preserve SP11 pull media order
ooaklee Aug 23, 2026
6bee957
ASoC: q6apm: match SP11 control routing
ooaklee Aug 23, 2026
99d0e80
ASoC: q6apm: resolve protected position map errors
ooaklee Sep 2, 2026
62be933
ASoC: q6apm: resume protected pull before prepare reuse
ooaklee Sep 2, 2026
1468b85
ASoC: q6apm: reserve the protected position token
ooaklee Sep 2, 2026
d0b7173
ASoC: q6apm: hard-stop uncertain protected pull
ooaklee Sep 2, 2026
b02ced1
soundwire: qcom: restore Denali feedback Offset2 parity
ooaklee Sep 3, 2026
9325970
ASoC: wsa884x: restore Denali PA lifecycle
ooaklee Sep 3, 2026
02007b7
ASoC: wsa884x: retain Denali state across clock stop
ooaklee Sep 3, 2026
081baa8
ASoC: qcom: defer Denali backend clears until graph stop
ooaklee Sep 3, 2026
d9ce34f
ASoC: wsa884x: preserve protected Denali PA transitions
ooaklee Sep 3, 2026
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
3 changes: 3 additions & 0 deletions Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ properties:
- qcom,sm8650-sndcard
- qcom,sm8750-sndcard
- const: qcom,sm8450-sndcard
- items:
- const: microsoft,denali-sndcard
- const: qcom,x1e80100-sndcard
- enum:
- dell,xps13-9345-sndcard
- fairphone,fp4-sndcard
Expand Down
35 changes: 33 additions & 2 deletions Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,39 @@ properties:
minItems: 6
maxItems: 6

qcom,enable-cps:
type: boolean
description: Enable the dedicated CPS SoundWire source DAI on data port 6.

qcom,cps-offset1:
$ref: /schemas/types.yaml#/definitions/uint32
maximum: 255
description: |
Slave-only SoundWire DP6 OffsetCtrl1 override for CPS. This does not
change the physical master-port schedule selected by qcom,port-mapping.

qcom,visense-channel-mask:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 255
description: |
Native WSA data-port-5 channel-enable mask for the VISENSE protection
sidechain. If absent, the codec default is used.

qcom,speaker-load-ohms:
enum: [4, 8]
description: |
Nominal speaker load impedance in ohms. A 4-ohm load selects the
matching PA gain and PBR thresholds when the amplifier reports a 2S
VPHX supply. If absent, the existing 8-ohm defaults are retained.

'#sound-dai-cells':
const: 0
enum: [0, 1]
description: |
Zero selects the legacy single speaker-playback DAI. With one cell,
DAI 0 is speaker playback, DAI 1 is the render-coupled VISENSE
protection-feedback sidechain, and DAI 2 is the dedicated CPS feedback
sidechain when qcom,enable-cps is present.

vdd-1p8-supply: true
vdd-io-supply: true
Expand Down Expand Up @@ -75,7 +106,7 @@ examples:
pinctrl-names = "default";
pinctrl-0 = <&spkr_2_sd_n_active>;
powerdown-gpios = <&lpass_tlmm 18 GPIO_ACTIVE_LOW>;
#sound-dai-cells = <0>;
#sound-dai-cells = <1>;
sound-name-prefix = "SpkrRight";
vdd-1p8-supply = <&vreg_l15b_1p8>;
vdd-io-supply = <&vreg_l3g_1p2>;
Expand Down
62 changes: 58 additions & 4 deletions arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,8 @@
};

sound {
compatible = "qcom,x1e80100-sndcard";
compatible = "microsoft,denali-sndcard",
"qcom,x1e80100-sndcard";
model = "X1E80100-Microsoft-Surface-Pro-11";
audio-routing = "SpkrLeft IN", "WSA WSA_SPK1 OUT",
"SpkrRight IN", "WSA WSA_SPK2 OUT",
Expand All @@ -333,7 +334,7 @@
link-name = "WSA Playback";

codec {
sound-dai = <&left_spkr>, <&right_spkr>,
sound-dai = <&left_spkr 0>, <&right_spkr 0>,
<&swr0 0>, <&lpass_wsamacro 0>;
};

Expand All @@ -346,6 +347,51 @@
};
};

wsa-vi-dai-link {
link-name = "WSA VI Protection";

/*
* One two-channel Windows-equivalent feedback transport:
* amplifier VISENSE ports 10/11 -> WSA macro VI ->
* SoundWire DIN0 -> AudioReach WSA TX0.
*/
codec {
sound-dai = <&left_spkr 1>, <&right_spkr 1>,
<&swr0 9>, <&lpass_wsamacro 2>;
};

cpu {
sound-dai = <&q6apmbedai WSA_CODEC_DMA_TX_0>;
};

platform {
sound-dai = <&q6apm>;
};
};

wsa-cps-dai-link {
link-name = "WSA CPS Protection";

/*
* Dedicated CPS sidechain: both WSA8845 DP6 sources share
* physical SoundWire master port 13. swr0 DAI 10 is only
* the independent ASoC/SoundWire stream handle; qcom,port-mapping
* below remains authoritative for the physical master ports.
*/
codec {
sound-dai = <&left_spkr 2>, <&right_spkr 2>,
<&swr0 10>, <&lpass_wsamacro 4>;
};

cpu {
sound-dai = <&q6apmbedai WSA_CODEC_DMA_TX_1>;
};

platform {
sound-dai = <&q6apm>;
};
};

va-dai-link {
link-name = "VA Capture";

Expand Down Expand Up @@ -1142,23 +1188,31 @@
compatible = "sdw20217020400";
reg = <0 0>;
reset-gpios = <&lpass_tlmm 12 GPIO_ACTIVE_LOW>;
#sound-dai-cells = <0>;
#sound-dai-cells = <1>;
sound-name-prefix = "SpkrLeft";
vdd-1p8-supply = <&vreg_l15b_1p8>;
vdd-io-supply = <&vreg_l12b_1p2>;
qcom,port-mapping = <1 2 3 7 10 13>;
qcom,speaker-load-ohms = <4>;
qcom,visense-channel-mask = <3>;
qcom,enable-cps;
qcom,cps-offset1 = <0>;
};

/* WSA8845, Right Speaker */
right_spkr: speaker@0,1 {
compatible = "sdw20217020400";
reg = <0 1>;
reset-gpios = <&lpass_tlmm 12 GPIO_ACTIVE_LOW>;
#sound-dai-cells = <0>;
#sound-dai-cells = <1>;
sound-name-prefix = "SpkrRight";
vdd-1p8-supply = <&vreg_l15b_1p8>;
vdd-io-supply = <&vreg_l12b_1p2>;
qcom,port-mapping = <4 5 6 7 11 13>;
qcom,speaker-load-ohms = <4>;
qcom,visense-channel-mask = <3>;
qcom,enable-cps;
qcom,cps-offset1 = <25>;
};
};

Expand Down
61 changes: 48 additions & 13 deletions drivers/soc/qcom/apr.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,35 @@ int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt)
}
EXPORT_SYMBOL_GPL(apr_send_pkt);

void gpr_free_port(gpr_port_t *port)
static void pkt_router_svc_put(struct pkt_router_svc *svc)
{
if (refcount_dec_and_test(&svc->callback_refs))
complete(&svc->callbacks_drained);
}

static void pkt_router_svc_remove(struct pkt_router_svc *svc)
{
struct packet_router *gpr = port->pr;
struct packet_router *pr = svc->pr;
unsigned long flags;

spin_lock_irqsave(&gpr->svcs_lock, flags);
idr_remove(&gpr->svcs_idr, port->id);
spin_unlock_irqrestore(&gpr->svcs_lock, flags);
spin_lock_irqsave(&pr->svcs_lock, flags);
idr_remove(&pr->svcs_idr, svc->id);
spin_unlock_irqrestore(&pr->svcs_lock, flags);

if (!refcount_dec_and_test(&svc->callback_refs))
wait_for_completion(&svc->callbacks_drained);
}

/**
* gpr_free_port() - unregister a dynamic GPR port after callbacks drain
* @port: dynamic port returned by gpr_alloc_port()
*
* Context: process context, and never from @port's own callback.
*/
void gpr_free_port(gpr_port_t *port)
{
might_sleep();
pkt_router_svc_remove(port);
kfree(port);
}
EXPORT_SYMBOL_GPL(gpr_free_port);
Expand All @@ -105,6 +125,8 @@ gpr_port_t *gpr_alloc_port(struct apr_device *gdev, struct device *dev,
svc->priv = priv;
svc->dev = dev;
spin_lock_init(&svc->lock);
refcount_set(&svc->callback_refs, 1);
init_completion(&svc->callbacks_drained);

spin_lock(&pr->svcs_lock);
id = idr_alloc_cyclic(&pr->svcs_idr, svc, GPR_DYNAMIC_PORT_START,
Expand Down Expand Up @@ -191,7 +213,7 @@ static int apr_do_rx_callback(struct packet_router *apr, struct apr_rx_buf *abuf
{
uint16_t hdr_size, msg_type, ver, svc_id;
struct pkt_router_svc *svc;
struct apr_device *adev;
struct apr_device *adev = NULL;
struct apr_driver *adrv = NULL;
struct apr_resp_pkt resp;
struct apr_hdr *hdr;
Expand Down Expand Up @@ -232,13 +254,17 @@ static int apr_do_rx_callback(struct packet_router *apr, struct apr_rx_buf *abuf
svc_id = hdr->dest_svc;
spin_lock_irqsave(&apr->svcs_lock, flags);
svc = idr_find(&apr->svcs_idr, svc_id);
if (svc && !refcount_inc_not_zero(&svc->callback_refs))
svc = NULL;
if (svc && svc->dev->driver) {
adev = svc_to_apr_device(svc);
adrv = to_apr_driver(adev->dev.driver);
}
spin_unlock_irqrestore(&apr->svcs_lock, flags);

if (!adrv || !adev) {
if (svc)
pkt_router_svc_put(svc);
dev_err(apr->dev, "APR: service is not registered (%d)\n",
svc_id);
return -EINVAL;
Expand All @@ -255,6 +281,7 @@ static int apr_do_rx_callback(struct packet_router *apr, struct apr_rx_buf *abuf
resp.payload = buf + hdr_size;

adrv->callback(adev, &resp);
pkt_router_svc_put(svc);

return 0;
}
Expand Down Expand Up @@ -298,6 +325,8 @@ static int gpr_do_rx_callback(struct packet_router *gpr, struct apr_rx_buf *abuf

spin_lock_irqsave(&gpr->svcs_lock, flags);
svc = idr_find(&gpr->svcs_idr, hdr->dest_port);
if (svc && !refcount_inc_not_zero(&svc->callback_refs))
svc = NULL;
spin_unlock_irqrestore(&gpr->svcs_lock, flags);

if (!svc) {
Expand All @@ -308,6 +337,7 @@ static int gpr_do_rx_callback(struct packet_router *gpr, struct apr_rx_buf *abuf

if (svc->callback)
svc->callback(&resp, svc->priv, 0);
pkt_router_svc_put(svc);

return 0;
}
Expand Down Expand Up @@ -378,13 +408,10 @@ static void apr_device_remove(struct device *dev)
{
struct apr_device *adev = to_apr_device(dev);
struct apr_driver *adrv = to_apr_driver(dev->driver);
struct packet_router *apr = dev_get_drvdata(adev->dev.parent);

pkt_router_svc_remove(&adev->svc);
if (adrv->remove)
adrv->remove(adev);
spin_lock(&apr->svcs_lock);
idr_remove(&apr->svcs_idr, adev->svc.id);
spin_unlock(&apr->svcs_lock);
}

static int apr_uevent(const struct device *dev, struct kobj_uevent_env *env)
Expand Down Expand Up @@ -428,6 +455,8 @@ static int apr_add_device(struct device *dev, struct device_node *np,
svc->priv = adev;
svc->dev = dev;
spin_lock_init(&svc->lock);
refcount_set(&svc->callback_refs, 1);
init_completion(&svc->callbacks_drained);

adev->domain_id = domain_id;

Expand Down Expand Up @@ -458,26 +487,32 @@ static int apr_add_device(struct device *dev, struct device_node *np,
spin_unlock(&apr->svcs_lock);
if (ret < 0) {
dev_err(dev, "idr_alloc failed: %d\n", ret);
goto out;
goto free_adev;
}

/* Protection domain is optional, it does not exist on older platforms */
ret = of_property_read_string_index(np, "qcom,protection-domain",
1, &adev->service_path);
if (ret < 0 && ret != -EINVAL) {
dev_err(dev, "Failed to read second value of qcom,protection-domain\n");
goto out;
goto remove_svc;
}

dev_info(dev, "Adding APR/GPR dev: %s\n", dev_name(&adev->dev));

ret = device_register(&adev->dev);
if (ret) {
dev_err(dev, "device_register failed: %d\n", ret);
pkt_router_svc_remove(svc);
put_device(&adev->dev);
}

out:
return ret;

remove_svc:
pkt_router_svc_remove(svc);
free_adev:
kfree(adev);
return ret;
}

Expand Down
4 changes: 4 additions & 0 deletions drivers/soundwire/bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ int sdw_find_col_index(int col);
* @ch_mask: Channel mask
* @transport_params: Transport parameters
* @port_params: Port parameters
* @transport_params_override_mask: Bitmask of per-slave transport overrides
* @transport_params_override: Per-slave transport override values
* @port_node: List node for Master or Slave port_list
* @lane: Which lane is used
*
Expand All @@ -128,6 +130,8 @@ struct sdw_port_runtime {
int ch_mask;
struct sdw_transport_params transport_params;
struct sdw_port_params port_params;
unsigned int transport_params_override_mask;
struct sdw_transport_params transport_params_override;
struct list_head port_node;
unsigned int lane;
};
Expand Down
Loading
Loading