summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/rt5677.c
diff options
context:
space:
mode:
authorOder Chiou <oder_chiou@realtek.com>2014-10-16 11:24:26 -0700
committerMark Brown <broonie@kernel.org>2014-10-22 11:43:14 +0100
commit5e3363ad1b7b2e1f197a3f56b01e21cb155ad454 (patch)
treed48dcf9a18002a24588c4f855388d2b7fbbf5452 /sound/soc/codecs/rt5677.c
parentac884fc47b7750b1e7eaf04f0236610c84ceee54 (diff)
ASoC: rt5677: add GPIO IRQ support
This allows to enable Mic Jack detection feature Signed-off-by: Oder Chiou <oder_chiou@realtek.com> Modified-by: Anatol Pomozov <anatol.pomozov@gmail.com> Signed-off-by: Anatol Pomozov <anatol.pomozov@gmail.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/codecs/rt5677.c')
-rw-r--r--sound/soc/codecs/rt5677.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index d17d079fdcf3..6c73dfd22a0c 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -3614,6 +3614,46 @@ static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
}
}
+static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+ struct regmap_irq_chip_data *data = rt5677->irq_data;
+ int irq;
+
+ if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) {
+ if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) ||
+ (rt5677->pdata.jd1_gpio == 2 &&
+ offset == RT5677_GPIO2) ||
+ (rt5677->pdata.jd1_gpio == 3 &&
+ offset == RT5677_GPIO3)) {
+ irq = RT5677_IRQ_JD1;
+ } else {
+ return -ENXIO;
+ }
+ }
+
+ if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) {
+ if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) ||
+ (rt5677->pdata.jd2_gpio == 2 &&
+ offset == RT5677_GPIO5) ||
+ (rt5677->pdata.jd2_gpio == 3 &&
+ offset == RT5677_GPIO6)) {
+ irq = RT5677_IRQ_JD2;
+ } else if ((rt5677->pdata.jd3_gpio == 1 &&
+ offset == RT5677_GPIO4) ||
+ (rt5677->pdata.jd3_gpio == 2 &&
+ offset == RT5677_GPIO5) ||
+ (rt5677->pdata.jd3_gpio == 3 &&
+ offset == RT5677_GPIO6)) {
+ irq = RT5677_IRQ_JD3;
+ } else {
+ return -ENXIO;
+ }
+ }
+
+ return regmap_irq_get_virq(data, irq);
+}
+
static struct gpio_chip rt5677_template_chip = {
.label = "rt5677",
.owner = THIS_MODULE,
@@ -3621,6 +3661,7 @@ static struct gpio_chip rt5677_template_chip = {
.set = rt5677_gpio_set,
.direction_input = rt5677_gpio_direction_in,
.get = rt5677_gpio_get,
+ .to_irq = rt5677_to_irq,
.can_sleep = 1,
};
@@ -3685,6 +3726,31 @@ static int rt5677_probe(struct snd_soc_codec *codec)
for (i = 0; i < RT5677_GPIO_NUM; i++)
rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]);
+ if (rt5677->irq_data) {
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, 0x8000,
+ 0x8000);
+ regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x0018,
+ 0x0008);
+
+ if (rt5677->pdata.jd1_gpio)
+ regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+ RT5677_SEL_GPIO_JD1_MASK,
+ rt5677->pdata.jd1_gpio <<
+ RT5677_SEL_GPIO_JD1_SFT);
+
+ if (rt5677->pdata.jd2_gpio)
+ regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+ RT5677_SEL_GPIO_JD2_MASK,
+ rt5677->pdata.jd2_gpio <<
+ RT5677_SEL_GPIO_JD2_SFT);
+
+ if (rt5677->pdata.jd3_gpio)
+ regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+ RT5677_SEL_GPIO_JD3_MASK,
+ rt5677->pdata.jd3_gpio <<
+ RT5677_SEL_GPIO_JD3_SFT);
+ }
+
mutex_init(&rt5677->dsp_cmd_lock);
return 0;
@@ -3915,9 +3981,74 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
of_property_read_u8_array(np, "realtek,gpio-config",
rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
+ of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio);
+ of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio);
+ of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio);
+
return 0;
}
+static struct regmap_irq rt5677_irqs[] = {
+ [RT5677_IRQ_JD1] = {
+ .reg_offset = 0,
+ .mask = RT5677_EN_IRQ_GPIO_JD1,
+ },
+ [RT5677_IRQ_JD2] = {
+ .reg_offset = 0,
+ .mask = RT5677_EN_IRQ_GPIO_JD2,
+ },
+ [RT5677_IRQ_JD3] = {
+ .reg_offset = 0,
+ .mask = RT5677_EN_IRQ_GPIO_JD3,
+ },
+};
+
+static struct regmap_irq_chip rt5677_irq_chip = {
+ .name = "rt5677",
+ .irqs = rt5677_irqs,
+ .num_irqs = ARRAY_SIZE(rt5677_irqs),
+
+ .num_regs = 1,
+ .status_base = RT5677_IRQ_CTRL1,
+ .mask_base = RT5677_IRQ_CTRL1,
+ .mask_invert = 1,
+};
+
+int rt5677_irq_init(struct i2c_client *i2c)
+{
+ int ret;
+ struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+ if (!rt5677->pdata.jd1_gpio &&
+ !rt5677->pdata.jd2_gpio &&
+ !rt5677->pdata.jd3_gpio)
+ return 0;
+
+ if (!i2c->irq) {
+ dev_err(&i2c->dev, "No interrupt specified\n");
+ return -EINVAL;
+ }
+
+ ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
+ &rt5677_irq_chip, &rt5677->irq_data);
+
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+void rt5677_irq_exit(struct i2c_client *i2c)
+{
+ struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+ if (rt5677->irq_data)
+ regmap_del_irq_chip(i2c->irq, rt5677->irq_data);
+}
+
static int rt5677_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -4015,6 +4146,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
}
rt5677_init_gpio(i2c);
+ rt5677_irq_init(i2c);
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
rt5677_dai, ARRAY_SIZE(rt5677_dai));
@@ -4022,6 +4154,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
static int rt5677_i2c_remove(struct i2c_client *i2c)
{
+ rt5677_irq_exit(i2c);
+
snd_soc_unregister_codec(&i2c->dev);
rt5677_free_gpio(i2c);