[PATCH 1/2] ASoC: dt-bindings: Add adi,ssm3515 amp schema
Add a DT schema for the SSM3515 amp by Analog Devices. It's a simple mono amplifier with digital input.
Signed-off-by: Martin Povišer povik+lin@cutebit.org --- .../bindings/sound/adi,ssm3515.yaml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/adi,ssm3515.yaml
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml b/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml new file mode 100644 index 000000000000..19b7185ae8e2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2019-20 Texas Instruments Incorporated +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/sound/adi,ssm3515.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Analog Devices SSM3515 Audio Amplifier + +maintainers: + - Martin Povišer povik+lin@cutebit.org + +description: | + SSM3515 is a mono Class-D audio amplifier with digital input. + + https://www.analog.com/media/en/technical-documentation/data-sheets/SSM3515.... + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - adi,ssm3515 + + reg: + maxItems: 1 + + adi,ana-gain: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] + description: | + The value to be set in the ANA_GAIN register field on the codec. This determines + the full voltage span of the codec's analog output. + + To quote the datasheet on the available options: + + 00: 8.4 V Full-Scale Gain Mapping + 01: 12.6 V Full-Scale Gain Mapping + 10: 14 V Full-Scale Gain Mapping + 11: 15 V Full-Scale Gain Mapping + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + - adi,ana-gain + +additionalProperties: true + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@14 { + compatible = "adi,ssm3515"; + reg = <0x14>; + #sound-dai-cells = <0>; + adi,ana-gain = <0>; + sound-name-prefix = "Left Tweeter"; + }; + };
The Analog Devices' SSM3515 is a mono audio amplifier with digital input, equipped on Apple's 2021 iMacs. Add an ASoC driver for it, and register both the driver code and schema in MAINTAINERS.
Signed-off-by: Martin Povišer povik+lin@cutebit.org --- MAINTAINERS | 2 + sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ssm3515.c | 482 +++++++++++++++++++++++++++++++++++++ 4 files changed, 492 insertions(+) create mode 100644 sound/soc/codecs/ssm3515.c
diff --git a/MAINTAINERS b/MAINTAINERS index 460f953f331b..78136300b026 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1990,9 +1990,11 @@ M: Martin Povišer povik+lin@cutebit.org L: asahi@lists.linux.dev L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/sound/adi,ssm3515.yaml F: Documentation/devicetree/bindings/sound/apple,* F: sound/soc/apple/* F: sound/soc/codecs/cs42l83-i2c.c +F: sound/soc/codecs/ssm3515.c
ARM/ARTPEC MACHINE SUPPORT M: Jesper Nilsson jesper.nilsson@axis.com diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8020097d4e4c..d5665c21b6f3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1652,6 +1652,12 @@ config SND_SOC_SSM2602_I2C select SND_SOC_SSM2602 select REGMAP_I2C
+config SND_SOC_SSM3515 + tristate "Analog Devices SSM3515 amplifier driver" + select REGMAP_I2C + depends on I2C + depends on OF + config SND_SOC_SSM4567 tristate "Analog Devices ssm4567 amplifier driver support" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5cdbae88e6e3..8a35bc01c486 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -256,6 +256,7 @@ snd-soc-ssm2518-objs := ssm2518.o snd-soc-ssm2602-objs := ssm2602.o snd-soc-ssm2602-spi-objs := ssm2602-spi.o snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o +snd-soc-ssm3515-objs := ssm3515.o snd-soc-ssm4567-objs := ssm4567.o snd-soc-sta32x-objs := sta32x.o snd-soc-sta350-objs := sta350.o @@ -623,6 +624,7 @@ obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o +obj-$(CONFIG_SND_SOC_SSM3515) += snd-soc-ssm3515.o obj-$(CONFIG_SND_SOC_SSM4567) += snd-soc-ssm4567.o obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o diff --git a/sound/soc/codecs/ssm3515.c b/sound/soc/codecs/ssm3515.c new file mode 100644 index 000000000000..278b57d029f6 --- /dev/null +++ b/sound/soc/codecs/ssm3515.c @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +// +// Analog Devices' SSM3515 audio amp driver +// +// Copyright (C) The Asahi Linux Contributors + +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> + +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + + +#define SSM3515_PWR 0x00 +#define SSM3515_PWR_APWDN_EN BIT(7) +#define SSM3515_PWR_BSNS_PWDN BIT(6) +#define SSM3515_PWR_S_RST BIT(1) +#define SSM3515_PWR_SPWDN BIT(0) + +#define SSM3515_GEC 0x01 +#define SSM3515_GEC_EDGE BIT(4) +#define SSM3515_GEC_EDGE_SHIFT 4 +#define SSM3515_GEC_ANA_GAIN GENMASK(1, 0) + +#define SSM3515_DAC 0x02 +#define SSM3515_DAC_HV BIT(7) +#define SSM3515_DAC_MUTE BIT(6) +#define SSM3515_DAC_HPF BIT(5) +#define SSM3515_DAC_LPM BIT(4) +#define SSM3515_DAC_FS GENMASK(2, 0) + +#define SSM3515_DAC_VOL 0x03 + +#define SSM3515_SAI1 0x04 +#define SSM3515_SAI1_DAC_POL BIT(7) +#define SSM3515_SAI1_BCLK_POL BIT(6) +#define SSM3515_SAI1_TDM_BCLKS GENMASK(5, 3) +#define SSM3515_SAI1_FSYNC_MODE BIT(2) +#define SSM3515_SAI1_SDATA_FMT BIT(1) +#define SSM3515_SAI1_SAI_MODE BIT(0) + +#define SSM3515_SAI2 0x05 +#define SSM3515_SAI2_DATA_WIDTH BIT(7) +#define SSM3515_SAI2_AUTO_SLOT BIT(4) +#define SSM3515_SAI2_TDM_SLOT GENMASK(3, 0) + +#define SSM3515_VBAT_OUT 0x06 + +#define SSM3515_STATUS 0x0a +#define SSM3515_STATUS_UVLO_REG BIT(6) +#define SSM3515_STATUS_LIM_EG BIT(5) +#define SSM3515_STATUS_CLIP BIT(4) +#define SSM3515_STATUS_AMP_OC BIT(3) +#define SSM3515_STATUS_OTF BIT(2) +#define SSM3515_STATUS_OTW BIT(1) +#define SSM3515_STATUS_BAT_WARN BIT(0) + +static bool ssm3515_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SSM3515_STATUS: + case SSM3515_VBAT_OUT: + return true; + + default: + return false; + } +} + +static const struct reg_default ssm3515_reg_defaults[] = { + { SSM3515_PWR, 0x81 }, + { SSM3515_GEC, 0x01 }, + { SSM3515_DAC, 0x32 }, + { SSM3515_DAC_VOL, 0x40 }, + { SSM3515_SAI1, 0x11 }, + { SSM3515_SAI2, 0x00 }, +}; + +static const struct regmap_config ssm3515_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = ssm3515_volatile_reg, + .max_register = 0xb, + .reg_defaults = ssm3515_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ssm3515_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +struct ssm3515_data { + struct device *dev; + struct regmap *regmap; + u32 ana_gain; +}; + +// The specced range is -71.25...24.00 dB with step size of 0.375 dB, +// and a mute item below that. This is represented by -71.62...24.00 dB +// with the mute item mapped onto the low end. +static DECLARE_TLV_DB_MINMAX_MUTE(ssm3515_dac_volume, -7162, 2400); + +static const struct snd_kcontrol_new ssm3515_snd_controls[] = { + SOC_SINGLE_TLV("DAC Playback Volume", SSM3515_DAC_VOL, + 0, 255, 1, ssm3515_dac_volume), + SOC_SINGLE("Low EMI Mode Switch", SSM3515_GEC, + __bf_shf(SSM3515_GEC_EDGE), 1, 0), + SOC_SINGLE("Soft Volume Ramping Switch", SSM3515_DAC, + __bf_shf(SSM3515_DAC_HV), 1, 1), + SOC_SINGLE("HPF Switch", SSM3515_DAC, + __bf_shf(SSM3515_DAC_HPF), 1, 0), + SOC_SINGLE("DAC Invert Switch", SSM3515_SAI1, + __bf_shf(SSM3515_SAI1_DAC_POL), 1, 0), +}; + +static void ssm3515_read_faults(struct snd_soc_component *component) +{ + int ret; + + ret = snd_soc_component_read(component, SSM3515_STATUS); + if (ret <= 0) { + /* + * If the read was erroneous, ASoC core has printed a message, + * and that's all that's appropriate in handling the error here. + */ + return; + } + + dev_err(component->dev, "device reports:%s%s%s%s%s%s%s\n", + FIELD_GET(SSM3515_STATUS_UVLO_REG, ret) ? " voltage regulator fault" : "", + FIELD_GET(SSM3515_STATUS_LIM_EG, ret) ? " limiter engaged" : "", + FIELD_GET(SSM3515_STATUS_CLIP, ret) ? " clipping detected" : "", + FIELD_GET(SSM3515_STATUS_AMP_OC, ret) ? " amp over-current fault" : "", + FIELD_GET(SSM3515_STATUS_OTF, ret) ? " overtemperature fault" : "", + FIELD_GET(SSM3515_STATUS_OTW, ret) ? " overtemperature warning" : "", + FIELD_GET(SSM3515_STATUS_BAT_WARN, ret) ? " bat voltage low warning" : ""); +} + +static int ssm3515_reset(struct snd_soc_component *component) +{ + int ret; + + ret = snd_soc_component_update_bits(component, SSM3515_PWR, + SSM3515_PWR_S_RST, SSM3515_PWR_S_RST); + + if (ret < 0) + return ret; + return 0; +} + +static int ssm3515_setup(struct snd_soc_component *component) +{ + struct ssm3515_data *data = + snd_soc_component_get_drvdata(component); + int ret; + + ret = snd_soc_component_update_bits(component, SSM3515_GEC, + SSM3515_GEC_ANA_GAIN, + FIELD_PREP(SSM3515_GEC_ANA_GAIN, data->ana_gain)); + if (ret < 0) + return ret; + + /* Start out muted */ + ret = snd_soc_component_update_bits(component, SSM3515_DAC, + SSM3515_DAC_MUTE, SSM3515_DAC_MUTE); + if (ret < 0) + return ret; + + /* Disable the 'master power-down' */ + ret = snd_soc_component_update_bits(component, SSM3515_PWR, + SSM3515_PWR_SPWDN, 0); + if (ret < 0) + return ret; + + return 0; +} + +static int ssm3515_probe(struct snd_soc_component *component) +{ + struct ssm3515_data *data = + snd_soc_component_get_drvdata(component); + int ret; + + ret = ssm3515_reset(component); + if (ret < 0) + return ret; + regmap_reinit_cache(data->regmap, &ssm3515_i2c_regmap); + + return ssm3515_setup(component); +} + +static int ssm3515_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + int ret; + + ret = snd_soc_component_update_bits(dai->component, + SSM3515_DAC, + SSM3515_DAC_MUTE, + FIELD_PREP(SSM3515_DAC_MUTE, mute)); + if (ret < 0) + return ret; + return 0; +} + +static int ssm3515_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + int ret, rateval; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16: + case SNDRV_PCM_FORMAT_S24: + ret = snd_soc_component_update_bits(component, + SSM3515_SAI2, SSM3515_SAI2_DATA_WIDTH, + FIELD_PREP(SSM3515_SAI2_DATA_WIDTH, + params_width(params) == 16)); + if (ret < 0) + return ret; + break; + + default: + return -EINVAL; + } + + switch (params_rate(params)) { + case 8000 ... 12000: + rateval = 0; + break; + case 16000 ... 24000: + rateval = 1; + break; + case 32000 ... 48000: + rateval = 2; + break; + case 64000 ... 96000: + rateval = 3; + break; + case 128000 ... 192000: + rateval = 4; + break; + case 48001 ... 63999: /* this is ...72000 but overlaps */ + rateval = 5; + break; + default: + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, + SSM3515_DAC, SSM3515_DAC_FS, + FIELD_PREP(SSM3515_DAC_FS, rateval)); + if (ret < 0) + return ret; + + return 0; +} + +static int ssm3515_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + bool fpol_inv = false; /* non-inverted: frame starts with low-to-high FSYNC */ + int ret; + u8 sai1 = 0; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_NF: + case SND_SOC_DAIFMT_IB_IF: + sai1 |= SSM3515_SAI1_BCLK_POL; + break; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + fpol_inv = 1; + sai1 &= ~SSM3515_SAI1_SDATA_FMT; /* 1 bit start delay */ + break; + case SND_SOC_DAIFMT_LEFT_J: + fpol_inv = 0; + sai1 |= SSM3515_SAI1_SDATA_FMT; /* no start delay */ + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + case SND_SOC_DAIFMT_IB_IF: + fpol_inv ^= 1; + break; + } + + /* Set the serial input to 'TDM mode' */ + sai1 |= SSM3515_SAI1_SAI_MODE; + + if (fpol_inv) { + /* + * We configure the codec in a 'TDM mode', in which the + * FSYNC_MODE bit of SAI1 is supposed to select between + * what the datasheet calls 'Pulsed FSYNC mode' and '50% + * FSYNC mode'. + * + * Experiments suggest that this bit in fact simply selects + * the FSYNC polarity, so go with that. + */ + sai1 |= SSM3515_SAI1_FSYNC_MODE; + } + + ret = snd_soc_component_update_bits(component, SSM3515_SAI1, + SSM3515_SAI1_BCLK_POL | SSM3515_SAI1_SDATA_FMT | + SSM3515_SAI1_SAI_MODE | SSM3515_SAI1_FSYNC_MODE, sai1); + + if (ret < 0) + return ret; + return 0; +} + +static int ssm3515_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + int slot, tdm_bclks_val, ret; + + if (tx_mask == 0 || rx_mask != 0) + return -EINVAL; + + slot = __ffs(tx_mask); + + if (tx_mask & ~BIT(slot)) + return -EINVAL; + + switch (slot_width) { + case 16: + tdm_bclks_val = 0; + break; + case 24: + tdm_bclks_val = 1; + break; + case 32: + tdm_bclks_val = 2; + break; + case 48: + tdm_bclks_val = 3; + break; + case 64: + tdm_bclks_val = 4; + break; + default: + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, SSM3515_SAI1, + SSM3515_SAI1_TDM_BCLKS, + FIELD_PREP(SSM3515_SAI1_TDM_BCLKS, tdm_bclks_val)); + if (ret < 0) + return ret; + + ret = snd_soc_component_update_bits(component, SSM3515_SAI2, + SSM3515_SAI2_TDM_SLOT, + FIELD_PREP(SSM3515_SAI2_TDM_SLOT, slot)); + if (ret < 0) + return ret; + + return 0; +} + +static int ssm3515_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + /* + * We don't get live notification of faults, so at least at + * this time, when playback is over, check if we have tripped + * over anything and if so, log it. + */ + ssm3515_read_faults(dai->component); + return 0; +} + +static const struct snd_soc_dai_ops ssm3515_dai_ops = { + .mute_stream = ssm3515_mute, + .hw_params = ssm3515_hw_params, + .set_fmt = ssm3515_set_fmt, + .set_tdm_slot = ssm3515_set_tdm_slot, + .hw_free = ssm3515_hw_free, +}; + +static struct snd_soc_dai_driver ssm3515_dai_driver = { + .name = "SSM3515 SAI", + .id = 0, + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &ssm3515_dai_ops, +}; + +static const struct snd_soc_dapm_widget ssm3515_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("OUT"), +}; + +static const struct snd_soc_dapm_route ssm3515_dapm_routes[] = { + {"OUT", NULL, "DAC"}, + {"DAC", NULL, "Playback"}, +}; + +static const struct snd_soc_component_driver ssm3515_asoc_component = { + .probe = ssm3515_probe, + .controls = ssm3515_snd_controls, + .num_controls = ARRAY_SIZE(ssm3515_snd_controls), + .dapm_widgets = ssm3515_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ssm3515_dapm_widgets), + .dapm_routes = ssm3515_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ssm3515_dapm_routes), + .endianness = 1, +}; + +static int ssm3515_parse_dt(struct ssm3515_data *data) +{ + int ret; + + ret = of_property_read_u32(data->dev->of_node, "adi,ana-gain", + &data->ana_gain); + if (ret) + return dev_err_probe(data->dev, -EINVAL, "missing adi,ana-gain property\n"); + + return 0; +} + +static int ssm3515_i2c_probe(struct i2c_client *client) +{ + struct ssm3515_data *data; + int ret; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = &client->dev; + i2c_set_clientdata(client, data); + + data->regmap = devm_regmap_init_i2c(client, &ssm3515_i2c_regmap); + if (IS_ERR(data->regmap)) + return dev_err_probe(data->dev, PTR_ERR(data->regmap), + "initializing register map"); + + ret = ssm3515_parse_dt(data); + if (ret < 0) + return ret; + + return devm_snd_soc_register_component(data->dev, + &ssm3515_asoc_component, + &ssm3515_dai_driver, 1); +} + +static const struct of_device_id ssm3515_of_match[] = { + { .compatible = "adi,ssm3515" }, + {} +}; +MODULE_DEVICE_TABLE(of, ssm3515_of_match); + +static struct i2c_driver ssm3515_i2c_driver = { + .driver = { + .name = "ssm3515", + .of_match_table = of_match_ptr(ssm3515_of_match), + }, + .probe_new = ssm3515_i2c_probe, +}; +module_i2c_driver(ssm3515_i2c_driver); + +MODULE_AUTHOR("Martin Povišer povik+lin@cutebit.org"); +MODULE_DESCRIPTION("ASoC SSM3515 audio amp driver"); +MODULE_LICENSE("Dual MIT/GPL");
On Tue, May 09, 2023 at 06:38:28PM +0200, Martin Povišer wrote:
+static int ssm3515_setup(struct snd_soc_component *component) +{
- struct ssm3515_data *data =
snd_soc_component_get_drvdata(component);
- int ret;
- ret = snd_soc_component_update_bits(component, SSM3515_GEC,
SSM3515_GEC_ANA_GAIN,
FIELD_PREP(SSM3515_GEC_ANA_GAIN, data->ana_gain));
- if (ret < 0)
return ret;
- /* Start out muted */
- ret = snd_soc_component_update_bits(component, SSM3515_DAC,
SSM3515_DAC_MUTE, SSM3515_DAC_MUTE);
- if (ret < 0)
return ret;
Why are we not using the chip defaults here? We use those for most things as what's appropraite for one user might not be appropriate for another and it's easier to agree to follow what the chip does than to select things. There's some exceptions like for zero cross options but not typically for gains and mutes.
+static int ssm3515_probe(struct snd_soc_component *component) +{
- struct ssm3515_data *data =
snd_soc_component_get_drvdata(component);
- int ret;
- ret = ssm3515_reset(component);
- if (ret < 0)
return ret;
- regmap_reinit_cache(data->regmap, &ssm3515_i2c_regmap);
- return ssm3515_setup(component);
+}
We don't normally reset things on component probe, only on bus level probe...
On 10. 5. 2023, at 4:16, Mark Brown broonie@kernel.org wrote:
On Tue, May 09, 2023 at 06:38:28PM +0200, Martin Povišer wrote:
+static int ssm3515_setup(struct snd_soc_component *component) +{
- struct ssm3515_data *data =
snd_soc_component_get_drvdata(component);
- int ret;
- ret = snd_soc_component_update_bits(component, SSM3515_GEC,
SSM3515_GEC_ANA_GAIN,
FIELD_PREP(SSM3515_GEC_ANA_GAIN, data->ana_gain));
- if (ret < 0)
return ret;
- /* Start out muted */
- ret = snd_soc_component_update_bits(component, SSM3515_DAC,
SSM3515_DAC_MUTE, SSM3515_DAC_MUTE);
- if (ret < 0)
return ret;
Why are we not using the chip defaults here? We use those for most things as what's appropraite for one user might not be appropriate for another and it's easier to agree to follow what the chip does than to select things. There's some exceptions like for zero cross options but not typically for gains and mutes.
This bit is controlled by the mute DAI op, where it is expected the component starts out muted. The datasheet promises pop-free experience if this bit is sequenced with the disablement of clocks, so it seems like a good fit for said op.
+static int ssm3515_probe(struct snd_soc_component *component) +{
- struct ssm3515_data *data =
snd_soc_component_get_drvdata(component);
- int ret;
- ret = ssm3515_reset(component);
- if (ret < 0)
return ret;
- regmap_reinit_cache(data->regmap, &ssm3515_i2c_regmap);
- return ssm3515_setup(component);
+}
We don't normally reset things on component probe, only on bus level probe...
I don’t think I have a strong reason to do this.
Hey Martin,
On Tue, May 09, 2023 at 06:38:27PM +0200, Martin Povišer wrote:
Add a DT schema for the SSM3515 amp by Analog Devices. It's a simple mono amplifier with digital input.
Signed-off-by: Martin Povišer povik+lin@cutebit.org
.../bindings/sound/adi,ssm3515.yaml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/adi,ssm3515.yaml
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml b/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml new file mode 100644 index 000000000000..19b7185ae8e2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2019-20 Texas Instruments Incorporated
Copyright here looks a little odd, copy & paste from the TI bindings you send patches for earlier, or intended?
+%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/sound/adi,ssm3515.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
Drop the quotes on these please.
+title: Analog Devices SSM3515 Audio Amplifier
+maintainers:
- Martin Povišer povik+lin@cutebit.org
+description: |
- SSM3515 is a mono Class-D audio amplifier with digital input.
- https://www.analog.com/media/en/technical-documentation/data-sheets/SSM3515....
+allOf:
- $ref: dai-common.yaml#
+properties:
- compatible:
- enum:
- adi,ssm3515
- reg:
- maxItems: 1
- adi,ana-gain:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3]
- description: |
The value to be set in the ANA_GAIN register field on the codec. This determines
the full voltage span of the codec's analog output.
To quote the datasheet on the available options:
00: 8.4 V Full-Scale Gain Mapping
01: 12.6 V Full-Scale Gain Mapping
10: 14 V Full-Scale Gain Mapping
11: 15 V Full-Scale Gain Mapping
Putting register values into the DT does not seem correct, although I know nothing about sound and will have to defer to Krzysztof & Co. on that front.
Cheers, Conor.
- '#sound-dai-cells':
- const: 0
+required:
- compatible
- reg
- adi,ana-gain
+additionalProperties: true
+examples:
- |
- i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@14 {
compatible = "adi,ssm3515";
reg = <0x14>;
#sound-dai-cells = <0>;
adi,ana-gain = <0>;
sound-name-prefix = "Left Tweeter";
};
- };
-- 2.38.3
Hello Conor,
On 9. 5. 2023, at 20:25, Conor Dooley conor@kernel.org wrote:
Hey Martin,
On Tue, May 09, 2023 at 06:38:27PM +0200, Martin Povišer wrote:
Add a DT schema for the SSM3515 amp by Analog Devices. It's a simple mono amplifier with digital input.
Signed-off-by: Martin Povišer povik+lin@cutebit.org
.../bindings/sound/adi,ssm3515.yaml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/adi,ssm3515.yaml
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml b/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml new file mode 100644 index 000000000000..19b7185ae8e2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2019-20 Texas Instruments Incorporated
Copyright here looks a little odd, copy & paste from the TI bindings you send patches for earlier, or intended?
Yeah, that must have been a copypaste from the other schemas. Not intended in any case. Thanks for the catch.
+%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/sound/adi,ssm3515.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
Drop the quotes on these please.
OK
- adi,ana-gain:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3]
- description: |
The value to be set in the ANA_GAIN register field on the codec. This determines
the full voltage span of the codec's analog output.
To quote the datasheet on the available options:
00: 8.4 V Full-Scale Gain Mapping
01: 12.6 V Full-Scale Gain Mapping
10: 14 V Full-Scale Gain Mapping
11: 15 V Full-Scale Gain Mapping
Putting register values into the DT does not seem correct, although I know nothing about sound and will have to defer to Krzysztof & Co. on that front.
It’s an analog gain selection, it just seemed most honest and convenient to defer to the register field in describing of what this property does.
I thought this should be here, and not with the other gain controls to be exported to userspace, since it relates to the supply voltage. You probably can’t select a gain value close or over the amp’s supply and expect proper functioning, so the value here should be the system’s integrator choice.
On second thought there doesn’t seem to be any risk of damage to the amp itself, so the knowledge of what’s the optimal value could be left up to ALSA use-case configuration, and there’s no real downside in treating it like other gain controls.
I think I will remove it in the next iteration.
Cheers, Conor.
Cheers, Martin
On Tue, May 09, 2023 at 09:38:46PM +0200, Martin Povišer wrote:
On 9. 5. 2023, at 20:25, Conor Dooley conor@kernel.org wrote:
00: 8.4 V Full-Scale Gain Mapping
01: 12.6 V Full-Scale Gain Mapping
10: 14 V Full-Scale Gain Mapping
11: 15 V Full-Scale Gain Mapping
Putting register values into the DT does not seem correct, although I know nothing about sound and will have to defer to Krzysztof & Co. on that front.
I thought this should be here, and not with the other gain controls to be exported to userspace, since it relates to the supply voltage. You probably can’t select a gain value close or over the amp’s supply and expect proper functioning, so the value here should be the system’s integrator choice.
On second thought there doesn’t seem to be any risk of damage to the amp itself, so the knowledge of what’s the optimal value could be left up to ALSA use-case configuration, and there’s no real downside in treating it like other gain controls.
Alternatively why not just query the supply voltage via the regulator API? Those are kind of weird numbers (eg, 12.6V rather than 12V) though, it looks like they're not expected to be the actual maximum supply values but rather something slightly less.
On 09/05/2023 20:25, Conor Dooley wrote:
Hey Martin,
On Tue, May 09, 2023 at 06:38:27PM +0200, Martin Povišer wrote:
Add a DT schema for the SSM3515 amp by Analog Devices. It's a simple mono amplifier with digital input.
Signed-off-by: Martin Povišer povik+lin@cutebit.org
.../bindings/sound/adi,ssm3515.yaml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/adi,ssm3515.yaml
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml b/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml new file mode 100644 index 000000000000..19b7185ae8e2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2019-20 Texas Instruments Incorporated
Copyright here looks a little odd, copy & paste from the TI bindings you send patches for earlier, or intended?
+%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/sound/adi,ssm3515.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
Drop the quotes on these please.
+title: Analog Devices SSM3515 Audio Amplifier
+maintainers:
- Martin Povišer povik+lin@cutebit.org
+description: |
- SSM3515 is a mono Class-D audio amplifier with digital input.
- https://www.analog.com/media/en/technical-documentation/data-sheets/SSM3515....
+allOf:
- $ref: dai-common.yaml#
+properties:
- compatible:
- enum:
- adi,ssm3515
- reg:
- maxItems: 1
- adi,ana-gain:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3]
- description: |
The value to be set in the ANA_GAIN register field on the codec. This determines
the full voltage span of the codec's analog output.
To quote the datasheet on the available options:
00: 8.4 V Full-Scale Gain Mapping
01: 12.6 V Full-Scale Gain Mapping
10: 14 V Full-Scale Gain Mapping
11: 15 V Full-Scale Gain Mapping
Putting register values into the DT does not seem correct, although I know nothing about sound and will have to defer to Krzysztof & Co. on that front.
Depends whether these are really voltages or something else (e.g. gain) just related to voltage.
Best regards, Krzysztof
On Wed, May 10, 2023 at 09:51:50AM +0200, Krzysztof Kozlowski wrote:
On 09/05/2023 20:25, Conor Dooley wrote:
On Tue, May 09, 2023 at 06:38:27PM +0200, Martin Povišer wrote:
00: 8.4 V Full-Scale Gain Mapping
01: 12.6 V Full-Scale Gain Mapping
10: 14 V Full-Scale Gain Mapping
11: 15 V Full-Scale Gain Mapping
Putting register values into the DT does not seem correct, although I know nothing about sound and will have to defer to Krzysztof & Co. on that front.
Depends whether these are really voltages or something else (e.g. gain) just related to voltage.
They are configuring the voltage range that the output will generate.
On 09/05/2023 18:38, Martin Povišer wrote:
Add a DT schema for the SSM3515 amp by Analog Devices. It's a simple mono amplifier with digital input.
Signed-off-by: Martin Povišer povik+lin@cutebit.org
- reg:
- maxItems: 1
- adi,ana-gain:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3]
- description: |
The value to be set in the ANA_GAIN register field on the codec. This determines
the full voltage span of the codec's analog output.
To quote the datasheet on the available options:
00: 8.4 V Full-Scale Gain Mapping
01: 12.6 V Full-Scale Gain Mapping
10: 14 V Full-Scale Gain Mapping
11: 15 V Full-Scale Gain Mapping
- '#sound-dai-cells':
- const: 0
+required:
- compatible
- reg
- adi,ana-gain
+additionalProperties: true
uinevaluatedProperties: false instead, so users can have name-prefix.
Best regards, Krzysztof
On 10. 5. 2023, at 9:51, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:
On 09/05/2023 18:38, Martin Povišer wrote:
Add a DT schema for the SSM3515 amp by Analog Devices. It's a simple mono amplifier with digital input.
Signed-off-by: Martin Povišer povik+lin@cutebit.org
- reg:
- maxItems: 1
- adi,ana-gain:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3]
- description: |
The value to be set in the ANA_GAIN register field on the codec. This determines
the full voltage span of the codec's analog output.
To quote the datasheet on the available options:
00: 8.4 V Full-Scale Gain Mapping
01: 12.6 V Full-Scale Gain Mapping
10: 14 V Full-Scale Gain Mapping
11: 15 V Full-Scale Gain Mapping
- '#sound-dai-cells':
- const: 0
+required:
- compatible
- reg
- adi,ana-gain
+additionalProperties: true
uinevaluatedProperties: false instead, so users can have name-prefix.
I actually tweaked this to have the example passing, which has sound-name-prefix, which I guess is what you have in mind. Not that I exactly understand what these options do (both additionalProperties and unevaluatedProperties), the schema docs didn’t enlighten me right away when I looked into it.
If 'unevaluatedProperties: false' is the way to go here, I will change it.
Kind regards, Martin
Best regards, Krzysztof
On 10/05/2023 10:15, Martin Povišer wrote:
On 10. 5. 2023, at 9:51, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:
On 09/05/2023 18:38, Martin Povišer wrote:
Add a DT schema for the SSM3515 amp by Analog Devices. It's a simple mono amplifier with digital input.
Signed-off-by: Martin Povišer povik+lin@cutebit.org
- reg:
- maxItems: 1
- adi,ana-gain:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3]
- description: |
The value to be set in the ANA_GAIN register field on the codec. This determines
the full voltage span of the codec's analog output.
To quote the datasheet on the available options:
00: 8.4 V Full-Scale Gain Mapping
01: 12.6 V Full-Scale Gain Mapping
10: 14 V Full-Scale Gain Mapping
11: 15 V Full-Scale Gain Mapping
- '#sound-dai-cells':
- const: 0
+required:
- compatible
- reg
- adi,ana-gain
+additionalProperties: true
uinevaluatedProperties: false instead, so users can have name-prefix.
I actually tweaked this to have the example passing, which has sound-name-prefix,
true is not allowed anyway - it makes your schema simply not effective almost at all as it allows anything...
which I guess is what you have in mind. Not that I exactly understand what these options do (both additionalProperties and unevaluatedProperties), the schema docs didn’t enlighten me right away when I looked into it.
The way to go and to start always is to look at example-schema. It tells you explicitly to use additionalProperties:false and switch to unevaluated "If and only if another schema is referenced".
Best regards, Krzysztof
On 10. 5. 2023, at 10:23, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:
On 10/05/2023 10:15, Martin Povišer wrote:
On 10. 5. 2023, at 9:51, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:
On 09/05/2023 18:38, Martin Povišer wrote:
Add a DT schema for the SSM3515 amp by Analog Devices. It's a simple mono amplifier with digital input.
Signed-off-by: Martin Povišer povik+lin@cutebit.org
+additionalProperties: true
uinevaluatedProperties: false instead, so users can have name-prefix.
I actually tweaked this to have the example passing, which has sound-name-prefix,
true is not allowed anyway - it makes your schema simply not effective almost at all as it allows anything...
That makes sense.
which I guess is what you have in mind. Not that I exactly understand what these options do (both additionalProperties and unevaluatedProperties), the schema docs didn’t enlighten me right away when I looked into it.
The way to go and to start always is to look at example-schema. It tells you explicitly to use additionalProperties:false and switch to unevaluated "If and only if another schema is referenced".
OK. While I have you on the line, what does unevaluated do? In what sense are props unevaluated?
Best regards, Krzysztof
Regards, Martin
On 10/05/2023 10:29, Martin Povišer wrote:
On 10. 5. 2023, at 10:23, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:
On 10/05/2023 10:15, Martin Povišer wrote:
On 10. 5. 2023, at 9:51, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:
On 09/05/2023 18:38, Martin Povišer wrote:
Add a DT schema for the SSM3515 amp by Analog Devices. It's a simple mono amplifier with digital input.
Signed-off-by: Martin Povišer povik+lin@cutebit.org
+additionalProperties: true
uinevaluatedProperties: false instead, so users can have name-prefix.
I actually tweaked this to have the example passing, which has sound-name-prefix,
true is not allowed anyway - it makes your schema simply not effective almost at all as it allows anything...
That makes sense.
which I guess is what you have in mind. Not that I exactly understand what these options do (both additionalProperties and unevaluatedProperties), the schema docs didn’t enlighten me right away when I looked into it.
The way to go and to start always is to look at example-schema. It tells you explicitly to use additionalProperties:false and switch to unevaluated "If and only if another schema is referenced".
OK. While I have you on the line, what does unevaluated do? In what sense are props unevaluated?
Properties can be evaluated by some other referenced schema (e.g. dai-common.yaml). If nothing evaluated them, they are unevaluated, thus unknown and not allowed.
Best regards, Krzysztof
participants (4)
-
Conor Dooley
-
Krzysztof Kozlowski
-
Mark Brown
-
Martin Povišer