Unverified Commit 2884c291 authored by Paul Handrigan's avatar Paul Handrigan Committed by Mark Brown
Browse files

ASoC: cs530x: Support for cs530x ADCs



Add support for the cs530x family of high performance
ADCs.

Signed-off-by: default avatarPaul Handrigan <paulha@opensource.cirrus.com>
Link: https://patch.msgid.link/20240621151757.1661265-3-paulha@opensource.cirrus.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 0e2407ae
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ config SND_SOC_ALL_CODECS
	imply SND_SOC_CS47L90
	imply SND_SOC_CS47L92
	imply SND_SOC_CS53L30
	imply SND_SOC_CS530X_I2C
	imply SND_SOC_CX20442
	imply SND_SOC_CX2072X
	imply SND_SOC_DA7210
@@ -1000,6 +1001,19 @@ config SND_SOC_CS53L30
	tristate "Cirrus Logic CS53L30 CODEC"
	depends on I2C

config SND_SOC_CS530X
	tristate

config SND_SOC_CS530X_I2C
	tristate "Cirrus Logic CS530x ADCs (I2C)"
	depends on I2C
	select REGMAP
	select REGMAP_I2C
	select SND_SOC_CS530X
	help
	  Enable support for Cirrus Logic CS530X ADCs
	  with I2C control.

config SND_SOC_CX20442
	tristate
	depends on TTY
+4 −0
Original line number Diff line number Diff line
@@ -107,6 +107,8 @@ snd-soc-cs47l85-y := cs47l85.o
snd-soc-cs47l90-y := cs47l90.o
snd-soc-cs47l92-y := cs47l92.o
snd-soc-cs53l30-y := cs53l30.o
snd-soc-cs530x-y := cs530x.o
snd-soc-cs530x-i2c-y := cs530x-i2c.o
snd-soc-cx20442-y := cx20442.o
snd-soc-cx2072x-y := cx2072x.o
snd-soc-da7210-y := da7210.o
@@ -509,6 +511,8 @@ obj-$(CONFIG_SND_SOC_CS47L85) += snd-soc-cs47l85.o
obj-$(CONFIG_SND_SOC_CS47L90)	+= snd-soc-cs47l90.o
obj-$(CONFIG_SND_SOC_CS47L92)	+= snd-soc-cs47l92.o
obj-$(CONFIG_SND_SOC_CS53L30)	+= snd-soc-cs53l30.o
obj-$(CONFIG_SND_SOC_CS530X)	+= snd-soc-cs530x.o
obj-$(CONFIG_SND_SOC_CS530X_I2C)	+= snd-soc-cs530x-i2c.o
obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_CX2072X)	+= snd-soc-cx2072x.o
obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
+72 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
//
// CS530x CODEC driver
//
// Copyright (C) 2024 Cirrus Logic, Inc. and
//                    Cirrus Logic International Semiconductor Ltd.

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

#include "cs530x.h"

static const struct of_device_id cs530x_of_match[] = {
	{
		.compatible = "cirrus,cs5302",
		.data = (void *)CS5302,
	}, {
		.compatible = "cirrus,cs5304",
		.data = (void *)CS5304,
	}, {
		.compatible = "cirrus,cs5308",
		.data = (void *)CS5308,
	},
	{}
};
MODULE_DEVICE_TABLE(of, cs530x_of_match);

static const struct i2c_device_id cs530x_i2c_id[] = {
	{ "cs5302", CS5302 },
	{ "cs5304", CS5304 },
	{ "cs5308", CS5308 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, cs530x_i2c_id);

static int cs530x_i2c_probe(struct i2c_client *client)
{
	struct cs530x_priv *cs530x;

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

	i2c_set_clientdata(client, cs530x);

	cs530x->regmap = devm_regmap_init_i2c(client, &cs530x_regmap);
	if (IS_ERR(cs530x->regmap))
		return dev_err_probe(&client->dev, PTR_ERR(cs530x->regmap),
			      "Failed to allocate register map\n");

	cs530x->devtype = (uintptr_t)i2c_get_match_data(client);
	cs530x->dev = &client->dev;

	return cs530x_probe(cs530x);
}

static struct i2c_driver cs530x_i2c_driver = {
	.driver = {
		.name = "cs530x",
		.of_match_table = cs530x_of_match,
	},
	.probe = cs530x_i2c_probe,
	.id_table = cs530x_i2c_id,
};
module_i2c_driver(cs530x_i2c_driver);

MODULE_DESCRIPTION("I2C CS530X driver");
MODULE_IMPORT_NS(SND_SOC_CS530X);
MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paulha@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
+966 −0

File added.

Preview size limit exceeded, changes collapsed.

+223 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * CS530x CODEC driver internal data
 *
 * Copyright (C) 2023-2024 Cirrus Logic, Inc. and
 *                         Cirrus Logic International Semiconductor Ltd.
 */

#ifndef _CS530X_H
#define _CS530X_H

#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>

/* Devices */
#define CS530X_2CH_ADC_DEV_ID		 0x5302
#define CS530X_4CH_ADC_DEV_ID		 0x5304
#define CS530X_8CH_ADC_DEV_ID		 0x5308

/* Registers */

#define CS530X_DEVID			0x0000000
#define CS530X_REVID			0x0000004
#define CS530X_SW_RESET			0x0000022

#define CS530X_CLK_CFG_0		0x0000040
#define CS530X_CLK_CFG_1		0x0000042
#define CS530X_CHIP_ENABLE		0x0000044
#define CS530X_ASP_CFG			0x0000048
#define CS530X_SIGNAL_PATH_CFG		0x0000050
#define CS530X_IN_ENABLES		0x0000080
#define CS530X_IN_RAMP_SUM		0x0000082
#define CS530X_IN_FILTER		0x0000086
#define CS530X_IN_HIZ			0x0000088
#define CS530X_IN_INV			0x000008A
#define CS530X_IN_VOL_CTRL1_0	        0x0000090
#define CS530X_IN_VOL_CTRL1_1	        0x0000092
#define CS530X_IN_VOL_CTRL2_0	        0x0000094
#define CS530X_IN_VOL_CTRL2_1	        0x0000096
#define CS530X_IN_VOL_CTRL3_0	        0x0000098
#define CS530X_IN_VOL_CTRL3_1	        0x000009A
#define CS530X_IN_VOL_CTRL4_0	        0x000009C
#define CS530X_IN_VOL_CTRL4_1	        0x000009E
#define CS530X_IN_VOL_CTRL5		0x00000A0

#define CS530X_PAD_FN			0x0003D24
#define CS530X_PAD_LVL			0x0003D28

#define CS530X_MAX_REGISTER		CS530X_PAD_LVL

/* Register Fields */

/* REVID */
#define CS530X_MTLREVID			GENMASK(3, 0)
#define CS530X_AREVID			GENMASK(7, 4)

/* SW_RESET */
#define CS530X_SW_RST_SHIFT		8
#define CS530X_SW_RST_VAL		(0x5A << CS530X_SW_RST_SHIFT)

/* CLK_CFG_0 */
#define CS530X_PLL_REFCLK_SRC_MASK	BIT(0)
#define CS530X_PLL_REFCLK_FREQ_MASK	GENMASK(5, 4)
#define CS530X_SYSCLK_SRC_MASK		BIT(12)
#define CS530X_SYSCLK_SRC_SHIFT		12
#define CS530X_REFCLK_2P822_3P072	0
#define CS530X_REFCLK_5P6448_6P144	0x10
#define CS530X_REFCLK_11P2896_12P288	0x20
#define CS530X_REFCLK_24P5792_24P576	0x30

/* CLK_CFG_1 */
#define CS530X_SAMPLE_RATE_MASK		GENMASK(2, 0)
#define CS530X_FS_32K			0
#define CS530X_FS_48K_44P1K		1
#define CS530X_FS_96K_88P2K		2
#define CS530X_FS_192K_176P4K		3
#define CS530X_FS_384K_356P8K		4
#define CS530X_FS_768K_705P6K		5

/* CHIP_ENABLE */
#define CS530X_GLOBAL_EN		BIT(0)

/* ASP_CFG */
#define CS530X_ASP_BCLK_FREQ_MASK	GENMASK(1, 0)
#define CS530X_ASP_PRIMARY		BIT(5)
#define CS530X_ASP_BCLK_INV		BIT(6)
#define CS530X_BCLK_2P822_3P072		0
#define CS530X_BCLK_5P6448_6P144	1
#define CS530X_BCLK_11P2896_12P288	2
#define CS530X_BCLK_24P5792_24P576	3

/* SIGNAL_PATH_CFG */
#define CS530X_ASP_FMT_MASK		GENMASK(2, 0)
#define CS530X_ASP_TDM_SLOT_MASK	GENMASK(5, 3)
#define CS530X_ASP_TDM_SLOT_SHIFT	3
#define CS530X_ASP_CH_REVERSE		BIT(9)
#define CS530X_ASP_FMT_I2S		0
#define CS530X_ASP_FMT_LJ		1
#define CS530X_ASP_FMT_DSP_A		0x6

/* TDM Slots */
#define CS530X_0_1_TDM_SLOT_MASK	GENMASK(1, 0)
#define CS530X_0_3_TDM_SLOT_MASK	GENMASK(3, 0)
#define CS530X_0_7_TDM_SLOT_MASK	GENMASK(7, 0)
#define CS530X_0_7_TDM_SLOT_VAL		0

#define CS530X_2_3_TDM_SLOT_MASK	GENMASK(3, 2)
#define CS530X_2_3_TDM_SLOT_VAL		1

#define CS530X_4_5_TDM_SLOT_MASK	GENMASK(5, 4)
#define CS530X_4_7_TDM_SLOT_MASK	GENMASK(7, 4)
#define CS530X_4_7_TDM_SLOT_VAL		2

#define CS530X_6_7_TDM_SLOT_MASK	GENMASK(7, 6)
#define CS530X_6_7_TDM_SLOT_VAL		3

#define CS530X_8_9_TDM_SLOT_MASK	GENMASK(9, 8)
#define CS530X_8_11_TDM_SLOT_MASK	GENMASK(11, 8)
#define CS530X_8_15_TDM_SLOT_MASK	GENMASK(15, 8)
#define CS530X_8_15_TDM_SLOT_VAL	4

#define CS530X_10_11_TDM_SLOT_MASK	GENMASK(11, 10)
#define CS530X_10_11_TDM_SLOT_VAL	5

#define CS530X_12_13_TDM_SLOT_MASK	GENMASK(13, 12)
#define CS530X_12_15_TDM_SLOT_MASK	GENMASK(15, 12)
#define CS530X_12_15_TDM_SLOT_VAL	6

#define CS530X_14_15_TDM_SLOT_MASK	GENMASK(15, 14)
#define CS530X_14_15_TDM_SLOT_VAL	7

/* IN_RAMP_SUM */
#define CS530X_RAMP_RATE_INC_SHIFT	0
#define CS530X_RAMP_RATE_DEC_SHIFT	4
#define CS530X_IN_SUM_MODE_SHIFT	13

/* IN_FILTER */
#define CS530X_IN_FILTER_SHIFT		8
#define CS530X_IN_HPF_EN_SHIFT		12

/* IN_HIZ */
#define CS530X_IN12_HIZ			BIT(0)
#define CS530X_IN34_HIZ			BIT(1)
#define CS530X_IN56_HIZ			BIT(2)
#define CS530X_IN78_HIZ			BIT(3)

/* IN_INV */
#define CS530X_IN1_INV_SHIFT		0
#define CS530X_IN2_INV_SHIFT		1
#define CS530X_IN3_INV_SHIFT		2
#define CS530X_IN4_INV_SHIFT		3
#define CS530X_IN5_INV_SHIFT		4
#define CS530X_IN6_INV_SHIFT		5
#define CS530X_IN7_INV_SHIFT		6
#define CS530X_IN8_INV_SHIFT		7

/* IN_VOL_CTLy_z */
#define CS530X_IN_MUTE			BIT(15)

/* IN_VOL_CTL5 */
#define CS530X_IN_VU			BIT(0)

/* PAD_FN */
#define CS530X_DOUT2_FN			BIT(0)
#define CS530X_DOUT3_FN			BIT(1)
#define CS530X_DOUT4_FN			BIT(2)
#define CS530X_SPI_CS_FN		BIT(3)
#define CS530X_CONFIG2_FN		BIT(6)
#define CS530X_CONFIG3_FN		BIT(7)
#define CS530X_CONFIG4_FN		BIT(8)
#define CS530X_CONFIG5_FN		BIT(9)

/* PAD_LVL */
#define CS530X_CONFIG2_LVL		BIT(6)
#define CS530X_CONFIG3_LVL		BIT(7)
#define CS530X_CONFIG4_LVL		BIT(8)
#define CS530X_CONFIG5_LVL		BIT(9)

/* System Clock Source */
#define CS530X_SYSCLK_SRC_MCLK		0
#define CS530X_SYSCLK_SRC_PLL		1

/* PLL Reference Clock Source */
#define CS530X_PLL_SRC_BCLK		0
#define CS530X_PLL_SRC_MCLK		1

#define CS530X_NUM_SUPPLIES		2

enum cs530x_type {
	CS5302,
	CS5304,
	CS5308,
};

/* codec private data */
struct cs530x_priv {
	struct regmap *regmap;
	struct device *dev;
	struct snd_soc_dai_driver *dev_dai;

	enum cs530x_type devtype;
	int num_adcs;
	int num_dacs;

	struct regulator_bulk_data supplies[CS530X_NUM_SUPPLIES];

	unsigned int mclk_rate;

	int tdm_width;
	int tdm_slots;
	int bclk;
	int fs;
	int adc_pairs_count;

	struct gpio_desc *reset_gpio;
};

extern const struct regmap_config cs530x_regmap;
int cs530x_probe(struct cs530x_priv *cs530x);

#endif