Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 132814
b: refs/heads/master
c: 04eb093
h: refs/heads/master
v: v3
  • Loading branch information
Timur Tabi authored and Mark Brown committed Jan 30, 2009
1 parent fe8ff54 commit 69c5a8f
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 81 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7393958f630ac91e591e62058f2bdb61523ec60c
refs/heads/master: 04eb093c7c81d118efeb96228f69bc0179f71897
177 changes: 97 additions & 80 deletions trunk/sound/soc/codecs/cs4270.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,21 +490,17 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
};

/*
* Global variable to store socdev for i2c probe function.
* Global variable to store codec for the ASoC probe function.
*
* If struct i2c_driver had a private_data field, we wouldn't need to use
* cs4270_socdec. This is the only way to pass the socdev structure to
* cs4270_i2c_probe().
*
* The real solution to cs4270_socdev is to create a mechanism
* that maps I2C addresses to snd_soc_device structures. Perhaps the
* creation of the snd_soc_device object should be moved out of
* cs4270_probe() and into cs4270_i2c_probe(), but that would make this
* driver dependent on I2C. The CS4270 supports "stand-alone" mode, whereby
* the chip is *not* connected to the I2C bus, but is instead configured via
* input pins.
* cs4270_codec. This is the only way to pass the codec structure from
* cs4270_i2c_probe() to cs4270_probe(). Unfortunately, there is no good
* way to synchronize these two functions. cs4270_i2c_probe() can be called
* multiple times before cs4270_probe() is called even once. So for now, we
* also only allow cs4270_i2c_probe() to be run once. That means that we do
* not support more than one cs4270 device in the system, at least for now.
*/
static struct snd_soc_device *cs4270_socdev;
static struct snd_soc_codec *cs4270_codec;

struct snd_soc_dai cs4270_dai = {
.name = "cs4270",
Expand All @@ -531,6 +527,70 @@ struct snd_soc_dai cs4270_dai = {
};
EXPORT_SYMBOL_GPL(cs4270_dai);

/*
* ASoC probe function
*/
static int cs4270_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = cs4270_codec;
unsigned int i;
int ret;

/* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
socdev->card->codec = codec;

/* Register PCMs */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
printk(KERN_ERR "cs4270: failed to create PCMs\n");
return ret;
}

/* Add the non-DAPM controls */
for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) {
struct snd_kcontrol *kctrl;

kctrl = snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL);
if (!kctrl) {
printk(KERN_ERR "cs4270: error creating control '%s'\n",
cs4270_snd_controls[i].name);
ret = -ENOMEM;
goto error_free_pcms;
}

ret = snd_ctl_add(codec->card, kctrl);
if (ret < 0) {
printk(KERN_ERR "cs4270: error adding control '%s'\n",
cs4270_snd_controls[i].name);
goto error_free_pcms;
}
}

/* And finally, register the socdev */
ret = snd_soc_init_card(socdev);
if (ret < 0) {
printk(KERN_ERR "cs4270: failed to register card\n");
goto error_free_pcms;
}

return 0;

error_free_pcms:
snd_soc_free_pcms(socdev);

return ret;
}

static int cs4270_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);

snd_soc_free_pcms(socdev);

return 0;
};

/*
* Initialize the I2C interface of the CS4270
*
Expand All @@ -543,17 +603,27 @@ EXPORT_SYMBOL_GPL(cs4270_dai);
static int cs4270_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = cs4270_socdev;
struct snd_soc_codec *codec;
struct cs4270_private *cs4270;
int i;
int ret = 0;
int ret;

/* For now, we only support one cs4270 device in the system. See the
* comment for cs4270_codec.
*/
if (cs4270_codec) {
printk(KERN_ERR "cs4270: ignoring CS4270 at addr %X\n",
i2c_client->addr);
printk(KERN_ERR "cs4270: only one CS4270 per board allowed\n");
/* Should we return something other than ENODEV here? */
return -ENODEV;
}

/* Verify that we have a CS4270 */

ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
if (ret < 0) {
printk(KERN_ERR "cs4270: failed to read I2C\n");
printk(KERN_ERR "cs4270: failed to read I2C at addr %X\n",
i2c_client->addr);
return ret;
}
/* The top four bits of the chip ID should be 1100. */
Expand All @@ -575,7 +645,7 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
return -ENOMEM;
}
codec = &cs4270->codec;
socdev->card->codec = codec;
cs4270_codec = codec;

mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
Expand All @@ -600,50 +670,20 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
goto error_free_codec;
}

/* Register PCMs */

ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
/* Register the DAI. If all the other ASoC driver have already
* registered, then this will call our probe function, so
* cs4270_codec needs to be ready.
*/
ret = snd_soc_register_dai(&cs4270_dai);
if (ret < 0) {
printk(KERN_ERR "cs4270: failed to create PCMs\n");
printk(KERN_ERR "cs4270: failed to register DAIe\n");
goto error_free_codec;
}

/* Add the non-DAPM controls */

for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) {
struct snd_kcontrol *kctrl;

kctrl = snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL);
if (!kctrl) {
printk(KERN_ERR "cs4270: error creating control '%s'\n",
cs4270_snd_controls[i].name);
ret = -ENOMEM;
goto error_free_pcms;
}

ret = snd_ctl_add(codec->card, kctrl);
if (ret < 0) {
printk(KERN_ERR "cs4270: error adding control '%s'\n",
cs4270_snd_controls[i].name);
goto error_free_pcms;
}
}

/* Initialize the SOC device */

ret = snd_soc_init_card(socdev);
if (ret < 0) {
printk(KERN_ERR "cs4270: failed to register card\n");
goto error_free_pcms;;
}

i2c_set_clientdata(i2c_client, socdev);
i2c_set_clientdata(i2c_client, cs4270);

return 0;

error_free_pcms:
snd_soc_free_pcms(socdev);

error_free_codec:
kfree(cs4270);

Expand All @@ -652,11 +692,8 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,

static int cs4270_i2c_remove(struct i2c_client *i2c_client)
{
struct snd_soc_device *socdev = i2c_get_clientdata(i2c_client);
struct snd_soc_codec *codec = socdev->card->codec;
struct cs4270_private *cs4270 = codec->private_data;
struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client);

snd_soc_free_pcms(socdev);
kfree(cs4270);

return 0;
Expand All @@ -678,26 +715,6 @@ static struct i2c_driver cs4270_i2c_driver = {
.remove = cs4270_i2c_remove,
};

/*
* ASoC probe function
*
* This function is called when the machine driver calls
* platform_device_add().
*/
static int cs4270_probe(struct platform_device *pdev)
{
cs4270_socdev = platform_get_drvdata(pdev);;

return i2c_add_driver(&cs4270_i2c_driver);
}

static int cs4270_remove(struct platform_device *pdev)
{
i2c_del_driver(&cs4270_i2c_driver);

return 0;
}

/*
* ASoC codec device structure
*
Expand All @@ -714,13 +731,13 @@ static int __init cs4270_init(void)
{
printk(KERN_INFO "Cirrus Logic CS4270 ALSA SoC Codec Driver\n");

return snd_soc_register_dai(&cs4270_dai);
return i2c_add_driver(&cs4270_i2c_driver);
}
module_init(cs4270_init);

static void __exit cs4270_exit(void)
{
snd_soc_unregister_dai(&cs4270_dai);
i2c_del_driver(&cs4270_i2c_driver);
}
module_exit(cs4270_exit);

Expand Down

0 comments on commit 69c5a8f

Please sign in to comment.