[alsa-devel] [PATCH v2 2/2] ASoC: Add driver support fro Conexant CX2092X DSP
simon.ho.cnxt at gmail.com
simon.ho.cnxt at gmail.com
Tue Feb 21 02:01:52 CET 2017
From: Simon Ho <simon.ho at conexant.com>
Initial commit of Conexant CX20921/CX20924 I2S Audio DSP driver
Signed-off-by: Simon Ho <simon.ho at conexant.com>
---
sound/soc/codecs/Kconfig | 17 ++
sound/soc/codecs/Makefile | 6 +
sound/soc/codecs/cx2092x-i2c.c | 54 ++++++
sound/soc/codecs/cx2092x-spi.c | 57 ++++++
sound/soc/codecs/cx2092x.c | 411 +++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/cx2092x.h | 26 +++
6 files changed, 571 insertions(+)
create mode 100644 sound/soc/codecs/cx2092x-i2c.c
create mode 100644 sound/soc/codecs/cx2092x-spi.c
create mode 100644 sound/soc/codecs/cx2092x.c
create mode 100644 sound/soc/codecs/cx2092x.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index e49e9da..a98d3c2 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -63,6 +63,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS47L24 if MFD_CS47L24
select SND_SOC_CS53L30 if I2C
select SND_SOC_CX20442 if TTY
+ select SND_SOC_CX2092X_I2C if I2C
+ select SND_SOC_CX2092X_SPI if SPI_MASTER
select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
select SND_SOC_DA7213 if I2C
select SND_SOC_DA7218 if I2C
@@ -491,6 +493,21 @@ config SND_SOC_CX20442
tristate
depends on TTY
+config SND_SOC_CX2092X
+ tristate
+
+config SND_SOC_CX2092X_I2C
+ tristate "Conexant CX20921/CX2094 CODEC (I2C)"
+ depends on I2C
+ select SND_SOC_CX2092X
+ select REGMAP_I2C
+
+config SND_SOC_CX2092X_SPI
+ tristate "Conexant CX20921/CX2094 CODEC (SPI)"
+ depends on SPI_MASTER
+ select SND_SOC_CX2092X
+ select REGMAP_SPI
+
config SND_SOC_JZ4740_CODEC
select REGMAP_MMIO
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 1796cb9..e30a398 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -56,6 +56,9 @@ snd-soc-cs4349-objs := cs4349.o
snd-soc-cs47l24-objs := cs47l24.o
snd-soc-cs53l30-objs := cs53l30.o
snd-soc-cx20442-objs := cx20442.o
+snd-soc-cx2092x-objs := cx2092x.o
+snd-soc-cx2092x-i2c-objs := cx2092x-i2c.o
+snd-soc-cx2092x-spi-objs := cx2092x-spi.o
snd-soc-da7210-objs := da7210.o
snd-soc-da7213-objs := da7213.o
snd-soc-da7218-objs := da7218.o
@@ -286,6 +289,9 @@ obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o
obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o
obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
+obj-$(CONFIG_SND_SOC_CX2092X) += snd-soc-cx2092x.o
+obj-$(CONFIG_SND_SOC_CX2092X_I2C) += snd-soc-cx2092x-i2c.o
+obj-$(CONFIG_SND_SOC_CX2092X_SPI) += snd-soc-cx2092x-spi.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
obj-$(CONFIG_SND_SOC_DA7218) += snd-soc-da7218.o
diff --git a/sound/soc/codecs/cx2092x-i2c.c b/sound/soc/codecs/cx2092x-i2c.c
new file mode 100644
index 0000000..a07800e
--- /dev/null
+++ b/sound/soc/codecs/cx2092x-i2c.c
@@ -0,0 +1,54 @@
+/*
+ * cx2092x-i2c.c -- CX20921 and CX20924 I2C Audio driver
+ *
+ * Copyright: (C) 2017 Conexant Systems, Inc.
+ *
+ * This is based on Alexander Sverdlin's CS4271 driver code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "cx2092x.h"
+
+static int cx2092x_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ return cx2092x_dev_probe(&i2c->dev,
+ devm_regmap_init_i2c(i2c, &cx2092x_regmap_config));
+}
+static int cx2092x_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id cx2092x_i2c_id[] = {
+ {"cx20921", 0},
+ {"cx20924", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cx2092x_i2c_id);
+
+static struct i2c_driver cx2092x_i2c_driver = {
+ .driver = {
+ .name = "cx2092x",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(cx2092x_dt_ids),
+ },
+ .id_table = cx2092x_i2c_id,
+ .probe = cx2092x_i2c_probe,
+ .remove = cx2092x_i2c_remove,
+};
+module_i2c_driver(cx2092x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CX2092X I2C Driver");
+MODULE_AUTHOR("Simon Ho <simon.ho at conexant.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cx2092x-spi.c b/sound/soc/codecs/cx2092x-spi.c
new file mode 100644
index 0000000..3723909
--- /dev/null
+++ b/sound/soc/codecs/cx2092x-spi.c
@@ -0,0 +1,57 @@
+/*
+ * cx2092x-spi.c -- CX20921 and CX20924 SPI Audio driver
+ *
+ * Copyright: (C) 2017 Conexant Systems, Inc.
+ *
+ * This is based on Alexander Sverdlin's CS4271 driver code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "cx2092x.h"
+
+static int cx2092x_spi_probe(struct spi_device *spi)
+{
+ struct regmap_config config;
+
+ config = cx2092x_regmap_config;
+ config.write_flag_mask = 0x81;
+
+ return cx2092x_dev_probe(&spi->dev,
+ devm_regmap_init_spi(spi, &cx2092x_regmap_config));
+}
+
+static int cx2092x_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static const struct spi_device_id cx2092x_spi_id[] = {
+ {"cx20921", 0},
+ {"cx20924", 0},
+ {}
+};
+
+static struct spi_driver cx2092x_spi_driver = {
+ .driver = {
+ .name = "cx2092x",
+ .of_match_table = of_match_ptr(cx2092x_dt_ids),
+ },
+ .id_table = cx2092x_spi_id,
+ .probe = cx2092x_spi_probe,
+ .remove = cx2092x_spi_remove,
+};
+
+module_spi_driver(cx2092x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC CX2092X SPI Driver");
+MODULE_AUTHOR("Simon Ho <simon.ho at conexant.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cx2092x.c b/sound/soc/codecs/cx2092x.c
new file mode 100644
index 0000000..a15e3f9
--- /dev/null
+++ b/sound/soc/codecs/cx2092x.c
@@ -0,0 +1,411 @@
+/*
+ * cx2092x.c -- CX20921 and CX20924 ALSA SoC Audio driver
+ *
+ * Copyright: (C) 2017 Conexant Systems, Inc.
+ *
+ * This is based on Alexander Sverdlin's CS4271 driver code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include "cx2092x.h"
+
+#define CX2092X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define CX2092X_CAPE_ID(a, b, c, d) (((a) - 0x20) << 8 | \
+ ((b) - 0x20) << 14| \
+ ((c) - 0x20) << 20| \
+ ((d) - 0x20) << 26)
+
+#define CX2092X_ID2CH_A(id) (((((unsigned int)(id)) >> 8) & 0x3f) + 0x20)
+#define CX2092X_ID2CH_B(id) (((((unsigned int)(id)) >> 14) & 0x3f) + 0x20)
+#define CX2092X_ID2CH_C(id) (((((unsigned int)(id)) >> 20) & 0x3f) + 0x20)
+#define CX2092X_ID2CH_D(id) (((((unsigned int)(id)) >> 26) & 0x3f) + 0x20)
+
+#define CX2092X_CONTROL(xname, xinfo, xget, xput, xaccess) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = xaccess, .info = xinfo, .get = xget, .put = xput, \
+ }
+
+#define CX2092X_CMD_GET(item) ((item) | 0x0100)
+#define CX2092X_CMD_SIZE 13
+
+/*
+ * Defines the command format which is used to communicate with cx2092x device.
+ */
+struct cx2092x_cmd {
+ int num_32b_words:16; /* Indicates how many data to be sent.
+ * If operation is successful, this will
+ * be updated with the number of returned
+ * data in word. one word == 4 bytes.
+ */
+
+ u32 command_id:15;
+ u32 reply:1; /* The device will set this flag once
+ * the operation is complete.
+ */
+ u32 app_module_id;
+ u32 data[CX2092X_CMD_SIZE]; /* Used for storing parameters and
+ * receiving the returned data from
+ * device.
+ */
+};
+
+/* codec private data*/
+struct cx2092x_priv {
+ struct device *dev;
+ struct regmap *regmap;
+ struct gpio_desc *gpiod_reset;
+ struct cx2092x_cmd cmd;
+ int cmd_res;
+};
+
+/*
+ * This functions takes cx2092x_cmd structure as input and output parameters
+ * to communicate CX2092X. If operation is successfully, it returns number of
+ * returned data and stored the returned data in "cmd->data" array.
+ * Otherwise, it returns the error code.
+ */
+static int cx2092x_sendcmd(struct snd_soc_codec *codec,
+ struct cx2092x_cmd *cmd)
+{
+ struct cx2092x_priv *cx2092x = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+ int num_32b_words = cmd->num_32b_words;
+ unsigned long time_out;
+ u32 *i2c_data = (u32 *)cmd;
+ int size = num_32b_words + 2;
+
+ /* calculate how many WORD that will be wrote to device*/
+ cmd->num_32b_words = cmd->command_id & CX2092X_CMD_GET(0) ?
+ CX2092X_CMD_SIZE : num_32b_words;
+
+
+ /* write all command data except fo frist 4 bytes*/
+ ret = regmap_bulk_write(cx2092x->regmap, 4, &i2c_data[1], size - 1);
+ if (ret < 0) {
+ dev_err(cx2092x->dev, "Failed to write command data\n");
+ goto LEAVE;
+ }
+
+ /* write first 4 bytes command data*/
+ ret = regmap_bulk_write(cx2092x->regmap, 0, i2c_data, 1);
+ if (ret < 0) {
+ dev_err(cx2092x->dev, "Failed to write command\n");
+ goto LEAVE;
+ }
+
+ /* continuously read the first bytes data from device until
+ * either timeout or the flag 'reply' is set.
+ */
+ time_out = msecs_to_jiffies(2000);
+ time_out += jiffies;
+ do {
+ regmap_bulk_read(cx2092x->regmap, 0, &i2c_data[0], 1);
+ if (cmd->reply == 1)
+ break;
+ mdelay(10);
+
+ } while (!time_after(jiffies, time_out));
+
+ if (cmd->reply == 1) {
+ /* check if there is returned data. If yes copy the returned
+ * data to cmd->data array
+ */
+ if (cmd->num_32b_words > 0)
+ regmap_bulk_read(cx2092x->regmap, 8, &i2c_data[2],
+ cmd->num_32b_words);
+ /* return error code if operation is not successful.*/
+ else if (cmd->num_32b_words < 0)
+ dev_err(cx2092x->dev, "SendCmd failed, err = %d\n",
+ cmd->num_32b_words);
+
+ ret = cmd->num_32b_words;
+ } else {
+ dev_err(cx2092x->dev, "SendCmd timeout\n");
+ ret = -EBUSY;
+ }
+
+LEAVE:
+ return ret;
+}
+
+
+static int cmd_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = sizeof(struct cx2092x_cmd);
+
+ return 0;
+}
+
+static int cmd_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cx2092x_priv *cx2092x =
+ snd_soc_component_get_drvdata(component);
+
+ memcpy(ucontrol->value.bytes.data, &cx2092x->cmd,
+ sizeof(cx2092x->cmd));
+
+ return 0;
+}
+
+static int cmd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cx2092x_priv *cx2092x = snd_soc_component_get_drvdata(component);
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+ memcpy(&cx2092x->cmd, ucontrol->value.bytes.data,
+ sizeof(cx2092x->cmd));
+
+ cx2092x->cmd_res = cx2092x_sendcmd(codec, &cx2092x->cmd);
+
+ if (cx2092x->cmd_res < 0)
+ dev_err(codec->dev, "Failed to send cmd, ret = %d\n",
+ cx2092x->cmd_res);
+
+ return cx2092x->cmd_res < 0 ? cx2092x->cmd_res : 0;
+}
+
+
+static int mode_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = 4;
+
+ return 0;
+}
+
+static int mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+ struct cx2092x_cmd cmd;
+ int ret = 0;
+
+ cmd.command_id = 0x12f; /*CX2092X_CMD_GET(SOS_RESOURCE);*/
+ cmd.reply = 0;
+ cmd.app_module_id = CX2092X_CAPE_ID('S', 'O', 'S', ' ');
+ cmd.num_32b_words = 1;
+ cmd.data[0] = CX2092X_CAPE_ID('C', 'T', 'R', 'L');
+
+ ret = cx2092x_sendcmd(codec, &cmd);
+ if (ret <= 0)
+ dev_err(codec->dev, "Failed to get current mode, ret = %d\n",
+ ret);
+ else {
+ ucontrol->value.bytes.data[0] = CX2092X_ID2CH_A(cmd.data[0]);
+ ucontrol->value.bytes.data[1] = CX2092X_ID2CH_B(cmd.data[0]);
+ ucontrol->value.bytes.data[2] = CX2092X_ID2CH_C(cmd.data[0]);
+ ucontrol->value.bytes.data[3] = CX2092X_ID2CH_D(cmd.data[0]);
+
+ dev_dbg(codec->dev, "Current mode = %c%c%c%c\n",
+ ucontrol->value.bytes.data[0],
+ ucontrol->value.bytes.data[1],
+ ucontrol->value.bytes.data[2],
+ ucontrol->value.bytes.data[3]);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+ struct cx2092x_cmd cmd;
+ int ret = -1;
+
+ cmd.command_id = 4;
+ cmd.reply = 0;
+ cmd.app_module_id = CX2092X_CAPE_ID('C', 'T', 'R', 'L');
+ cmd.num_32b_words = 1;
+ cmd.data[0] = CX2092X_CAPE_ID(ucontrol->value.bytes.data[0],
+ ucontrol->value.bytes.data[1],
+ ucontrol->value.bytes.data[2],
+ ucontrol->value.bytes.data[3]);
+
+ ret = cx2092x_sendcmd(codec, &cmd);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set mode, ret =%d\n", ret);
+ } else {
+ dev_dbg(codec->dev, "Set mode successfully, ret = %d\n", ret);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new cx2092x_snd_controls[] = {
+ CX2092X_CONTROL("SendCmd", cmd_info, cmd_get, cmd_put,
+ SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE|
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+ CX2092X_CONTROL("Mode", mode_info, mode_get, mode_put,
+ SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE|
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+};
+
+
+static const struct snd_soc_dapm_widget cx2092x_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_OUT("Mic AIF", "Capture", 0,
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_INPUT("MIC"),
+};
+
+static const struct snd_soc_dapm_route cx2092x_intercon[] = {
+ {"Mic AIF", NULL, "MIC"},
+};
+
+
+static struct snd_soc_dai_driver soc_codec_cx2092x_dai[] = {
+ {
+ .name = "cx2092x-aif",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = CX2092X_FORMATS,
+ },
+ },
+ {
+ .name = "cx2092x-dsp",
+ .capture = {
+ .stream_name = "AEC Ref",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = CX2092X_FORMATS,
+ },
+ },
+};
+
+static int cx2092x_reset(struct snd_soc_codec *codec)
+{
+ struct cx2092x_priv *cx2092x = snd_soc_codec_get_drvdata(codec);
+
+ if (cx2092x->gpiod_reset) {
+ gpiod_set_value_cansleep(cx2092x->gpiod_reset, 0);
+ mdelay(10);
+ gpiod_set_value_cansleep(cx2092x->gpiod_reset, 1);
+ }
+
+ return 0;
+}
+
+const struct of_device_id cx2092x_dt_ids[] = {
+ { .compatible = "cnxt,cx20921", },
+ { .compatible = "cnxt,cx20924", },
+ { }
+};
+EXPORT_SYMBOL_GPL(cx2092x_dt_ids);
+MODULE_DEVICE_TABLE(of, cx2092x_dt_ids);
+
+static int cx2092x_probe(struct snd_soc_codec *codec)
+{
+ return cx2092x_reset(codec);
+}
+
+static int cx2092x_remove(struct snd_soc_codec *codec)
+{
+ struct cx2092x_priv *cx2092x = snd_soc_codec_get_drvdata(codec);
+
+ if (cx2092x->gpiod_reset)
+ /* Set codec to the reset state */
+ gpiod_set_value_cansleep(cx2092x->gpiod_reset, 0);
+
+ return 0;
+}
+
+static const struct snd_soc_codec_driver soc_codec_driver_cx2092x = {
+ .probe = cx2092x_probe,
+ .remove = cx2092x_remove,
+
+ .component_driver = {
+ .controls = cx2092x_snd_controls,
+ .num_controls = ARRAY_SIZE(cx2092x_snd_controls),
+ .dapm_widgets = cx2092x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cx2092x_dapm_widgets),
+ .dapm_routes = cx2092x_intercon,
+ .num_dapm_routes = ARRAY_SIZE(cx2092x_intercon),
+ },
+};
+EXPORT_SYMBOL_GPL(soc_codec_driver_cx2092x);
+
+static bool cx2092x_volatile_register(struct device *dev, unsigned int reg)
+{
+ return true; /*all register are volatile*/
+}
+
+const struct regmap_config cx2092x_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = CX2092X_REG_MAX,
+ .cache_type = REGCACHE_NONE,
+ .volatile_reg = cx2092x_volatile_register,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+};
+EXPORT_SYMBOL_GPL(cx2092x_regmap_config);
+
+int cx2092x_dev_probe(struct device *dev, struct regmap *regmap)
+{
+ struct cx2092x_priv *cx2092x;
+ int ret;
+
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ cx2092x = devm_kzalloc(dev, sizeof(*cx2092x), GFP_KERNEL);
+ if (!cx2092x)
+ return -ENOMEM;
+
+ /* GPIOs */
+ cx2092x->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(cx2092x->gpiod_reset))
+ return PTR_ERR(cx2092x->gpiod_reset);
+
+ dev_set_drvdata(dev, cx2092x);
+ cx2092x->regmap = regmap;
+ cx2092x->dev = dev;
+
+ ret = snd_soc_register_codec(cx2092x->dev, &soc_codec_driver_cx2092x,
+ soc_codec_cx2092x_dai,
+ ARRAY_SIZE(soc_codec_cx2092x_dai));
+ if (ret < 0)
+ dev_err(dev, "Failed to register codec: %d\n", ret);
+ else
+ dev_dbg(dev, "%s: Register codec.\n", __func__);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cx2092x_dev_probe);
+
+MODULE_DESCRIPTION("ASoC CX2092X ALSA SoC Driver");
+MODULE_AUTHOR("Simon Ho <simon.ho at conexant.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cx2092x.h b/sound/soc/codecs/cx2092x.h
new file mode 100644
index 0000000..9577be8
--- /dev/null
+++ b/sound/soc/codecs/cx2092x.h
@@ -0,0 +1,26 @@
+/*
+ * cx2092x.h -- CX20921 and CX20924 Audio driver
+ *
+ * Copyright: (C) 2017 Conexant Systems, Inc.
+ *
+ * This is based on Alexander Sverdlin's CS4271 driver code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CX2092X_PRIV_H__
+#define __CX2092X_PRIV_H__
+
+#include <linux/regmap.h>
+
+extern const struct of_device_id cx2092x_dt_ids[];
+extern const struct regmap_config cx2092x_regmap_config;
+
+int cx2092x_dev_probe(struct device *dev, struct regmap *regmap);
+
+#define CX2092X_REG_MAX 0x2000
+
+#endif
--
2.7.4
More information about the Alsa-devel
mailing list