Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
June 2024
- 96 participants
- 202 discussions
Hi Mark, Pierre-Louis, Jerome
Cc each ASoC driver maintainer
This is v5 of DPCM cleanup
As we discussed in [1], we don't need to use dpcm_playback/capture flag,
so we remove it. But we have been using it for 10 years, some driver might
get damage. The most likely case is that the device/driver can use both
playback/capture, but have only one flag, and not using xxx_only flag.
[1/3] patch indicates warning in such case.
These adds grace time for DPCM cleanup.
I'm not sure when dpcm_xxx will be removed, and Codec check bypass will be
error, but maybe v6.11 or v6.12 ?
Please check each driver by that time.
Previous patch-set try to check both CPU and Codec in DPCM, but we noticed
that there are some special DAI which we can't handle today [2]. So I will
escape it in this patch-set.
[1] https://lore.kernel.org/r/87edaym2cg.wl-kuninori.morimoto.gx@renesas.com
[2] https://lore.kernel.org/all/3e67d62d-fe08-4f55-ab5b-ece8a57154f9@linux.inteā¦
Link: https://lore.kernel.org/r/87edaym2cg.wl-kuninori.morimoto.gx@renesas.com
Link: https://lore.kernel.org/r/87wmo6dyxg.wl-kuninori.morimoto.gx@renesas.com
Link: https://lore.kernel.org/r/87msole5wc.wl-kuninori.morimoto.gx@renesas.com
Link: https://lore.kernel.org/r/871q5tnuok.wl-kuninori.morimoto.gx@renesas.com
v4 -> v5
- typo fix: limition -> limitation
- typo fix: catpure -> capture
- include Intel patch
v3 -> v4
- don't check Codec on DPCM
- include Jerome's dpcm_xxx update patch
v2 -> v3
- tidyup typo (reuqsts -> requests)
- add Tested-by on git-log
v1 -> v2
- tidyup Codec check warning output condition
Jerome Brunet (1):
ASoC: amlogic: do not use dpcm_playback/capture flags
Kuninori Morimoto (2):
ASoC: soc-pcm: Indicate warning if dpcm_playback/capture were used for availability limition
ASoC: remove snd_soc_dai_link_set_capabilities()
Pierre-Louis Bossart (1):
ASoC: Intel: sof_sdw: use playback/capture_only flags
include/sound/soc-dai.h | 1 -
include/sound/soc.h | 1 +
sound/soc/fsl/imx-card.c | 3 --
sound/soc/generic/audio-graph-card.c | 2 -
sound/soc/generic/audio-graph-card2.c | 2 -
sound/soc/generic/simple-card.c | 2 -
sound/soc/intel/boards/sof_sdw.c | 4 +-
sound/soc/meson/axg-card.c | 11 +++--
sound/soc/meson/gx-card.c | 1 -
sound/soc/meson/meson-card-utils.c | 4 +-
sound/soc/qcom/common.c | 1 -
sound/soc/soc-dai.c | 38 ----------------
sound/soc/soc-pcm.c | 65 +++++++++++++++------------
13 files changed, 47 insertions(+), 88 deletions(-)
--
2.43.0
2
9
[RFC PATCH 00/16] soundwire/ASoC: speed-up downloads with BTP/BRA protocol
by Pierre-Louis Bossart 20 Aug '24
by Pierre-Louis Bossart 20 Aug '24
20 Aug '24
This RFC patchset suggests a new API for ASoC codec drivers to use for
firmware/table downloads.
Problem statement:
All existing transfers initiated by codec drivers rely on SoundWire
read/write commands, which can only support ONE byte per frame. With
the typical 48kHz frame rate, this means 384 kbits/s.
In addition, the command/control is typically handled with a FIFO and
interrupts which adds more software overhead. To give a practical
reference, sending 32Kb takes 2.5s on Intel platforms, which means
about 105kbit/s only. Additional non-audio activity is likely to
adversely impact interrupt scheduling and further decrease the
transfer speeds.
New SDCA-based codecs have a need to download tables and DSP firmware
which are typically between 20 and 256 Kb. The slow bus operation has
a direct impact on boot/resume times, and clearly having to wait more
than 300ms is a showstopper in terms of latency requirements and
user-experience.
Suggested solution:
The MIPI specification and most of the new codecs support the Bulk
Transfer Protocol (BTP) and specifically the Bulk Register Access
(BRA) configuration. This mode reclaims the 'audio' data space of the
SoundWire frame to send firmware/coefficients over the DataPort 0
(DP0).
The API suggested is rather simple, with the following sequence
expected:
open(): reserve resources and prepare hardware
send_async(): trigger DMAs and perform SoundWire bank switch
wait(): wait for DMA completion and disable DMAs
close(): release resources
Benefits:
Even after accounting for the protocol overhead, the data can be sent
8x or 16x faster on the link than with the regular commands.
With the use of DMAs, the software overhead becomes limited to the
initialization. Measured results show that transferring the same 32Kb
takes about 100ms, a 25x improvement on the baseline write() commands
with an actual bitrate of 2.6 Mbits/s. These results are a measure of
bus/hardware performance mainly, and will typically not be too
modified by the CPU activity and scheduling.
The performance for reads is similar, with a 25x speedup measured.
Limitations:
Setting up the transfers over DP0 takes time, and the reliance on DMAs
on the host side brings alignment restrictions. The BTP/BRA protocol
is really only relevant for "large" transfers done during boot/resume
*before* audio transfers take place. Mixing BTP/BRA and audio is a
nightmare, this patchset suggests a mutual-exclusion between two
usages.
Scope:
This patchset only exposes the API and a debugfs interface to initiate
commands, validate results and measure performance. The actual use of
the API is left as an exercise for codec driver developers.
This patchset depends on a number of pre-requisite patches and will
not build on top of any for-next branches. The main intent of this RFC
is to gather comments on the usage, API, benefits and restrictions.
The code and functionality was tested on an Intel LunarLake RVP platform
connected to a Realtek RT711-SDCA device.
Acknowledgements:
Thanks to Zeek Tsai at Realtek for providing test sequences that
helped reconcile the data formatted by the host driver with the
expected results on the code side.
Pierre-Louis Bossart (16):
Documentation: driver: add SoundWire BRA description
soundwire: cadence: add BTP support for DP0
soundwire: stream: extend sdw_alloc_stream() to take 'type' parameter
soundwire: extend sdw_stream_type to BPT
soundwire: stream: special-case the bus compute_params() routine
soundwire: stream: reuse existing code for BPT stream
soundwire: bus: add API for BPT protocol
soundwire: bus: add bpt_stream pointer
soundwire: crc8: add constant table
soundwire: cadence: add BTP/BRA helpers to format data
soundwire: intel_auxdevice: add indirection for BPT
open/close/send_async/wait
ASoC: SOF: Intel: hda-sdw-bpt: add helpers for SoundWire BPT DMA
soundwire: intel: add BPT context definition
soundwire: intel_ace2x: add BPT open/close/send_async/wait
soundwire: debugfs: add interface for BPT/BRA transfers
ASoC: rt711-sdca: add DP0 support
Documentation/driver-api/soundwire/bra.rst | 478 +++++++++++++
Documentation/driver-api/soundwire/index.rst | 1 +
Documentation/driver-api/soundwire/stream.rst | 2 +-
.../driver-api/soundwire/summary.rst | 5 +-
drivers/soundwire/Kconfig | 1 +
drivers/soundwire/Makefile | 4 +-
drivers/soundwire/amd_manager.c | 2 +-
drivers/soundwire/bus.c | 77 +++
drivers/soundwire/bus.h | 18 +
drivers/soundwire/cadence_master.c | 646 +++++++++++++++++-
drivers/soundwire/cadence_master.h | 30 +
drivers/soundwire/crc8.c | 277 ++++++++
drivers/soundwire/crc8.h | 11 +
drivers/soundwire/debugfs.c | 122 +++-
.../soundwire/generic_bandwidth_allocation.c | 84 ++-
drivers/soundwire/intel.h | 12 +
drivers/soundwire/intel_ace2x.c | 377 ++++++++++
drivers/soundwire/intel_auxdevice.c | 55 ++
drivers/soundwire/qcom.c | 2 +-
drivers/soundwire/stream.c | 137 +++-
include/linux/soundwire/sdw.h | 91 ++-
include/linux/soundwire/sdw_intel.h | 16 +
include/sound/hda-sdw-bpt.h | 76 +++
sound/soc/codecs/rt711-sdca-sdw.c | 8 +
sound/soc/qcom/sdw.c | 2 +-
sound/soc/sof/intel/Kconfig | 8 +-
sound/soc/sof/intel/Makefile | 4 +
sound/soc/sof/intel/hda-sdw-bpt.c | 328 +++++++++
28 files changed, 2810 insertions(+), 64 deletions(-)
create mode 100644 Documentation/driver-api/soundwire/bra.rst
create mode 100644 drivers/soundwire/crc8.c
create mode 100644 drivers/soundwire/crc8.h
create mode 100644 include/sound/hda-sdw-bpt.h
create mode 100644 sound/soc/sof/intel/hda-sdw-bpt.c
--
2.39.2
4
60
[PATCH v6 6/7] arm64: dts: imx8m: update spdif sound card node properties
by Elinor Montmasson 19 Aug '24
by Elinor Montmasson 19 Aug '24
19 Aug '24
The merge of imx-spdif driver into fsl-asoc-card brought
new DT properties that can be used with the "fsl,imx-audio-spdif"
compatible:
* The "spdif-controller" property from imx-spdif is named "audio-cpu"
in fsl-asoc-card.
* fsl-asoc-card uses codecs explicitly declared in DT
with "audio-codec".
With an S/PDIF, codec drivers spdif_transmitter and
spdif_receiver should be used.
Driver imx-spdif used instead the dummy codec and a pair of
boolean properties, "spdif-in" and "spdif-out".
While backward compatibility is kept to support properties
"spdif-controller", "spdif-in" and "spdif-out", using new properties has
several benefits:
* "audio-cpu" and "audio-codec" are more generic names reflecting
that the fsl-asoc-card driver supports multiple hardware.
They are properties already used by devices using the
fsl-asoc-card driver.
They are also similar to properties of simple-card: "cpu" and "codec".
* "spdif-in" and "spdif-out" imply the use of the dummy codec in the
driver. However, there are already two codec drivers for the S/PDIF,
spdif_transmitter and spdif_receiver.
It is better to declare S/PDIF Tx and Rx devices in a DT, and then
reference them with "audio-codec" than using the dummy codec.
For those reasons, this commit updates in-tree DTs to use the new
properties:
* Rename "spdif-controller" property to "audio-cpu".
* Declare S/PDIF transmitter and/or receiver devices, and use them with
the "audio-codec" property instead of "spdif-out" and/or "spdif-in".
These modifications were tested only on an imx8mn-evk board.
Note that out-of-tree and old DTs are still supported.
Signed-off-by: Elinor Montmasson <elinor.montmasson(a)savoirfairelinux.com>
---
arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi | 15 +++++++++---
arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi | 15 +++++++++---
arch/arm64/boot/dts/freescale/imx8mq-evk.dts | 24 +++++++++++++++----
3 files changed, 43 insertions(+), 11 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
index 90d1901df2b1..348855a41852 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
@@ -180,12 +180,21 @@ cpu {
};
};
+ spdif_out: spdif-out {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dit";
+ };
+
+ spdif_in: spdif-in {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dir";
+ };
+
sound-spdif {
compatible = "fsl,imx-audio-spdif";
model = "imx-spdif";
- spdif-controller = <&spdif1>;
- spdif-out;
- spdif-in;
+ audio-cpu = <&spdif1>;
+ audio-codec = <&spdif_out>, <&spdif_in>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
index 9e0259ddf4bc..6a47e09703a7 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
@@ -124,12 +124,21 @@ sound-wm8524 {
"Line Out Jack", "LINEVOUTR";
};
+ spdif_out: spdif-out {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dit";
+ };
+
+ spdif_in: spdif-in {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dir";
+ };
+
sound-spdif {
compatible = "fsl,imx-audio-spdif";
model = "imx-spdif";
- spdif-controller = <&spdif1>;
- spdif-out;
- spdif-in;
+ audio-cpu = <&spdif1>;
+ audio-codec = <&spdif_out>, <&spdif_in>;
};
sound-micfil {
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
index 7507548cdb16..b953865f0b46 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
@@ -125,19 +125,33 @@ link_codec: simple-audio-card,codec {
};
};
+ spdif_out: spdif-out {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dit";
+ };
+
+ spdif_in: spdif-in {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dir";
+ };
+
sound-spdif {
compatible = "fsl,imx-audio-spdif";
model = "imx-spdif";
- spdif-controller = <&spdif1>;
- spdif-out;
- spdif-in;
+ audio-cpu = <&spdif1>;
+ audio-codec = <&spdif_out>, <&spdif_in>;
+ };
+
+ hdmi_arc_in: hdmi-arc-in {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dir";
};
sound-hdmi-arc {
compatible = "fsl,imx-audio-spdif";
model = "imx-hdmi-arc";
- spdif-controller = <&spdif2>;
- spdif-in;
+ audio-cpu = <&spdif2>;
+ audio-codec = <&hdmi_arc_in>;
};
};
--
2.34.1
2
2
19 Aug '24
This patch series updated the spi-nor, spi core and the AMD-Xilinx GQSPI
driver to add stacked and parallel memories support.
The first nine patches
https://lore.kernel.org/all/20230119185342.2093323-1-amit.kumar-mahapatra@aā¦
https://lore.kernel.org/all/20230310173217.3429788-2-amit.kumar-mahapatra@aā¦
https://lore.kernel.org/all/20230310173217.3429788-3-amit.kumar-mahapatra@aā¦
https://lore.kernel.org/all/20230310173217.3429788-4-amit.kumar-mahapatra@aā¦
https://lore.kernel.org/all/20230310173217.3429788-5-amit.kumar-mahapatra@aā¦
https://lore.kernel.org/all/20230310173217.3429788-6-amit.kumar-mahapatra@aā¦
https://lore.kernel.org/all/20230310173217.3429788-7-amit.kumar-mahapatra@aā¦
https://lore.kernel.org/all/20230310173217.3429788-8-amit.kumar-mahapatra@aā¦
https://lore.kernel.org/all/20230310173217.3429788-9-amit.kumar-mahapatra@aā¦
of the previous series got applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
for-next But the rest of the patches in the series did not get applied as
failure was reported for spi driver with GPIO CS, so send the remaining
patches in the series after rebasing it on top of for-next branch and
fixing the issue.
CS GPIO is not tested on our hardware, but it has been tested by @Stefan
https://lore.kernel.org/all/005001da1efc$619ad5a0$24d080e0$@opensource.cirrā¦
---
BRANCH: for-next
Changes in v11:
- Rebased patch series on top of latest for-next branch.
- Added a new patch(1/10) to replace spi->chip_select with
spi_get_chipselect() call in tps6594-spi.c.
- Added a new patch(2/10) to replace spi->chip_select with
spi_get_chipseletc() call in cs35l56_hda_spi.c.
- In spi.c initialized unused CS[] to 0xff and spi->cs_index_mask
to 0x01 in all flows.
- Updated spi_dev_check() to compare the CS of old spi device with
the new spi device CS.
- Updated cover letter description to add information regarding GPIO CS
testing and added Stefen's Tested-by tag in 3/10 patch.
Changes in v10:
- Rebased patch series on top of latest for-next branch and fixed
merge conflicts.
Changes in v9:
- Updated 1/8 patch description to add an high-level overview of
parallel(multi-cs) & stacked design.
- Initialized all unused CS to 0xFF.
- Moved CS check from spi_add_device() to __spi_add_device().
- Updated __spi_add_device() to check to make sure that multiple logical CS
don't map to the same physical CS and same physical CS doesn't map to
different logical CS.
- Updated 1/8, 5/8 & 7/8 to support arbitrary number of flash devices
connected in parallel or stacked mode.
- Updated documentation for chip_select.
- Added a new spi-nor structure member nor->num_flash to keep track of the
number of flashes connected.
- Added a new patch in the series 4/8 to move write_enable call just before
spi_mem ops call in SPI-NOR.
- Added comments in SPI core & SPI-NOR.
- Rebased the patch series on top of the latest for-next branch.
Changes in v8:
- Updated __spi_add_device() and spi_set_cs() to fix spi driver failure
with GPIO CS.
- Rebased the patch series on top of latest for-next branch and fixed
merge conflicts.
- Updated cover letter description to add information regarding GPIO CS
testing and request Stefan to provide his Tested-by tag for 1/7 patch.
- Updated 1/7 patch description.
Changes in v7:
- Updated spi_dev_check() to avoid failures for spi driver GPIO CS and
moved the error message from __spi_add_device() to spi_dev_check().
- Resolved code indentation issue in spi_set_cs().
- In spi_set_cs() call spi_delay_exec( ) once if the controller supports
multi cs with both the CS backed by GPIO.
- Updated __spi_validate()to add checks for both the GPIO CS.
- Replaced cs_index_mask bit mask with SPI_CS_CNT_MAX.
- Updated struct spi_controller to represent multi CS capability of the
spi controller through a flag bit SPI_CONTROLLER_MULTI_CS instead of
a boolen structure member "multi_cs_cap".
- Updated 1/7 patch description .
Changes in v6:
- Rebased on top of latest v6.3-rc1 and fixed merge conflicts in
spi-mpc512x-psc.c, sfdp.c, spansion.c files and removed spi-omap-100k.c.
- Updated spi_dev_check( ) to reject new devices if any one of the
chipselect is used by another device.
Changes in v5:
- Rebased the patches on top of v6.3-rc1 and fixed the merge conflicts.
- Fixed compilation warnings in spi-sh-msiof.c with shmobile_defconfig
Changes in v4:
- Fixed build error in spi-pl022.c file - reported by Mark.
- Fixed build error in spi-sn-f-ospi.c file.
- Added Reviewed-by: Serge Semin <fancer.lancer(a)gmail.com> tag.
- Added two more patches to replace spi->chip_select with API calls in
mpc832x_rdb.c & cs35l41_hda_spi.c files.
Changes in v3:
- Rebased the patches on top of
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
- Added a patch to convert spi_nor_otp_region_len(nor) &
spi_nor_otp_n_regions(nor) macros into inline functions
- Added Reviewed-by & Acked-by tags
Changes in v2:
- Rebased the patches on top of v6.2-rc1
- Created separate patch to add get & set APIs for spi->chip_select &
spi->cs_gpiod, and replaced all spi->chip_select and spi->cs_gpiod
references with the API calls.
- Created separate patch to add get & set APIs for nor->params.
---
Amit Kumar Mahapatra (10):
mfd: tps6594: Use set/get APIs to access spi->chip_select
ALSA: hda/cs35l56: Use set/get APIs to access spi->chip_select
spi: Add multi-cs memories support in SPI core
mtd: spi-nor: Convert macros with inline functions
mtd: spi-nor: Add APIs to set/get nor->params
mtd: spi-nor: Move write enable inside specific write & erase APIs
mtd: spi-nor: Add stacked memories support in spi-nor
spi: spi-zynqmp-gqspi: Add stacked memories support in GQSPI driver
mtd: spi-nor: Add parallel memories support in spi-nor
spi: spi-zynqmp-gqspi: Add parallel memories support in GQSPI driver
drivers/mfd/tps6594-spi.c | 2 +-
drivers/mtd/spi-nor/atmel.c | 17 +-
drivers/mtd/spi-nor/core.c | 683 +++++++++++++++++++++++++------
drivers/mtd/spi-nor/core.h | 8 +
drivers/mtd/spi-nor/debugfs.c | 4 +-
drivers/mtd/spi-nor/gigadevice.c | 4 +-
drivers/mtd/spi-nor/issi.c | 11 +-
drivers/mtd/spi-nor/macronix.c | 10 +-
drivers/mtd/spi-nor/micron-st.c | 35 +-
drivers/mtd/spi-nor/otp.c | 48 ++-
drivers/mtd/spi-nor/sfdp.c | 33 +-
drivers/mtd/spi-nor/spansion.c | 57 +--
drivers/mtd/spi-nor/sst.c | 7 +-
drivers/mtd/spi-nor/swp.c | 25 +-
drivers/mtd/spi-nor/winbond.c | 2 +-
drivers/mtd/spi-nor/xilinx.c | 18 +-
drivers/spi/spi-zynqmp-gqspi.c | 58 ++-
drivers/spi/spi.c | 259 ++++++++++--
include/linux/mtd/spi-nor.h | 21 +-
include/linux/spi/spi.h | 51 ++-
sound/pci/hda/cs35l56_hda_spi.c | 2 +-
21 files changed, 1085 insertions(+), 270 deletions(-)
--
2.17.1
10
61
[PATCH v2 0/6] ASoC: codecs: wsa88xx: add support for static port mapping.
by srinivas.kandagatlaļ¼ linaro.org 15 Aug '24
by srinivas.kandagatlaļ¼ linaro.org 15 Aug '24
15 Aug '24
Existing way of allocating soundwire master ports on Qualcommm platforms is
dynamic, and in linear order starting from 1 to MAX_PORTS.
This will work as long as soundwire device ports are 1:1 mapped
linearly. However on most Qcom SoCs like SM8550, SM8650, x1e80100, these
are NOT mapped in that order.
The result of this is that only one speaker among the pair of speakers
is always silent, With recent changes for WSA codec to support codec
versions and along with these patches we are able to get all speakers
working on these SoCs.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla(a)linaro.org>
---
Changes in v2:
- used dev_dbg instead of dev_info
- Link to v1: https://lore.kernel.org/r/20240626-port-map-v1-0-bd8987d2b332@linaro.org
---
Manikantan R (1):
ASoC: dt-bindings: wsa883x: Document port mapping property
Srinivas Kandagatla (5):
ASoC: codecs: wsa883x: parse port-mapping information
ASoC: dt-bindings: wsa8840: Document port mapping property
ASoC: codecs: wsa884x: parse port-mapping information
arm64: dts: x1e80100-crd: fix wsa soundwire port mapping
arm64: dts: x1e80100-qcp: fix wsa soundwire port mapping
Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml | 8 ++++++++
Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml | 8 ++++++++
arch/arm64/boot/dts/qcom/x1e80100-crd.dts | 4 ++++
arch/arm64/boot/dts/qcom/x1e80100-qcp.dts | 2 ++
sound/soc/codecs/wsa883x.c | 8 ++++++++
sound/soc/codecs/wsa884x.c | 8 ++++++++
6 files changed, 38 insertions(+)
---
base-commit: 9935be184a55dd84fc3275094f2df095491f6ea1
change-id: 20240626-port-map-ef50c3304d4a
Best regards,
--
Srinivas Kandagatla <srinivas.kandagatla(a)linaro.org>
5
10
It was reported that recent fix for memory corruption during topology
load, causes corruption in other cases. Instead of being overeager with
checking topology, assume that it is properly formatted and just
duplicate strings.
Reported-by: Pierre-Louis Bossart <pierre-louis.bossart(a)linux.intel.com>
Closes: https://lore.kernel.org/linux-sound/171812236450.201359.3019210915105428447ā¦
Suggested-by: PĆ©ter Ujfalusi <peter.ujfalusi(a)linux.intel.com>
Signed-off-by: Amadeusz SÅawiÅski <amadeuszx.slawinski(a)linux.intel.com>
---
sound/soc/soc-topology.c | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 0225bc5fc425a..4b166294602fa 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -1052,21 +1052,15 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
break;
}
- route->source = devm_kmemdup(tplg->dev, elem->source,
- min(strlen(elem->source), maxlen),
- GFP_KERNEL);
- route->sink = devm_kmemdup(tplg->dev, elem->sink,
- min(strlen(elem->sink), maxlen),
- GFP_KERNEL);
+ route->source = devm_kstrdup(tplg->dev, elem->source, GFP_KERNEL);
+ route->sink = devm_kstrdup(tplg->dev, elem->sink, GFP_KERNEL);
if (!route->source || !route->sink) {
ret = -ENOMEM;
break;
}
if (strnlen(elem->control, maxlen) != 0) {
- route->control = devm_kmemdup(tplg->dev, elem->control,
- min(strlen(elem->control), maxlen),
- GFP_KERNEL);
+ route->control = devm_kstrdup(tplg->dev, elem->control, GFP_KERNEL);
if (!route->control) {
ret = -ENOMEM;
break;
--
2.34.1
5
6
11 Aug '24
Requriment from customer to add new kcontrol to set tas2563 digital gain
and set "Speaker Force Firmware Load" as the common kcontrol for both
tas27871 and tas2563.
Signed-off-by: Shenghao Ding <shenghao-ding(a)ti.com>
---
v1:
- Changed the copyright year to 2024 in tas2781-tlv.h.
- Changed the copyright year to 2024 in tas2781.h.
- Set "Speaker Force Firmware Load" as the common kcontrol for for both
tas27871 and tas2563, that is tasdevice_snd_controls.
- Only tas2781_snd_controls only for gain setting.
- Add tas2563_dvc_tlv kcontrol for tas2563 digital gain setting.
- In codec probe, for tas2563, loading tas2563 gain control; for tas2781,
loading tas2781 gain control.
---
include/sound/tas2781-tlv.h | 262 ++++++++++++++++++++++++++++++++-
include/sound/tas2781.h | 3 +-
sound/soc/codecs/tas2781-i2c.c | 135 ++++++++++++++++-
3 files changed, 392 insertions(+), 8 deletions(-)
diff --git a/include/sound/tas2781-tlv.h b/include/sound/tas2781-tlv.h
index 1dc59005d241..99c41bfc7827 100644
--- a/include/sound/tas2781-tlv.h
+++ b/include/sound/tas2781-tlv.h
@@ -2,7 +2,7 @@
//
// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
//
-// Copyright (C) 2022 - 2023 Texas Instruments Incorporated
+// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2781 driver implements a flexible and configurable
@@ -17,5 +17,265 @@
static const __maybe_unused DECLARE_TLV_DB_SCALE(dvc_tlv, -10000, 100, 0);
static const DECLARE_TLV_DB_SCALE(amp_vol_tlv, 1100, 50, 0);
+static const DECLARE_TLV_DB_SCALE(tas2563_dvc_tlv, -12150, 50, 1);
+/* pow(10, db/20) * pow(2,30) */
+static const unsigned char tas2563_dvc_table[][4] = {
+ { 0X00, 0X00, 0X00, 0X00 }, /* -121.5db */
+ { 0X00, 0X00, 0X03, 0XBC }, /* -121.0db */
+ { 0X00, 0X00, 0X03, 0XF5 }, /* -120.5db */
+ { 0X00, 0X00, 0X04, 0X31 }, /* -120.0db */
+ { 0X00, 0X00, 0X04, 0X71 }, /* -119.5db */
+ { 0X00, 0X00, 0X04, 0XB4 }, /* -119.0db */
+ { 0X00, 0X00, 0X04, 0XFC }, /* -118.5db */
+ { 0X00, 0X00, 0X05, 0X47 }, /* -118.0db */
+ { 0X00, 0X00, 0X05, 0X97 }, /* -117.5db */
+ { 0X00, 0X00, 0X05, 0XEC }, /* -117.0db */
+ { 0X00, 0X00, 0X06, 0X46 }, /* -116.5db */
+ { 0X00, 0X00, 0X06, 0XA5 }, /* -116.0db */
+ { 0X00, 0X00, 0X07, 0X0A }, /* -115.5db */
+ { 0X00, 0X00, 0X07, 0X75 }, /* -115.0db */
+ { 0X00, 0X00, 0X07, 0XE6 }, /* -114.5db */
+ { 0X00, 0X00, 0X08, 0X5E }, /* -114.0db */
+ { 0X00, 0X00, 0X08, 0XDD }, /* -113.5db */
+ { 0X00, 0X00, 0X09, 0X63 }, /* -113.0db */
+ { 0X00, 0X00, 0X09, 0XF2 }, /* -112.5db */
+ { 0X00, 0X00, 0X0A, 0X89 }, /* -112.0db */
+ { 0X00, 0X00, 0X0B, 0X28 }, /* -111.5db */
+ { 0X00, 0X00, 0X0B, 0XD2 }, /* -111.0db */
+ { 0X00, 0X00, 0X0C, 0X85 }, /* -110.5db */
+ { 0X00, 0X00, 0X0D, 0X43 }, /* -110.0db */
+ { 0X00, 0X00, 0X0E, 0X0C }, /* -109.5db */
+ { 0X00, 0X00, 0X0E, 0XE1 }, /* -109.0db */
+ { 0X00, 0X00, 0X0F, 0XC3 }, /* -108.5db */
+ { 0X00, 0X00, 0X10, 0XB2 }, /* -108.0db */
+ { 0X00, 0X00, 0X11, 0XAF }, /* -107.5db */
+ { 0X00, 0X00, 0X12, 0XBC }, /* -107.0db */
+ { 0X00, 0X00, 0X13, 0XD8 }, /* -106.5db */
+ { 0X00, 0X00, 0X15, 0X05 }, /* -106.0db */
+ { 0X00, 0X00, 0X16, 0X44 }, /* -105.5db */
+ { 0X00, 0X00, 0X17, 0X96 }, /* -105.0db */
+ { 0X00, 0X00, 0X18, 0XFB }, /* -104.5db */
+ { 0X00, 0X00, 0X1A, 0X76 }, /* -104.0db */
+ { 0X00, 0X00, 0X1C, 0X08 }, /* -103.5db */
+ { 0X00, 0X00, 0X1D, 0XB1 }, /* -103.0db */
+ { 0X00, 0X00, 0X1F, 0X73 }, /* -102.5db */
+ { 0X00, 0X00, 0X21, 0X51 }, /* -102.0db */
+ { 0X00, 0X00, 0X23, 0X4A }, /* -101.5db */
+ { 0X00, 0X00, 0X25, 0X61 }, /* -101.0db */
+ { 0X00, 0X00, 0X27, 0X98 }, /* -100.5db */
+ { 0X00, 0X00, 0X29, 0XF1 }, /* -100.0db */
+ { 0X00, 0X00, 0X2C, 0X6D }, /* -99.5db */
+ { 0X00, 0X00, 0X2F, 0X0F }, /* -99.0db */
+ { 0X00, 0X00, 0X31, 0XD9 }, /* -98.5db */
+ { 0X00, 0X00, 0X34, 0XCD }, /* -98.0db */
+ { 0X00, 0X00, 0X37, 0XEE }, /* -97.5db */
+ { 0X00, 0X00, 0X3B, 0X3F }, /* -97.0db */
+ { 0X00, 0X00, 0X3E, 0XC1 }, /* -96.5db */
+ { 0X00, 0X00, 0X42, 0X79 }, /* -96.0db */
+ { 0X00, 0X00, 0X46, 0X6A }, /* -95.5db */
+ { 0X00, 0X00, 0X4A, 0X96 }, /* -95.0db */
+ { 0X00, 0X00, 0X4F, 0X01 }, /* -94.5db */
+ { 0X00, 0X00, 0X53, 0XAF }, /* -94.0db */
+ { 0X00, 0X00, 0X58, 0XA5 }, /* -93.5db */
+ { 0X00, 0X00, 0X5D, 0XE6 }, /* -93.0db */
+ { 0X00, 0X00, 0X63, 0X76 }, /* -92.5db */
+ { 0X00, 0X00, 0X69, 0X5B }, /* -92.0db */
+ { 0X00, 0X00, 0X6F, 0X99 }, /* -91.5db */
+ { 0X00, 0X00, 0X76, 0X36 }, /* -91.0db */
+ { 0X00, 0X00, 0X7D, 0X37 }, /* -90.5db */
+ { 0X00, 0X00, 0X84, 0XA2 }, /* -90.0db */
+ { 0X00, 0X00, 0X8C, 0X7E }, /* -89.5db */
+ { 0X00, 0X00, 0X94, 0XD1 }, /* -89.0db */
+ { 0X00, 0X00, 0X9D, 0XA3 }, /* -88.5db */
+ { 0X00, 0X00, 0XA6, 0XFA }, /* -88.0db */
+ { 0X00, 0X00, 0XB0, 0XDF }, /* -87.5db */
+ { 0X00, 0X00, 0XBB, 0X5A }, /* -87.0db */
+ { 0X00, 0X00, 0XC6, 0X74 }, /* -86.5db */
+ { 0X00, 0X00, 0XD2, 0X36 }, /* -86.0db */
+ { 0X00, 0X00, 0XDE, 0XAB }, /* -85.5db */
+ { 0X00, 0X00, 0XEB, 0XDC }, /* -85.0db */
+ { 0X00, 0X00, 0XF9, 0XD6 }, /* -84.5db */
+ { 0X00, 0X01, 0X08, 0XA4 }, /* -84.0db */
+ { 0X00, 0X01, 0X18, 0X52 }, /* -83.5db */
+ { 0X00, 0X01, 0X28, 0XEF }, /* -83.0db */
+ { 0X00, 0X01, 0X3A, 0X87 }, /* -82.5db */
+ { 0X00, 0X01, 0X4D, 0X2A }, /* -82.0db */
+ { 0X00, 0X01, 0X60, 0XE8 }, /* -81.5db */
+ { 0X00, 0X01, 0X75, 0XD1 }, /* -81.0db */
+ { 0X00, 0X01, 0X8B, 0XF7 }, /* -80.5db */
+ { 0X00, 0X01, 0XA3, 0X6E }, /* -80.0db */
+ { 0X00, 0X01, 0XBC, 0X48 }, /* -79.5db */
+ { 0X00, 0X01, 0XD6, 0X9B }, /* -79.0db */
+ { 0X00, 0X01, 0XF2, 0X7E }, /* -78.5db */
+ { 0X00, 0X02, 0X10, 0X08 }, /* -78.0db */
+ { 0X00, 0X02, 0X2F, 0X51 }, /* -77.5db */
+ { 0X00, 0X02, 0X50, 0X76 }, /* -77.0db */
+ { 0X00, 0X02, 0X73, 0X91 }, /* -76.5db */
+ { 0X00, 0X02, 0X98, 0XC0 }, /* -76.0db */
+ { 0X00, 0X02, 0XC0, 0X24 }, /* -75.5db */
+ { 0X00, 0X02, 0XE9, 0XDD }, /* -75.0db */
+ { 0X00, 0X03, 0X16, 0X0F }, /* -74.5db */
+ { 0X00, 0X03, 0X44, 0XDF }, /* -74.0db */
+ { 0X00, 0X03, 0X76, 0X76 }, /* -73.5db */
+ { 0X00, 0X03, 0XAA, 0XFC }, /* -73.0db */
+ { 0X00, 0X03, 0XE2, 0XA0 }, /* -72.5db */
+ { 0X00, 0X04, 0X1D, 0X8F }, /* -72.0db */
+ { 0X00, 0X04, 0X5B, 0XFD }, /* -71.5db */
+ { 0X00, 0X04, 0X9E, 0X1D }, /* -71.0db */
+ { 0X00, 0X04, 0XE4, 0X29 }, /* -70.5db */
+ { 0X00, 0X05, 0X2E, 0X5A }, /* -70.0db */
+ { 0X00, 0X05, 0X7C, 0XF2 }, /* -69.5db */
+ { 0X00, 0X05, 0XD0, 0X31 }, /* -69.0db */
+ { 0X00, 0X06, 0X28, 0X60 }, /* -68.5db */
+ { 0X00, 0X06, 0X85, 0XC8 }, /* -68.0db */
+ { 0X00, 0X06, 0XE8, 0XB9 }, /* -67.5db */
+ { 0X00, 0X07, 0X51, 0X86 }, /* -67.0db */
+ { 0X00, 0X07, 0XC0, 0X8A }, /* -66.5db */
+ { 0X00, 0X08, 0X36, 0X21 }, /* -66.0db */
+ { 0X00, 0X08, 0XB2, 0XB0 }, /* -65.5db */
+ { 0X00, 0X09, 0X36, 0XA1 }, /* -65.0db */
+ { 0X00, 0X09, 0XC2, 0X63 }, /* -64.5db */
+ { 0X00, 0X0A, 0X56, 0X6D }, /* -64.0db */
+ { 0X00, 0X0A, 0XF3, 0X3C }, /* -63.5db */
+ { 0X00, 0X0B, 0X99, 0X56 }, /* -63.0db */
+ { 0X00, 0X0C, 0X49, 0X48 }, /* -62.5db */
+ { 0X00, 0X0D, 0X03, 0XA7 }, /* -62.0db */
+ { 0X00, 0X0D, 0XC9, 0X11 }, /* -61.5db */
+ { 0X00, 0X0E, 0X9A, 0X2D }, /* -61.0db */
+ { 0X00, 0X0F, 0X77, 0XAD }, /* -60.5db */
+ { 0X00, 0X10, 0X62, 0X4D }, /* -60.0db */
+ { 0X00, 0X11, 0X5A, 0XD5 }, /* -59.5db */
+ { 0X00, 0X12, 0X62, 0X16 }, /* -59.0db */
+ { 0X00, 0X13, 0X78, 0XF0 }, /* -58.5db */
+ { 0X00, 0X14, 0XA0, 0X50 }, /* -58.0db */
+ { 0X00, 0X15, 0XD9, 0X31 }, /* -57.5db */
+ { 0X00, 0X17, 0X24, 0X9C }, /* -57.0db */
+ { 0X00, 0X18, 0X83, 0XAA }, /* -56.5db */
+ { 0X00, 0X19, 0XF7, 0X86 }, /* -56.0db */
+ { 0X00, 0X1B, 0X81, 0X6A }, /* -55.5db */
+ { 0X00, 0X1D, 0X22, 0XA4 }, /* -55.0db */
+ { 0X00, 0X1E, 0XDC, 0X98 }, /* -54.5db */
+ { 0X00, 0X20, 0XB0, 0XBC }, /* -54.0db */
+ { 0X00, 0X22, 0XA0, 0X9D }, /* -53.5db */
+ { 0X00, 0X24, 0XAD, 0XE0 }, /* -53.0db */
+ { 0X00, 0X26, 0XDA, 0X43 }, /* -52.5db */
+ { 0X00, 0X29, 0X27, 0X9D }, /* -52.0db */
+ { 0X00, 0X2B, 0X97, 0XE3 }, /* -51.5db */
+ { 0X00, 0X2E, 0X2D, 0X27 }, /* -51.0db */
+ { 0X00, 0X30, 0XE9, 0X9A }, /* -50.5db */
+ { 0X00, 0X33, 0XCF, 0X8D }, /* -50.0db */
+ { 0X00, 0X36, 0XE1, 0X78 }, /* -49.5db */
+ { 0X00, 0X3A, 0X21, 0XF3 }, /* -49.0db */
+ { 0X00, 0X3D, 0X93, 0XC3 }, /* -48.5db */
+ { 0X00, 0X41, 0X39, 0XD3 }, /* -48.0db */
+ { 0X00, 0X45, 0X17, 0X3B }, /* -47.5db */
+ { 0X00, 0X49, 0X2F, 0X44 }, /* -47.0db */
+ { 0X00, 0X4D, 0X85, 0X66 }, /* -46.5db */
+ { 0X00, 0X52, 0X1D, 0X50 }, /* -46.0db */
+ { 0X00, 0X56, 0XFA, 0XE8 }, /* -45.5db */
+ { 0X00, 0X5C, 0X22, 0X4E }, /* -45.0db */
+ { 0X00, 0X61, 0X97, 0XE1 }, /* -44.5db */
+ { 0X00, 0X67, 0X60, 0X44 }, /* -44.0db */
+ { 0X00, 0X6D, 0X80, 0X60 }, /* -43.5db */
+ { 0X00, 0X73, 0XFD, 0X65 }, /* -43.0db */
+ { 0X00, 0X7A, 0XDC, 0XD7 }, /* -42.5db */
+ { 0X00, 0X82, 0X24, 0X8A }, /* -42.0db */
+ { 0X00, 0X89, 0XDA, 0XAB }, /* -41.5db */
+ { 0X00, 0X92, 0X05, 0XC6 }, /* -41.0db */
+ { 0X00, 0X9A, 0XAC, 0XC8 }, /* -40.5db */
+ { 0X00, 0XA3, 0XD7, 0X0A }, /* -40.0db */
+ { 0X00, 0XAD, 0X8C, 0X52 }, /* -39.5db */
+ { 0X00, 0XB7, 0XD4, 0XDD }, /* -39.0db */
+ { 0X00, 0XC2, 0XB9, 0X65 }, /* -38.5db */
+ { 0X00, 0XCE, 0X43, 0X28 }, /* -38.0db */
+ { 0X00, 0XDA, 0X7B, 0XF1 }, /* -37.5db */
+ { 0X00, 0XE7, 0X6E, 0X1E }, /* -37.0db */
+ { 0X00, 0XF5, 0X24, 0XAC }, /* -36.5db */
+ { 0X01, 0X03, 0XAB, 0X3D }, /* -36.0db */
+ { 0X01, 0X13, 0X0E, 0X24 }, /* -35.5db */
+ { 0X01, 0X23, 0X5A, 0X71 }, /* -35.0db */
+ { 0X01, 0X34, 0X9D, 0XF8 }, /* -34.5db */
+ { 0X01, 0X46, 0XE7, 0X5D }, /* -34.0db */
+ { 0X01, 0X5A, 0X46, 0X27 }, /* -33.5db */
+ { 0X01, 0X6E, 0XCA, 0XC5 }, /* -33.0db */
+ { 0X01, 0X84, 0X86, 0X9F }, /* -32.5db */
+ { 0X01, 0X9B, 0X8C, 0X27 }, /* -32.0db */
+ { 0X01, 0XB3, 0XEE, 0XE5 }, /* -31.5db */
+ { 0X01, 0XCD, 0XC3, 0X8C }, /* -31.0db */
+ { 0X01, 0XE9, 0X20, 0X05 }, /* -30.5db */
+ { 0X02, 0X06, 0X1B, 0X89 }, /* -30.0db */
+ { 0X02, 0X24, 0XCE, 0XB0 }, /* -29.5db */
+ { 0X02, 0X45, 0X53, 0X85 }, /* -29.0db */
+ { 0X02, 0X67, 0XC5, 0XA2 }, /* -28.5db */
+ { 0X02, 0X8C, 0X42, 0X3F }, /* -28.0db */
+ { 0X02, 0XB2, 0XE8, 0X55 }, /* -27.5db */
+ { 0X02, 0XDB, 0XD8, 0XAD }, /* -27.0db */
+ { 0X03, 0X07, 0X36, 0X05 }, /* -26.5db */
+ { 0X03, 0X35, 0X25, 0X29 }, /* -26.0db */
+ { 0X03, 0X65, 0XCD, 0X13 }, /* -25.5db */
+ { 0X03, 0X99, 0X57, 0X0C }, /* -25.0db */
+ { 0X03, 0XCF, 0XEE, 0XCF }, /* -24.5db */
+ { 0X04, 0X09, 0XC2, 0XB0 }, /* -24.0db */
+ { 0X04, 0X47, 0X03, 0XC1 }, /* -23.5db */
+ { 0X04, 0X87, 0XE5, 0XFB }, /* -23.0db */
+ { 0X04, 0XCC, 0XA0, 0X6D }, /* -22.5db */
+ { 0X05, 0X15, 0X6D, 0X68 }, /* -22.0db */
+ { 0X05, 0X62, 0X8A, 0XB3 }, /* -21.5db */
+ { 0X05, 0XB4, 0X39, 0XBC }, /* -21.0db */
+ { 0X06, 0X0A, 0XBF, 0XD4 }, /* -20.5db */
+ { 0X06, 0X66, 0X66, 0X66 }, /* -20.0db */
+ { 0X06, 0XC7, 0X7B, 0X36 }, /* -19.5db */
+ { 0X07, 0X2E, 0X50, 0XA6 }, /* -19.0db */
+ { 0X07, 0X9B, 0X3D, 0XF6 }, /* -18.5db */
+ { 0X08, 0X0E, 0X9F, 0X96 }, /* -18.0db */
+ { 0X08, 0X88, 0XD7, 0X6D }, /* -17.5db */
+ { 0X09, 0X0A, 0X4D, 0X2F }, /* -17.0db */
+ { 0X09, 0X93, 0X6E, 0XB8 }, /* -16.5db */
+ { 0X0A, 0X24, 0XB0, 0X62 }, /* -16.0db */
+ { 0X0A, 0XBE, 0X8D, 0X70 }, /* -15.5db */
+ { 0X0B, 0X61, 0X88, 0X71 }, /* -15.0db */
+ { 0X0C, 0X0E, 0X2B, 0XB0 }, /* -14.5db */
+ { 0X0C, 0XC5, 0X09, 0XAB }, /* -14.0db */
+ { 0X0D, 0X86, 0XBD, 0X8D }, /* -13.5db */
+ { 0X0E, 0X53, 0XEB, 0XB3 }, /* -13.0db */
+ { 0X0F, 0X2D, 0X42, 0X38 }, /* -12.5db */
+ { 0X10, 0X13, 0X79, 0X87 }, /* -12.0db */
+ { 0X11, 0X07, 0X54, 0XF9 }, /* -11.5db */
+ { 0X12, 0X09, 0XA3, 0X7A }, /* -11.0db */
+ { 0X13, 0X1B, 0X40, 0X39 }, /* -10.5db */
+ { 0X14, 0X3D, 0X13, 0X62 }, /* -10.0db */
+ { 0X15, 0X70, 0X12, 0XE1 }, /* -9.5db */
+ { 0X16, 0XB5, 0X43, 0X37 }, /* -9.0db */
+ { 0X18, 0X0D, 0XB8, 0X54 }, /* -8.5db */
+ { 0X19, 0X7A, 0X96, 0X7F }, /* -8.0db */
+ { 0X1A, 0XFD, 0X13, 0X54 }, /* -7.5db */
+ { 0X1C, 0X96, 0X76, 0XC6 }, /* -7.0db */
+ { 0X1E, 0X48, 0X1C, 0X37 }, /* -6.5db */
+ { 0X20, 0X13, 0X73, 0X9E }, /* -6.0db */
+ { 0X21, 0XFA, 0X02, 0XBF }, /* -5.5db */
+ { 0X23, 0XFD, 0X66, 0X78 }, /* -5.0db */
+ { 0X26, 0X1F, 0X54, 0X1C }, /* -4.5db */
+ { 0X28, 0X61, 0X9A, 0XE9 }, /* -4.0db */
+ { 0X2A, 0XC6, 0X25, 0X91 }, /* -3.5db */
+ { 0X2D, 0X4E, 0XFB, 0XD5 }, /* -3.0db */
+ { 0X2F, 0XFE, 0X44, 0X48 }, /* -2.5db */
+ { 0X32, 0XD6, 0X46, 0X17 }, /* -2.0db */
+ { 0X35, 0XD9, 0X6B, 0X02 }, /* -1.5db */
+ { 0X39, 0X0A, 0X41, 0X5F }, /* -1.0db */
+ { 0X3C, 0X6B, 0X7E, 0X4F }, /* -0.5db */
+ { 0X40, 0X00, 0X00, 0X00 }, /* 0.0db */
+ { 0X43, 0XCA, 0XD0, 0X22 }, /* 0.5db */
+ { 0X47, 0XCF, 0X26, 0X7D }, /* 1.0db */
+ { 0X4C, 0X10, 0X6B, 0XA5 }, /* 1.5db */
+ { 0X50, 0X92, 0X3B, 0XE3 }, /* 2.0db */
+ { 0X55, 0X58, 0X6A, 0X46 }, /* 2.5db */
+ { 0X5A, 0X67, 0X03, 0XDF }, /* 3.0db */
+ { 0X5F, 0XC2, 0X53, 0X32 }, /* 3.5db */
+ { 0X65, 0X6E, 0XE3, 0XDB }, /* 4.0db */
+ { 0X6B, 0X71, 0X86, 0X68 }, /* 4.5db */
+ { 0X71, 0XCF, 0X54, 0X71 }, /* 5.0db */
+ { 0X78, 0X8D, 0XB4, 0XE9 }, /* 5.5db */
+ { 0XFF, 0XFF, 0XFF, 0XFF }, /* 6.0db */
+};
#endif
diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h
index cd8ce522b78e..3275575f5bfb 100644
--- a/include/sound/tas2781.h
+++ b/include/sound/tas2781.h
@@ -2,7 +2,7 @@
//
// ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier
//
-// Copyright (C) 2022 - 2023 Texas Instruments Incorporated
+// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2563/TAS2781 driver implements a flexible and configurable
@@ -50,6 +50,7 @@
#define TASDEVICE_I2CChecksum TASDEVICE_REG(0x0, 0x0, 0x7E)
/* Volume control */
+#define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0C)
#define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1A)
#define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03)
#define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1)
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 4d1a0d836e77..4960ab6577f7 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -30,6 +30,7 @@
#include <sound/tas2781.h>
#include <sound/tlv.h>
#include <sound/tas2781-tlv.h>
+#include <asm/unaligned.h>
static const struct i2c_device_id tasdevice_id[] = {
{ "tas2563", TAS2563 },
@@ -103,7 +104,7 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
return tasdevice_amp_putvol(tas_priv, ucontrol, mc);
}
-static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
+static int tasdev_force_fwload_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
@@ -118,7 +119,7 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
+static int tasdev_force_fwload_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
@@ -127,18 +128,114 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
snd_soc_component_get_drvdata(component);
bool change, val = (bool)ucontrol->value.integer.value[0];
+ mutex_lock(&tas_priv->codec_lock);
if (tas_priv->force_fwload_status == val)
change = false;
else {
change = true;
tas_priv->force_fwload_status = val;
}
+ mutex_unlock(&tas_priv->codec_lock);
dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
tas_priv->force_fwload_status ? "ON" : "OFF");
return change;
}
+static int tas2563_digital_gain_get(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
+ unsigned int l = 0, r = mc->max;
+ unsigned int target, ar_mid, mid, ar_l, ar_r;
+ unsigned int reg = mc->reg;
+ unsigned char data[4];
+ int ret;
+
+ mutex_lock(&tas_dev->codec_lock);
+ /* Read the primary device */
+ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
+ if (ret) {
+ dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
+ goto out;
+ }
+
+ target = get_unaligned_be32(&data[0]);
+
+ while (r > 1 + l) {
+ mid = (l + r) / 2;
+ ar_mid = get_unaligned_be32(tas2563_dvc_table[mid]);
+ if (target < ar_mid)
+ r = mid;
+ else
+ l = mid;
+ }
+
+ ar_l = get_unaligned_be32(tas2563_dvc_table[l]);
+ ar_r = get_unaligned_be32(tas2563_dvc_table[r]);
+
+ /* find out the member same as or closer to the current volume */
+ ucontrol->value.integer.value[0] =
+ abs(target - ar_l) <= abs(target - ar_r) ? l : r;
+out:
+ mutex_unlock(&tas_dev->codec_lock);
+ return 0;
+}
+
+static int tas2563_digital_gain_put(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
+ unsigned int reg = mc->reg;
+ unsigned int volrd, volwr;
+ int vol = ucontrol->value.integer.value[0];
+ int max = mc->max, i, ret = 1;
+ unsigned char data[4];
+
+ vol = clamp(vol, 0, max);
+ mutex_lock(&tas_dev->codec_lock);
+ /* Read the primary device */
+ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
+ if (ret) {
+ dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
+ goto out;
+ }
+
+ volrd = get_unaligned_be32(&data[0]);
+ volwr = get_unaligned_be32(tas2563_dvc_table[vol]);
+
+ if (volrd == volwr) {
+ ret = 0;
+ goto out;
+ }
+
+ for (i = 0; i < tas_dev->ndev; i++) {
+ ret = tasdevice_dev_bulk_write(tas_dev, i, reg,
+ (unsigned char *)tas2563_dvc_table[vol], 4);
+ if (ret)
+ dev_err(tas_dev->dev,
+ "%s, set digital vol error in device %d\n",
+ __func__, i);
+ }
+
+out:
+ mutex_unlock(&tas_dev->codec_lock);
+ return ret;
+}
+
+static const struct snd_kcontrol_new tasdevice_snd_controls[] = {
+ SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
+ tasdev_force_fwload_get, tasdev_force_fwload_put),
+};
+
static const struct snd_kcontrol_new tas2781_snd_controls[] = {
SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL,
1, 0, 20, 0, tas2781_amp_getvol,
@@ -146,8 +243,13 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = {
SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL,
0, 0, 200, 1, tas2781_digital_getvol,
tas2781_digital_putvol, dvc_tlv),
- SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
- tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
+static const struct snd_kcontrol_new tas2563_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2563_DVC_LVL, 0,
+ 0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0,
+ tas2563_digital_gain_get, tas2563_digital_gain_put,
+ tas2563_dvc_tlv),
};
static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
@@ -578,6 +680,27 @@ static struct snd_soc_dai_driver tasdevice_dai_driver[] = {
static int tasdevice_codec_probe(struct snd_soc_component *codec)
{
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int rc;
+
+ if (tas_priv->chip_id == TAS2781) {
+ rc = snd_soc_add_component_controls(codec,
+ tas2781_snd_controls,
+ ARRAY_SIZE(tas2781_snd_controls));
+ if (rc < 0) {
+ dev_err(tas_priv->dev, "%s: Add control err rc = %d",
+ __func__, rc);
+ return rc;
+ }
+ } else {
+ rc = snd_soc_add_component_controls(codec,
+ tas2563_snd_controls,
+ ARRAY_SIZE(tas2563_snd_controls));
+ if (rc < 0) {
+ dev_err(tas_priv->dev, "%s: Add control err rc = %d",
+ __func__, rc);
+ return rc;
+ }
+ }
tas_priv->name_prefix = codec->name_prefix;
return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready);
@@ -605,8 +728,8 @@ static const struct snd_soc_component_driver
soc_codec_driver_tasdevice = {
.probe = tasdevice_codec_probe,
.remove = tasdevice_codec_remove,
- .controls = tas2781_snd_controls,
- .num_controls = ARRAY_SIZE(tas2781_snd_controls),
+ .controls = tasdevice_snd_controls,
+ .num_controls = ARRAY_SIZE(tasdevice_snd_controls),
.dapm_widgets = tasdevice_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tasdevice_dapm_widgets),
.dapm_routes = tasdevice_audio_map,
--
2.34.1
4
3
This patchset updates some sample rate definition for eARC support.
Notably it:
* adds the definition for 128kHz
* update the ASoC spdif codecs to include all supported rates, up to 768kHz
* adds missing IEC958 definition for 128k, 352.4k, 384k and 705.6kHz
On that last point, as noted in the related commit description, I'd like to
stress that I have found the definitions using a testing equipement. I
do not have access to the IEC958 specification. It would be best if someone
with access to this specification could review/ack patch #2, before
applying it.
Jerome Brunet (3):
ALSA: pcm: add support for 128kHz sample rate
ALSA: IEC958 definition for consumer status channel update
ASoC: spdif: extend supported rates to 768kHz
include/sound/asoundef.h | 6 +++++-
include/sound/pcm.h | 13 +++++++------
sound/core/pcm_native.c | 6 +++---
sound/soc/codecs/spdif_receiver.c | 3 ++-
sound/soc/codecs/spdif_transmitter.c | 3 ++-
5 files changed, 19 insertions(+), 12 deletions(-)
--
2.43.0
5
15
[PATCH v1] ASoc: tas2781: Add Calibration Kcontrols and tas2563 digtial gain for Chromebook
by Shenghao Ding 09 Aug '24
by Shenghao Ding 09 Aug '24
09 Aug '24
Calibrated data will be set to default after loading DSP config params,
which will cause speaker protection work abnormally. Reload calibrated
data after loading DSP config params.
Signed-off-by: Shenghao Ding <shenghao-ding(a)ti.com>
---
v1:
- Changed the copyright year to 2024 in the related files.
- Add CAL_DAT_SZ for calibrated data size.
- Add TAS2563_DVC_LVL for digtial gain kcontrol.
- Add registers for TAS2563 and TAS2781 calibration.
- Add cali_data_restore for regsiter restore after calibration.
- Add is_user_space_calidata to store the flag where the calibrated
from, user space or bin file from driver parsing.
- Add TASDEVICE_RCA_FW_OK to support only register setting bin in the
device.
- Add tas2563_dvc_table for relationship between tas2563 digtial gains
and register values.
- Correct the filename in the header comments of tas2781-comlib.c,
tas2781-lib.c --> tas2781-comlib.c.
- tasdevice_chn_switch for chip switch among multiple chips(tas2563
or tas2781)
- Add loading the calibrated values from user space in
tasdev_load_calibrated_data
- Correct no dsp no work, it can still work in bypass mode.
- Add calibrated register setting for tas2563&tas2781.
- Add mutex into each kcontrol.
- rename tas2781_force_fwload_get, tas2781_force_fwload_put-->
tasdev_force_fwload_get, tasdev_force_fwload_put
- rename tas2781_codec --> tasdev_codec
- define tas2781_snd_control and tas2563_snd_control for volume
- define tas2781_cali_control and tas2563_cali_control for calibration
---
include/sound/tas2781-dsp.h | 1 +
include/sound/tas2781.h | 92 ++-
sound/soc/codecs/tas2781-comlib.c | 35 +-
sound/soc/codecs/tas2781-fmwlib.c | 51 +-
sound/soc/codecs/tas2781-i2c.c | 941 +++++++++++++++++++++++++++++-
5 files changed, 1061 insertions(+), 59 deletions(-)
diff --git a/include/sound/tas2781-dsp.h b/include/sound/tas2781-dsp.h
index 7fba7ea26a4b..74ab6f113029 100644
--- a/include/sound/tas2781-dsp.h
+++ b/include/sound/tas2781-dsp.h
@@ -121,6 +121,7 @@ enum tasdevice_dsp_fw_state {
TASDEVICE_DSP_FW_NONE = 0,
TASDEVICE_DSP_FW_PENDING,
TASDEVICE_DSP_FW_FAIL,
+ TASDEVICE_RCA_FW_OK,
TASDEVICE_DSP_FW_ALL_OK,
};
diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h
index 99ca3e401fd1..2fb3d03d0040 100644
--- a/include/sound/tas2781.h
+++ b/include/sound/tas2781.h
@@ -2,7 +2,7 @@
//
// ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier
//
-// Copyright (C) 2022 - 2023 Texas Instruments Incorporated
+// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2563/TAS2781 driver implements a flexible and configurable
@@ -23,6 +23,8 @@
#define SMARTAMP_MODULE_NAME "tas2781"
#define TAS2781_GLOBAL_ADDR 0x40
#define TAS2563_GLOBAL_ADDR 0x48
+#define CAL_DAT_SZ 20
+
#define TASDEVICE_RATES (SNDRV_PCM_RATE_44100 |\
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\
SNDRV_PCM_RATE_88200)
@@ -31,6 +33,11 @@
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
+#define TASDEVICE_CMD_SING_W 0x1
+#define TASDEVICE_CMD_BURST 0x2
+#define TASDEVICE_CMD_DELAY 0x3
+#define TASDEVICE_CMD_FIELD_W 0x4
+
/*PAGE Control Register (available in page0 of each book) */
#define TASDEVICE_PAGE_SELECT 0x00
#define TASDEVICE_BOOKCTL_PAGE 0x00
@@ -43,21 +50,73 @@
(page * 128)) + reg)
/*Software Reset */
-#define TAS2781_REG_SWRESET TASDEVICE_REG(0x0, 0X0, 0x01)
-#define TAS2781_REG_SWRESET_RESET BIT(0)
+#define TASDEVICE_REG_SWRESET TASDEVICE_REG(0x00, 0X00, 0x01)
+#define TASDEVICE_REG_SWRESET_RESET BIT(0)
/*I2C Checksum */
-#define TASDEVICE_I2CChecksum TASDEVICE_REG(0x0, 0x0, 0x7E)
+#define TASDEVICE_I2CChecksum TASDEVICE_REG(0x00, 0x00, 0x7E)
+
+/* XM_340 */
+#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x02, 0x4c)
+/* XM_341 */
+#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x02, 0x64)
/* Volume control */
-#define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1A)
-#define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03)
+#define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0C)
+#define TAS2781_DVC_LVL TASDEVICE_REG(0x00, 0x00, 0x1A)
+#define TAS2781_AMP_LEVEL TASDEVICE_REG(0x00, 0x00, 0x03)
#define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1)
-#define TASDEVICE_CMD_SING_W 0x1
-#define TASDEVICE_CMD_BURST 0x2
-#define TASDEVICE_CMD_DELAY 0x3
-#define TASDEVICE_CMD_FIELD_W 0x4
+#define TAS2563_PRM_R0_REG TASDEVICE_REG(0x00, 0x0f, 0x34)
+#define TAS2563_PRM_R0_LOW_REG TASDEVICE_REG(0x00, 0x0f, 0x48)
+#define TAS2563_PRM_INVR0_REG TASDEVICE_REG(0x00, 0x0f, 0x40)
+#define TAS2563_PRM_POW_REG TASDEVICE_REG(0x00, 0x0d, 0x3c)
+#define TAS2563_PRM_TLIMIT_REG TASDEVICE_REG(0x00, 0x10, 0x14)
+
+#define TAS2563_RUNTIME_RE_REG_TF TASDEVICE_REG(0x64, 0x02, 0x70)
+#define TAS2563_RUNTIME_RE_REG TASDEVICE_REG(0x64, 0x02, 0x48)
+
+#define TAS2563_PRM_ENFF_REG TASDEVICE_REG(0x00, 0x0d, 0x54)
+#define TAS2563_PRM_DISTCK_REG TASDEVICE_REG(0x00, 0x0d, 0x58)
+#define TAS2563_PRM_TE_SCTHR_REG TASDEVICE_REG(0x00, 0x0f, 0x60)
+#define TAS2563_PRM_PLT_FLAG_REG TASDEVICE_REG(0x00, 0x0d, 0x74)
+#define TAS2563_PRM_SINEGAIN_REG TASDEVICE_REG(0x00, 0x0d, 0x7c)
+/* prm_Int_B0 */
+#define TAS2563_TE_TA1_REG TASDEVICE_REG(0x00, 0x10, 0x0c)
+/* prm_Int_A1 */
+#define TAS2563_TE_TA1_AT_REG TASDEVICE_REG(0x00, 0x10, 0x10)
+/* prm_TE_Beta */
+#define TAS2563_TE_TA2_REG TASDEVICE_REG(0x00, 0x0f, 0x64)
+/* prm_TE_Beta1 */
+#define TAS2563_TE_AT_REG TASDEVICE_REG(0x00, 0x0f, 0x68)
+/* prm_TE_1_Beta1 */
+#define TAS2563_TE_DT_REG TASDEVICE_REG(0x00, 0x0f, 0x70)
+
+#define TAS2781_PRM_R0_REG TASDEVICE_REG(0x00, 0x17, 0x74)
+#define TAS2781_PRM_R0_LOW_REG TASDEVICE_REG(0x00, 0x18, 0x0c)
+#define TAS2781_PRM_INVR0_REG TASDEVICE_REG(0x00, 0x18, 0x14)
+#define TAS2781_PRM_POW_REG TASDEVICE_REG(0x00, 0x13, 0x70)
+#define TAS2781_PRM_TLIMIT_REG TASDEVICE_REG(0x00, 0x18, 0x7c)
+
+#define TAS2781_PRM_INT_MASK_REG TASDEVICE_REG(0x00, 0x00, 0x3b)
+#define TAS2781_PRM_CLK_CFG_REG TASDEVICE_REG(0x00, 0x00, 0x5c)
+#define TAS2781_PRM_RSVD_REG TASDEVICE_REG(0x00, 0x01, 0x19)
+#define TAS2781_PRM_TEST_57_REG TASDEVICE_REG(0x00, 0xfd, 0x39)
+#define TAS2781_PRM_TEST_62_REG TASDEVICE_REG(0x00, 0xfd, 0x3e)
+#define TAS2781_PRM_PVDD_UVLO_REG TASDEVICE_REG(0x00, 0x00, 0x71)
+#define TAS2781_PRM_CHNL_0_REG TASDEVICE_REG(0x00, 0x00, 0x03)
+#define TAS2781_PRM_NG_CFG0_REG TASDEVICE_REG(0x00, 0x00, 0x35)
+#define TAS2781_PRM_IDLE_CH_DET_REG TASDEVICE_REG(0x00, 0x00, 0x66)
+#define TAS2781_PRM_PLT_FLAG_REG TASDEVICE_REG(0x00, 0x14, 0x38)
+#define TAS2781_PRM_SINEGAIN_REG TASDEVICE_REG(0x00, 0x14, 0x40)
+#define TAS2781_PRM_SINEGAIN2_REG TASDEVICE_REG(0x00, 0x14, 0x44)
+
+#define TAS2781_TEST_UNLOCK_REG TASDEVICE_REG(0x00, 0xFD, 0x0D)
+#define TAS2781_TEST_PAGE_UNLOCK 0x0D
+
+#define TAS2781_RUNTIME_LATCH_RE_REG TASDEVICE_REG(0x00, 0x00, 0x49)
+#define TAS2781_RUNTIME_RE_REG_TF TASDEVICE_REG(0x64, 0x62, 0x48)
+#define TAS2781_RUNTIME_RE_REG TASDEVICE_REG(0x64, 0x63, 0x44)
enum audio_device {
TAS2563,
@@ -69,7 +128,15 @@ enum device_catlog_id {
OTHERS
};
+struct bulk_reg_val {
+ int reg;
+ unsigned char val[4];
+ unsigned char val_len;
+ bool is_locked;
+};
+
struct tasdevice {
+ struct bulk_reg_val *cali_data_restore;
struct tasdevice_fw *cali_data_fmw;
unsigned int dev_addr;
unsigned int err_code;
@@ -88,6 +155,8 @@ struct tasdevice_irqinfo {
struct calidata {
unsigned char *data;
unsigned long total_sz;
+ unsigned int *reg_array;
+ unsigned int reg_array_sz;
};
struct tasdevice_priv {
@@ -122,6 +191,7 @@ struct tasdevice_priv {
bool force_fwload_status;
bool playback_started;
bool isacpi;
+ bool is_user_space_calidata;
unsigned int global_addr;
int (*fw_parse_variable_header)(struct tasdevice_priv *tas_priv,
@@ -148,6 +218,8 @@ int tasdevice_init(struct tasdevice_priv *tas_priv);
void tasdevice_remove(struct tasdevice_priv *tas_priv);
int tasdevice_save_calibration(struct tasdevice_priv *tas_priv);
void tasdevice_apply_calibration(struct tasdevice_priv *tas_priv);
+int tasdevice_chn_switch(struct tasdevice_priv *tas_priv,
+ unsigned short chn);
int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int *value);
int tasdevice_dev_write(struct tasdevice_priv *tas_priv,
diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c
index 3aa81514dad7..9d7b56663b6b 100644
--- a/sound/soc/codecs/tas2781-comlib.c
+++ b/sound/soc/codecs/tas2781-comlib.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
//
-// tas2781-lib.c -- TAS2781 Common functions for HDA and ASoC Audio drivers
+// tas2781-comlib.c -- TAS2781 Common functions for HDA and ASoC Audio drivers
//
-// Copyright 2023 Texas Instruments, Inc.
+// Copyright 2023 - 2024 Texas Instruments, Inc.
//
// Author: Shenghao Ding <shenghao-ding(a)ti.com>
@@ -89,6 +89,33 @@ static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv,
return ret;
}
+int tasdevice_chn_switch(struct tasdevice_priv *tas_priv,
+ unsigned short chn)
+{
+ struct i2c_client *client = (struct i2c_client *)tas_priv->client;
+ struct tasdevice *tasdev = &tas_priv->tasdevice[chn];
+ struct regmap *map = tas_priv->regmap;
+ int ret;
+
+ if (client->addr != tasdev->dev_addr) {
+ client->addr = tasdev->dev_addr;
+ /* All devices share the same regmap, clear the page
+ * inside regmap once switching to another device.
+ * Register 0 at any pages and any books inside tas2781
+ * is the same one for page-switching.
+ */
+ ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s, E=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tasdevice_chn_switch);
+
int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int *val)
{
@@ -254,8 +281,8 @@ void tas2781_reset(struct tasdevice_priv *tas_dev)
} else {
for (i = 0; i < tas_dev->ndev; i++) {
ret = tasdevice_dev_write(tas_dev, i,
- TAS2781_REG_SWRESET,
- TAS2781_REG_SWRESET_RESET);
+ TASDEVICE_REG_SWRESET,
+ TASDEVICE_REG_SWRESET_RESET);
if (ret < 0)
dev_err(tas_dev->dev,
"dev %d swreset fail, %d\n",
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index 265a8ca25cbb..19a5133083dc 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -2153,20 +2153,39 @@ static int tasdevice_load_data(struct tasdevice_priv *tas_priv,
static void tasdev_load_calibrated_data(struct tasdevice_priv *priv, int i)
{
+ struct tasdevice_fw *cal_fmw = priv->tasdevice[i].cali_data_fmw;
+ struct calidata *cali_data = &priv->cali_data;
+ unsigned char *data = cali_data->data;
struct tasdevice_calibration *cal;
- struct tasdevice_fw *cal_fmw;
+ int k = i * (CAL_DAT_SZ + 1);
+ int j, rc;
- cal_fmw = priv->tasdevice[i].cali_data_fmw;
+ if (!priv->is_user_space_calidata &&
+ cal_fmw) {
+ cal = cal_fmw->calibrations;
- /* No calibrated data for current devices, playback will go ahead. */
- if (!cal_fmw)
+ if (cal)
+ load_calib_data(priv, &cal->dev_data);
return;
-
- cal = cal_fmw->calibrations;
- if (cal)
+ }
+ if (!priv->is_user_space_calidata)
return;
-
- load_calib_data(priv, &cal->dev_data);
+ /* load calibrated data from user space */
+ if (data[k] != i) {
+ dev_err(priv->dev, "%s: no cal-data for dev %d from usr-spc\n",
+ __func__, i);
+ return;
+ }
+ for (j = 0; j < cali_data->reg_array_sz; j++) {
+ if (data[k] != j)
+ rc = tasdevice_dev_bulk_write(priv, i,
+ cali_data->reg_array[j],
+ &(data[k + 4 * j]), 4);
+ if (rc < 0)
+ dev_err(priv->dev,
+ "chn %d calib %d bulk_wr err = %d\n",
+ i, j, rc);
+ }
}
int tasdevice_select_tuningprm_cfg(void *context, int prm_no,
@@ -2261,9 +2280,10 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no,
tas_priv->tasdevice[i].cur_conf = cfg_no;
}
}
- } else
+ } else {
dev_dbg(tas_priv->dev, "%s: Unneeded loading dsp conf %d\n",
__func__, cfg_no);
+ }
status |= cfg_info[rca_conf_no]->active_dev;
@@ -2324,13 +2344,15 @@ void tasdevice_tuning_switch(void *context, int state)
struct tasdevice_fw *tas_fmw = tas_priv->fmw;
int profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
- if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) {
- dev_err(tas_priv->dev, "DSP bin file not loaded\n");
+ /* Only RCA file loaded still can work without speaker protection */
+ if (!(tas_priv->fw_state == TASDEVICE_RCA_FW_OK ||
+ tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK)) {
+ dev_err(tas_priv->dev, "No firmware loaded\n");
return;
}
if (state == 0) {
- if (tas_priv->cur_prog < tas_fmw->nr_programs) {
+ if (tas_fmw && tas_priv->cur_prog < tas_fmw->nr_programs) {
/*dsp mode or tuning mode*/
profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
tasdevice_select_tuningprm_cfg(tas_priv,
@@ -2340,9 +2362,10 @@ void tasdevice_tuning_switch(void *context, int state)
tasdevice_select_cfg_blk(tas_priv, profile_cfg_id,
TASDEVICE_BIN_BLK_PRE_POWER_UP);
- } else
+ } else {
tasdevice_select_cfg_blk(tas_priv, profile_cfg_id,
TASDEVICE_BIN_BLK_PRE_SHUTDOWN);
+ }
}
EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch,
SND_SOC_TAS2781_FMWLIB);
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 9350972dfefe..239f3538c558 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -13,6 +13,7 @@
// Author: Kevin Lu <kevin-lu(a)ti.com>
//
+#include <asm/unaligned.h>
#include <linux/crc8.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
@@ -31,6 +32,122 @@
#include <sound/tlv.h>
#include <sound/tas2781-tlv.h>
+static const struct bulk_reg_val tas2563_cali_start_reg[] = {
+ {
+ .reg = TAS2563_PRM_ENFF_REG,
+ .val = { 0x40, 0x00, 0x00, 0x00 },
+ },
+ {
+ .reg = TAS2563_PRM_DISTCK_REG,
+ .val = { 0x40, 0x00, 0x00, 0x00 },
+ },
+ {
+ .reg = TAS2563_PRM_TE_SCTHR_REG,
+ .val = { 0x7f, 0xff, 0xff, 0xff },
+ },
+ {
+ .reg = TAS2563_PRM_PLT_FLAG_REG,
+ .val = { 0x40, 0x00, 0x00, 0x00 },
+ },
+ {
+ .reg = TAS2563_PRM_SINEGAIN_REG,
+ .val = { 0x0a, 0x3d, 0x70, 0xa4 },
+ },
+ {
+ .reg = TAS2563_TE_TA1_REG,
+ .val = { 0x00, 0x36, 0x91, 0x5e },
+ },
+ {
+ .reg = TAS2563_TE_TA1_AT_REG,
+ .val = { 0x00, 0x36, 0x91, 0x5e },
+ },
+ {
+ .reg = TAS2563_TE_TA2_REG,
+ .val = { 0x00, 0x06, 0xd3, 0x72 },
+ },
+ {
+ .reg = TAS2563_TE_AT_REG,
+ .val = { 0x00, 0x36, 0x91, 0x5e },
+ },
+ {
+ .reg = TAS2563_TE_DT_REG,
+ .val = { 0x00, 0x36, 0x91, 0x5e },
+ },
+};
+
+static const struct bulk_reg_val tas2781_cali_start_reg[] = {
+ {
+ .reg = TAS2781_PRM_INT_MASK_REG,
+ .val = { 0xfe },
+ .val_len = 1,
+ .is_locked = false
+ },
+ {
+ .reg = TAS2781_PRM_CLK_CFG_REG,
+ .val = { 0xdd },
+ .val_len = 1,
+ .is_locked = false
+ },
+ {
+ .reg = TAS2781_PRM_RSVD_REG,
+ .val = { 0x20 },
+ .val_len = 1,
+ .is_locked = false
+ },
+ {
+ .reg = TAS2781_PRM_TEST_57_REG,
+ .val = { 0x14 },
+ .val_len = 1,
+ .is_locked = true
+ },
+ {
+ .reg = TAS2781_PRM_TEST_62_REG,
+ .val = { 0x45 },
+ .val_len = 1,
+ .is_locked = true
+ },
+ {
+ .reg = TAS2781_PRM_PVDD_UVLO_REG,
+ .val = { 0x03 },
+ .val_len = 1,
+ .is_locked = false
+ },
+ {
+ .reg = TAS2781_PRM_CHNL_0_REG,
+ .val = { 0xA8 },
+ .val_len = 1,
+ .is_locked = false
+ },
+ {
+ .reg = TAS2781_PRM_NG_CFG0_REG,
+ .val = { 0xb9 },
+ .val_len = 1,
+ .is_locked = false
+ },
+ {
+ .reg = TAS2781_PRM_IDLE_CH_DET_REG,
+ .val = { 0x92 },
+ .val_len = 1,
+ .is_locked = false
+ },
+ {
+ .reg = TAS2781_PRM_PLT_FLAG_REG,
+ .val = { 0x40, 0x00, 0x00, 0x00 },
+ .val_len = 4,
+ .is_locked = false
+ },
+ {
+ .reg = TAS2781_PRM_SINEGAIN_REG,
+ .val_len = 4,
+ .is_locked = false
+ },
+ {
+ .reg = TAS2781_PRM_SINEGAIN2_REG,
+ .val_len = 4,
+ .is_locked = false
+ },
+};
+
static const struct i2c_device_id tasdevice_id[] = {
{ "tas2563", TAS2563 },
{ "tas2781", TAS2781 },
@@ -47,6 +164,22 @@ static const struct of_device_id tasdevice_of_match[] = {
MODULE_DEVICE_TABLE(of, tasdevice_of_match);
#endif
+static const int tas2563_cali_data_reg[] = {
+ TAS2563_PRM_R0_REG,
+ TAS2563_PRM_R0_LOW_REG,
+ TAS2563_PRM_INVR0_REG,
+ TAS2563_PRM_POW_REG,
+ TAS2563_PRM_TLIMIT_REG,
+};
+
+static const int tas2781_cali_data_reg[] = {
+ TAS2781_PRM_R0_REG,
+ TAS2781_PRM_R0_LOW_REG,
+ TAS2781_PRM_INVR0_REG,
+ TAS2781_PRM_POW_REG,
+ TAS2781_PRM_TLIMIT_REG,
+};
+
/**
* tas2781_digital_getvol - get the volum control
* @kcontrol: control pointer
@@ -65,8 +198,13 @@ static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol,
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
+ int rc;
+
+ mutex_lock(&tas_priv->codec_lock);
+ rc = tasdevice_digital_getvol(tas_priv, ucontrol, mc);
+ mutex_unlock(&tas_priv->codec_lock);
- return tasdevice_digital_getvol(tas_priv, ucontrol, mc);
+ return rc;
}
static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol,
@@ -76,8 +214,13 @@ static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol,
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
+ int rc;
+
+ mutex_lock(&tas_priv->codec_lock);
+ rc = tasdevice_digital_putvol(tas_priv, ucontrol, mc);
+ mutex_unlock(&tas_priv->codec_lock);
- return tasdevice_digital_putvol(tas_priv, ucontrol, mc);
+ return rc;
}
static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
@@ -87,8 +230,13 @@ static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
+ int rc;
+
+ mutex_lock(&tas_priv->codec_lock);
+ rc = tasdevice_amp_getvol(tas_priv, ucontrol, mc);
+ mutex_unlock(&tas_priv->codec_lock);
- return tasdevice_amp_getvol(tas_priv, ucontrol, mc);
+ return rc;
}
static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
@@ -99,11 +247,16 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
snd_soc_component_get_drvdata(codec);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
+ int rc;
+
+ mutex_lock(&tas_priv->codec_lock);
+ rc = tasdevice_amp_putvol(tas_priv, ucontrol, mc);
+ mutex_unlock(&tas_priv->codec_lock);
- return tasdevice_amp_putvol(tas_priv, ucontrol, mc);
+ return rc;
}
-static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
+static int tasdev_force_fwload_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
@@ -118,7 +271,7 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
+static int tasdev_force_fwload_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
@@ -127,18 +280,496 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
snd_soc_component_get_drvdata(component);
bool change, val = (bool)ucontrol->value.integer.value[0];
+ mutex_lock(&tas_priv->codec_lock);
if (tas_priv->force_fwload_status == val)
change = false;
else {
change = true;
tas_priv->force_fwload_status = val;
}
+ mutex_unlock(&tas_priv->codec_lock);
dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
tas_priv->force_fwload_status ? "ON" : "OFF");
return change;
}
+static int tasdev_cali_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ unsigned char *data = tas_priv->cali_data.data;
+
+ mutex_lock(&tas_priv->codec_lock);
+ if (!tas_priv->is_user_space_calidata ||
+ tas_priv->cali_data.total_sz != bytes_ext->max) {
+ goto out;
+ }
+ memcpy(dst, data, bytes_ext->max);
+out:
+ mutex_unlock(&tas_priv->codec_lock);
+ return 0;
+}
+
+static int calib_data_get(struct tasdevice_priv *tas_priv, int reg,
+ unsigned char *dst, int data_len)
+{
+ struct i2c_client *clt = (struct i2c_client *)tas_priv->client;
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ int rc = -1;
+ int i;
+
+ if (data_len != 4)
+ return rc;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (clt->addr == tasdev[i].dev_addr) {
+ /* First byte is the device index. */
+ dst[0] = i;
+ tasdevice_dev_bulk_read(tas_priv, i, reg, &dst[1],
+ 4);
+ rc = 0;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static int tas2781_calib_start_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
+ unsigned char *dat = ucontrol->value.bytes.data;
+ int rc = 1;
+ int i, j;
+
+ mutex_lock(&tas_priv->codec_lock);
+ if (tas_priv->chip_id != TAS2781 &&
+ bytes_ext->max != 8 * tas_priv->ndev) {
+ rc = -1;
+ goto out;
+ }
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ struct bulk_reg_val *p = tasdev[i].cali_data_restore;
+ int k = i * 9;
+
+ if (p == NULL)
+ continue;
+
+ for (j = 0; j < sum; j++) {
+ if (p[j].val_len == 1) {
+ if (p[j].is_locked)
+ tasdevice_dev_write(tas_priv, i,
+ TAS2781_TEST_UNLOCK_REG,
+ TAS2781_TEST_PAGE_UNLOCK);
+ tasdevice_dev_read(tas_priv, i, p[j].reg,
+ (int *)&p[j].val[0]);
+ } else
+ tasdevice_dev_bulk_read(tas_priv, i, p[j].reg,
+ p[j].val, 4);
+ }
+
+ for (j = 0; j < sum - 2; j++) {
+ if (p[j].val_len == 1) {
+ if (p[j].is_locked)
+ tasdevice_dev_write(tas_priv, i,
+ TAS2781_TEST_UNLOCK_REG,
+ TAS2781_TEST_PAGE_UNLOCK);
+ tasdevice_dev_write(tas_priv, i, p[j].reg,
+ tas2781_cali_start_reg[j].val[0]);
+ } else
+ tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
+ (unsigned char *)
+ tas2781_cali_start_reg[j].val, 4);
+ }
+
+ if (dat[k] != i) {
+ dev_err(tas_priv->dev,
+ "%s: no cal-setting for dev %d\n", __func__,
+ i);
+ continue;
+ }
+ tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
+ &dat[i * 9 + 1], 4);
+ tasdevice_dev_bulk_write(tas_priv, i, p[j + 1].reg,
+ &dat[i * 9 + 5], 4);
+ }
+out:
+ mutex_unlock(&tas_priv->codec_lock);
+ return rc;
+}
+
+static void tas2781_calib_stop_put(struct tasdevice_priv *tas_priv)
+{
+ const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
+ int i, j;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ struct bulk_reg_val *p = tasdev[i].cali_data_restore;
+
+ if (p == NULL)
+ continue;
+
+ for (j = 0; j < sum; j++) {
+ if (p[j].val_len == 1) {
+ if (p[j].is_locked)
+ tasdevice_dev_write(tas_priv, i,
+ TAS2781_TEST_UNLOCK_REG,
+ TAS2781_TEST_PAGE_UNLOCK);
+ tasdevice_dev_write(tas_priv, i, p[j].reg,
+ p[j].val[0]);
+ } else
+ tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
+ p[j].val, 4);
+ }
+ }
+}
+
+static int tas2563_calib_start_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ const int sum = ARRAY_SIZE(tas2563_cali_start_reg);
+ int rc = 1;
+ int i, j;
+
+ mutex_lock(&tas_priv->codec_lock);
+ if (tas_priv->chip_id != TAS2563) {
+ rc = -1;
+ goto out;
+ }
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ struct bulk_reg_val *p = tasdev[i].cali_data_restore;
+
+ if (p == NULL)
+ continue;
+ for (j = 0; j < sum; j++) {
+ tasdevice_dev_bulk_read(tas_priv, i, p[j].reg,
+ p[j].val, 4);
+ }
+
+ for (j = 0; j < sum; j++) {
+ tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
+ (unsigned char *)tas2563_cali_start_reg[j].val,
+ 4);
+ }
+ }
+out:
+ mutex_unlock(&tas_priv->codec_lock);
+ return rc;
+}
+
+static void tas2563_calib_stop_put(struct tasdevice_priv *tas_priv)
+{
+ const int sum = ARRAY_SIZE(tas2563_cali_start_reg);
+ int i, j;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ struct bulk_reg_val *p = tasdev[i].cali_data_restore;
+
+ if (p == NULL)
+ continue;
+
+ for (j = 0; j < sum; j++) {
+ tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
+ p[j].val, 4);
+ }
+ }
+}
+
+static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+
+ mutex_lock(&tas_priv->codec_lock);
+ if (tas_priv->chip_id == TAS2563)
+ tas2563_calib_stop_put(tas_priv);
+ else
+ tas2781_calib_stop_put(tas_priv);
+ mutex_unlock(&tas_priv->codec_lock);
+
+ return 1;
+}
+
+static int tasdev_cali_data_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *data = tas_priv->cali_data.data;
+ int rc = 1;
+
+ mutex_lock(&tas_priv->codec_lock);
+ if (tas_priv->cali_data.total_sz != bytes_ext->max) {
+ rc = -1;
+ goto out;
+ }
+ tas_priv->is_user_space_calidata = true;
+ memcpy(data, ucontrol->value.bytes.data, bytes_ext->max);
+out:
+ mutex_unlock(&tas_priv->codec_lock);
+ return rc;
+}
+
+static int tas2781_latch_reg_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct i2c_client *clt = (struct i2c_client *)tas_priv->client;
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ int i, val, rc = -1;
+
+ mutex_lock(&tas_priv->codec_lock);
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (clt->addr == tasdev[i].dev_addr) {
+ /* First byte is the device index. */
+ dst[0] = i;
+ tasdevice_dev_read(tas_priv, i,
+ TAS2781_RUNTIME_LATCH_RE_REG, &val);
+ dst[1] = val;
+ rc = 0;
+ break;
+ }
+ }
+ mutex_unlock(&tas_priv->codec_lock);
+ return rc;
+}
+
+static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ unsigned int reg;
+ int rc = -1;
+
+ if (tas_priv->chip_id == TAS2781)
+ reg = TAS2781_RUNTIME_RE_REG_TF;
+ else
+ reg = TAS2563_RUNTIME_RE_REG_TF;
+
+ mutex_lock(&tas_priv->codec_lock);
+ rc = calib_data_get(tas_priv, reg, dst, bytes_ext->max - 1);
+ mutex_unlock(&tas_priv->codec_lock);
+
+ return rc;
+}
+
+static int tasdev_re_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ unsigned int reg;
+ int rc = -1;
+
+ if (tas_priv->chip_id == TAS2781)
+ reg = TAS2781_RUNTIME_RE_REG;
+ else
+ reg = TAS2563_RUNTIME_RE_REG;
+ mutex_lock(&tas_priv->codec_lock);
+ rc = calib_data_get(tas_priv, reg, dst, bytes_ext->max - 1);
+ mutex_unlock(&tas_priv->codec_lock);
+
+ return rc;
+}
+
+static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ unsigned int reg;
+ int rc = -1;
+
+ if (tas_priv->chip_id == TAS2781)
+ reg = TAS2781_PRM_R0_REG;
+ else
+ reg = TAS2563_PRM_R0_REG;
+ mutex_lock(&tas_priv->codec_lock);
+ rc = calib_data_get(tas_priv, reg, dst, bytes_ext->max - 1);
+ mutex_unlock(&tas_priv->codec_lock);
+
+ return rc;
+}
+
+static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ unsigned int reg = TASDEVICE_XM_A1_REG;
+ int rc = -1;
+
+ mutex_lock(&tas_priv->codec_lock);
+ rc = calib_data_get(tas_priv, reg, dst, bytes_ext->max - 1);
+ mutex_unlock(&tas_priv->codec_lock);
+
+ return rc;
+}
+
+static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ unsigned int reg = TASDEVICE_XM_A2_REG;
+ int rc = -1;
+
+ mutex_lock(&tas_priv->codec_lock);
+ rc = calib_data_get(tas_priv, reg, dst, bytes_ext->max - 1);
+ mutex_unlock(&tas_priv->codec_lock);
+
+ return rc;
+}
+
+static int tasdev_nop_get(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return 0;
+}
+
+static int tas2563_digital_gain_get(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
+ unsigned int l = 0, r = mc->max;
+ unsigned int target, ar_mid, mid, ar_l, ar_r;
+ unsigned int reg = mc->reg;
+ unsigned char data[4];
+ int ret;
+
+ mutex_lock(&tas_dev->codec_lock);
+ /* Read the primary device */
+ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
+ if (ret) {
+ dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
+ goto out;
+ }
+
+ target = get_unaligned_be32(&data[0]);
+
+ while (r > 1 + l) {
+ mid = (l + r) / 2;
+ ar_mid = get_unaligned_be32(tas2563_dvc_table[mid]);
+ if (target < ar_mid)
+ r = mid;
+ else
+ l = mid;
+ }
+
+ ar_l = get_unaligned_be32(tas2563_dvc_table[l]);
+ ar_r = get_unaligned_be32(tas2563_dvc_table[r]);
+
+ ucontrol->value.integer.value[0] =
+ abs(target - ar_l) <= abs(target - ar_r) ? l : r;
+out:
+ mutex_unlock(&tas_dev->codec_lock);
+ return 0;
+}
+
+static int tas2563_digital_gain_put(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
+ unsigned int reg = mc->reg;
+ unsigned int volrd, volwr;
+ int vol = ucontrol->value.integer.value[0];
+ int max = mc->max, i, ret = 1;
+ unsigned char data[4];
+
+ vol = clamp(vol, 0, max);
+ mutex_lock(&tas_dev->codec_lock);
+ /* Read the primary device */
+ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
+ if (ret) {
+ dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
+ goto out;
+ }
+
+ volrd = get_unaligned_be32(&data[0]);
+ volwr = get_unaligned_be32(tas2563_dvc_table[vol]);
+
+ if (volrd == volwr) {
+ ret = 0;
+ goto out;
+ }
+
+ for (i = 0; i < tas_dev->ndev; i++) {
+ ret = tasdevice_dev_bulk_write(tas_dev, i, reg,
+ (unsigned char *)tas2563_dvc_table[vol], 4);
+ if (ret)
+ dev_err(tas_dev->dev,
+ "%s, set digital vol error in device %d\n",
+ __func__, i);
+ }
+
+out:
+ mutex_unlock(&tas_dev->codec_lock);
+ return ret;
+}
+
+static const struct snd_kcontrol_new tasdevice_snd_controls[] = {
+ SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
+ tasdev_force_fwload_get, tasdev_force_fwload_put),
+};
+
+static const struct snd_kcontrol_new tasdevice_cali_controls[] = {
+ SOC_SINGLE_EXT("Calibration Stop", SND_SOC_NOPM, 0, 1, 0,
+ tasdev_nop_get, tasdev_calib_stop_put),
+ SND_SOC_BYTES_EXT("Amp TF Data", 5, tasdev_tf_data_get, NULL),
+ SND_SOC_BYTES_EXT("Amp RE Data", 5, tasdev_re_data_get, NULL),
+ SND_SOC_BYTES_EXT("Amp R0 Data", 5, tasdev_r0_data_get, NULL),
+ SND_SOC_BYTES_EXT("Amp XMA1 Data", 5, tasdev_XMA1_data_get, NULL),
+ SND_SOC_BYTES_EXT("Amp XMA2 Data", 5, tasdev_XMA2_data_get, NULL),
+};
+
static const struct snd_kcontrol_new tas2781_snd_controls[] = {
SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL,
1, 0, 20, 0, tas2781_amp_getvol,
@@ -146,8 +777,22 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = {
SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL,
0, 0, 200, 1, tas2781_digital_getvol,
tas2781_digital_putvol, dvc_tlv),
- SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
- tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
+static const struct snd_kcontrol_new tas2781_cali_controls[] = {
+ SND_SOC_BYTES_EXT("Amp Latch Data", 2, tas2781_latch_reg_get, NULL),
+};
+
+static const struct snd_kcontrol_new tas2563_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2563_DVC_LVL, 0,
+ 0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0,
+ tas2563_digital_gain_get, tas2563_digital_gain_put,
+ tas2563_dvc_tlv),
+};
+
+static const struct snd_kcontrol_new tas2563_cali_controls[] = {
+ SOC_SINGLE_EXT("Calibration Start", SND_SOC_NOPM, 0, 1, 0,
+ tasdev_nop_get, tas2563_calib_start_put),
};
static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
@@ -167,6 +812,31 @@ static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
return ret;
}
+static int tasdevice_info_active_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = (int)tas_priv->ndev - 1;
+
+ return 0;
+}
+
+static int tasdevice_info_chip_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = TAS2563;
+ uinfo->value.integer.max = TAS2781;
+
+ return 0;
+}
+
static int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -223,6 +893,17 @@ static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
return 0;
}
+static int tasdevice_get_chip_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = tas_priv->chip_id;
+
+ return 0;
+}
+
static int tasdevice_create_control(struct tasdevice_priv *tas_priv)
{
struct snd_kcontrol_new *prof_ctrls;
@@ -316,15 +997,54 @@ static int tasdevice_configuration_put(
return ret;
}
-static int tasdevice_dsp_create_ctrls(
- struct tasdevice_priv *tas_priv)
+static int tasdevice_active_id_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct i2c_client *clt = (struct i2c_client *)tas_priv->client;
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ int i;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (clt->addr == tasdev[i].dev_addr) {
+ ucontrol->value.integer.value[0] = i;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int tasdevice_active_id_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int nr_dev = ucontrol->value.integer.value[0];
+ int max = tas_priv->ndev - 1, rc;
+
+ nr_dev = clamp(nr_dev, 0, max);
+
+ mutex_lock(&tas_priv->codec_lock);
+ rc = tasdevice_chn_switch(tas_priv, nr_dev);
+ mutex_unlock(&tas_priv->codec_lock);
+
+ return rc;
+}
+
+static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
{
+ char *active_dev_name, *cali_name, *chip_id, *conf_name, *prog_name;
+ struct calidata *cali_data = &tas_priv->cali_data;
struct snd_kcontrol_new *dsp_ctrls;
- char *prog_name, *conf_name;
- int nr_controls = 2;
+ struct soc_bytes_ext *ext_cali_data;
+ int nr_controls = 5;
int mix_index = 0;
int ret;
+ if (tas_priv->chip_id == TAS2781)
+ nr_controls++;
/* Alloc kcontrol via devm_kzalloc, which don't manually
* free the kcontrol
*/
@@ -336,11 +1056,20 @@ static int tasdevice_dsp_create_ctrls(
}
/* Create a mixer item for selecting the active profile */
- prog_name = devm_kzalloc(tas_priv->dev,
+ active_dev_name = devm_kzalloc(tas_priv->dev,
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN, GFP_KERNEL);
+ cali_name = devm_kzalloc(tas_priv->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ GFP_KERNEL);
+ chip_id = devm_kzalloc(tas_priv->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ GFP_KERNEL);
+ conf_name = devm_kzalloc(tas_priv->dev,
SNDRV_CTL_ELEM_ID_NAME_MAXLEN, GFP_KERNEL);
- conf_name = devm_kzalloc(tas_priv->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ prog_name = devm_kzalloc(tas_priv->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
GFP_KERNEL);
- if (!prog_name || !conf_name) {
+ ext_cali_data = devm_kzalloc(tas_priv->dev, sizeof(*ext_cali_data),
+ GFP_KERNEL);
+ if (!active_dev_name || !cali_name || !conf_name || !chip_id ||
+ !ext_cali_data || !prog_name) {
ret = -ENOMEM;
goto out;
}
@@ -363,6 +1092,68 @@ static int tasdevice_dsp_create_ctrls(
dsp_ctrls[mix_index].put = tasdevice_configuration_put;
mix_index++;
+ scnprintf(active_dev_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "Activate Tasdevice Id");
+ dsp_ctrls[mix_index].name = active_dev_name;
+ dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ dsp_ctrls[mix_index].info = tasdevice_info_active_id;
+ dsp_ctrls[mix_index].get = tasdevice_active_id_get;
+ dsp_ctrls[mix_index].put = tasdevice_active_id_put;
+ mix_index++;
+
+ scnprintf(chip_id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "Tasdevice Chip Id");
+ dsp_ctrls[mix_index].name = chip_id;
+ dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ dsp_ctrls[mix_index].info = tasdevice_info_chip_id;
+ dsp_ctrls[mix_index].get = tasdevice_get_chip_id;
+ mix_index++;
+
+ scnprintf(cali_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "Speaker Calibrated Data");
+ ext_cali_data->max = tas_priv->ndev * CAL_DAT_SZ;
+ tas_priv->cali_data.total_sz = ext_cali_data->max;
+ tas_priv->cali_data.data = devm_kzalloc(tas_priv->dev,
+ ext_cali_data->max, GFP_KERNEL);
+ dsp_ctrls[mix_index].name = cali_name;
+ dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ dsp_ctrls[mix_index].info = snd_soc_bytes_info_ext;
+ dsp_ctrls[mix_index].get = tasdev_cali_data_get;
+ dsp_ctrls[mix_index].put = tasdev_cali_data_put;
+ dsp_ctrls[mix_index].private_value = (unsigned long)ext_cali_data;
+ mix_index++;
+
+ cali_data->data = devm_kzalloc(tas_priv->dev, tas_priv->ndev *
+ (cali_data->reg_array_sz * 4 + 1), GFP_KERNEL);
+ if (!cali_data->data)
+ return -ENOMEM;
+
+ if (tas_priv->chip_id == TAS2781) {
+ struct soc_bytes_ext *ext_cali_start;
+ char *cali_start_name;
+
+ cali_start_name = devm_kzalloc(tas_priv->dev,
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN, GFP_KERNEL);
+ ext_cali_start = devm_kzalloc(tas_priv->dev,
+ sizeof(*ext_cali_start), GFP_KERNEL);
+ if (!cali_start_name || !ext_cali_start) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ scnprintf(cali_start_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "Calibration Start");
+ ext_cali_data->max = tas_priv->ndev * 9;
+ dsp_ctrls[mix_index].name = cali_start_name;
+ dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ dsp_ctrls[mix_index].info = snd_soc_bytes_info_ext;
+ dsp_ctrls[mix_index].put = tas2781_calib_start_put;
+ dsp_ctrls[mix_index].get = tasdev_nop_get;
+ dsp_ctrls[mix_index].private_value =
+ (unsigned long)ext_cali_start;
+ mix_index++;
+ }
+
ret = snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls,
nr_controls < mix_index ? nr_controls : mix_index);
@@ -370,6 +1161,54 @@ static int tasdevice_dsp_create_ctrls(
return ret;
}
+static int tasdevice_create_cali_ctrls(struct tasdevice_priv *tas_priv)
+{
+ struct calidata *cali_data = &tas_priv->cali_data;
+ struct snd_kcontrol_new *cali_ctrls;
+ unsigned int num_controls;
+ int rc;
+
+ rc = snd_soc_add_component_controls(tas_priv->codec,
+ tasdevice_cali_controls, ARRAY_SIZE(tasdevice_cali_controls));
+ if (rc < 0) {
+ dev_err(tas_priv->dev, "%s: Add cali control err rc = %d",
+ __func__, rc);
+ return rc;
+ }
+
+ if (tas_priv->chip_id == TAS2781) {
+ cali_ctrls = (struct snd_kcontrol_new *)tas2781_cali_controls;
+ num_controls = ARRAY_SIZE(tas2781_cali_controls);
+ cali_data->reg_array = (unsigned int *)tas2781_cali_data_reg;
+ cali_data->reg_array_sz = ARRAY_SIZE(tas2781_cali_data_reg);
+ } else {
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ int i;
+
+ cali_ctrls = (struct snd_kcontrol_new *)tas2563_cali_controls;
+ num_controls = ARRAY_SIZE(tas2563_cali_controls);
+ cali_data->reg_array = (unsigned int *)tas2563_cali_data_reg;
+ cali_data->reg_array_sz = sizeof(tas2563_cali_data_reg);
+ for (i = 0; i < tas_priv->ndev; i++) {
+ tasdev[i].cali_data_restore =
+ kmemdup(tas2563_cali_start_reg,
+ sizeof(tas2563_cali_start_reg), GFP_KERNEL);
+ if (!tasdev[i].cali_data_restore)
+ return -ENOMEM;
+ }
+ }
+
+ rc = snd_soc_add_component_controls(tas_priv->codec, cali_ctrls,
+ num_controls);
+ if (rc < 0) {
+ dev_err(tas_priv->dev, "%s: Add control err rc = %d",
+ __func__, rc);
+ return rc;
+ }
+
+ return rc;
+}
+
static void tasdevice_fw_ready(const struct firmware *fmw,
void *context)
{
@@ -380,23 +1219,36 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
mutex_lock(&tas_priv->codec_lock);
ret = tasdevice_rca_parser(tas_priv, fmw);
- if (ret)
+ if (ret) {
+ tasdevice_config_info_remove(tas_priv);
goto out;
+ }
tasdevice_create_control(tas_priv);
tasdevice_dsp_remove(tas_priv);
tasdevice_calbin_remove(tas_priv);
- tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+ tas_priv->fw_state = TASDEVICE_RCA_FW_OK;
scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin",
tas_priv->dev_name);
+
ret = tasdevice_dsp_parser(tas_priv);
if (ret) {
dev_err(tas_priv->dev, "dspfw load %s error\n",
tas_priv->coef_binaryname);
- tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
goto out;
}
- tasdevice_dsp_create_ctrls(tas_priv);
+
+ ret = tasdevice_dsp_create_ctrls(tas_priv);
+ if (ret) {
+ dev_err(tas_priv->dev, "dsp controls error\n");
+ goto out;
+ }
+
+ ret = tasdevice_create_cali_ctrls(tas_priv);
+ if (ret) {
+ dev_err(tas_priv->dev, "cali controls error\n");
+ goto out;
+ }
tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
@@ -417,9 +1269,8 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
tasdevice_prmg_load(tas_priv, 0);
tas_priv->cur_prog = 0;
out:
- if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) {
- /*If DSP FW fail, kcontrol won't be created */
- tasdevice_config_info_remove(tas_priv);
+ if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) {
+ /*If DSP FW fail, DSP kcontrol won't be created */
tasdevice_dsp_remove(tas_priv);
}
mutex_unlock(&tas_priv->codec_lock);
@@ -466,14 +1317,14 @@ static int tasdevice_startup(struct snd_pcm_substream *substream,
{
struct snd_soc_component *codec = dai->component;
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
- int ret = 0;
- if (tas_priv->fw_state != TASDEVICE_DSP_FW_ALL_OK) {
- dev_err(tas_priv->dev, "DSP bin file not loaded\n");
- ret = -EINVAL;
+ if (!(tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK ||
+ tas_priv->fw_state == TASDEVICE_RCA_FW_OK)) {
+ dev_err(tas_priv->dev, "Bin file not loaded\n");
+ return -EINVAL;
}
- return ret;
+ return 0;
}
static int tasdevice_hw_params(struct snd_pcm_substream *substream,
@@ -541,7 +1392,7 @@ static const struct snd_soc_dai_ops tasdevice_dai_ops = {
static struct snd_soc_dai_driver tasdevice_dai_driver[] = {
{
- .name = "tas2781_codec",
+ .name = "tasdev_codec",
.id = 0,
.playback = {
.stream_name = "Playback",
@@ -565,13 +1416,41 @@ static struct snd_soc_dai_driver tasdevice_dai_driver[] = {
static int tasdevice_codec_probe(struct snd_soc_component *codec)
{
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int rc;
+
+ if (tas_priv->chip_id == TAS2781) {
+ rc = snd_soc_add_component_controls(codec,
+ tas2781_snd_controls,
+ ARRAY_SIZE(tas2781_snd_controls));
+ if (rc < 0) {
+ dev_err(tas_priv->dev, "%s: Add control err rc = %d",
+ __func__, rc);
+ return rc;
+ }
+ } else {
+ rc = snd_soc_add_component_controls(codec,
+ tas2563_snd_controls,
+ ARRAY_SIZE(tas2563_snd_controls));
+ if (rc < 0) {
+ dev_err(tas_priv->dev, "%s: Add control err rc = %d",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ rc = tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready);
- return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready);
+ return rc;
}
static void tasdevice_deinit(void *context)
{
struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ int i;
+
+ for (i = 0; i < tas_priv->ndev; i++)
+ kfree(tasdev[i].cali_data_restore);
tasdevice_config_info_remove(tas_priv);
tasdevice_dsp_remove(tas_priv);
@@ -591,8 +1470,8 @@ static const struct snd_soc_component_driver
soc_codec_driver_tasdevice = {
.probe = tasdevice_codec_probe,
.remove = tasdevice_codec_remove,
- .controls = tas2781_snd_controls,
- .num_controls = ARRAY_SIZE(tas2781_snd_controls),
+ .controls = tasdevice_snd_controls,
+ .num_controls = ARRAY_SIZE(tasdevice_snd_controls),
.dapm_widgets = tasdevice_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tasdevice_dapm_widgets),
.dapm_routes = tasdevice_audio_map,
--
2.34.1
5
6
08 Aug '24
Add initial support for the PantherLake platform, and initial ACPI
configurations.
This patchset depends on the first patch of "[PATCH 0/3] ALSA/PCI: add
PantherLake audio support"
Bard Liao (2):
ASoC: Intel: soc-acpi-intel-ptl-match: add rt711-sdca table
ASoC: Intel: soc-acpi-intel-ptl-match: Add rt722 support
Fred Oh (1):
ASoC: SOF: Intel: add PTL specific power control register
Pierre-Louis Bossart (2):
ASoC: SOF: Intel: add initial support for PTL
ASoC: Intel: soc-acpi: add PTL match tables
include/sound/soc-acpi-intel-match.h | 2 +
sound/soc/intel/common/Makefile | 1 +
.../intel/common/soc-acpi-intel-ptl-match.c | 121 ++++++++++++++++++
sound/soc/sof/intel/Kconfig | 17 +++
sound/soc/sof/intel/Makefile | 2 +
sound/soc/sof/intel/hda-dsp.c | 1 +
sound/soc/sof/intel/hda.h | 1 +
sound/soc/sof/intel/lnl.c | 27 ++++
sound/soc/sof/intel/mtl.c | 16 ++-
sound/soc/sof/intel/mtl.h | 2 +
sound/soc/sof/intel/pci-ptl.c | 77 +++++++++++
sound/soc/sof/intel/shim.h | 1 +
12 files changed, 266 insertions(+), 2 deletions(-)
create mode 100644 sound/soc/intel/common/soc-acpi-intel-ptl-match.c
create mode 100644 sound/soc/sof/intel/pci-ptl.c
--
2.43.0
2
9