Commit 6f03b446 authored by Richard Fitzgerald's avatar Richard Fitzgerald Committed by Takashi Iwai
Browse files

ALSA: hda: cs35l56: Add support for speaker id



Add handling of the "spk-id-gpios" _DSD property. If present, the
value indicated by the GPIOs is appended to the subsystem-id
part of the firmware name to load the appropriate tunings for that
speaker.

Some manufacturers use multiple sources of speakers, which need
different tunings for best performance. On these models the type
of speaker fitted is indicated by the values of one or more GPIOs.
The number formed by the GPIOs identifies the tuning required.

The speaker ID is only used in combination with a _SUB identifier
because the value is only meaningful if the exact model is known.

The code to get the speaker ID value has been implemented as a
new library so that the cs35l41_hda driver can be switched in
future to share common code. This library can be extended for
other common functionality shared by Cirrus Logic amp drivers.

Signed-off-by: default avatarRichard Fitzgerald <rf@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20230918095129.440-2-rf@opensource.cirrus.com


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 6e743781
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4912,6 +4912,7 @@ F: drivers/spi/spi-cs42l43*
F:	include/dt-bindings/sound/cs*
F:	include/linux/mfd/cs42l43*
F:	include/sound/cs*
F:	sound/pci/hda/cirrus*
F:	sound/pci/hda/cs*
F:	sound/pci/hda/hda_cs_dsp_ctl.*
F:	sound/soc/codecs/cs*
+5 −0
Original line number Diff line number Diff line
@@ -91,6 +91,9 @@ config SND_HDA_PATCH_LOADER
	  start up.  The "patch" file can be specified via patch module
	  option, such as patch=hda-init.

config SND_HDA_CIRRUS_SCODEC
	tristate

config SND_HDA_SCODEC_CS35L41
	tristate
	select SND_HDA_GENERIC
@@ -144,6 +147,7 @@ config SND_HDA_SCODEC_CS35L56_I2C
	select SND_HDA_GENERIC
	select SND_SOC_CS35L56_SHARED
	select SND_HDA_SCODEC_CS35L56
	select SND_HDA_CIRRUS_SCODEC
	select SND_HDA_CS_DSP_CONTROLS
	help
	  Say Y or M here to include CS35L56 amplifier support with
@@ -158,6 +162,7 @@ config SND_HDA_SCODEC_CS35L56_SPI
	select SND_HDA_GENERIC
	select SND_SOC_CS35L56_SHARED
	select SND_HDA_SCODEC_CS35L56
	select SND_HDA_CIRRUS_SCODEC
	select SND_HDA_CS_DSP_CONTROLS
	help
	  Say Y or M here to include CS35L56 amplifier support with
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ snd-hda-codec-via-objs := patch_via.o
snd-hda-codec-hdmi-objs :=	patch_hdmi.o hda_eld.o

# side codecs
snd-hda-cirrus-scodec-objs :=		cirrus_scodec.o
snd-hda-scodec-cs35l41-objs :=		cs35l41_hda.o cs35l41_hda_property.o
snd-hda-scodec-cs35l41-i2c-objs :=	cs35l41_hda_i2c.o
snd-hda-scodec-cs35l41-spi-objs :=	cs35l41_hda_spi.o
@@ -56,6 +57,7 @@ obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o

# side codecs
obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o
+73 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
//
// Common code for Cirrus side-codecs.
//
// Copyright (C) 2021, 2023 Cirrus Logic, Inc. and
//               Cirrus Logic International Semiconductor Ltd.

#include <linux/dev_printk.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>

#include "cirrus_scodec.h"

int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index,
				 int num_amps, int fixed_gpio_id)
{
	struct gpio_desc *speaker_id_desc;
	int speaker_id = -ENOENT;

	if (fixed_gpio_id >= 0) {
		dev_dbg(dev, "Found Fixed Speaker ID GPIO (index = %d)\n", fixed_gpio_id);
		speaker_id_desc = gpiod_get_index(dev, NULL, fixed_gpio_id, GPIOD_IN);
		if (IS_ERR(speaker_id_desc)) {
			speaker_id = PTR_ERR(speaker_id_desc);
			return speaker_id;
		}
		speaker_id = gpiod_get_value_cansleep(speaker_id_desc);
		gpiod_put(speaker_id_desc);
	} else {
		int base_index;
		int gpios_per_amp;
		int count;
		int tmp;
		int i;

		count = gpiod_count(dev, "spk-id");
		if (count > 0) {
			speaker_id = 0;
			gpios_per_amp = count / num_amps;
			base_index = gpios_per_amp * amp_index;

			if (count % num_amps)
				return -EINVAL;

			dev_dbg(dev, "Found %d Speaker ID GPIOs per Amp\n", gpios_per_amp);

			for (i = 0; i < gpios_per_amp; i++) {
				speaker_id_desc = gpiod_get_index(dev, "spk-id", i + base_index,
								  GPIOD_IN);
				if (IS_ERR(speaker_id_desc)) {
					speaker_id = PTR_ERR(speaker_id_desc);
					break;
				}
				tmp = gpiod_get_value_cansleep(speaker_id_desc);
				gpiod_put(speaker_id_desc);
				if (tmp < 0) {
					speaker_id = tmp;
					break;
				}
				speaker_id |= tmp << i;
			}
		}
	}

	dev_dbg(dev, "Speaker ID = %d\n", speaker_id);

	return speaker_id;
}
EXPORT_SYMBOL_NS_GPL(cirrus_scodec_get_speaker_id, SND_HDA_CIRRUS_SCODEC);

MODULE_DESCRIPTION("HDA Cirrus side-codec library");
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
+13 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0
 *
 * Copyright (C) 2023 Cirrus Logic, Inc. and
 *                    Cirrus Logic International Semiconductor Ltd.
 */

#ifndef CIRRUS_SCODEC_H
#define CIRRUS_SCODEC_H

int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index,
				 int num_amps, int fixed_gpio_id);

#endif /* CIRRUS_SCODEC_H */
Loading