diff options
author | Ben Zhang <benzh@chromium.org> | 2019-06-18 19:45:54 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-06-19 07:46:24 -0400 |
commit | 4f7b018b55db0361718161e1471d8b7a16fdfa47 (patch) | |
tree | 945bda9d9c81f66f461b26492e9895aea504cc80 | |
parent | 16395ceee11f8f8af764bac76adc20a43ba1a153 (diff) |
ASoC: rt5677: clear interrupts by polarity flip
The rt5677 jack detection function has a requirement that the polarity
of an interrupt be flipped after it fires in order to clear the
interrupt.
This patch implements an irq_chip with irq_domain directly instead of
using regmap-irq, so that interrupt source line polarities can be
flipped in the irq handler.
The reason that this patch does not add this feature within regmap-irq
is that future patches will add hotword detection support to this irq
handler. Those patches will require adding additional logic that would
not make sense to have in regmap-irq.
Signed-off-by: Ben Zhang <benzh@chromium.org>
Signed-off-by: Fletcher Woodruff <fletcherw@chromium.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/codecs/rt5677.c | 173 | ||||
-rw-r--r-- | sound/soc/codecs/rt5677.h | 8 |
2 files changed, 145 insertions, 36 deletions
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 87a92ba0d040..b5ae61ff87af 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c | |||
@@ -23,6 +23,10 @@ | |||
23 | #include <linux/firmware.h> | 23 | #include <linux/firmware.h> |
24 | #include <linux/of_device.h> | 24 | #include <linux/of_device.h> |
25 | #include <linux/property.h> | 25 | #include <linux/property.h> |
26 | #include <linux/irq.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/irqdomain.h> | ||
29 | #include <linux/workqueue.h> | ||
26 | #include <sound/core.h> | 30 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
28 | #include <sound/pcm_params.h> | 32 | #include <sound/pcm_params.h> |
@@ -4620,7 +4624,6 @@ static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, | |||
4620 | static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) | 4624 | static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) |
4621 | { | 4625 | { |
4622 | struct rt5677_priv *rt5677 = gpiochip_get_data(chip); | 4626 | struct rt5677_priv *rt5677 = gpiochip_get_data(chip); |
4623 | struct regmap_irq_chip_data *data = rt5677->irq_data; | ||
4624 | int irq; | 4627 | int irq; |
4625 | 4628 | ||
4626 | if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) || | 4629 | if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) || |
@@ -4646,7 +4649,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) | |||
4646 | return -ENXIO; | 4649 | return -ENXIO; |
4647 | } | 4650 | } |
4648 | 4651 | ||
4649 | return regmap_irq_get_virq(data, irq); | 4652 | return irq_create_mapping(rt5677->domain, irq); |
4650 | } | 4653 | } |
4651 | 4654 | ||
4652 | static const struct gpio_chip rt5677_template_chip = { | 4655 | static const struct gpio_chip rt5677_template_chip = { |
@@ -5042,30 +5045,130 @@ static void rt5677_read_device_properties(struct rt5677_priv *rt5677, | |||
5042 | rt5677->pdata.jd3_gpio = val; | 5045 | rt5677->pdata.jd3_gpio = val; |
5043 | } | 5046 | } |
5044 | 5047 | ||
5045 | static struct regmap_irq rt5677_irqs[] = { | 5048 | struct rt5677_irq_desc { |
5049 | unsigned int enable_mask; | ||
5050 | unsigned int status_mask; | ||
5051 | unsigned int polarity_mask; | ||
5052 | }; | ||
5053 | |||
5054 | static const struct rt5677_irq_desc rt5677_irq_descs[] = { | ||
5046 | [RT5677_IRQ_JD1] = { | 5055 | [RT5677_IRQ_JD1] = { |
5047 | .reg_offset = 0, | 5056 | .enable_mask = RT5677_EN_IRQ_GPIO_JD1, |
5048 | .mask = RT5677_EN_IRQ_GPIO_JD1, | 5057 | .status_mask = RT5677_STA_GPIO_JD1, |
5058 | .polarity_mask = RT5677_INV_GPIO_JD1, | ||
5049 | }, | 5059 | }, |
5050 | [RT5677_IRQ_JD2] = { | 5060 | [RT5677_IRQ_JD2] = { |
5051 | .reg_offset = 0, | 5061 | .enable_mask = RT5677_EN_IRQ_GPIO_JD2, |
5052 | .mask = RT5677_EN_IRQ_GPIO_JD2, | 5062 | .status_mask = RT5677_STA_GPIO_JD2, |
5063 | .polarity_mask = RT5677_INV_GPIO_JD2, | ||
5053 | }, | 5064 | }, |
5054 | [RT5677_IRQ_JD3] = { | 5065 | [RT5677_IRQ_JD3] = { |
5055 | .reg_offset = 0, | 5066 | .enable_mask = RT5677_EN_IRQ_GPIO_JD3, |
5056 | .mask = RT5677_EN_IRQ_GPIO_JD3, | 5067 | .status_mask = RT5677_STA_GPIO_JD3, |
5068 | .polarity_mask = RT5677_INV_GPIO_JD3, | ||
5057 | }, | 5069 | }, |
5058 | }; | 5070 | }; |
5059 | 5071 | ||
5060 | static struct regmap_irq_chip rt5677_irq_chip = { | 5072 | static irqreturn_t rt5677_irq(int unused, void *data) |
5061 | .name = RT5677_DRV_NAME, | 5073 | { |
5062 | .irqs = rt5677_irqs, | 5074 | struct rt5677_priv *rt5677 = data; |
5063 | .num_irqs = ARRAY_SIZE(rt5677_irqs), | 5075 | int ret = 0, i, reg_irq, virq; |
5076 | bool irq_fired = false; | ||
5077 | |||
5078 | mutex_lock(&rt5677->irq_lock); | ||
5079 | /* Read interrupt status */ | ||
5080 | ret = regmap_read(rt5677->regmap, RT5677_IRQ_CTRL1, ®_irq); | ||
5081 | if (ret) { | ||
5082 | dev_err(rt5677->dev, "failed reading IRQ status: %d\n", ret); | ||
5083 | goto exit; | ||
5084 | } | ||
5085 | |||
5086 | for (i = 0; i < RT5677_IRQ_NUM; i++) { | ||
5087 | if (reg_irq & rt5677_irq_descs[i].status_mask) { | ||
5088 | irq_fired = true; | ||
5089 | virq = irq_find_mapping(rt5677->domain, i); | ||
5090 | if (virq) | ||
5091 | handle_nested_irq(virq); | ||
5092 | |||
5093 | /* Clear the interrupt by flipping the polarity of the | ||
5094 | * interrupt source line that fired | ||
5095 | */ | ||
5096 | reg_irq ^= rt5677_irq_descs[i].polarity_mask; | ||
5097 | } | ||
5098 | } | ||
5099 | |||
5100 | if (!irq_fired) | ||
5101 | goto exit; | ||
5102 | |||
5103 | ret = regmap_write(rt5677->regmap, RT5677_IRQ_CTRL1, reg_irq); | ||
5104 | if (ret) { | ||
5105 | dev_err(rt5677->dev, "failed updating IRQ status: %d\n", ret); | ||
5106 | goto exit; | ||
5107 | } | ||
5108 | exit: | ||
5109 | mutex_unlock(&rt5677->irq_lock); | ||
5110 | if (irq_fired) | ||
5111 | return IRQ_HANDLED; | ||
5112 | else | ||
5113 | return IRQ_NONE; | ||
5114 | } | ||
5115 | |||
5116 | static void rt5677_irq_bus_lock(struct irq_data *data) | ||
5117 | { | ||
5118 | struct rt5677_priv *rt5677 = irq_data_get_irq_chip_data(data); | ||
5119 | |||
5120 | mutex_lock(&rt5677->irq_lock); | ||
5121 | } | ||
5122 | |||
5123 | static void rt5677_irq_bus_sync_unlock(struct irq_data *data) | ||
5124 | { | ||
5125 | struct rt5677_priv *rt5677 = irq_data_get_irq_chip_data(data); | ||
5126 | |||
5127 | // Set the enable/disable bits for the jack detect IRQs. | ||
5128 | regmap_update_bits(rt5677->regmap, RT5677_IRQ_CTRL1, | ||
5129 | RT5677_EN_IRQ_GPIO_JD1 | RT5677_EN_IRQ_GPIO_JD2 | | ||
5130 | RT5677_EN_IRQ_GPIO_JD3, rt5677->irq_en); | ||
5131 | mutex_unlock(&rt5677->irq_lock); | ||
5132 | } | ||
5133 | |||
5134 | static void rt5677_irq_enable(struct irq_data *data) | ||
5135 | { | ||
5136 | struct rt5677_priv *rt5677 = irq_data_get_irq_chip_data(data); | ||
5137 | |||
5138 | rt5677->irq_en |= rt5677_irq_descs[data->hwirq].enable_mask; | ||
5139 | } | ||
5064 | 5140 | ||
5065 | .num_regs = 1, | 5141 | static void rt5677_irq_disable(struct irq_data *data) |
5066 | .status_base = RT5677_IRQ_CTRL1, | 5142 | { |
5067 | .mask_base = RT5677_IRQ_CTRL1, | 5143 | struct rt5677_priv *rt5677 = irq_data_get_irq_chip_data(data); |
5068 | .mask_invert = 1, | 5144 | |
5145 | rt5677->irq_en &= ~rt5677_irq_descs[data->hwirq].enable_mask; | ||
5146 | } | ||
5147 | |||
5148 | static struct irq_chip rt5677_irq_chip = { | ||
5149 | .name = "rt5677_irq_chip", | ||
5150 | .irq_bus_lock = rt5677_irq_bus_lock, | ||
5151 | .irq_bus_sync_unlock = rt5677_irq_bus_sync_unlock, | ||
5152 | .irq_disable = rt5677_irq_disable, | ||
5153 | .irq_enable = rt5677_irq_enable, | ||
5154 | }; | ||
5155 | |||
5156 | static int rt5677_irq_map(struct irq_domain *h, unsigned int virq, | ||
5157 | irq_hw_number_t hw) | ||
5158 | { | ||
5159 | struct rt5677_priv *rt5677 = h->host_data; | ||
5160 | |||
5161 | irq_set_chip_data(virq, rt5677); | ||
5162 | irq_set_chip(virq, &rt5677_irq_chip); | ||
5163 | irq_set_nested_thread(virq, 1); | ||
5164 | irq_set_noprobe(virq); | ||
5165 | return 0; | ||
5166 | } | ||
5167 | |||
5168 | |||
5169 | static const struct irq_domain_ops rt5677_domain_ops = { | ||
5170 | .map = rt5677_irq_map, | ||
5171 | .xlate = irq_domain_xlate_twocell, | ||
5069 | }; | 5172 | }; |
5070 | 5173 | ||
5071 | static int rt5677_init_irq(struct i2c_client *i2c) | 5174 | static int rt5677_init_irq(struct i2c_client *i2c) |
@@ -5084,6 +5187,8 @@ static int rt5677_init_irq(struct i2c_client *i2c) | |||
5084 | return -EINVAL; | 5187 | return -EINVAL; |
5085 | } | 5188 | } |
5086 | 5189 | ||
5190 | mutex_init(&rt5677->irq_lock); | ||
5191 | |||
5087 | /* | 5192 | /* |
5088 | * Select RC as the debounce clock so that GPIO works even when | 5193 | * Select RC as the debounce clock so that GPIO works even when |
5089 | * MCLK is gated which happens when there is no audio stream | 5194 | * MCLK is gated which happens when there is no audio stream |
@@ -5092,7 +5197,6 @@ static int rt5677_init_irq(struct i2c_client *i2c) | |||
5092 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, | 5197 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, |
5093 | RT5677_IRQ_DEBOUNCE_SEL_MASK, | 5198 | RT5677_IRQ_DEBOUNCE_SEL_MASK, |
5094 | RT5677_IRQ_DEBOUNCE_SEL_RC); | 5199 | RT5677_IRQ_DEBOUNCE_SEL_RC); |
5095 | |||
5096 | /* Enable auto power on RC when GPIO states are changed */ | 5200 | /* Enable auto power on RC when GPIO states are changed */ |
5097 | regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL1, 0xff, 0xff); | 5201 | regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL1, 0xff, 0xff); |
5098 | 5202 | ||
@@ -5115,24 +5219,21 @@ static int rt5677_init_irq(struct i2c_client *i2c) | |||
5115 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, | 5219 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, |
5116 | RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); | 5220 | RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); |
5117 | 5221 | ||
5118 | ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq, | 5222 | /* Ready to listen for interrupts */ |
5119 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, | 5223 | rt5677->domain = irq_domain_add_linear(i2c->dev.of_node, |
5120 | &rt5677_irq_chip, &rt5677->irq_data); | 5224 | RT5677_IRQ_NUM, &rt5677_domain_ops, rt5677); |
5121 | 5225 | if (!rt5677->domain) { | |
5122 | if (ret != 0) { | 5226 | dev_err(&i2c->dev, "Failed to create IRQ domain\n"); |
5123 | dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret); | 5227 | return -ENOMEM; |
5124 | return ret; | ||
5125 | } | 5228 | } |
5126 | 5229 | ||
5127 | return 0; | 5230 | ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, rt5677_irq, |
5128 | } | 5231 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, |
5232 | "rt5677", rt5677); | ||
5233 | if (ret) | ||
5234 | dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret); | ||
5129 | 5235 | ||
5130 | static void rt5677_free_irq(struct i2c_client *i2c) | 5236 | return ret; |
5131 | { | ||
5132 | struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); | ||
5133 | |||
5134 | if (rt5677->irq_data) | ||
5135 | regmap_del_irq_chip(i2c->irq, rt5677->irq_data); | ||
5136 | } | 5237 | } |
5137 | 5238 | ||
5138 | static int rt5677_i2c_probe(struct i2c_client *i2c) | 5239 | static int rt5677_i2c_probe(struct i2c_client *i2c) |
@@ -5146,6 +5247,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c) | |||
5146 | if (rt5677 == NULL) | 5247 | if (rt5677 == NULL) |
5147 | return -ENOMEM; | 5248 | return -ENOMEM; |
5148 | 5249 | ||
5250 | rt5677->dev = &i2c->dev; | ||
5149 | i2c_set_clientdata(i2c, rt5677); | 5251 | i2c_set_clientdata(i2c, rt5677); |
5150 | 5252 | ||
5151 | if (i2c->dev.of_node) { | 5253 | if (i2c->dev.of_node) { |
@@ -5259,7 +5361,9 @@ static int rt5677_i2c_probe(struct i2c_client *i2c) | |||
5259 | RT5677_MICBIAS1_CTRL_VDD_3_3V); | 5361 | RT5677_MICBIAS1_CTRL_VDD_3_3V); |
5260 | 5362 | ||
5261 | rt5677_init_gpio(i2c); | 5363 | rt5677_init_gpio(i2c); |
5262 | rt5677_init_irq(i2c); | 5364 | ret = rt5677_init_irq(i2c); |
5365 | if (ret) | ||
5366 | dev_err(&i2c->dev, "Failed to initialize irq: %d\n", ret); | ||
5263 | 5367 | ||
5264 | return devm_snd_soc_register_component(&i2c->dev, | 5368 | return devm_snd_soc_register_component(&i2c->dev, |
5265 | &soc_component_dev_rt5677, | 5369 | &soc_component_dev_rt5677, |
@@ -5268,7 +5372,6 @@ static int rt5677_i2c_probe(struct i2c_client *i2c) | |||
5268 | 5372 | ||
5269 | static int rt5677_i2c_remove(struct i2c_client *i2c) | 5373 | static int rt5677_i2c_remove(struct i2c_client *i2c) |
5270 | { | 5374 | { |
5271 | rt5677_free_irq(i2c); | ||
5272 | rt5677_free_gpio(i2c); | 5375 | rt5677_free_gpio(i2c); |
5273 | 5376 | ||
5274 | return 0; | 5377 | return 0; |
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index c26edd387e34..45633d8b6a19 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h | |||
@@ -1749,6 +1749,7 @@ enum { | |||
1749 | RT5677_IRQ_JD1, | 1749 | RT5677_IRQ_JD1, |
1750 | RT5677_IRQ_JD2, | 1750 | RT5677_IRQ_JD2, |
1751 | RT5677_IRQ_JD3, | 1751 | RT5677_IRQ_JD3, |
1752 | RT5677_IRQ_NUM, | ||
1752 | }; | 1753 | }; |
1753 | 1754 | ||
1754 | enum rt5677_type { | 1755 | enum rt5677_type { |
@@ -1827,6 +1828,7 @@ struct rt5677_platform_data { | |||
1827 | 1828 | ||
1828 | struct rt5677_priv { | 1829 | struct rt5677_priv { |
1829 | struct snd_soc_component *component; | 1830 | struct snd_soc_component *component; |
1831 | struct device *dev; | ||
1830 | struct rt5677_platform_data pdata; | 1832 | struct rt5677_platform_data pdata; |
1831 | struct regmap *regmap, *regmap_physical; | 1833 | struct regmap *regmap, *regmap_physical; |
1832 | const struct firmware *fw1, *fw2; | 1834 | const struct firmware *fw1, *fw2; |
@@ -1847,9 +1849,13 @@ struct rt5677_priv { | |||
1847 | struct gpio_chip gpio_chip; | 1849 | struct gpio_chip gpio_chip; |
1848 | #endif | 1850 | #endif |
1849 | bool dsp_vad_en; | 1851 | bool dsp_vad_en; |
1850 | struct regmap_irq_chip_data *irq_data; | ||
1851 | bool is_dsp_mode; | 1852 | bool is_dsp_mode; |
1852 | bool is_vref_slow; | 1853 | bool is_vref_slow; |
1854 | |||
1855 | /* Interrupt handling */ | ||
1856 | struct irq_domain *domain; | ||
1857 | struct mutex irq_lock; | ||
1858 | unsigned int irq_en; | ||
1853 | }; | 1859 | }; |
1854 | 1860 | ||
1855 | int rt5677_sel_asrc_clk_src(struct snd_soc_component *component, | 1861 | int rt5677_sel_asrc_clk_src(struct snd_soc_component *component, |