aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/codecs/tpa6130a2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/tpa6130a2.c')
-rw-r--r--sound/soc/codecs/tpa6130a2.c223
1 files changed, 84 insertions, 139 deletions
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index d2c24309567..8fc5a647453 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Nokia Corporation
*
- * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -29,11 +29,17 @@
#include <linux/slab.h>
#include <sound/tpa6130a2-plat.h>
#include <sound/soc.h>
-#include <sound/soc-dapm.h>
#include <sound/tlv.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include "tpa6130a2.h"
+enum tpa_model {
+ TPA6130A2,
+ TPA6140A2,
+};
+
static struct i2c_client *tpa6130a2_client;
/* This struct is used to save the context */
@@ -42,7 +48,7 @@ struct tpa6130a2_data {
unsigned char regs[TPA6130A2_CACHEREGNUM];
struct regulator *supply;
int power_gpio;
- unsigned char power_state;
+ u8 power_state:1;
enum tpa_model id;
};
@@ -51,7 +57,8 @@ static int tpa6130a2_i2c_read(int reg)
struct tpa6130a2_data *data;
int val;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
/* If powered off, return the cached value */
@@ -73,7 +80,8 @@ static int tpa6130a2_i2c_write(int reg, u8 value)
struct tpa6130a2_data *data;
int val = 0;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
if (data->power_state) {
@@ -94,7 +102,8 @@ static u8 tpa6130a2_read(int reg)
{
struct tpa6130a2_data *data;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return 0;
data = i2c_get_clientdata(tpa6130a2_client);
return data->regs[reg];
@@ -105,7 +114,8 @@ static int tpa6130a2_initialize(void)
struct tpa6130a2_data *data;
int i, ret = 0;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
for (i = 1; i < TPA6130A2_REG_VERSION; i++) {
@@ -117,27 +127,30 @@ static int tpa6130a2_initialize(void)
return ret;
}
-static int tpa6130a2_power(int power)
+static int tpa6130a2_power(u8 power)
{
struct tpa6130a2_data *data;
u8 val;
int ret = 0;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
mutex_lock(&data->mutex);
- if (power && !data->power_state) {
- /* Power on */
- if (data->power_gpio >= 0)
- gpio_set_value(data->power_gpio, 1);
+ if (power == data->power_state)
+ goto exit;
+ if (power) {
ret = regulator_enable(data->supply);
if (ret != 0) {
dev_err(&tpa6130a2_client->dev,
"Failed to enable supply: %d\n", ret);
goto exit;
}
+ /* Power on */
+ if (data->power_gpio >= 0)
+ gpio_set_value(data->power_gpio, 1);
data->power_state = 1;
ret = tpa6130a2_initialize();
@@ -150,12 +163,7 @@ static int tpa6130a2_power(int power)
data->power_state = 0;
goto exit;
}
-
- /* Clear SWS */
- val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
- val &= ~TPA6130A2_SWS;
- tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
- } else if (!power && data->power_state) {
+ } else {
/* set SWS */
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
val |= TPA6130A2_SWS;
@@ -192,7 +200,8 @@ static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol,
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
mutex_lock(&data->mutex);
@@ -222,7 +231,8 @@ static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int val = (ucontrol->value.integer.value[0] & mask);
unsigned int val_reg;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
if (invert)
@@ -300,6 +310,7 @@ static void tpa6130a2_channel_enable(u8 channel, int enable)
/* Enable amplifier */
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
val |= channel;
+ val &= ~TPA6130A2_SWS;
tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
/* Unmute channel */
@@ -320,72 +331,24 @@ static void tpa6130a2_channel_enable(u8 channel, int enable)
}
}
-static int tpa6130a2_left_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 1);
- break;
- case SND_SOC_DAPM_POST_PMD:
- tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 0);
- break;
- }
- return 0;
-}
-
-static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 1);
- break;
- case SND_SOC_DAPM_POST_PMD:
- tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 0);
- break;
- }
- return 0;
-}
-
-static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable)
{
int ret = 0;
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
+ if (enable) {
ret = tpa6130a2_power(1);
- break;
- case SND_SOC_DAPM_POST_PMD:
+ if (ret < 0)
+ return ret;
+ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
+ 1);
+ } else {
+ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
+ 0);
ret = tpa6130a2_power(0);
- break;
}
+
return ret;
}
-
-static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
- SND_SOC_DAPM_PGA_E("TPA6130A2 Left", SND_SOC_NOPM,
- 0, 0, NULL, 0, tpa6130a2_left_event,
- SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA_E("TPA6130A2 Right", SND_SOC_NOPM,
- 0, 0, NULL, 0, tpa6130a2_right_event,
- SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SUPPLY("TPA6130A2 Enable", SND_SOC_NOPM,
- 0, 0, tpa6130a2_supply_event,
- SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
- /* Outputs */
- SND_SOC_DAPM_OUTPUT("TPA6130A2 Headphone Left"),
- SND_SOC_DAPM_OUTPUT("TPA6130A2 Headphone Right"),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
- {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Left"},
- {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Right"},
-
- {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Enable"},
- {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Enable"},
-};
+EXPORT_SYMBOL_GPL(tpa6130a2_stereo_enable);
int tpa6130a2_add_controls(struct snd_soc_codec *codec)
{
@@ -396,51 +359,48 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
data = i2c_get_clientdata(tpa6130a2_client);
- snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
- ARRAY_SIZE(tpa6130a2_dapm_widgets));
-
- snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
if (data->id == TPA6140A2)
- return snd_soc_add_controls(codec, tpa6140a2_controls,
+ return snd_soc_add_codec_controls(codec, tpa6140a2_controls,
ARRAY_SIZE(tpa6140a2_controls));
else
- return snd_soc_add_controls(codec, tpa6130a2_controls,
+ return snd_soc_add_codec_controls(codec, tpa6130a2_controls,
ARRAY_SIZE(tpa6130a2_controls));
-
}
EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);
-static int __devinit tpa6130a2_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tpa6130a2_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct device *dev;
struct tpa6130a2_data *data;
- struct tpa6130a2_platform_data *pdata;
+ struct tpa6130a2_platform_data *pdata = client->dev.platform_data;
+ struct device_node *np = client->dev.of_node;
const char *regulator;
int ret;
dev = &client->dev;
- if (client->dev.platform_data == NULL) {
- dev_err(dev, "Platform data not set\n");
- dump_stack();
- return -ENODEV;
- }
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (data == NULL) {
dev_err(dev, "Can not allocate memory\n");
return -ENOMEM;
}
+ if (pdata) {
+ data->power_gpio = pdata->power_gpio;
+ } else if (np) {
+ data->power_gpio = of_get_named_gpio(np, "power-gpio", 0);
+ } else {
+ dev_err(dev, "Platform data not set\n");
+ dump_stack();
+ return -ENODEV;
+ }
+
tpa6130a2_client = client;
i2c_set_clientdata(tpa6130a2_client, data);
- pdata = client->dev.platform_data;
- data->power_gpio = pdata->power_gpio;
- data->id = pdata->id;
+ data->id = id->driver_data;
mutex_init(&data->mutex);
@@ -450,7 +410,8 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
TPA6130A2_MUTE_L;
if (data->power_gpio >= 0) {
- ret = gpio_request(data->power_gpio, "tpa6130a2 enable");
+ ret = devm_gpio_request(dev, data->power_gpio,
+ "tpa6130a2 enable");
if (ret < 0) {
dev_err(dev, "Failed to request power GPIO (%d)\n",
data->power_gpio);
@@ -462,7 +423,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
switch (data->id) {
default:
dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
- pdata->id);
+ data->id);
case TPA6130A2:
regulator = "Vdd";
break;
@@ -471,16 +432,16 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
break;
}
- data->supply = regulator_get(dev, regulator);
+ data->supply = devm_regulator_get(dev, regulator);
if (IS_ERR(data->supply)) {
ret = PTR_ERR(data->supply);
dev_err(dev, "Failed to request supply: %d\n", ret);
- goto err_regulator;
+ goto err_gpio;
}
ret = tpa6130a2_power(1);
if (ret != 0)
- goto err_power;
+ goto err_gpio;
/* Read version */
@@ -492,69 +453,53 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
/* Disable the chip */
ret = tpa6130a2_power(0);
if (ret != 0)
- goto err_power;
+ goto err_gpio;
return 0;
-err_power:
- regulator_put(data->supply);
-err_regulator:
- if (data->power_gpio >= 0)
- gpio_free(data->power_gpio);
err_gpio:
- kfree(data);
- i2c_set_clientdata(tpa6130a2_client, NULL);
tpa6130a2_client = NULL;
return ret;
}
-static int __devexit tpa6130a2_remove(struct i2c_client *client)
+static int tpa6130a2_remove(struct i2c_client *client)
{
- struct tpa6130a2_data *data = i2c_get_clientdata(client);
-
tpa6130a2_power(0);
-
- if (data->power_gpio >= 0)
- gpio_free(data->power_gpio);
-
- regulator_put(data->supply);
-
- kfree(data);
tpa6130a2_client = NULL;
return 0;
}
static const struct i2c_device_id tpa6130a2_id[] = {
- { "tpa6130a2", 0 },
+ { "tpa6130a2", TPA6130A2 },
+ { "tpa6140a2", TPA6140A2 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tpa6130a2_id);
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id tpa6130a2_of_match[] = {
+ { .compatible = "ti,tpa6130a2", },
+ { .compatible = "ti,tpa6140a2" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tpa6130a2_of_match);
+#endif
+
static struct i2c_driver tpa6130a2_i2c_driver = {
.driver = {
.name = "tpa6130a2",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tpa6130a2_of_match),
},
.probe = tpa6130a2_probe,
- .remove = __devexit_p(tpa6130a2_remove),
+ .remove = tpa6130a2_remove,
.id_table = tpa6130a2_id,
};
-static int __init tpa6130a2_init(void)
-{
- return i2c_add_driver(&tpa6130a2_i2c_driver);
-}
-
-static void __exit tpa6130a2_exit(void)
-{
- i2c_del_driver(&tpa6130a2_i2c_driver);
-}
+module_i2c_driver(tpa6130a2_i2c_driver);
-MODULE_AUTHOR("Peter Ujfalusi");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
MODULE_LICENSE("GPL");
-
-module_init(tpa6130a2_init);
-module_exit(tpa6130a2_exit);