aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/codecs/cx20442.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/cx20442.c')
-rw-r--r--sound/soc/codecs/cx20442.c246
1 files changed, 100 insertions, 146 deletions
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index e000cdfec1e..d5fd00a6474 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -14,17 +14,20 @@
*/
#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/initval.h>
-#include <sound/soc-dapm.h>
+#include <sound/soc.h>
#include "cx20442.h"
struct cx20442_priv {
- struct snd_soc_codec codec;
- u8 reg_cache[1];
+ void *control_data;
+ struct regulator *por;
};
#define CX20442_PM 0x0
@@ -85,23 +88,12 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = {
{"ADC", NULL, "Input Mixer"},
};
-static int cx20442_add_widgets(struct snd_soc_codec *codec)
-{
- snd_soc_dapm_new_controls(codec, cx20442_dapm_widgets,
- ARRAY_SIZE(cx20442_dapm_widgets));
-
- snd_soc_dapm_add_routes(codec, cx20442_audio_map,
- ARRAY_SIZE(cx20442_audio_map));
-
- return 0;
-}
-
static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u8 *reg_cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EINVAL;
return reg_cache[reg];
@@ -163,16 +155,17 @@ static int cx20442_pm_to_v253_vsp(u8 value)
static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
+ struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
u8 *reg_cache = codec->reg_cache;
int vls, vsp, old, len;
char buf[18];
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EINVAL;
/* hw_write and control_data pointers required for talking to the modem
* are expected to be set by the line discipline initialization code */
- if (!codec->hw_write || !codec->control_data)
+ if (!codec->hw_write || !cx20442->control_data)
return -EIO;
old = reg_cache[reg];
@@ -201,17 +194,13 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
return -ENOMEM;
dev_dbg(codec->dev, "%s: %s\n", __func__, buf);
- if (codec->hw_write(codec->control_data, buf, len) != len)
+ if (codec->hw_write(cx20442->control_data, buf, len) != len)
return -EIO;
return 0;
}
-/* Moved up here as line discipline referres it during initialization */
-static struct snd_soc_codec *cx20442_codec;
-
-
/*
* Line discpline related code
*
@@ -227,15 +216,15 @@ static const char *v253_init = "ate0m0q0+fclass=8\r";
/* Line discipline .open() */
static int v253_open(struct tty_struct *tty)
{
- struct snd_soc_codec *codec = cx20442_codec;
int ret, len = strlen(v253_init);
/* Doesn't make sense without write callback */
if (!tty->ops->write)
return -EINVAL;
- /* Pass the codec structure address for use by other ldisc callbacks */
- tty->disc_data = codec;
+ /* Won't work if no codec pointer has been passed by a card driver */
+ if (!tty->disc_data)
+ return -ENODEV;
if (tty->ops->write(tty, v253_init, len) != len) {
ret = -EIO;
@@ -252,16 +241,19 @@ err:
static void v253_close(struct tty_struct *tty)
{
struct snd_soc_codec *codec = tty->disc_data;
+ struct cx20442_priv *cx20442;
tty->disc_data = NULL;
if (!codec)
return;
+ cx20442 = snd_soc_codec_get_drvdata(codec);
+
/* Prevent the codec driver from further accessing the modem */
codec->hw_write = NULL;
- codec->control_data = NULL;
- codec->pop_time = 0;
+ cx20442->control_data = NULL;
+ codec->card->pop_time = 0;
}
/* Line discipline .hangup() */
@@ -276,17 +268,20 @@ static void v253_receive(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct snd_soc_codec *codec = tty->disc_data;
+ struct cx20442_priv *cx20442;
if (!codec)
return;
- if (!codec->control_data) {
+ cx20442 = snd_soc_codec_get_drvdata(codec);
+
+ if (!cx20442->control_data) {
/* First modem response, complete setup procedure */
/* Set up codec driver access to modem controls */
- codec->control_data = tty;
+ cx20442->control_data = tty;
codec->hw_write = (hw_write_t)tty->ops->write;
- codec->pop_time = 1;
+ codec->card->pop_time = 1;
}
}
@@ -312,8 +307,8 @@ EXPORT_SYMBOL_GPL(v253_ops);
* Codec DAI
*/
-struct snd_soc_dai cx20442_dai = {
- .name = "CX20442",
+static struct snd_soc_dai_driver cx20442_dai = {
+ .name = "cx20442-voice",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -329,161 +324,120 @@ struct snd_soc_dai cx20442_dai = {
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
};
-EXPORT_SYMBOL_GPL(cx20442_dai);
-static int cx20442_codec_probe(struct platform_device *pdev)
+static int cx20442_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- if (!cx20442_codec) {
- dev_err(&pdev->dev, "cx20442 not yet discovered\n");
- return -ENODEV;
- }
- codec = cx20442_codec;
-
- socdev->card->codec = codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- goto pcm_err;
+ struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
+ int err = 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_PREPARE:
+ if (codec->dapm.bias_level != SND_SOC_BIAS_STANDBY)
+ break;
+ if (IS_ERR(cx20442->por))
+ err = PTR_ERR(cx20442->por);
+ else
+ err = regulator_enable(cx20442->por);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level != SND_SOC_BIAS_PREPARE)
+ break;
+ if (IS_ERR(cx20442->por))
+ err = PTR_ERR(cx20442->por);
+ else
+ err = regulator_disable(cx20442->por);
+ break;
+ default:
+ break;
}
+ if (!err)
+ codec->dapm.bias_level = level;
- cx20442_add_widgets(codec);
-
-pcm_err:
- return ret;
+ return err;
}
-/* power down chip */
-static int cx20442_codec_remove(struct platform_device *pdev)
+static int cx20442_codec_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct cx20442_priv *cx20442;
+
+ cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
+ if (cx20442 == NULL)
+ return -ENOMEM;
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ cx20442->por = regulator_get(codec->dev, "POR");
+ if (IS_ERR(cx20442->por))
+ dev_warn(codec->dev, "failed to get the regulator");
+ cx20442->control_data = NULL;
+
+ snd_soc_codec_set_drvdata(codec, cx20442);
+ codec->hw_write = NULL;
+ codec->card->pop_time = 0;
return 0;
}
-struct snd_soc_codec_device cx20442_codec_dev = {
- .probe = cx20442_codec_probe,
- .remove = cx20442_codec_remove,
-};
-EXPORT_SYMBOL_GPL(cx20442_codec_dev);
-
-static int cx20442_register(struct cx20442_priv *cx20442)
+/* power down chip */
+static int cx20442_codec_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &cx20442->codec;
- int ret;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
+ struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
- codec->name = "CX20442";
- codec->owner = THIS_MODULE;
- codec->private_data = cx20442;
-
- codec->dai = &cx20442_dai;
- codec->num_dai = 1;
-
- codec->reg_cache = &cx20442->reg_cache;
- codec->reg_cache_size = ARRAY_SIZE(cx20442->reg_cache);
- codec->read = cx20442_read_reg_cache;
- codec->write = cx20442_write;
-
- codec->bias_level = SND_SOC_BIAS_OFF;
-
- cx20442_dai.dev = codec->dev;
-
- cx20442_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
+ if (cx20442->control_data) {
+ struct tty_struct *tty = cx20442->control_data;
+ tty_hangup(tty);
}
- ret = snd_soc_register_dai(&cx20442_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
+ if (!IS_ERR(cx20442->por)) {
+ /* should be already in STANDBY, hence disabled */
+ regulator_put(cx20442->por);
}
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- cx20442_codec = NULL;
+ snd_soc_codec_set_drvdata(codec, NULL);
kfree(cx20442);
- return ret;
+ return 0;
}
-static void cx20442_unregister(struct cx20442_priv *cx20442)
-{
- snd_soc_unregister_dai(&cx20442_dai);
- snd_soc_unregister_codec(&cx20442->codec);
+static const u8 cx20442_reg;
- cx20442_codec = NULL;
- kfree(cx20442);
-}
+static struct snd_soc_codec_driver cx20442_codec_dev = {
+ .probe = cx20442_codec_probe,
+ .remove = cx20442_codec_remove,
+ .set_bias_level = cx20442_set_bias_level,
+ .reg_cache_default = &cx20442_reg,
+ .reg_cache_size = 1,
+ .reg_word_size = sizeof(u8),
+ .read = cx20442_read_reg_cache,
+ .write = cx20442_write,
+ .dapm_widgets = cx20442_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets),
+ .dapm_routes = cx20442_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cx20442_audio_map),
+};
static int cx20442_platform_probe(struct platform_device *pdev)
{
- struct cx20442_priv *cx20442;
- struct snd_soc_codec *codec;
-
- cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
- if (cx20442 == NULL)
- return -ENOMEM;
-
- codec = &cx20442->codec;
-
- codec->control_data = NULL;
- codec->hw_write = NULL;
- codec->pop_time = 0;
-
- codec->dev = &pdev->dev;
- platform_set_drvdata(pdev, cx20442);
-
- return cx20442_register(cx20442);
+ return snd_soc_register_codec(&pdev->dev,
+ &cx20442_codec_dev, &cx20442_dai, 1);
}
static int __exit cx20442_platform_remove(struct platform_device *pdev)
{
- struct cx20442_priv *cx20442 = platform_get_drvdata(pdev);
-
- cx20442_unregister(cx20442);
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver cx20442_platform_driver = {
.driver = {
- .name = "cx20442",
+ .name = "cx20442-codec",
.owner = THIS_MODULE,
},
.probe = cx20442_platform_probe,
.remove = __exit_p(cx20442_platform_remove),
};
-static int __init cx20442_init(void)
-{
- return platform_driver_register(&cx20442_platform_driver);
-}
-module_init(cx20442_init);
-
-static void __exit cx20442_exit(void)
-{
- platform_driver_unregister(&cx20442_platform_driver);
-}
-module_exit(cx20442_exit);
+module_platform_driver(cx20442_platform_driver);
MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
MODULE_AUTHOR("Janusz Krzysztofik");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:cx20442");
+MODULE_ALIAS("platform:cx20442-codec");