#include "rt5677-spi.h"
+#define DRV_NAME "rt5677spi"
+
#define RT5677_SPI_BURST_LEN 240
#define RT5677_SPI_HEADER 5
#define RT5677_SPI_FREQ 6000000
* RT5677_SPI_READ/WRITE_32: Transfer 4 bytes
* RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes
*
- * For example, reading 260 bytes at 0x60030002 uses the following commands:
- * 0x60030002 RT5677_SPI_READ_16 2 bytes
+ * Note:
+ * 16 Bit writes and reads are restricted to the address range
+ * 0x18020000 ~ 0x18021000
+ *
+ * For example, reading 256 bytes at 0x60030004 uses the following commands:
* 0x60030004 RT5677_SPI_READ_32 4 bytes
* 0x60030008 RT5677_SPI_READ_BURST 240 bytes
* 0x600300F8 RT5677_SPI_READ_BURST 8 bytes
* 0x60030100 RT5677_SPI_READ_32 4 bytes
- * 0x60030104 RT5677_SPI_READ_16 2 bytes
*
* Input:
* @read: true for read commands; false for write commands
{
u8 cmd;
- if (align == 2 || align == 6 || remain == 2) {
- cmd = RT5677_SPI_READ_16;
- *len = 2;
- } else if (align == 4 || remain <= 6) {
+ if (align == 4 || remain <= 4) {
cmd = RT5677_SPI_READ_32;
*len = 4;
} else {
cmd = RT5677_SPI_READ_BURST;
- *len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN);
+ *len = (((remain - 1) >> 3) + 1) << 3;
+ *len = min_t(u32, *len, RT5677_SPI_BURST_LEN);
}
return read ? cmd : cmd + 1;
}
}
}
- /* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */
+ /* Read DSP address space using SPI. addr and len have to be 4-byte aligned. */
int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
{
u32 offset;
if (!g_spi)
return -ENODEV;
- if ((addr & 1) || (len & 1)) {
+ if ((addr & 3) || (len & 3)) {
dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len);
return -EACCES;
}
}
EXPORT_SYMBOL_GPL(rt5677_spi_read);
- /* Write DSP address space using SPI. addr has to be 2-byte aligned.
- * If len is not 2-byte aligned, an extra byte of zero is written at the end
+ /* Write DSP address space using SPI. addr has to be 4-byte aligned.
+ * If len is not 4-byte aligned, then extra zeros are written at the end
* as padding.
*/
int rt5677_spi_write(u32 addr, const void *txbuf, size_t len)
{
- u32 offset, len_with_pad = len;
+ u32 offset;
int status = 0;
struct spi_transfer t;
struct spi_message m;
if (!g_spi)
return -ENODEV;
- if (addr & 1) {
+ if (addr & 3) {
dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len);
return -EACCES;
}
- if (len & 1)
- len_with_pad = len + 1;
-
memset(&t, 0, sizeof(t));
t.tx_buf = buf;
t.speed_hz = RT5677_SPI_FREQ;
spi_message_init_with_transfers(&m, &t, 1);
- for (offset = 0; offset < len_with_pad;) {
+ for (offset = 0; offset < len;) {
spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7,
- len_with_pad - offset, &t.len);
+ len - offset, &t.len);
/* Construct SPI message header */
buf[0] = spi_cmd;
static struct spi_driver rt5677_spi_driver = {
.driver = {
- .name = "rt5677",
+ .name = DRV_NAME,
.acpi_match_table = ACPI_PTR(rt5677_spi_acpi_id),
},
.probe = rt5677_spi_probe,
select SND_SOC_SOF_CANNONLAKE if SND_SOC_SOF_CANNONLAKE_SUPPORT
select SND_SOC_SOF_COFFEELAKE if SND_SOC_SOF_COFFEELAKE_SUPPORT
select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT
+ select SND_SOC_SOF_COMETLAKE_LP if SND_SOC_SOF_COMETLAKE_LP_SUPPORT
+ select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT
help
This option is not user-selectable but automagically handled by
'select' statements at a higher level
config SND_SOC_SOF_INTEL_ATOM_HIFI_EP
tristate
- select SND_SOC_INTEL_COMMON
+ select SND_SOC_SOF_INTEL_COMMON
select SND_SOC_SOF_INTEL_HIFI_EP_IPC
help
This option is not user-selectable but automagically handled by
This option is not user-selectable but automagically handled by
'select' statements at a higher level
+config SND_SOC_SOF_COMETLAKE_LP
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
+ help
+ This option is not user-selectable but automagically handled by
+ 'select' statements at a higher level
+
+config SND_SOC_SOF_COMETLAKE_LP_SUPPORT
+ bool "SOF support for CometLake-LP"
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the Cometlake-LP processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_SOF_COMETLAKE_H
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
+ help
+ This option is not user-selectable but automagically handled by
+ 'select' statements at a higher level
+
+config SND_SOC_SOF_COMETLAKE_H_SUPPORT
+ bool "SOF support for CometLake-H"
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the Cometlake-H processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
config SND_SOC_SOF_HDA_COMMON
tristate
select SND_SOC_SOF_INTEL_COMMON
* details.
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/module.h>
#define STM32_I2S_TXDR_REG 0X20
#define STM32_I2S_RXDR_REG 0x30
#define STM32_I2S_CGFR_REG 0X50
+#define STM32_I2S_HWCFGR_REG 0x3F0
+#define STM32_I2S_VERR_REG 0x3F4
+#define STM32_I2S_IPIDR_REG 0x3F8
+#define STM32_I2S_SIDR_REG 0x3FC
/* Bit definition for SPI2S_CR1 register */
#define I2S_CR1_SPE BIT(0)
#define I2S_CGFR_ODD BIT(I2S_CGFR_ODD_SHIFT)
#define I2S_CGFR_MCKOE BIT(25)
+/* Registers below apply to I2S version 1.1 and more */
+
+/* Bit definition for SPI_HWCFGR register */
+#define I2S_HWCFGR_I2S_SUPPORT_MASK GENMASK(15, 12)
+
+/* Bit definition for SPI_VERR register */
+#define I2S_VERR_MIN_MASK GENMASK(3, 0)
+#define I2S_VERR_MAJ_MASK GENMASK(7, 4)
+
+/* Bit definition for SPI_IPIDR register */
+#define I2S_IPIDR_ID_MASK GENMASK(31, 0)
+
+/* Bit definition for SPI_SIDR register */
+#define I2S_SIDR_ID_MASK GENMASK(31, 0)
+
+#define I2S_IPIDR_NUMBER 0x00130022
+
enum i2s_master_mode {
I2S_MS_NOT_SET,
I2S_MS_MASTER,
case STM32_I2S_SR_REG:
case STM32_I2S_RXDR_REG:
case STM32_I2S_CGFR_REG:
+ case STM32_I2S_HWCFGR_REG:
+ case STM32_I2S_VERR_REG:
+ case STM32_I2S_IPIDR_REG:
+ case STM32_I2S_SIDR_REG:
return true;
default:
return false;
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .max_register = STM32_I2S_CGFR_REG,
+ .max_register = STM32_I2S_SIDR_REG,
.readable_reg = stm32_i2s_readable_reg,
.volatile_reg = stm32_i2s_volatile_reg,
.writeable_reg = stm32_i2s_writeable_reg,
+ .num_reg_defaults_raw = STM32_I2S_SIDR_REG / sizeof(u32) + 1,
.fast_io = true,
.cache_type = REGCACHE_FLAT,
};
static const struct snd_pcm_hardware stm32_i2s_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
.buffer_bytes_max = 8 * PAGE_SIZE,
- .period_bytes_max = 2048,
+ .period_bytes_min = 1024,
+ .period_bytes_max = 4 * PAGE_SIZE,
.periods_min = 2,
.periods_max = 8,
};
static int stm32_i2s_probe(struct platform_device *pdev)
{
struct stm32_i2s_data *i2s;
+ u32 val;
int ret;
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
return ret;
/* Set SPI/I2S in i2s mode */
- return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
- I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD);
+ ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+ I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(i2s->regmap, STM32_I2S_IPIDR_REG, &val);
+ if (ret)
+ return ret;
+
+ if (val == I2S_IPIDR_NUMBER) {
+ ret = regmap_read(i2s->regmap, STM32_I2S_HWCFGR_REG, &val);
+ if (ret)
+ return ret;
+
+ if (!FIELD_GET(I2S_HWCFGR_I2S_SUPPORT_MASK, val)) {
+ dev_err(&pdev->dev,
+ "Device does not support i2s mode\n");
+ return -EPERM;
+ }
+
+ ret = regmap_read(i2s->regmap, STM32_I2S_VERR_REG, &val);
+
+ dev_dbg(&pdev->dev, "I2S version: %lu.%lu registered\n",
+ FIELD_GET(I2S_VERR_MAJ_MASK, val),
+ FIELD_GET(I2S_VERR_MIN_MASK, val));
+ }
+
+ return ret;
}
MODULE_DEVICE_TABLE(of, stm32_i2s_ids);
* details.
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
#define STM32_SPDIFRX_DR 0x10
#define STM32_SPDIFRX_CSR 0x14
#define STM32_SPDIFRX_DIR 0x18
+#define STM32_SPDIFRX_VERR 0x3F4
+#define STM32_SPDIFRX_IDR 0x3F8
+#define STM32_SPDIFRX_SIDR 0x3FC
/* Bit definition for SPDIF_CR register */
#define SPDIFRX_CR_SPDIFEN_SHIFT 0
#define SPDIFRX_SPDIFEN_SYNC 0x1
#define SPDIFRX_SPDIFEN_ENABLE 0x3
+/* Bit definition for SPDIFRX_VERR register */
+#define SPDIFRX_VERR_MIN_MASK GENMASK(3, 0)
+#define SPDIFRX_VERR_MAJ_MASK GENMASK(7, 4)
+
+/* Bit definition for SPDIFRX_IDR register */
+#define SPDIFRX_IDR_ID_MASK GENMASK(31, 0)
+
+/* Bit definition for SPDIFRX_SIDR register */
+#define SPDIFRX_SIDR_SID_MASK GENMASK(31, 0)
+
+#define SPDIFRX_IPIDR_NUMBER 0x00130041
+
#define SPDIFRX_IN1 0x1
#define SPDIFRX_IN2 0x2
#define SPDIFRX_IN3 0x3
if (wait_for_completion_interruptible_timeout(&spdifrx->cs_completion,
msecs_to_jiffies(100))
<= 0) {
- dev_err(&spdifrx->pdev->dev, "Failed to get control data\n");
+ dev_dbg(&spdifrx->pdev->dev, "Failed to get control data\n");
ret = -EAGAIN;
}
case STM32_SPDIFRX_DR:
case STM32_SPDIFRX_CSR:
case STM32_SPDIFRX_DIR:
+ case STM32_SPDIFRX_VERR:
+ case STM32_SPDIFRX_IDR:
+ case STM32_SPDIFRX_SIDR:
return true;
default:
return false;
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .max_register = STM32_SPDIFRX_DIR,
+ .max_register = STM32_SPDIFRX_SIDR,
.readable_reg = stm32_spdifrx_readable_reg,
.volatile_reg = stm32_spdifrx_volatile_reg,
.writeable_reg = stm32_spdifrx_writeable_reg,
+ .num_reg_defaults_raw = STM32_SPDIFRX_SIDR / sizeof(u32) + 1,
.fast_io = true,
.cache_type = REGCACHE_FLAT,
};
static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
.buffer_bytes_max = 8 * PAGE_SIZE,
- .period_bytes_max = 2048, /* MDMA constraint */
+ .period_bytes_min = 1024,
+ .period_bytes_max = 4 * PAGE_SIZE,
.periods_min = 2,
.periods_max = 8,
};
struct stm32_spdifrx_data *spdifrx;
struct reset_control *rst;
const struct snd_dmaengine_pcm_config *pcm_config = NULL;
+ u32 ver, idr;
int ret;
spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL);
goto error;
}
- return 0;
+ ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_IDR, &idr);
+ if (ret)
+ goto error;
+
+ if (idr == SPDIFRX_IPIDR_NUMBER) {
+ ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_VERR, &ver);
+
+ dev_dbg(&pdev->dev, "SPDIFRX version: %lu.%lu registered\n",
+ FIELD_GET(SPDIFRX_VERR_MAJ_MASK, ver),
+ FIELD_GET(SPDIFRX_VERR_MIN_MASK, ver));
+ }
+
+ return ret;
error:
if (!IS_ERR(spdifrx->ctrl_chan))