drivers/soundwire/cs35l56: Support Cirrus Logic CS35L56 Smart Amplifier Family
Add support for Class-D Smart Amplifiers: CS35L56, CS35L57 and CS35L63.
CS35L56 and CS35L57 are 18.5 V Class D Smart Amplifiers with Multi-Cell
Battery Boost.
CS35L63 is a PC Smart Amplifier with Speaker Protection and Audio
Enhancement Algorithms.
The driver was written based on the Datasheets for these parts and
generates the audio SSDT information for the amplifiers. Since all
three parts are part of the same family they all have similar SoundWire
settings.
The user can configure which part, SSID and Speaker ID is generated in
ACPI, as well as define each amplifier's Soundwire Unique ID and Link
ID.
These parts support DisCo Version v2.1, but coreboot currently only
supports DisCo v1.0, so ACPI is only generated based on DisCo v1.0.
These parts also support the SDCA v1.0 Specification (from DisCo v2.1)
is also not currently supported by coreboot, therefore SDCA ACPI
properties are also not generated.
This is currently only tested using QEMU using example configuration:
chip drivers/soundwire/cs35l56
# SoundWire Link 2 ID 3
register "desc" = ""Left Speaker Amp""
register "part_id" = "MIPI_DEV_ID_CIRRUS_CS35L56"
register "sub" = ""12345678""
device generic 2.3 on end
end
Which produces the ACPI:
Device (SW23)
{
Name (_ADR, 0x00023301FA355601) // _ADR: Address
Name (_DDN, "Left Speaker Amp") // _DDN: DOS Device Name
Name (_SUB, "12345678") // _SUB: Subsystem ID
Method (_STA, 0, NotSerialized) // _STA: Status
{
Return (0x0F)
}
Name (_DSD, Package (0x04) // _DSD: Device-Specific Data
{
ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301") /* Device Properties for _DSD */,
Package (0x0F)
{
Package (0x02)
{
"mipi-sdw-sw-interface-revision",
0x00010000
},
[...]
Package (0x02)
{
"mipi-sdw-source-port-list",
0x18
},
Package (0x02)
{
"mipi-sdw-sink-port-list",
0x06
}
},
ToUUID ("dbb8e3e6-5886-4ba6-8795-1319f52a966b") /* Hierarchical Data Extension */,
Package (0x06)
{
Package (0x02)
{
"mipi-sdw-port-bra-mode-0",
"BRA0"
},
Package (0x02)
{
"mipi-sdw-dp-0-subproperties",
"DP0"
},
Package (0x02)
{
"mipi-sdw-dp-1-sink-subproperties",
"SNK1"
},
Package (0x02)
{
"mipi-sdw-dp-2-sink-subproperties",
"SNK2"
},
Package (0x02)
{
"mipi-sdw-dp-3-source-subproperties",
"SRC3"
},
Package (0x02)
{
"mipi-sdw-dp-4-source-subproperties",
"SRC4"
}
}
})
Name (BRA0, Package (0x02)
{
ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301") /* Device Properties for _DSD */,
Package (0x04)
{
Package (0x02)
{
"mipi-sdw-bra-mode-min-bus-frequency",
Zero
},
Package (0x02)
{
"mipi-sdw-bra-mode-max-bus-frequency",
Zero
},
Package (0x02)
{
"mipi-sdw-bra-mode-max-data-per-frame",
0x01D6
},
Package (0x02)
{
"mipi-sdw-bra-mode-min-us-between-transactions",
Zero
}
}
})
Name (DP0, Package (0x04)
{
ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301") /* Device Properties for _DSD */,
Package (0x07)
{
Package (0x02)
{
"mipi-sdw-port-wordlength-configs",
Package (0x03)
{
0x08,
0x10,
0x18
}
},
[...]
},
ToUUID ("dbb8e3e6-5886-4ba6-8795-1319f52a966b") /* Hierarchical Data Extension */,
Package (0x01)
{
Package (0x02)
{
"mipi-sdw-port-bra-mode-0",
"BRA0"
}
}
})
Name (SNK1, Package (0x02)
{
ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301") /* Device Properties for _DSD */,
Package (0x0C)
{
Package (0x02)
{
"mipi-sdw-data-port-type",
Zero
},
Package (0x02)
{
"mipi-sdw-max-grouping-supported",
Zero
},
Package (0x02)
{
"mipi-sdw-imp-def-dpn-interrupts-supported",
Zero
},
Package (0x02)
{
"mipi-sdw-modes-supported",
One
},
Package (0x02)
{
"mipi-sdw-max-async-buffer",
Zero
},
Package (0x02)
{
"mipi-sdw-block-packing-mode",
One
},
Package (0x02)
{
"mipi-sdw-port-encoding-type",
One
},
Package (0x02)
{
"mipi-sdw-port-wordlength-configs",
Package (0x03)
{
0x08,
0x10,
0x18
}
},
Package (0x02)
{
"mipi-sdw-simplified-channelprepare-sm",
Zero
},
Package (0x02)
{
"mipi-sdw-port-channelprepare-timeout",
Zero
},
Package (0x02)
{
"mipi-sdw-channel-number-list",
Package (0x02)
{
Zero,
One
}
},
Package (0x02)
{
"mipi-sdw-channel-combination-list",
Package (0x01)
{
0x03
}
}
}
})
Name (SNK2, Package (0x02)
{
[... same as SNK1 ...]
})
Name (SRC3, Package (0x02)
{
[... same as SNK1 ...]
})
Name (SRC4, Package (0x02)
{
[... same as SNK1 ...]
})
}
Change-Id: Ie04020f008862051f26e0101828b5944d212e706
Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/89131
Reviewed-by: Paul Menzel <paulepanter@mailbox.org>
Reviewed-by: Matt DeVillier <matt.devillier@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
7d44128b2f
commit
a5252bd5b9
5 changed files with 203 additions and 0 deletions
10
src/drivers/soundwire/cs35l56/Kconfig
Normal file
10
src/drivers/soundwire/cs35l56/Kconfig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
## SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config DRIVERS_SOUNDWIRE_CS35L56_FAMILY
|
||||
bool
|
||||
depends on HAVE_ACPI_TABLES
|
||||
default n
|
||||
help
|
||||
SoundWire CS35L56 Family audio amp SSDT generator.
|
||||
This supports the CS35L56, CS35L57, and CS35L63 audio amplifiers
|
||||
from Cirrus Logic.
|
||||
3
src/drivers/soundwire/cs35l56/Makefile.mk
Normal file
3
src/drivers/soundwire/cs35l56/Makefile.mk
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
## SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
ramstage-$(CONFIG_DRIVERS_SOUNDWIRE_CS35L56_FAMILY) += cs35l56.c
|
||||
26
src/drivers/soundwire/cs35l56/chip.h
Normal file
26
src/drivers/soundwire/cs35l56/chip.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef __DRIVERS_SOUNDWIRE_CS35L56_FAMILY_CHIP_H__
|
||||
#define __DRIVERS_SOUNDWIRE_CS35L56_FAMILY_CHIP_H__
|
||||
|
||||
#include <acpi/acpi.h>
|
||||
#include <acpi/acpi_device.h>
|
||||
#include <mipi/ids.h>
|
||||
|
||||
enum cs35l56_part_ids {
|
||||
CS35L56_PART_ID_CS35L56 = MIPI_DEV_ID_CIRRUS_CS35L56,
|
||||
CS35L56_PART_ID_CS35L57 = MIPI_DEV_ID_CIRRUS_CS35L57,
|
||||
CS35L63_PART_ID_CS35L63 = MIPI_DEV_ID_CIRRUS_CS35L63
|
||||
};
|
||||
|
||||
struct drivers_soundwire_cs35l56_config {
|
||||
char acpi_name[ACPI_NAME_BUFFER_SIZE]; /* Set by the acpi_name ops */
|
||||
const char *desc;
|
||||
enum cs35l56_part_ids part_id;
|
||||
const char *sub; /* SUB ID to uniquely identify system */
|
||||
|
||||
/* Use GPIO based spkid gpio */
|
||||
struct acpi_gpio spkid_gpio;
|
||||
};
|
||||
|
||||
#endif /* __DRIVERS_SOUNDWIRE_CS35L56_FAMILY_CHIP_H__ */
|
||||
161
src/drivers/soundwire/cs35l56/cs35l56.c
Normal file
161
src/drivers/soundwire/cs35l56/cs35l56.c
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <acpi/acpigen.h>
|
||||
#include <acpi/acpi_device.h>
|
||||
#include <acpi/acpi_soundwire.h>
|
||||
#include <device/device.h>
|
||||
#include <device/soundwire.h>
|
||||
#include <mipi/ids.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "chip.h"
|
||||
|
||||
static struct soundwire_address cs35l56_address = {
|
||||
.version = SOUNDWIRE_VERSION_1_2,
|
||||
.manufacturer_id = MIPI_MFG_ID_CIRRUS,
|
||||
.class = MIPI_CLASS_SDCA
|
||||
};
|
||||
|
||||
static struct soundwire_slave cs35l56_slave = {
|
||||
.wake_up_unavailable = false,
|
||||
.test_mode_supported = false,
|
||||
.clock_stop_mode1_supported = false,
|
||||
.simplified_clockstopprepare_sm_supported = false,
|
||||
.paging_supported = true,
|
||||
.source_port_list = SOUNDWIRE_PORT(3) | SOUNDWIRE_PORT(4),
|
||||
.sink_port_list = SOUNDWIRE_PORT(1) | SOUNDWIRE_PORT(2),
|
||||
};
|
||||
|
||||
static struct soundwire_dp0 cs35l56_dp0 = {
|
||||
.port_wordlength_configs_count = 3,
|
||||
.port_wordlength_configs = {8, 16, 24},
|
||||
.bra_flow_controlled = true,
|
||||
.bra_imp_def_response_supported = true,
|
||||
.bra_role_supported = true,
|
||||
.imp_def_dp0_interrupts_supported = 0,
|
||||
.imp_def_bpt_supported = false,
|
||||
.bra_mode_count = 1,
|
||||
.bra_mode_list = { 0 }
|
||||
};
|
||||
|
||||
static struct soundwire_bra_mode cs35l56_dp0_bra_mode = {
|
||||
.max_data_per_frame = 470,
|
||||
.block_alignment = 4,
|
||||
};
|
||||
|
||||
static struct soundwire_dpn cs35l56_dpn = {
|
||||
.data_port_type = FULL_DATA_PORT,
|
||||
.max_grouping_supported = BLOCK_GROUP_COUNT_1,
|
||||
.modes_supported = MODE_ISOCHRONOUS,
|
||||
.max_async_buffer = 0,
|
||||
.block_packing_mode = true,
|
||||
.port_encoding_type = ENCODE_TWOS_COMPLEMENT,
|
||||
.port_wordlength_configs_count = 3,
|
||||
.port_wordlength_configs = {8, 16, 24},
|
||||
.simplified_channelprepare_sm = false,
|
||||
.channel_number_list_count = 2,
|
||||
.channel_number_list = {0, 1},
|
||||
.channel_combination_list_count = 1,
|
||||
.channel_combination_list = {0x3},
|
||||
.port_audio_mode_count = 0,
|
||||
};
|
||||
|
||||
static const struct soundwire_codec cs35l56_codec = {
|
||||
.slave = &cs35l56_slave,
|
||||
.dp0 = &cs35l56_dp0,
|
||||
.dp0_bra_mode = { &cs35l56_dp0_bra_mode },
|
||||
.dpn = {
|
||||
{
|
||||
/* Data Input for Speaker Path */
|
||||
.port = 1,
|
||||
.sink = &cs35l56_dpn
|
||||
},
|
||||
{
|
||||
/* Data Input for Speaker Path */
|
||||
.port = 2,
|
||||
.sink = &cs35l56_dpn
|
||||
},
|
||||
{
|
||||
/* Data Output for Feedback Path */
|
||||
.port = 3,
|
||||
.source = &cs35l56_dpn
|
||||
},
|
||||
{
|
||||
/* Data Output for Feedback Path */
|
||||
.port = 4,
|
||||
.source = &cs35l56_dpn
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static void soundwire_cs35l56_fill_ssdt(const struct device *dev)
|
||||
{
|
||||
struct drivers_soundwire_cs35l56_config *config = dev->chip_info;
|
||||
const char *scope = acpi_device_scope(dev);
|
||||
struct acpi_dp *dsd;
|
||||
|
||||
if (!scope)
|
||||
return;
|
||||
|
||||
acpigen_write_scope(scope);
|
||||
acpigen_write_device(acpi_device_name(dev));
|
||||
|
||||
/* Set codec address IDs. */
|
||||
cs35l56_address.link_id = dev->path.generic.id;
|
||||
cs35l56_address.unique_id = dev->path.generic.subid;
|
||||
cs35l56_address.part_id = config->part_id;
|
||||
|
||||
acpigen_write_ADR_soundwire_device(&cs35l56_address);
|
||||
acpigen_write_name_string("_DDN", config->desc ? : dev->chip_ops->name);
|
||||
acpigen_write_name_string("_SUB", config->sub);
|
||||
acpigen_write_STA(acpi_device_status(dev));
|
||||
|
||||
/* for spkid gpio */
|
||||
if (config->spkid_gpio.pin_count) {
|
||||
acpigen_write_name("_CRS");
|
||||
acpigen_write_resourcetemplate_header();
|
||||
acpi_device_write_gpio(&config->spkid_gpio);
|
||||
acpigen_write_resourcetemplate_footer();
|
||||
}
|
||||
|
||||
dsd = acpi_dp_new_table("_DSD");
|
||||
soundwire_gen_codec(dsd, &cs35l56_codec, NULL);
|
||||
|
||||
if (config->spkid_gpio.pin_count)
|
||||
acpi_dp_add_gpio(dsd, "spk-id-gpios", acpi_device_path(dev),
|
||||
0, /* Index = 0 */
|
||||
0, /* Pin = 0 (There is a single pin in the GPIO resource). */
|
||||
config->spkid_gpio.active_low);
|
||||
|
||||
acpi_dp_write(dsd);
|
||||
|
||||
acpigen_pop_len(); /* Device */
|
||||
acpigen_pop_len(); /* Scope */
|
||||
}
|
||||
|
||||
static const char *soundwire_cs35l56_acpi_name(const struct device *dev)
|
||||
{
|
||||
struct drivers_soundwire_cs35l56_config *config = dev->chip_info;
|
||||
if (config->acpi_name[0] != 0)
|
||||
return config->acpi_name;
|
||||
snprintf(config->acpi_name, sizeof(config->acpi_name), "SW%1X%1X",
|
||||
dev->path.generic.id, dev->path.generic.subid);
|
||||
return config->acpi_name;
|
||||
}
|
||||
|
||||
static struct device_operations soundwire_cs35l56_ops = {
|
||||
.read_resources = noop_read_resources,
|
||||
.set_resources = noop_set_resources,
|
||||
.acpi_name = soundwire_cs35l56_acpi_name,
|
||||
.acpi_fill_ssdt = soundwire_cs35l56_fill_ssdt,
|
||||
};
|
||||
|
||||
static void soundwire_cs35l56_enable(struct device *dev)
|
||||
{
|
||||
dev->ops = &soundwire_cs35l56_ops;
|
||||
}
|
||||
|
||||
struct chip_operations drivers_soundwire_cs35l56_ops = {
|
||||
.name = "Cirrus CS35L56 SoundWire Amplifier",
|
||||
.enable_dev = soundwire_cs35l56_enable
|
||||
};
|
||||
|
|
@ -34,5 +34,8 @@
|
|||
|
||||
#define MIPI_MFG_ID_CIRRUS 0x01fa
|
||||
#define MIPI_DEV_ID_CIRRUS_CS42L42 0x4242
|
||||
#define MIPI_DEV_ID_CIRRUS_CS35L56 0x3556
|
||||
#define MIPI_DEV_ID_CIRRUS_CS35L57 0x3557
|
||||
#define MIPI_DEV_ID_CIRRUS_CS35L63 0x3563
|
||||
|
||||
#endif /* __MIPI_IDS_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue