arm64: dts: qcom: milos-fairphone-fp6: enable Senary MI2S dai-link

Uncomment the Senary MI2S speaker dai-link. The sc8280xp machine driver
gained Senary MI2S support and the aw88261 power-up check is fixed (both
carried on this branch), so the link is functional: both AW88261 amps
load their ACF firmware and play.

This restores the enablement that was lost when the audio carries were
rebased from the v7.0.8 stack onto v7.1.2-milos: only the two driver
patches were carried over, leaving the sound card with zero dai-links
(the card registers but stays empty - no PCMs, no controls).

Assisted-by: Claude:claude-fable-5
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
This commit is contained in:
Jorijn van der Graaf 2026-07-05 02:51:59 +02:00
commit 4a0d53f108
3 changed files with 198 additions and 2 deletions

View file

@ -216,7 +216,6 @@
pinctrl-names = "default",
"sleep";
/*
i2s-dai-link {
link-name = "Senary MI2S Playback";
@ -232,7 +231,6 @@
sound-dai = <&q6apm>;
};
};
*/
};
thermal-zones {

View file

@ -0,0 +1,135 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2026, Jorijn van der Graaf
*
* SoundWire slave driver for the Qualcomm WCD9378 audio codec.
*
* Bring-up skeleton: binds to the two WCD9378 SoundWire devices (TX and
* RX), maps the SDCA control space through regmap and verifies the device
* identity registers. No audio paths yet.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw_type.h>
#include "wcd9378.h"
struct wcd9378_sdw_priv {
struct sdw_slave *sdev;
struct regmap *regmap;
};
static const struct regmap_config wcd9378_sdw_regmap_config = {
.name = "wcd9378_sdw",
.reg_bits = 32,
.val_bits = 8,
.cache_type = REGCACHE_NONE,
.max_register = WCD9378_MAX_REGISTER,
};
static void wcd9378_sdw_read_id(struct wcd9378_sdw_priv *wcd)
{
struct device *dev = &wcd->sdev->dev;
static const struct {
const char *name;
unsigned int reg;
} id_regs[] = {
{ "DEV_MANU_ID_0", WCD9378_DEV_MANU_ID_0 },
{ "DEV_MANU_ID_1", WCD9378_DEV_MANU_ID_1 },
{ "DEV_PART_ID_0", WCD9378_DEV_PART_ID_0 },
{ "DEV_PART_ID_1", WCD9378_DEV_PART_ID_1 },
{ "DEV_VER", WCD9378_DEV_VER },
{ "FUNC_EXT_ID_0", WCD9378_FUNC_EXT_ID_0 },
{ "FUNC_EXT_ID_1", WCD9378_FUNC_EXT_ID_1 },
{ "ANA_BIAS", WCD9378_ANA_BIAS },
{ "ANA_TX_CH1", WCD9378_ANA_TX_CH1 },
{ "ANA_MICB1", WCD9378_ANA_MICB1 },
{ "SYS_USAGE_CTRL", WCD9378_SYS_USAGE_CTRL },
};
unsigned int val, packed, pval;
int i, ret, pret;
for (i = 0; i < ARRAY_SIZE(id_regs); i++) {
/* downstream WCD9378_REG() wire packing */
packed = ((id_regs[i].reg & 0x0ff00000) >> 8) |
(id_regs[i].reg & 0xfff);
ret = regmap_read(wcd->regmap, id_regs[i].reg, &val);
pret = regmap_read(wcd->regmap, packed, &pval);
dev_info(dev, "%s: virt %#010x = %#04x (ret %d), packed %#07x = %#04x (ret %d)\n",
id_regs[i].name,
id_regs[i].reg, ret ? 0xdead : val, ret,
packed, pret ? 0xdead : pval, pret);
}
}
static int wcd9378_sdw_update_status(struct sdw_slave *slave,
enum sdw_slave_status status)
{
struct wcd9378_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
dev_info(&slave->dev, "status %d (dev_num %d)\n", status,
slave->dev_num);
if (status == SDW_SLAVE_ATTACHED)
wcd9378_sdw_read_id(wcd);
return 0;
}
static const struct sdw_slave_ops wcd9378_sdw_ops = {
.update_status = wcd9378_sdw_update_status,
};
static int wcd9378_sdw_probe(struct sdw_slave *pdev,
const struct sdw_device_id *id)
{
struct device *dev = &pdev->dev;
struct wcd9378_sdw_priv *wcd;
wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
if (!wcd)
return -ENOMEM;
wcd->sdev = pdev;
dev_set_drvdata(dev, wcd);
pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF |
SDW_SCP_INT1_BUS_CLASH |
SDW_SCP_INT1_PARITY;
pdev->prop.simple_clk_stop_capable = true;
/* The SDCA control space sits above the 16-bit address range */
pdev->prop.paging_support = true;
wcd->regmap = devm_regmap_init_sdw(pdev, &wcd9378_sdw_regmap_config);
if (IS_ERR(wcd->regmap))
return dev_err_probe(dev, PTR_ERR(wcd->regmap),
"regmap init failed\n");
dev_info(dev, "wcd9378 sdw slave probed\n");
return 0;
}
static const struct sdw_device_id wcd9378_sdw_id[] = {
SDW_SLAVE_ENTRY(0x0217, 0x0110, 0),
{ },
};
MODULE_DEVICE_TABLE(sdw, wcd9378_sdw_id);
static struct sdw_driver wcd9378_sdw_driver = {
.probe = wcd9378_sdw_probe,
.ops = &wcd9378_sdw_ops,
.id_table = wcd9378_sdw_id,
.driver = {
.name = "wcd9378-sdw",
},
};
module_sdw_driver(wcd9378_sdw_driver);
MODULE_DESCRIPTION("WCD9378 SoundWire slave driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,63 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2026, Jorijn van der Graaf
*
* Register map for the Qualcomm WCD9378 audio codec.
*
* The codec exposes its control registers in the SoundWire SDCA control
* address space (bit 30 set, SDCA function number in bits 25:22), accessed
* through the TX SoundWire slave. The analog core registers (function 0,
* implementation-defined region at +0x180000) are layout-compatible with
* the WCD937x family.
*/
#ifndef __WCD9378_H__
#define __WCD9378_H__
#include <linux/regmap.h>
#include <sound/soc.h>
/* SDCA function 0 (extension unit): device identity */
#define WCD9378_FUNC_EXT_ID_0 0x40000048
#define WCD9378_FUNC_EXT_ID_1 0x40000049
#define WCD9378_FUNC_EXT_VER 0x40000050
#define WCD9378_FUNC_STAT 0x40080000
#define WCD9378_DEV_MANU_ID_0 0x40100060
#define WCD9378_DEV_MANU_ID_1 0x40100061
#define WCD9378_DEV_PART_ID_0 0x40100068
#define WCD9378_DEV_PART_ID_1 0x40100069
#define WCD9378_DEV_VER 0x40100070
/* Analog core (WCD937x-compatible layout), function 0 + 0x180000 */
#define WCD9378_ANA_PAGE 0x40180000
#define WCD9378_ANA_BIAS 0x40180001
#define WCD9378_ANA_RX_SUPPLIES 0x40180008
#define WCD9378_ANA_TX_CH1 0x4018000e
#define WCD9378_ANA_TX_CH2 0x4018000f
#define WCD9378_ANA_TX_CH3 0x40180010
#define WCD9378_ANA_MICB1 0x40180022
#define WCD9378_ANA_MICB2 0x40180023
#define WCD9378_ANA_MICB2_RAMP 0x40180024
#define WCD9378_ANA_MICB3 0x40180025
/* Sequencer block (SEQR) */
#define WCD9378_SYS_USAGE_CTRL 0x40180501
#define WCD9378_SM0_MB_SEL 0x401805b0
#define WCD9378_SM1_MB_SEL 0x401805b1
#define WCD9378_SM2_MB_SEL 0x401805b2
/* SDCA function activation (one per function) */
#define WCD9378_SMP_AMP_FUNC_STAT 0x40880000
#define WCD9378_SMP_AMP_FUNC_ACT 0x40880008
#define WCD9378_SMP_JACK_FUNC_STAT 0x40c80000
#define WCD9378_SMP_JACK_FUNC_ACT 0x40c80008
#define WCD9378_SMP_MIC_CTRL0_FUNC_STAT 0x41080000
#define WCD9378_SMP_MIC_CTRL0_FUNC_ACT 0x41080008
#define WCD9378_SMP_MIC_CTRL1_FUNC_STAT 0x41480000
#define WCD9378_SMP_MIC_CTRL1_FUNC_ACT 0x41480008
#define WCD9378_SMP_MIC_CTRL2_FUNC_STAT 0x41880000
#define WCD9378_SMP_MIC_CTRL2_FUNC_ACT 0x41880008
#define WCD9378_MAX_REGISTER 0x41900070
#endif /* __WCD9378_H__ */