aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/extcon')
-rw-r--r--drivers/extcon/Kconfig8
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-arizona.c491
3 files changed, 500 insertions, 0 deletions
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 29c5cf852efc..bb385ac629a8 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -29,4 +29,12 @@ config EXTCON_MAX8997
29 Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory 29 Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory
30 detector and switch. 30 detector and switch.
31 31
32config EXTCON_ARIZONA
33 tristate "Wolfson Arizona EXTCON support"
34 depends on MFD_ARIZONA
35 help
36 Say Y here to enable support for external accessory detection
37 with Wolfson Arizona devices. These are audio CODECs with
38 advanced audio accessory detection support.
39
32endif # MULTISTATE_SWITCH 40endif # MULTISTATE_SWITCH
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 86020bdb6da0..e932caaa311c 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -5,3 +5,4 @@
5obj-$(CONFIG_EXTCON) += extcon_class.o 5obj-$(CONFIG_EXTCON) += extcon_class.o
6obj-$(CONFIG_EXTCON_GPIO) += extcon_gpio.o 6obj-$(CONFIG_EXTCON_GPIO) += extcon_gpio.o
7obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o 7obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
8obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
new file mode 100644
index 000000000000..b068bc9defe1
--- /dev/null
+++ b/drivers/extcon/extcon-arizona.c
@@ -0,0 +1,491 @@
1/*
2 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
3 *
4 * Copyright (C) 2012 Wolfson Microelectronics plc
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/interrupt.h>
22#include <linux/err.h>
23#include <linux/gpio.h>
24#include <linux/platform_device.h>
25#include <linux/pm_runtime.h>
26#include <linux/regulator/consumer.h>
27#include <linux/extcon.h>
28
29#include <linux/mfd/arizona/core.h>
30#include <linux/mfd/arizona/pdata.h>
31#include <linux/mfd/arizona/registers.h>
32
33struct arizona_extcon_info {
34 struct device *dev;
35 struct arizona *arizona;
36 struct mutex lock;
37 struct regulator *micvdd;
38
39 int micd_mode;
40 const struct arizona_micd_config *micd_modes;
41 int micd_num_modes;
42
43 bool micd_reva;
44
45 bool mic;
46 bool detecting;
47 int jack_flips;
48
49 struct extcon_dev edev;
50};
51
52static const struct arizona_micd_config micd_default_modes[] = {
53 { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
54 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
55};
56
57#define ARIZONA_CABLE_MECHANICAL "Mechanical"
58#define ARIZONA_CABLE_HEADPHONE "Headphone"
59#define ARIZONA_CABLE_HEADSET "Headset"
60
61static const char *arizona_cable[] = {
62 ARIZONA_CABLE_MECHANICAL,
63 ARIZONA_CABLE_HEADSET,
64 ARIZONA_CABLE_HEADPHONE,
65 NULL,
66};
67
68static const u32 arizona_exclusions[] = {
69 0x6, /* Headphone and headset */
70 0,
71};
72
73static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
74{
75 struct arizona *arizona = info->arizona;
76
77 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
78 info->micd_modes[mode].gpio);
79 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
80 ARIZONA_MICD_BIAS_SRC_MASK,
81 info->micd_modes[mode].bias);
82 regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
83 ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
84
85 info->micd_mode = mode;
86
87 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
88}
89
90static void arizona_start_mic(struct arizona_extcon_info *info)
91{
92 struct arizona *arizona = info->arizona;
93 bool change;
94 int ret;
95
96 info->detecting = true;
97 info->mic = false;
98 info->jack_flips = 0;
99
100 /* Microphone detection can't use idle mode */
101 pm_runtime_get(info->dev);
102
103 ret = regulator_enable(info->micvdd);
104 if (ret != 0) {
105 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
106 ret);
107 }
108
109 if (info->micd_reva) {
110 regmap_write(arizona->regmap, 0x80, 0x3);
111 regmap_write(arizona->regmap, 0x294, 0);
112 regmap_write(arizona->regmap, 0x80, 0x0);
113 }
114
115 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
116 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
117 &change);
118 if (!change) {
119 regulator_disable(info->micvdd);
120 pm_runtime_put_autosuspend(info->dev);
121 }
122}
123
124static void arizona_stop_mic(struct arizona_extcon_info *info)
125{
126 struct arizona *arizona = info->arizona;
127 bool change;
128
129 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
130 ARIZONA_MICD_ENA, 0,
131 &change);
132
133 if (info->micd_reva) {
134 regmap_write(arizona->regmap, 0x80, 0x3);
135 regmap_write(arizona->regmap, 0x294, 2);
136 regmap_write(arizona->regmap, 0x80, 0x0);
137 }
138
139 if (change) {
140 regulator_disable(info->micvdd);
141 pm_runtime_put_autosuspend(info->dev);
142 }
143}
144
145static irqreturn_t arizona_micdet(int irq, void *data)
146{
147 struct arizona_extcon_info *info = data;
148 struct arizona *arizona = info->arizona;
149 unsigned int val;
150 int ret;
151
152 mutex_lock(&info->lock);
153
154 ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
155 if (ret != 0) {
156 dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
157 return IRQ_NONE;
158 }
159
160 dev_dbg(arizona->dev, "MICDET: %x\n", val);
161
162 if (!(val & ARIZONA_MICD_VALID)) {
163 dev_warn(arizona->dev, "Microphone detection state invalid\n");
164 mutex_unlock(&info->lock);
165 return IRQ_NONE;
166 }
167
168 /* Due to jack detect this should never happen */
169 if (!(val & ARIZONA_MICD_STS)) {
170 dev_warn(arizona->dev, "Detected open circuit\n");
171 info->detecting = false;
172