diff options
Diffstat (limited to 'sound/soc/codecs/tpa6130a2.c')
| -rw-r--r-- | sound/soc/codecs/tpa6130a2.c | 223 |
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); |
