summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2025-07-28 14:28:21 +0200
committerTakashi Iwai <tiwai@suse.de>2025-07-28 14:28:21 +0200
commitd35cdd6ed55e15f0c3ed60b36fc97beb5571332c (patch)
treee400a34476bd812c34f613ec4131daf3dfc76cb3
parent8a15ca0ca51399b652b1bbb23b590b220cf03d62 (diff)
parente95122a32e777309412e30dc638dbc88b9036811 (diff)
Merge tag 'asoc-v6.17-2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: More updates for v6.17 A few more updates, mostly fixes and device IDs plus some small enhancements for the FSL xcvr driver.
-rw-r--r--Documentation/devicetree/bindings/sound/atmel,at91-ssc.yaml11
-rw-r--r--include/sound/sdca_function.h14
-rw-r--r--sound/soc/codecs/aw88399.c9
-rw-r--r--sound/soc/fsl/fsl_xcvr.c25
-rw-r--r--sound/soc/fsl/imx-card.c40
-rw-r--r--sound/soc/sdca/sdca_functions.c99
-rw-r--r--sound/soc/sdca/sdca_regmap.c29
7 files changed, 172 insertions, 55 deletions
diff --git a/Documentation/devicetree/bindings/sound/atmel,at91-ssc.yaml b/Documentation/devicetree/bindings/sound/atmel,at91-ssc.yaml
index a05e61431824..ce99c2d8c35d 100644
--- a/Documentation/devicetree/bindings/sound/atmel,at91-ssc.yaml
+++ b/Documentation/devicetree/bindings/sound/atmel,at91-ssc.yaml
@@ -16,9 +16,14 @@ description:
properties:
compatible:
- enum:
- - atmel,at91rm9200-ssc
- - atmel,at91sam9g45-ssc
+ oneOf:
+ - enum:
+ - atmel,at91rm9200-ssc
+ - atmel,at91sam9g45-ssc
+ - items:
+ - enum:
+ - microchip,sam9x7-ssc
+ - const: atmel,at91sam9g45-ssc
reg:
maxItems: 1
diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h
index 90d77fc46416..06ec126cdcc3 100644
--- a/include/sound/sdca_function.h
+++ b/include/sound/sdca_function.h
@@ -742,14 +742,14 @@ struct sdca_control_range {
* struct sdca_control - information for one SDCA Control
* @label: Name for the Control, from SDCA Specification v1.0, section 7.1.7.
* @sel: Identifier used for addressing.
- * @value: Holds the Control value for constants and defaults.
* @nbits: Number of bits used in the Control.
- * @interrupt_position: SCDA interrupt line that will alert to changes on this
- * Control.
+ * @values: Holds the Control value for constants and defaults.
* @cn_list: A bitmask showing the valid Control Numbers within this Control,
* Control Numbers typically represent channels.
- * @range: Buffer describing valid range of values for the Control.
+ * @interrupt_position: SCDA interrupt line that will alert to changes on this
+ * Control.
* @type: Format of the data in the Control.
+ * @range: Buffer describing valid range of values for the Control.
* @mode: Access mode of the Control.
* @layers: Bitmask of access layers of the Control.
* @deferrable: Indicates if the access to the Control can be deferred.
@@ -760,13 +760,13 @@ struct sdca_control {
const char *label;
int sel;
- int value;
int nbits;
- int interrupt_position;
+ int *values;
u64 cn_list;
+ int interrupt_position;
- struct sdca_control_range range;
enum sdca_control_datatype type;
+ struct sdca_control_range range;
enum sdca_access_mode mode;
u8 layers;
diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c
index bad3ad6b8c0e..c23e70d64d0c 100644
--- a/sound/soc/codecs/aw88399.c
+++ b/sound/soc/codecs/aw88399.c
@@ -2330,9 +2330,18 @@ static const struct i2c_device_id aw88399_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, aw88399_i2c_id);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id aw88399_acpi_match[] = {
+ { "AWDZ8399", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, aw88399_acpi_match);
+#endif
+
static struct i2c_driver aw88399_i2c_driver = {
.driver = {
.name = AW88399_I2C_NAME,
+ .acpi_match_table = ACPI_PTR(aw88399_acpi_match),
},
.probe = aw88399_i2c_probe,
.id_table = aw88399_i2c_id,
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index e3111dd80be4..5d804860f7d8 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -1395,7 +1395,7 @@ static irqreturn_t irq0_isr(int irq, void *devid)
if (isr & FSL_XCVR_IRQ_NEW_CS) {
dev_dbg(dev, "Received new CS block\n");
isr_clr |= FSL_XCVR_IRQ_NEW_CS;
- if (!xcvr->soc_data->spdif_only) {
+ if (xcvr->soc_data->fw_name) {
/* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_PAGE_MASK,
@@ -1423,6 +1423,26 @@ static irqreturn_t irq0_isr(int irq, void *devid)
/* clear CS control register */
memset_io(reg_ctrl, 0, sizeof(val));
}
+ } else {
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_0,
+ (u32 *)&xcvr->rx_iec958.status[0]);
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_1,
+ (u32 *)&xcvr->rx_iec958.status[4]);
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_2,
+ (u32 *)&xcvr->rx_iec958.status[8]);
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_3,
+ (u32 *)&xcvr->rx_iec958.status[12]);
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_4,
+ (u32 *)&xcvr->rx_iec958.status[16]);
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_5,
+ (u32 *)&xcvr->rx_iec958.status[20]);
+ for (i = 0; i < 6; i++) {
+ val = *(u32 *)(xcvr->rx_iec958.status + i * 4);
+ *(u32 *)(xcvr->rx_iec958.status + i * 4) =
+ bitrev32(val);
+ }
+ regmap_set_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
+ FSL_XCVR_RX_DPTH_CTRL_CSA);
}
}
if (isr & FSL_XCVR_IRQ_NEW_UD) {
@@ -1497,6 +1517,7 @@ static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = {
};
static const struct fsl_xcvr_soc_data fsl_xcvr_imx95_data = {
+ .fw_name = "imx/xcvr/xcvr-imx95.bin",
.spdif_only = true,
.use_phy = true,
.use_edma = true,
@@ -1786,7 +1807,7 @@ static int fsl_xcvr_runtime_resume(struct device *dev)
}
}
- if (xcvr->mode == FSL_XCVR_MODE_EARC) {
+ if (xcvr->soc_data->fw_name) {
ret = fsl_xcvr_load_firmware(xcvr);
if (ret) {
dev_err(dev, "failed to load firmware.\n");
diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c
index ea5dbb54b584..28699d7b75ca 100644
--- a/sound/soc/fsl/imx-card.c
+++ b/sound/soc/fsl/imx-card.c
@@ -26,6 +26,7 @@ enum codec_type {
CODEC_AK4497,
CODEC_AK5552,
CODEC_CS42888,
+ CODEC_WM8524,
};
/*
@@ -196,6 +197,13 @@ static struct imx_akcodec_tdm_fs_mul cs42888_tdm_fs_mul[] = {
{ .min = 256, .max = 256, .mul = 256 },
};
+static struct imx_akcodec_fs_mul wm8524_fs_mul[] = {
+ { .rmin = 8000, .rmax = 32000, .wmin = 256, .wmax = 1152, },
+ { .rmin = 44100, .rmax = 48000, .wmin = 256, .wmax = 768, },
+ { .rmin = 88200, .rmax = 96000, .wmin = 128, .wmax = 384, },
+ { .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 192, },
+};
+
static const u32 akcodec_rates[] = {
8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
96000, 176400, 192000, 352800, 384000, 705600, 768000,
@@ -229,6 +237,10 @@ static const u32 cs42888_tdm_channels[] = {
1, 2, 3, 4, 5, 6, 7, 8,
};
+static const u32 wm8524_channels[] = {
+ 2,
+};
+
static bool format_is_dsd(struct snd_pcm_hw_params *params)
{
snd_pcm_format_t format = params_format(params);
@@ -261,6 +273,7 @@ static bool codec_is_akcodec(unsigned int type)
case CODEC_AK5558:
case CODEC_AK5552:
case CODEC_CS42888:
+ case CODEC_WM8524:
return true;
default:
break;
@@ -477,9 +490,24 @@ static int imx_aif_startup(struct snd_pcm_substream *substream)
return ret;
}
+static void imx_aif_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai;
+ struct snd_soc_dai *codec_dai;
+ int i;
+
+ for_each_rtd_cpu_dais(rtd, i, cpu_dai)
+ snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT);
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai)
+ snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN);
+}
+
static const struct snd_soc_ops imx_aif_ops = {
.hw_params = imx_aif_hw_params,
.startup = imx_aif_startup,
+ .shutdown = imx_aif_shutdown,
};
static const struct snd_soc_ops imx_aif_ops_be = {
@@ -632,6 +660,8 @@ static int imx_card_parse_of(struct imx_card_data *data)
plat_data->type = CODEC_AK5552;
else if (!strcmp(link->codecs->dai_name, "cs42888"))
plat_data->type = CODEC_CS42888;
+ else if (!strcmp(link->codecs->dai_name, "wm8524-hifi"))
+ plat_data->type = CODEC_WM8524;
} else {
link->codecs = &snd_soc_dummy_dlc;
@@ -805,6 +835,10 @@ static int imx_card_probe(struct platform_device *pdev)
data->dapm_routes[1].sink = "CPU-Capture";
data->dapm_routes[1].source = "Capture";
break;
+ case CODEC_WM8524:
+ data->dapm_routes[0].sink = "Playback";
+ data->dapm_routes[0].source = "CPU-Playback";
+ break;
default:
break;
}
@@ -854,6 +888,12 @@ static int imx_card_probe(struct platform_device *pdev)
plat_data->support_tdm_channels = cs42888_tdm_channels;
plat_data->num_tdm_channels = ARRAY_SIZE(cs42888_tdm_channels);
break;
+ case CODEC_WM8524:
+ plat_data->fs_mul = wm8524_fs_mul;
+ plat_data->num_fs_mul = ARRAY_SIZE(wm8524_fs_mul);
+ plat_data->support_channels = wm8524_channels;
+ plat_data->num_channels = ARRAY_SIZE(wm8524_channels);
+ break;
default:
break;
}
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index 93767e73bc5f..f26f597dca9e 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -814,6 +814,43 @@ static int find_sdca_control_range(struct device *dev,
return 0;
}
+static int find_sdca_control_value(struct device *dev, struct sdca_entity *entity,
+ struct fwnode_handle *control_node,
+ struct sdca_control *control,
+ const char * const label)
+{
+ char property[SDCA_PROPERTY_LENGTH];
+ bool global = true;
+ int ret, cn, i;
+ u32 tmp;
+
+ snprintf(property, sizeof(property), "mipi-sdca-control-%s", label);
+
+ ret = fwnode_property_read_u32(control_node, property, &tmp);
+ if (ret == -EINVAL)
+ global = false;
+ else if (ret)
+ return ret;
+
+ i = 0;
+ for_each_set_bit(cn, (unsigned long *)&control->cn_list,
+ BITS_PER_TYPE(control->cn_list)) {
+ if (!global) {
+ snprintf(property, sizeof(property),
+ "mipi-sdca-control-cn-%d-%s", cn, label);
+
+ ret = fwnode_property_read_u32(control_node, property, &tmp);
+ if (ret)
+ return ret;
+ }
+
+ control->values[i] = tmp;
+ i++;
+ }
+
+ return 0;
+}
+
/*
* TODO: Add support for -cn- properties, allowing different channels to have
* different defaults etc.
@@ -843,44 +880,44 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
control->layers = tmp;
+ ret = fwnode_property_read_u64(control_node, "mipi-sdca-control-cn-list",
+ &control->cn_list);
+ if (ret == -EINVAL) {
+ /* Spec allows not specifying cn-list if only the first number is used */
+ control->cn_list = 0x1;
+ } else if (ret || !control->cn_list) {
+ dev_err(dev, "%s: control %#x: cn list missing: %d\n",
+ entity->label, control->sel, ret);
+ return ret;
+ }
+
+ control->values = devm_kzalloc(dev, hweight64(control->cn_list), GFP_KERNEL);
+ if (!control->values)
+ return -ENOMEM;
+
switch (control->mode) {
case SDCA_ACCESS_MODE_DC:
- ret = fwnode_property_read_u32(control_node,
- "mipi-sdca-control-dc-value",
- &tmp);
+ ret = find_sdca_control_value(dev, entity, control_node, control,
+ "dc-value");
if (ret) {
dev_err(dev, "%s: control %#x: dc value missing: %d\n",
entity->label, control->sel, ret);
return ret;
}
- control->value = tmp;
control->has_fixed = true;
break;
case SDCA_ACCESS_MODE_RW:
case SDCA_ACCESS_MODE_DUAL:
- ret = fwnode_property_read_u32(control_node,
- "mipi-sdca-control-default-value",
- &tmp);
- if (!ret) {
- control->value = tmp;
+ ret = find_sdca_control_value(dev, entity, control_node, control,
+ "default-value");
+ if (!ret)
control->has_default = true;
- }
-
- ret = fwnode_property_read_u32(control_node,
- "mipi-sdca-control-fixed-value",
- &tmp);
- if (!ret) {
- if (control->has_default && control->value != tmp) {
- dev_err(dev,
- "%s: control %#x: default and fixed value don't match\n",
- entity->label, control->sel);
- return -EINVAL;
- }
- control->value = tmp;
+ ret = find_sdca_control_value(dev, entity, control_node, control,
+ "fixed-value");
+ if (!ret)
control->has_fixed = true;
- }
fallthrough;
case SDCA_ACCESS_MODE_RO:
control->deferrable = fwnode_property_read_bool(control_node,
@@ -897,17 +934,6 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
return ret;
}
- ret = fwnode_property_read_u64(control_node, "mipi-sdca-control-cn-list",
- &control->cn_list);
- if (ret == -EINVAL) {
- /* Spec allows not specifying cn-list if only the first number is used */
- control->cn_list = 0x1;
- } else if (ret || !control->cn_list) {
- dev_err(dev, "%s: control %#x: cn list missing: %d\n",
- entity->label, control->sel, ret);
- return ret;
- }
-
ret = fwnode_property_read_u32(control_node,
"mipi-sdca-control-interrupt-position",
&tmp);
@@ -923,11 +949,10 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
control->type = find_sdca_control_datatype(entity, control);
control->nbits = find_sdca_control_bits(entity, control);
- dev_info(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d value %#x %s\n",
+ dev_info(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d %s\n",
entity->label, control->label, control->sel,
control->mode, control->layers, control->cn_list,
- control->interrupt_position, control->value,
- control->deferrable ? "deferrable" : "");
+ control->interrupt_position, control->deferrable ? "deferrable" : "");
return 0;
}
diff --git a/sound/soc/sdca/sdca_regmap.c b/sound/soc/sdca/sdca_regmap.c
index 66e7eee7d7f4..5cb3048ea8cf 100644
--- a/sound/soc/sdca/sdca_regmap.c
+++ b/sound/soc/sdca/sdca_regmap.c
@@ -72,12 +72,18 @@ bool sdca_regmap_readable(struct sdca_function_data *function, unsigned int reg)
if (!control)
return false;
+ if (!(BIT(SDW_SDCA_CTL_CNUM(reg)) & control->cn_list))
+ return false;
+
switch (control->mode) {
case SDCA_ACCESS_MODE_RW:
case SDCA_ACCESS_MODE_RO:
- case SDCA_ACCESS_MODE_DUAL:
case SDCA_ACCESS_MODE_RW1S:
case SDCA_ACCESS_MODE_RW1C:
+ if (SDW_SDCA_NEXT_CTL(0) & reg)
+ return false;
+ fallthrough;
+ case SDCA_ACCESS_MODE_DUAL:
/* No access to registers marked solely for device use */
return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
default:
@@ -104,11 +110,17 @@ bool sdca_regmap_writeable(struct sdca_function_data *function, unsigned int reg
if (!control)
return false;
+ if (!(BIT(SDW_SDCA_CTL_CNUM(reg)) & control->cn_list))
+ return false;
+
switch (control->mode) {
case SDCA_ACCESS_MODE_RW:
- case SDCA_ACCESS_MODE_DUAL:
case SDCA_ACCESS_MODE_RW1S:
case SDCA_ACCESS_MODE_RW1C:
+ if (SDW_SDCA_NEXT_CTL(0) & reg)
+ return false;
+ fallthrough;
+ case SDCA_ACCESS_MODE_DUAL:
/* No access to registers marked solely for device use */
return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
default:
@@ -241,7 +253,7 @@ int sdca_regmap_populate_constants(struct device *dev,
struct sdca_function_data *function,
struct reg_default *consts)
{
- int i, j, k;
+ int i, j, k, l;
for (i = 0, k = 0; i < function->num_entities; i++) {
struct sdca_entity *entity = &function->entities[i];
@@ -253,13 +265,15 @@ int sdca_regmap_populate_constants(struct device *dev,
if (control->mode != SDCA_ACCESS_MODE_DC)
continue;
+ l = 0;
for_each_set_bit(cn, (unsigned long *)&control->cn_list,
BITS_PER_TYPE(control->cn_list)) {
consts[k].reg = SDW_SDCA_CTL(function->desc->adr,
entity->id,
control->sel, cn);
- consts[k].def = control->value;
+ consts[k].def = control->values[l];
k++;
+ l++;
}
}
}
@@ -283,7 +297,7 @@ EXPORT_SYMBOL_NS(sdca_regmap_populate_constants, "SND_SOC_SDCA");
int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
struct sdca_function_data *function)
{
- int i, j;
+ int i, j, k;
int ret;
for (i = 0; i < function->num_entities; i++) {
@@ -299,6 +313,7 @@ int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
if (!control->has_default && !control->has_fixed)
continue;
+ k = 0;
for_each_set_bit(cn, (unsigned long *)&control->cn_list,
BITS_PER_TYPE(control->cn_list)) {
unsigned int reg;
@@ -306,9 +321,11 @@ int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
reg = SDW_SDCA_CTL(function->desc->adr, entity->id,
control->sel, cn);
- ret = regmap_write(regmap, reg, control->value);
+ ret = regmap_write(regmap, reg, control->values[k]);
if (ret)
return ret;
+
+ k++;
}
}
}