Commit 7667428f authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/wm2200', 'asoc/topic/wm5100',...

Merge remote-tracking branches 'asoc/topic/wm2200', 'asoc/topic/wm5100', 'asoc/topic/wm8731', 'asoc/topic/wm8804' and 'asoc/topic/wm8996' into asoc-next
...@@ -10,6 +10,13 @@ Required properties: ...@@ -10,6 +10,13 @@ Required properties:
- reg : the I2C address of the device for I2C, the chip select - reg : the I2C address of the device for I2C, the chip select
number for SPI. number for SPI.
- PVDD-supply, DVDD-supply : Power supplies for the device, as covered
in Documentation/devicetree/bindings/regulator/regulator.txt
Optional properties:
- wlf,reset-gpio: A GPIO specifier for the GPIO controlling the reset pin
Example: Example:
codec: wm8804@1a { codec: wm8804@1a {
......
...@@ -413,3 +413,88 @@ void devm_regulator_bulk_unregister_supply_alias(struct device *dev, ...@@ -413,3 +413,88 @@ void devm_regulator_bulk_unregister_supply_alias(struct device *dev,
devm_regulator_unregister_supply_alias(dev, id[i]); devm_regulator_unregister_supply_alias(dev, id[i]);
} }
EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias); EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias);
struct regulator_notifier_match {
struct regulator *regulator;
struct notifier_block *nb;
};
static int devm_regulator_match_notifier(struct device *dev, void *res,
void *data)
{
struct regulator_notifier_match *match = res;
struct regulator_notifier_match *target = data;
return match->regulator == target->regulator && match->nb == target->nb;
}
static void devm_regulator_destroy_notifier(struct device *dev, void *res)
{
struct regulator_notifier_match *match = res;
regulator_unregister_notifier(match->regulator, match->nb);
}
/**
* devm_regulator_register_notifier - Resource managed
* regulator_register_notifier
*
* @regulator: regulator source
* @nb: notifier block
*
* The notifier will be registers under the consumer device and be
* automatically be unregistered when the source device is unbound.
*/
int devm_regulator_register_notifier(struct regulator *regulator,
struct notifier_block *nb)
{
struct regulator_notifier_match *match;
int ret;
match = devres_alloc(devm_regulator_destroy_notifier,
sizeof(struct regulator_notifier_match),
GFP_KERNEL);
if (!match)
return -ENOMEM;
match->regulator = regulator;
match->nb = nb;
ret = regulator_register_notifier(regulator, nb);
if (ret < 0) {
devres_free(match);
return ret;
}
devres_add(regulator->dev, match);
return 0;
}
EXPORT_SYMBOL_GPL(devm_regulator_register_notifier);
/**
* devm_regulator_unregister_notifier - Resource managed
* regulator_unregister_notifier()
*
* @regulator: regulator source
* @nb: notifier block
*
* Unregister a notifier registered with devm_regulator_register_notifier().
* Normally this function will not need to be called and the resource
* management code will ensure that the resource is freed.
*/
void devm_regulator_unregister_notifier(struct regulator *regulator,
struct notifier_block *nb)
{
struct regulator_notifier_match match;
int rc;
match.regulator = regulator;
match.nb = nb;
rc = devres_release(regulator->dev, devm_regulator_destroy_notifier,
devm_regulator_match_notifier, &match);
if (rc != 0)
WARN_ON(rc);
}
EXPORT_SYMBOL_GPL(devm_regulator_unregister_notifier);
...@@ -252,8 +252,12 @@ int regulator_list_hardware_vsel(struct regulator *regulator, ...@@ -252,8 +252,12 @@ int regulator_list_hardware_vsel(struct regulator *regulator,
/* regulator notifier block */ /* regulator notifier block */
int regulator_register_notifier(struct regulator *regulator, int regulator_register_notifier(struct regulator *regulator,
struct notifier_block *nb); struct notifier_block *nb);
int devm_regulator_register_notifier(struct regulator *regulator,
struct notifier_block *nb);
int regulator_unregister_notifier(struct regulator *regulator, int regulator_unregister_notifier(struct regulator *regulator,
struct notifier_block *nb); struct notifier_block *nb);
void devm_regulator_unregister_notifier(struct regulator *regulator,
struct notifier_block *nb);
/* driver data - core doesn't touch */ /* driver data - core doesn't touch */
void *regulator_get_drvdata(struct regulator *regulator); void *regulator_get_drvdata(struct regulator *regulator);
...@@ -515,12 +519,24 @@ static inline int regulator_register_notifier(struct regulator *regulator, ...@@ -515,12 +519,24 @@ static inline int regulator_register_notifier(struct regulator *regulator,
return 0; return 0;
} }
static inline int devm_regulator_register_notifier(struct regulator *regulator,
struct notifier_block *nb)
{
return 0;
}
static inline int regulator_unregister_notifier(struct regulator *regulator, static inline int regulator_unregister_notifier(struct regulator *regulator,
struct notifier_block *nb) struct notifier_block *nb)
{ {
return 0; return 0;
} }
static inline int devm_regulator_unregister_notifier(struct regulator *regulator,
struct notifier_block *nb)
{
return 0;
}
static inline void *regulator_get_drvdata(struct regulator *regulator) static inline void *regulator_get_drvdata(struct regulator *regulator)
{ {
return NULL; return NULL;
......
...@@ -1554,7 +1554,6 @@ static int wm2200_probe(struct snd_soc_codec *codec) ...@@ -1554,7 +1554,6 @@ static int wm2200_probe(struct snd_soc_codec *codec)
int ret; int ret;
wm2200->codec = codec; wm2200->codec = codec;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2); ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2);
if (ret != 0) if (ret != 0)
...@@ -1942,6 +1941,7 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source, ...@@ -1942,6 +1941,7 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec); struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
struct _fll_div factors; struct _fll_div factors;
int ret, i, timeout; int ret, i, timeout;
unsigned long time_left;
if (!Fout) { if (!Fout) {
dev_dbg(codec->dev, "FLL disabled"); dev_dbg(codec->dev, "FLL disabled");
...@@ -2021,9 +2021,10 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source, ...@@ -2021,9 +2021,10 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
/* Poll for the lock; will use the interrupt to exit quickly */ /* Poll for the lock; will use the interrupt to exit quickly */
for (i = 0; i < timeout; i++) { for (i = 0; i < timeout; i++) {
if (i2c->irq) { if (i2c->irq) {
ret = wait_for_completion_timeout(&wm2200->fll_lock, time_left = wait_for_completion_timeout(
msecs_to_jiffies(25)); &wm2200->fll_lock,
if (ret > 0) msecs_to_jiffies(25));
if (time_left > 0)
break; break;
} else { } else {
msleep(1); msleep(1);
......
...@@ -1762,6 +1762,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source, ...@@ -1762,6 +1762,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
struct _fll_div factors; struct _fll_div factors;
struct wm5100_fll *fll; struct wm5100_fll *fll;
int ret, base, lock, i, timeout; int ret, base, lock, i, timeout;
unsigned long time_left;
switch (fll_id) { switch (fll_id) {
case WM5100_FLL1: case WM5100_FLL1:
...@@ -1842,9 +1843,9 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source, ...@@ -1842,9 +1843,9 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
/* Poll for the lock; will use interrupt when we can test */ /* Poll for the lock; will use interrupt when we can test */
for (i = 0; i < timeout; i++) { for (i = 0; i < timeout; i++) {
if (i2c->irq) { if (i2c->irq) {
ret = wait_for_completion_timeout(&fll->lock, time_left = wait_for_completion_timeout(&fll->lock,
msecs_to_jiffies(25)); msecs_to_jiffies(25));
if (ret > 0) if (time_left > 0)
break; break;
} else { } else {
msleep(1); msleep(1);
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/clk.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
...@@ -45,6 +46,7 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { ...@@ -45,6 +46,7 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
/* codec private data */ /* codec private data */
struct wm8731_priv { struct wm8731_priv {
struct regmap *regmap; struct regmap *regmap;
struct clk *mclk;
struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
const struct snd_pcm_hw_constraint_list *constraints; const struct snd_pcm_hw_constraint_list *constraints;
unsigned int sysclk; unsigned int sysclk;
...@@ -390,6 +392,8 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -390,6 +392,8 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
switch (clk_id) { switch (clk_id) {
case WM8731_SYSCLK_XTAL: case WM8731_SYSCLK_XTAL:
case WM8731_SYSCLK_MCLK: case WM8731_SYSCLK_MCLK:
if (wm8731->mclk && clk_set_rate(wm8731->mclk, freq))
return -EINVAL;
wm8731->sysclk_type = clk_id; wm8731->sysclk_type = clk_id;
break; break;
default: default:
...@@ -491,6 +495,8 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, ...@@ -491,6 +495,8 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
if (wm8731->mclk)
clk_prepare_enable(wm8731->mclk);
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
break; break;
...@@ -509,6 +515,8 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, ...@@ -509,6 +515,8 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8731_PWR, reg | 0x0040); snd_soc_write(codec, WM8731_PWR, reg | 0x0040);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
if (wm8731->mclk)
clk_disable_unprepare(wm8731->mclk);
snd_soc_write(codec, WM8731_PWR, 0xffff); snd_soc_write(codec, WM8731_PWR, 0xffff);
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
wm8731->supplies); wm8731->supplies);
...@@ -667,6 +675,19 @@ static int wm8731_spi_probe(struct spi_device *spi) ...@@ -667,6 +675,19 @@ static int wm8731_spi_probe(struct spi_device *spi)
if (wm8731 == NULL) if (wm8731 == NULL)
return -ENOMEM; return -ENOMEM;
wm8731->mclk = devm_clk_get(&spi->dev, "mclk");
if (IS_ERR(wm8731->mclk)) {
ret = PTR_ERR(wm8731->mclk);
if (ret == -ENOENT) {
wm8731->mclk = NULL;
dev_warn(&spi->dev, "Assuming static MCLK\n");
} else {
dev_err(&spi->dev, "Failed to get MCLK: %d\n",
ret);
return ret;
}
}
mutex_init(&wm8731->lock); mutex_init(&wm8731->lock);
wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap);
...@@ -718,6 +739,19 @@ static int wm8731_i2c_probe(struct i2c_client *i2c, ...@@ -718,6 +739,19 @@ static int wm8731_i2c_probe(struct i2c_client *i2c,
if (wm8731 == NULL) if (wm8731 == NULL)
return -ENOMEM; return -ENOMEM;
wm8731->mclk = devm_clk_get(&i2c->dev, "mclk");
if (IS_ERR(wm8731->mclk)) {
ret = PTR_ERR(wm8731->mclk);
if (ret == -ENOENT) {
wm8731->mclk = NULL;
dev_warn(&i2c->dev, "Assuming static MCLK\n");
} else {
dev_err(&i2c->dev, "Failed to get MCLK: %d\n",
ret);
return ret;
}
}
mutex_init(&wm8731->lock); mutex_init(&wm8731->lock);
wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap); wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap);
......
...@@ -50,6 +50,7 @@ static struct i2c_driver wm8804_i2c_driver = { ...@@ -50,6 +50,7 @@ static struct i2c_driver wm8804_i2c_driver = {
.driver = { .driver = {
.name = "wm8804", .name = "wm8804",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &wm8804_pm,
.of_match_table = wm8804_of_match, .of_match_table = wm8804_of_match,
}, },
.probe = wm8804_i2c_probe, .probe = wm8804_i2c_probe,
......
...@@ -43,6 +43,7 @@ static struct spi_driver wm8804_spi_driver = { ...@@ -43,6 +43,7 @@ static struct spi_driver wm8804_spi_driver = {
.driver = { .driver = {
.name = "wm8804", .name = "wm8804",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &wm8804_pm,
.of_match_table = wm8804_of_match, .of_match_table = wm8804_of_match,
}, },
.probe = wm8804_spi_probe, .probe = wm8804_spi_probe,
......
This diff is collapsed.
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
#define WM8804_MCLKDIV_128FS 1 #define WM8804_MCLKDIV_128FS 1
extern const struct regmap_config wm8804_regmap_config; extern const struct regmap_config wm8804_regmap_config;
extern const struct dev_pm_ops wm8804_pm;
int wm8804_probe(struct device *dev, struct regmap *regmap); int wm8804_probe(struct device *dev, struct regmap *regmap);
void wm8804_remove(struct device *dev); void wm8804_remove(struct device *dev);
......
...@@ -2009,7 +2009,7 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source, ...@@ -2009,7 +2009,7 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c = to_i2c_client(codec->dev); struct i2c_client *i2c = to_i2c_client(codec->dev);
struct _fll_div fll_div; struct _fll_div fll_div;
unsigned long timeout; unsigned long timeout, time_left;
int ret, reg, retry; int ret, reg, retry;
/* Any change? */ /* Any change? */
...@@ -2110,13 +2110,15 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source, ...@@ -2110,13 +2110,15 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
if (i2c->irq) if (i2c->irq)
timeout *= 10; timeout *= 10;
else else
timeout /= 2; /* ensure timeout of atleast 1 jiffies */
timeout = timeout/2 ? : 1;
for (retry = 0; retry < 10; retry++) { for (retry = 0; retry < 10; retry++) {
ret = wait_for_completion_timeout(&wm8996->fll_lock, time_left = wait_for_completion_timeout(&wm8996->fll_lock,
timeout); timeout);
if (ret != 0) { if (time_left != 0) {
WARN_ON(!i2c->irq); WARN_ON(!i2c->irq);
ret = 1;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment