aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/codecs/tlv320dac33.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/tlv320dac33.c')
-rw-r--r--sound/soc/codecs/tlv320dac33.c276
1 files changed, 105 insertions, 171 deletions
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 8651b01ed22..d251ff54a2d 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -66,8 +66,6 @@
static void dac33_calculate_times(struct snd_pcm_substream *substream);
static int dac33_prepare_chip(struct snd_pcm_substream *substream);
-static struct snd_soc_codec *tlv320dac33_codec;
-
enum dac33_state {
DAC33_IDLE = 0,
DAC33_PREFILL,
@@ -93,7 +91,7 @@ struct tlv320dac33_priv {
struct mutex mutex;
struct workqueue_struct *dac33_wq;
struct work_struct work;
- struct snd_soc_codec codec;
+ struct snd_soc_codec *codec;
struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
struct snd_pcm_substream *substream;
int power_gpio;
@@ -128,6 +126,8 @@ struct tlv320dac33_priv {
unsigned int uthr;
enum dac33_state state;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
@@ -524,6 +524,22 @@ static const struct soc_enum dac33_fifo_mode_enum =
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
dac33_fifo_mode_texts);
+/* L/R Line Output Gain */
+static const char *lr_lineout_gain_texts[] = {
+ "Line -12dB DAC 0dB", "Line -6dB DAC 6dB",
+ "Line 0dB DAC 12dB", "Line 6dB DAC 18dB",
+};
+
+static const struct soc_enum l_lineout_gain_enum =
+ SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0,
+ ARRAY_SIZE(lr_lineout_gain_texts),
+ lr_lineout_gain_texts);
+
+static const struct soc_enum r_lineout_gain_enum =
+ SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0,
+ ARRAY_SIZE(lr_lineout_gain_texts),
+ lr_lineout_gain_texts);
+
/*
* DACL/R digital volume control:
* from 0 dB to -63.5 in 0.5 dB steps
@@ -541,6 +557,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1),
SOC_DOUBLE_R("Line to Line Out Volume",
DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
+ SOC_ENUM("Left Line Output Gain", l_lineout_gain_enum),
+ SOC_ENUM("Right Line Output Gain", r_lineout_gain_enum),
};
static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
@@ -650,9 +668,8 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
{
- struct snd_soc_codec *codec;
-
- codec = &dac33->codec;
+ struct snd_soc_codec *codec = dac33->codec;
+ unsigned int delay;
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
@@ -668,8 +685,9 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
dac33_write16(codec, DAC33_PREFILL_MSB,
DAC33_THRREG(dac33->alarm_threshold));
/* Enable Alarm Threshold IRQ with a delay */
- udelay(SAMPLES_TO_US(dac33->burst_rate,
- dac33->alarm_threshold));
+ delay = SAMPLES_TO_US(dac33->burst_rate,
+ dac33->alarm_threshold) + 1000;
+ usleep_range(delay, delay + 500);
dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
break;
case DAC33_FIFO_MODE7:
@@ -695,9 +713,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
{
- struct snd_soc_codec *codec;
-
- codec = &dac33->codec;
+ struct snd_soc_codec *codec = dac33->codec;
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
@@ -726,7 +742,7 @@ static void dac33_work(struct work_struct *work)
u8 reg;
dac33 = container_of(work, struct tlv320dac33_priv, work);
- codec = &dac33->codec;
+ codec = dac33->codec;
mutex_lock(&dac33->mutex);
switch (dac33->state) {
@@ -771,11 +787,11 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
static void dac33_oscwait(struct snd_soc_codec *codec)
{
- int timeout = 20;
+ int timeout = 60;
u8 reg;
do {
- msleep(1);
+ usleep_range(1000, 2000);
dac33_read(codec, DAC33_INT_OSC_STATUS, &reg);
} while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--);
if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL)
@@ -787,8 +803,7 @@ static int dac33_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
/* Stream started, save the substream pointer */
@@ -801,8 +816,7 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
dac33->substream = NULL;
@@ -817,8 +831,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* Check parameters for validity */
switch (params_rate(params)) {
@@ -856,8 +869,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
static int dac33_prepare_chip(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
u8 aictrl_a, aictrl_b, fifoctrl_a;
@@ -1049,8 +1061,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
static void dac33_calculate_times(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned int period_size = substream->runtime->period_size;
unsigned int rate = substream->runtime->rate;
@@ -1129,8 +1140,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
@@ -1163,8 +1173,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned long long t0, t1, t_now;
unsigned int time_delta, uthr;
@@ -1389,24 +1398,46 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
-static int dac33_soc_probe(struct platform_device *pdev)
+static int dac33_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct tlv320dac33_priv *dac33;
+ struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- BUG_ON(!tlv320dac33_codec);
+ codec->control_data = dac33->control_data;
+ codec->hw_write = (hw_write_t) i2c_master_send;
+ codec->idle_bias_off = 1;
+ dac33->codec = codec;
- codec = tlv320dac33_codec;
- socdev->card->codec = codec;
- dac33 = snd_soc_codec_get_drvdata(codec);
+ /* Read the tlv320dac33 ID registers */
+ ret = dac33_hard_power(codec, 1);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
+ goto err_power;
+ }
+ dac33_read_id(codec);
+ dac33_hard_power(codec, 0);
+
+ /* Check if the IRQ number is valid and request it */
+ if (dac33->irq >= 0) {
+ ret = request_irq(dac33->irq, dac33_interrupt_handler,
+ IRQF_TRIGGER_RISING | IRQF_DISABLED,
+ codec->name, codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
+ dac33->irq, ret);
+ dac33->irq = -1;
+ }
+ if (dac33->irq != -1) {
+ /* Setup work queue */
+ dac33->dac33_wq =
+ create_singlethread_workqueue("tlv320dac33");
+ if (dac33->dac33_wq == NULL) {
+ free_irq(dac33->irq, codec);
+ return -ENOMEM;
+ }
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms\n");
- goto pcm_err;
+ INIT_WORK(&dac33->work, dac33_work);
+ }
}
snd_soc_add_controls(codec, dac33_snd_controls,
@@ -1420,56 +1451,51 @@ static int dac33_soc_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, dac33_fifo_snd_controls,
ARRAY_SIZE(dac33_fifo_snd_controls));
}
-
dac33_add_widgets(codec);
- return 0;
-
-pcm_err:
- dac33_hard_power(codec, 0);
+err_power:
return ret;
}
-static int dac33_soc_remove(struct platform_device *pdev)
+static int dac33_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
+ if (dac33->irq >= 0) {
+ free_irq(dac33->irq, dac33->codec);
+ destroy_workqueue(dac33->dac33_wq);
+ }
return 0;
}
-static int dac33_soc_suspend(struct platform_device *pdev, pm_message_t state)
+static int dac33_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int dac33_soc_resume(struct platform_device *pdev)
+static int dac33_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_tlv320dac33 = {
+static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
+ .read = dac33_read_reg_cache,
+ .write = dac33_write_locked,
+ .set_bias_level = dac33_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(dac33_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = dac33_reg,
.probe = dac33_soc_probe,
.remove = dac33_soc_remove,
.suspend = dac33_soc_suspend,
.resume = dac33_soc_resume,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33);
#define DAC33_RATES (SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000)
@@ -1485,8 +1511,8 @@ static struct snd_soc_dai_ops dac33_dai_ops = {
.set_fmt = dac33_set_dai_fmt,
};
-struct snd_soc_dai dac33_dai = {
- .name = "tlv320dac33",
+static struct snd_soc_dai_driver dac33_dai = {
+ .name = "tlv320dac33-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -1495,14 +1521,12 @@ struct snd_soc_dai dac33_dai = {
.formats = DAC33_FORMATS,},
.ops = &dac33_dai_ops,
};
-EXPORT_SYMBOL_GPL(dac33_dai);
static int __devinit dac33_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tlv320dac33_platform_data *pdata;
struct tlv320dac33_priv *dac33;
- struct snd_soc_codec *codec;
int ret, i;
if (client->dev.platform_data == NULL) {
@@ -1515,33 +1539,9 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
if (dac33 == NULL)
return -ENOMEM;
- codec = &dac33->codec;
- snd_soc_codec_set_drvdata(codec, dac33);
- codec->control_data = client;
-
- mutex_init(&codec->mutex);
+ dac33->control_data = client;
mutex_init(&dac33->mutex);
spin_lock_init(&dac33->lock);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "tlv320dac33";
- codec->owner = THIS_MODULE;
- codec->read = dac33_read_reg_cache;
- codec->write = dac33_write_locked;
- codec->hw_write = (hw_write_t) i2c_master_send;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = dac33_set_bias_level;
- codec->idle_bias_off = 1;
- codec->dai = &dac33_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
- codec->reg_cache = kmemdup(dac33_reg, ARRAY_SIZE(dac33_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto error_reg;
- }
i2c_set_clientdata(client, dac33);
@@ -1561,125 +1561,59 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
/* Disable FIFO use by default */
dac33->fifo_mode = DAC33_FIFO_BYPASS;
- tlv320dac33_codec = codec;
-
- codec->dev = &client->dev;
- dac33_dai.dev = codec->dev;
-
/* Check if the reset GPIO number is valid and request it */
if (dac33->power_gpio >= 0) {
ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset");
if (ret < 0) {
- dev_err(codec->dev,
+ dev_err(&client->dev,
"Failed to request reset GPIO (%d)\n",
dac33->power_gpio);
- snd_soc_unregister_dai(&dac33_dai);
- snd_soc_unregister_codec(codec);
- goto error_gpio;
+ goto err_gpio;
}
gpio_direction_output(dac33->power_gpio, 0);
}
- /* Check if the IRQ number is valid and request it */
- if (dac33->irq >= 0) {
- ret = request_irq(dac33->irq, dac33_interrupt_handler,
- IRQF_TRIGGER_RISING | IRQF_DISABLED,
- codec->name, codec);
- if (ret < 0) {
- dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
- dac33->irq, ret);
- dac33->irq = -1;
- }
- if (dac33->irq != -1) {
- /* Setup work queue */
- dac33->dac33_wq =
- create_singlethread_workqueue("tlv320dac33");
- if (dac33->dac33_wq == NULL) {
- free_irq(dac33->irq, &dac33->codec);
- ret = -ENOMEM;
- goto error_wq;
- }
-
- INIT_WORK(&dac33->work, dac33_work);
- }
- }
-
for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
dac33->supplies[i].supply = dac33_supply_names[i];
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies),
+ ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
dac33->supplies);
if (ret != 0) {
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
goto err_get;
}
- /* Read the tlv320dac33 ID registers */
- ret = dac33_hard_power(codec, 1);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
- goto error_codec;
- }
- dac33_read_id(codec);
- dac33_hard_power(codec, 0);
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto error_codec;
- }
-
- ret = snd_soc_register_dai(&dac33_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- goto error_codec;
- }
+ ret = snd_soc_register_codec(&client->dev,
+ &soc_codec_dev_tlv320dac33, &dac33_dai, 1);
+ if (ret < 0)
+ goto err_register;
return ret;
-
-error_codec:
+err_register:
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
err_get:
- if (dac33->irq >= 0) {
- free_irq(dac33->irq, &dac33->codec);
- destroy_workqueue(dac33->dac33_wq);
- }
-error_wq:
if (dac33->power_gpio >= 0)
gpio_free(dac33->power_gpio);
-error_gpio:
- kfree(codec->reg_cache);
-error_reg:
- tlv320dac33_codec = NULL;
+err_gpio:
kfree(dac33);
-
return ret;
}
static int __devexit dac33_i2c_remove(struct i2c_client *client)
{
- struct tlv320dac33_priv *dac33;
-
- dac33 = i2c_get_clientdata(client);
+ struct tlv320dac33_priv *dac33 = i2c_get_clientdata(client);
if (unlikely(dac33->chip_power))
- dac33_hard_power(&dac33->codec, 0);
+ dac33_hard_power(dac33->codec, 0);
if (dac33->power_gpio >= 0)
gpio_free(dac33->power_gpio);
- if (dac33->irq >= 0)
- free_irq(dac33->irq, &dac33->codec);
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
- destroy_workqueue(dac33->dac33_wq);
- snd_soc_unregister_dai(&dac33_dai);
- snd_soc_unregister_codec(&dac33->codec);
- kfree(dac33->codec.reg_cache);
+ snd_soc_unregister_codec(&client->dev);
kfree(dac33);
- tlv320dac33_codec = NULL;
return 0;
}
@@ -1694,7 +1628,7 @@ static const struct i2c_device_id tlv320dac33_i2c_id[] = {
static struct i2c_driver tlv320dac33_i2c_driver = {
.driver = {
- .name = "tlv320dac33",
+ .name = "tlv320dac33-codec",
.owner = THIS_MODULE,
},
.probe = dac33_i2c_probe,