diff options
-rw-r--r-- | include/sound/wm8962.h | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8962.c | 60 |
2 files changed, 61 insertions, 1 deletions
diff --git a/include/sound/wm8962.h b/include/sound/wm8962.h index f70258e3471c..cc32aff53222 100644 --- a/include/sound/wm8962.h +++ b/include/sound/wm8962.h | |||
@@ -17,6 +17,8 @@ | |||
17 | struct wm8962_pdata { | 17 | struct wm8962_pdata { |
18 | u32 gpio_init[WM8962_MAX_GPIO]; | 18 | u32 gpio_init[WM8962_MAX_GPIO]; |
19 | 19 | ||
20 | bool irq_active_low; | ||
21 | |||
20 | bool spk_mono; /* Speaker outputs tied together as mono */ | 22 | bool spk_mono; /* Speaker outputs tied together as mono */ |
21 | }; | 23 | }; |
22 | 24 | ||
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 8e5f46691379..4fa5de873c8b 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -1461,6 +1461,29 @@ static struct snd_soc_dai_driver wm8962_dai = { | |||
1461 | .symmetric_rates = 1, | 1461 | .symmetric_rates = 1, |
1462 | }; | 1462 | }; |
1463 | 1463 | ||
1464 | static irqreturn_t wm8962_irq(int irq, void *data) | ||
1465 | { | ||
1466 | struct snd_soc_codec *codec = data; | ||
1467 | int mask; | ||
1468 | int active; | ||
1469 | |||
1470 | mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2); | ||
1471 | |||
1472 | active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2); | ||
1473 | active &= ~mask; | ||
1474 | |||
1475 | if (active & WM8962_FIFOS_ERR_EINT) | ||
1476 | dev_err(codec->dev, "FIFO error\n"); | ||
1477 | |||
1478 | if (active & WM8962_TEMP_SHUT_EINT) | ||
1479 | dev_crit(codec->dev, "Thermal shutdown\n"); | ||
1480 | |||
1481 | /* Acknowledge the interrupts */ | ||
1482 | snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active); | ||
1483 | |||
1484 | return IRQ_HANDLED; | ||
1485 | } | ||
1486 | |||
1464 | #ifdef CONFIG_PM | 1487 | #ifdef CONFIG_PM |
1465 | static int wm8962_resume(struct snd_soc_codec *codec) | 1488 | static int wm8962_resume(struct snd_soc_codec *codec) |
1466 | { | 1489 | { |
@@ -1632,7 +1655,9 @@ static int wm8962_probe(struct snd_soc_codec *codec) | |||
1632 | int ret; | 1655 | int ret; |
1633 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 1656 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
1634 | struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); | 1657 | struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); |
1635 | int i; | 1658 | struct i2c_client *i2c = container_of(codec->dev, struct i2c_client, |
1659 | dev); | ||
1660 | int i, trigger, irq_pol; | ||
1636 | 1661 | ||
1637 | wm8962->codec = codec; | 1662 | wm8962->codec = codec; |
1638 | 1663 | ||
@@ -1748,6 +1773,34 @@ static int wm8962_probe(struct snd_soc_codec *codec) | |||
1748 | 1773 | ||
1749 | wm8962_init_beep(codec); | 1774 | wm8962_init_beep(codec); |
1750 | 1775 | ||
1776 | if (i2c->irq) { | ||
1777 | if (pdata && pdata->irq_active_low) { | ||
1778 | trigger = IRQF_TRIGGER_LOW; | ||
1779 | irq_pol = WM8962_IRQ_POL; | ||
1780 | } else { | ||
1781 | trigger = IRQF_TRIGGER_HIGH; | ||
1782 | irq_pol = 0; | ||
1783 | } | ||
1784 | |||
1785 | snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL, | ||
1786 | WM8962_IRQ_POL, irq_pol); | ||
1787 | |||
1788 | ret = request_threaded_irq(i2c->irq, NULL, wm8962_irq, | ||
1789 | trigger | IRQF_ONESHOT, | ||
1790 | "wm8962", codec); | ||
1791 | if (ret != 0) { | ||
1792 | dev_err(codec->dev, "Failed to request IRQ %d: %d\n", | ||
1793 | i2c->irq, ret); | ||
1794 | /* Non-fatal */ | ||
1795 | } else { | ||
1796 | /* Enable error reporting IRQs by default */ | ||
1797 | snd_soc_update_bits(codec, | ||
1798 | WM8962_INTERRUPT_STATUS_2_MASK, | ||
1799 | WM8962_TEMP_SHUT_EINT | | ||
1800 | WM8962_FIFOS_ERR_EINT, 0); | ||
1801 | } | ||
1802 | } | ||
1803 | |||
1751 | return 0; | 1804 | return 0; |
1752 | 1805 | ||
1753 | err_enable: | 1806 | err_enable: |
@@ -1762,8 +1815,13 @@ err: | |||
1762 | static int wm8962_remove(struct snd_soc_codec *codec) | 1815 | static int wm8962_remove(struct snd_soc_codec *codec) |
1763 | { | 1816 | { |
1764 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 1817 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
1818 | struct i2c_client *i2c = container_of(codec->dev, struct i2c_client, | ||
1819 | dev); | ||
1765 | int i; | 1820 | int i; |
1766 | 1821 | ||
1822 | if (i2c->irq) | ||
1823 | free_irq(i2c->irq, codec); | ||
1824 | |||
1767 | wm8962_free_beep(codec); | 1825 | wm8962_free_beep(codec); |
1768 | for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) | 1826 | for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) |
1769 | regulator_unregister_notifier(wm8962->supplies[i].consumer, | 1827 | regulator_unregister_notifier(wm8962->supplies[i].consumer, |