Unverified Commit 73cfbfa9 authored by Simon Trimmer's avatar Simon Trimmer Committed by Mark Brown
Browse files

ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier



Add a driver for the Cirrus Logic CS35L56 amplifier. This uses the same
component binding API as the CS35L41 driver. This is not a standalone
HDA device; it provides control of the CS35L56 for systems that use a
combination of an HDA codec and CS35L56 amplifiers with audio routed
through the HDA codec.

The CS35L56 combines a high-performance mono audio amplifier, Class-H
tracking inductive boost converter, Halo Core(TM) DSP and a DC-DC boost
converter supporting Class-H tracking.

Control interfaces are I2C or SPI through the standard Linux I2C or SPI
bus framework.

Most chip functionality is controlled by on-board ROM firmware that is
always running. Firmware patches can be applied by the driver in the form
of a .wmfw file (firmware patch) and/or a .bin file (system tuning).

Signed-off-by: default avatarSimon Trimmer <simont@opensource.cirrus.com>
Signed-off-by: default avatarRichard Fitzgerald <rf@opensource.cirrus.com>
Reviewed-by: default avatarTakashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20230721132120.5523-12-rf@opensource.cirrus.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 64e05321
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -130,6 +130,37 @@ config SND_HDA_SCODEC_CS35L41_SPI
comment "Set to Y if you want auto-loading the side codec driver"
	depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_SPI=m

config SND_HDA_SCODEC_CS35L56
	tristate

config SND_HDA_SCODEC_CS35L56_I2C
	tristate "Build CS35L56 HD-audio side codec support for I2C Bus"
	depends on I2C
	depends on ACPI || COMPILE_TEST
	depends on SND_SOC
	select CS_DSP
	select SND_HDA_GENERIC
	select SND_SOC_CS35L56_SHARED
	select SND_HDA_SCODEC_CS35L56
	select SND_HDA_CS_DSP_CONTROLS
	help
	  Say Y or M here to include CS35L56 amplifier support with
	  I2C control.

config SND_HDA_SCODEC_CS35L56_SPI
	tristate "Build CS35L56 HD-audio side codec support for SPI Bus"
	depends on SPI_MASTER
	depends on ACPI || COMPILE_TEST
	depends on SND_SOC
	select CS_DSP
	select SND_HDA_GENERIC
	select SND_SOC_CS35L56_SHARED
	select SND_HDA_SCODEC_CS35L56
	select SND_HDA_CS_DSP_CONTROLS
	help
	  Say Y or M here to include CS35L56 amplifier support with
	  SPI control.

config SND_HDA_CODEC_REALTEK
	tristate "Build Realtek HD-audio codec support"
	select SND_HDA_GENERIC
+6 −0
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@ snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o
snd-hda-scodec-cs35l41-objs :=		cs35l41_hda.o
snd-hda-scodec-cs35l41-i2c-objs :=	cs35l41_hda_i2c.o
snd-hda-scodec-cs35l41-spi-objs :=	cs35l41_hda_spi.o
snd-hda-scodec-cs35l56-objs :=		cs35l56_hda.o
snd-hda-scodec-cs35l56-i2c-objs :=	cs35l56_hda_i2c.o
snd-hda-scodec-cs35l56-spi-objs :=	cs35l56_hda_spi.o
snd-hda-cs-dsp-ctls-objs :=		hda_cs_dsp_ctl.o

# common driver
@@ -55,6 +58,9 @@ obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.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
obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o

# this must be the last entry after codec drivers;
+995 −0

File added.

Preview size limit exceeded, changes collapsed.

+48 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only
 *
 * HDA audio driver for Cirrus Logic CS35L56 smart amp
 *
 * Copyright (C) 2023 Cirrus Logic, Inc. and
 *                    Cirrus Logic International Semiconductor Ltd.
 */

#ifndef __CS35L56_HDA_H__
#define __CS35L56_HDA_H__

#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/firmware/cirrus/cs_dsp.h>
#include <linux/firmware/cirrus/wmfw.h>
#include <linux/regulator/consumer.h>
#include <sound/cs35l56.h>

struct dentry;

struct cs35l56_hda {
	struct cs35l56_base base;
	struct hda_codec *codec;

	int index;
	const char *system_name;
	const char *amp_name;

	struct cs_dsp cs_dsp;
	bool playing;
	bool suspended;
	u8 asp_tx_mask;

	struct snd_kcontrol *posture_ctl;
	struct snd_kcontrol *volume_ctl;
	struct snd_kcontrol *mixer_ctl[4];

#if IS_ENABLED(CONFIG_SND_DEBUG)
	struct dentry *debugfs_root;
#endif
};

extern const struct dev_pm_ops cs35l56_hda_pm_ops;

int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id);
void cs35l56_hda_remove(struct device *dev);

#endif /*__CS35L56_HDA_H__*/
+69 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
//
// CS35L56 HDA audio driver I2C binding
//
// Copyright (C) 2023 Cirrus Logic, Inc. and
//                    Cirrus Logic International Semiconductor Ltd.

#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>

#include "cs35l56_hda.h"

static int cs35l56_hda_i2c_probe(struct i2c_client *clt)
{
	struct cs35l56_hda *cs35l56;
	int ret;

	cs35l56 = devm_kzalloc(&clt->dev, sizeof(*cs35l56), GFP_KERNEL);
	if (!cs35l56)
		return -ENOMEM;

	cs35l56->base.dev = &clt->dev;
	cs35l56->base.can_hibernate = true;
	cs35l56->base.regmap = devm_regmap_init_i2c(clt, &cs35l56_regmap_i2c);
	if (IS_ERR(cs35l56->base.regmap)) {
		ret = PTR_ERR(cs35l56->base.regmap);
		dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n",
			ret);
		return ret;
	}

	ret = cs35l56_hda_common_probe(cs35l56, clt->addr);
	if (ret)
		return ret;
	ret = cs35l56_irq_request(&cs35l56->base, clt->irq);
	if (ret < 0)
		cs35l56_hda_remove(cs35l56->base.dev);

	return ret;
}

static void cs35l56_hda_i2c_remove(struct i2c_client *clt)
{
	cs35l56_hda_remove(&clt->dev);
}

static const struct i2c_device_id cs35l56_hda_i2c_id[] = {
	{ "cs35l56-hda", 0 },
	{}
};

static struct i2c_driver cs35l56_hda_i2c_driver = {
	.driver = {
		.name		= "cs35l56-hda",
		.pm		= &cs35l56_hda_pm_ops,
	},
	.id_table	= cs35l56_hda_i2c_id,
	.probe		= cs35l56_hda_i2c_probe,
	.remove		= cs35l56_hda_i2c_remove,
};
module_i2c_driver(cs35l56_hda_i2c_driver);

MODULE_DESCRIPTION("HDA CS35L56 I2C driver");
MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56);
MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
Loading