Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 293198
b: refs/heads/master
c: 164548d
h: refs/heads/master
v: v3
  • Loading branch information
Mark Brown committed Jan 20, 2012
1 parent b9e6f16 commit d828be5
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 10 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: a4b5233792443a2caed0db91003e5a75c50bc6c9
refs/heads/master: 164548d3b3733b10990274e1e92848656e9d6d1e
94 changes: 85 additions & 9 deletions trunk/sound/soc/codecs/wm8993.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,11 @@ static struct {

struct wm8993_priv {
struct wm_hubs_data hubs_data;
struct device *dev;
struct regmap *regmap;
struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
struct wm8993_platform_data pdata;
struct completion fll_lock;
int master;
int sysclk_source;
int tdm_slots;
Expand All @@ -225,6 +227,7 @@ static bool wm8993_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM8993_SOFTWARE_RESET:
case WM8993_GPIO_CTRL_1:
case WM8993_DC_SERVO_0:
case WM8993_DC_SERVO_READBACK_0:
case WM8993_DC_SERVO_READBACK_1:
Expand Down Expand Up @@ -467,8 +470,10 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
{
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c = to_i2c_client(codec->dev);
u16 reg1, reg4, reg5;
struct _fll_div fll_div;
unsigned int timeout;
int ret;

/* Any change? */
Expand Down Expand Up @@ -539,14 +544,22 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT;
snd_soc_write(codec, WM8993_FLL_CONTROL_5, reg5);

/* If we've got an interrupt wired up make sure we get it */
if (i2c->irq)
timeout = msecs_to_jiffies(20);
else if (Fref < 1000000)
timeout = msecs_to_jiffies(3);
else
timeout = msecs_to_jiffies(1);

try_wait_for_completion(&wm8993->fll_lock);

/* Enable the FLL */
snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);

/* Both overestimates */
if (Fref < 1000000)
msleep(3);
else
msleep(1);
timeout = wait_for_completion_timeout(&wm8993->fll_lock, timeout);
if (i2c->irq && !timeout)
dev_warn(codec->dev, "Timed out waiting for FLL\n");

dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);

Expand Down Expand Up @@ -1471,6 +1484,45 @@ static int wm8993_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
return 0;
}

static irqreturn_t wm8993_irq(int irq, void *data)
{
struct wm8993_priv *wm8993 = data;
int mask, val, ret;

ret = regmap_read(wm8993->regmap, WM8993_GPIO_CTRL_1, &val);
if (ret != 0) {
dev_err(wm8993->dev, "Failed to read interrupt status: %d\n",
ret);
return IRQ_NONE;
}

ret = regmap_read(wm8993->regmap, WM8993_GPIOCTRL_2, &mask);
if (ret != 0) {
dev_err(wm8993->dev, "Failed to read interrupt mask: %d\n",
ret);
return IRQ_NONE;
}

/* The IRQ pin status is visible in the register too */
val &= ~(mask | WM8993_IRQ);
if (!val)
return IRQ_NONE;

if (val & WM8993_TEMPOK_EINT)
dev_crit(wm8993->dev, "Thermal warning\n");

if (val & WM8993_FLL_LOCK_EINT) {
dev_dbg(wm8993->dev, "FLL locked\n");
complete(&wm8993->fll_lock);
}

ret = regmap_write(wm8993->regmap, WM8993_GPIO_CTRL_1, val);
if (ret != 0)
dev_err(wm8993->dev, "Failed to ack interrupt: %d\n", ret);

return IRQ_HANDLED;
}

static const struct snd_soc_dai_ops wm8993_ops = {
.set_sysclk = wm8993_set_sysclk,
.set_fmt = wm8993_set_dai_fmt,
Expand Down Expand Up @@ -1671,6 +1723,9 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
if (wm8993 == NULL)
return -ENOMEM;

wm8993->dev = &i2c->dev;
init_completion(&wm8993->fll_lock);

wm8993->regmap = regmap_init_i2c(i2c, &wm8993_regmap);
if (IS_ERR(wm8993->regmap)) {
ret = PTR_ERR(wm8993->regmap);
Expand Down Expand Up @@ -1713,6 +1768,22 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
if (ret != 0)
goto err_enable;

if (i2c->irq) {
/* Put GPIO1 into interrupt mode (only GPIO1 can output IRQ) */
ret = regmap_update_bits(wm8993->regmap, WM8993_GPIO1,
WM8993_GPIO1_PD |
WM8993_GPIO1_SEL_MASK, 7);
if (ret != 0)
goto err_enable;

ret = request_threaded_irq(i2c->irq, NULL, wm8993_irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"wm8993", wm8993);
if (ret != 0)
goto err_enable;

}

regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);

regcache_cache_only(wm8993->regmap, true);
Expand All @@ -1721,11 +1792,14 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
&soc_codec_dev_wm8993, &wm8993_dai, 1);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
goto err_enable;
goto err_irq;
}

return 0;

err_irq:
if (i2c->irq)
free_irq(i2c->irq, wm8993);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
err_get:
Expand All @@ -1735,11 +1809,13 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
return ret;
}

static __devexit int wm8993_i2c_remove(struct i2c_client *client)
static __devexit int wm8993_i2c_remove(struct i2c_client *i2c)
{
struct wm8993_priv *wm8993 = i2c_get_clientdata(client);
struct wm8993_priv *wm8993 = i2c_get_clientdata(i2c);

snd_soc_unregister_codec(&client->dev);
snd_soc_unregister_codec(&i2c->dev);
if (i2c->irq)
free_irq(i2c->irq, wm8993);
regmap_exit(wm8993->regmap);
regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
Expand Down

0 comments on commit d828be5

Please sign in to comment.