// SPDX-License-Identifier: GPL-2.0
//
// TAS2781 HDA SPI driver
//
// Copyright 2024 - 2026 Texas Instruments, Inc.
//
// Author: Baojun Xu <baojun.xu@ti.com>
#include <linux/acpi.h>
#include <linux/array_size.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/crc8.h>
#include <linux/crc32.h>
#include <linux/efi.h>
#include <linux/firmware.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/time.h>
#include <linux/types.h>
#include <linux/units.h>
#include <sound/hda_codec.h>
#include <sound/soc.h>
#include <sound/tas2781.h>
#include <sound/tlv.h>
#include <sound/tas2781-tlv.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_component.h"
#include "hda_jack.h"
#include "../generic.h"
#include "tas2781_hda.h"
#define TASDEVICE_RANGE_MAX_SIZE (256 * 128)
#define TASDEVICE_WIN_LEN 128
#define TAS2781_SPI_MAX_FREQ (4 * HZ_PER_MHZ)
/* System Reset Check Register */
#define TAS2781_REG_CLK_CONFIG TASDEVICE_REG(0x0, 0x0, 0x5c)
#define TAS2781_REG_CLK_CONFIG_RESET 0x19
struct tas2781_hda_spi_priv {
struct snd_kcontrol *snd_ctls[3];
};
static const struct regmap_range_cfg tasdevice_ranges[] = {
{
.range_min = 0,
.range_max = TASDEVICE_RANGE_MAX_SIZE,
.selector_reg = TASDEVICE_PAGE_SELECT,
.selector_mask = GENMASK(7, 0),
.selector_shift = 0,
.window_start = 0,
.window_len = TASDEVICE_WIN_LEN,
},
};
static const struct regmap_config tasdevice_regmap = {
.reg_bits = 8,
.val_bits = 8,
.zero_flag_mask = true,
.read_flag_mask = 0x01,
.reg_shift = -1,
.cache_type = REGCACHE_NONE,
.ranges = tasdevice_ranges,
.num_ranges = ARRAY_SIZE(tasdevice_ranges),
.max_register = TASDEVICE_RANGE_MAX_SIZE,
};
static int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int *val)
{
int ret;
/*
* In our TAS2781 SPI mode, if read from other book (not book 0),
* or read from page number larger than 1 in book 0, one more byte
* read is needed, and first byte is a dummy byte, need to be ignored.
*/
if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
unsigned char data[2];
ret = tasdevice_dev_bulk_read(tas_priv, chn, reg,
data, sizeof(data));
*val = data[1];
} else {
ret = tasdevice_dev_read(tas_priv, chn, reg, val);
}
if (ret < 0)
dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
return ret;
}
static int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned char *data,
unsigned int len)
{
int ret;
/*
* In our TAS2781 SPI mode, if read from other book (not book 0),
* or read from page number larger than 1 in book 0, one more byte
* read is needed, and first byte is a dummy byte, need to be ignored.
*/
if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
unsigned char buf[TASDEVICE_WIN_LEN + 1];
ret = tasdevice_dev_bulk_read(tas_priv, chn, reg,
buf, len + 1);
memcpy(data, buf + 1, len);
} else {
ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, data, len);
}
if (ret < 0)
dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
return ret;
}
static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int mask,
unsigned int value)
{
int ret, val;
/*
* In TAS2781 SPI mode, when accessing non-book-zero or page numbers
* greater than 1 in book 0, an additional byte must be read. The
* first byte in such cases is a dummy byte and should be ignored.
*/
if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
unsigned char buf[2];
ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, buf, 2);
val = buf[1];
} else {
ret = tasdevice_dev_read(tas_priv, chn, reg, &val);
}
if (ret < 0) {
dev_err(tas_priv->dev, "%s, E=%d