aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8993.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-01-17 11:42:05 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-01-20 08:58:30 -0500
commit164548d3b3733b10990274e1e92848656e9d6d1e (patch)
treeb0c39dbf50eaa833f99861a0c3846c8c5f60842f /sound/soc/codecs/wm8993.c
parenta4b5233792443a2caed0db91003e5a75c50bc6c9 (diff)
ASoC: Implement basic WM8993 interrupt support
If an interrupt is supplied then use it for thermal warning and FLL lock notifications. When using the interrupt raise the timeout for the FLL lock substantially to reduce the chances of spurious warnings. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm8993.c')
-rw-r--r--sound/soc/codecs/wm8993.c94
1 files changed, 85 insertions, 9 deletions
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index e7ae9fda3f5b..eca93521124c 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -204,9 +204,11 @@ static struct {
204 204
205struct wm8993_priv { 205struct wm8993_priv {
206 struct wm_hubs_data hubs_data; 206 struct wm_hubs_data hubs_data;
207 struct device *dev;
207 struct regmap *regmap; 208 struct regmap *regmap;
208 struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES]; 209 struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
209 struct wm8993_platform_data pdata; 210 struct wm8993_platform_data pdata;
211 struct completion fll_lock;
210 int master; 212 int master;
211 int sysclk_source; 213 int sysclk_source;
212 int tdm_slots; 214 int tdm_slots;
@@ -225,6 +227,7 @@ static bool wm8993_volatile(struct device *dev, unsigned int reg)
225{ 227{
226 switch (reg) { 228 switch (reg) {
227 case WM8993_SOFTWARE_RESET: 229 case WM8993_SOFTWARE_RESET:
230 case WM8993_GPIO_CTRL_1:
228 case WM8993_DC_SERVO_0: 231 case WM8993_DC_SERVO_0:
229 case WM8993_DC_SERVO_READBACK_0: 232 case WM8993_DC_SERVO_READBACK_0:
230 case WM8993_DC_SERVO_READBACK_1: 233 case WM8993_DC_SERVO_READBACK_1:
@@ -467,8 +470,10 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
467 unsigned int Fref, unsigned int Fout) 470 unsigned int Fref, unsigned int Fout)
468{ 471{
469 struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); 472 struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
473 struct i2c_client *i2c = to_i2c_client(codec->dev);
470 u16 reg1, reg4, reg5; 474 u16 reg1, reg4, reg5;
471 struct _fll_div fll_div; 475 struct _fll_div fll_div;
476 unsigned int timeout;
472 int ret; 477 int ret;
473 478
474 /* Any change? */ 479 /* Any change? */
@@ -539,14 +544,22 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
539 reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT; 544 reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT;
540 snd_soc_write(codec, WM8993_FLL_CONTROL_5, reg5); 545 snd_soc_write(codec, WM8993_FLL_CONTROL_5, reg5);
541 546
547 /* If we've got an interrupt wired up make sure we get it */
548 if (i2c->irq)
549 timeout = msecs_to_jiffies(20);
550 else if (Fref < 1000000)
551 timeout = msecs_to_jiffies(3);
552 else
553 timeout = msecs_to_jiffies(1);
554
555 try_wait_for_completion(&wm8993->fll_lock);
556
542 /* Enable the FLL */ 557 /* Enable the FLL */
543 snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA); 558 snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
544 559
545 /* Both overestimates */ 560 timeout = wait_for_completion_timeout(&wm8993->fll_lock, timeout);
546 if (Fref < 1000000) 561 if (i2c->irq && !timeout)
547 msleep(3); 562 dev_warn(codec->dev, "Timed out waiting for FLL\n");
548 else
549 msleep(1);
550 563
551 dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); 564 dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
552 565
@@ -1471,6 +1484,45 @@ out:
1471 return 0; 1484 return 0;
1472} 1485}
1473 1486
1487static irqreturn_t wm8993_irq(int irq, void *data)
1488{
1489 struct wm8993_priv *wm8993 = data;
1490 int mask, val, ret;
1491
1492 ret = regmap_read(wm8993->regmap, WM8993_GPIO_CTRL_1, &val);
1493 if (ret != 0) {
1494 dev_err(wm8993->dev, "Failed to read interrupt status: %d\n",
1495 ret);
1496 return IRQ_NONE;
1497 }
1498
1499 ret = regmap_read(wm8993->regmap, WM8993_GPIOCTRL_2, &mask);
1500 if (ret != 0) {
1501 dev_err(wm8993->dev, "Failed to read interrupt mask: %d\n",
1502 ret);
1503 return IRQ_NONE;
1504 }
1505
1506 /* The IRQ pin status is visible in the register too */
1507 val &= ~(mask | WM8993_IRQ);
1508 if (!val)
1509 return IRQ_NONE;
1510
1511 if (val & WM8993_TEMPOK_EINT)
1512 dev_crit(wm8993->dev, "Thermal warning\n");
1513
1514 if (val & WM8993_FLL_LOCK_EINT) {
1515 dev_dbg(wm8993->dev, "FLL locked\n");
1516 complete(&wm8993->fll_lock);
1517 }
1518
1519 ret = regmap_write(wm8993->regmap, WM8993_GPIO_CTRL_1, val);
1520 if (ret != 0)
1521 dev_err(wm8993->dev, "Failed to ack interrupt: %d\n", ret);
1522
1523 return IRQ_HANDLED;
1524}
1525
1474static const struct snd_soc_dai_ops wm8993_ops = { 1526static const struct snd_soc_dai_ops wm8993_ops = {
1475 .set_sysclk = wm8993_set_sysclk, 1527 .set_sysclk = wm8993_set_sysclk,
1476 .set_fmt = wm8993_set_dai_fmt, 1528 .set_fmt = wm8993_set_dai_fmt,
@@ -1671,6 +1723,9 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
1671 if (wm8993 == NULL) 1723 if (wm8993 == NULL)
1672 return -ENOMEM; 1724 return -ENOMEM;
1673 1725
1726 wm8993->dev = &i2c->dev;
1727 init_completion(&wm8993->fll_lock);
1728
1674 wm8993->regmap = regmap_init_i2c(i2c, &wm8993_regmap); 1729 wm8993->regmap = regmap_init_i2c(i2c, &wm8993_regmap);
1675 if (IS_ERR(wm8993->regmap)) { 1730 if (IS_ERR(wm8993->regmap)) {
1676 ret = PTR_ERR(wm8993->regmap); 1731 ret = PTR_ERR(wm8993->regmap);
@@ -1713,6 +1768,22 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
1713 if (ret != 0) 1768 if (ret != 0)
1714 goto err_enable; 1769 goto err_enable;
1715 1770
1771 if (i2c->irq) {
1772 /* Put GPIO1 into interrupt mode (only GPIO1 can output IRQ) */
1773 ret = regmap_update_bits(wm8993->regmap, WM8993_GPIO1,
1774 WM8993_GPIO1_PD |
1775 WM8993_GPIO1_SEL_MASK, 7);
1776 if (ret != 0)
1777 goto err_enable;
1778
1779 ret = request_threaded_irq(i2c->irq, NULL, wm8993_irq,
1780 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
1781 "wm8993", wm8993);
1782 if (ret != 0)
1783 goto err_enable;
1784
1785 }
1786
1716 regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); 1787 regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
1717 1788
1718 regcache_cache_only(wm8993->regmap, true); 1789 regcache_cache_only(wm8993->regmap, true);
@@ -1721,11 +1792,14 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
1721 &soc_codec_dev_wm8993, &wm8993_dai, 1); 1792 &soc_codec_dev_wm8993, &wm8993_dai, 1);
1722 if (ret != 0) { 1793 if (ret != 0) {
1723 dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); 1794 dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
1724 goto err_enable; 1795 goto err_irq;
1725 } 1796 }
1726 1797
1727 return 0; 1798 return 0;
1728 1799
1800err_irq:
1801 if (i2c->irq)
1802 free_irq(i2c->irq, wm8993);
1729err_enable: 1803err_enable:
1730 regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); 1804 regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
1731err_get: 1805err_get:
@@ -1735,11 +1809,13 @@ err:
1735 return ret; 1809 return ret;
1736} 1810}
1737 1811
1738static __devexit int wm8993_i2c_remove(struct i2c_client *client) 1812static __devexit int wm8993_i2c_remove(struct i2c_client *i2c)
1739{ 1813{
1740 struct wm8993_priv *wm8993 = i2c_get_clientdata(client); 1814 struct wm8993_priv *wm8993 = i2c_get_clientdata(i2c);
1741 1815
1742 snd_soc_unregister_codec(&client->dev); 1816 snd_soc_unregister_codec(&i2c->dev);
1817 if (i2c->irq)
1818 free_irq(i2c->irq, wm8993);
1743 regmap_exit(wm8993->regmap); 1819 regmap_exit(wm8993->regmap);
1744 regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); 1820 regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
1745 regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); 1821 regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);