summaryrefslogtreecommitdiffstats
path: root/drivers/extcon/extcon-arizona.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/extcon/extcon-arizona.c')
-rw-r--r--drivers/extcon/extcon-arizona.c106
1 files changed, 88 insertions, 18 deletions
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 4b9f09cc38d8..4479781ee941 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -43,11 +43,18 @@
#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
+#define ARIZONA_TST_CAP_DEFAULT 0x3
+#define ARIZONA_TST_CAP_CLAMP 0x1
+
#define ARIZONA_HPDET_MAX 10000
#define HPDET_DEBOUNCE 500
#define DEFAULT_MICD_TIMEOUT 2000
+#define QUICK_HEADPHONE_MAX_OHM 3
+#define MICROPHONE_MIN_OHM 1257
+#define MICROPHONE_MAX_OHM 30000
+
#define MICD_DBTIME_TWO_READINGS 2
#define MICD_DBTIME_FOUR_READINGS 4
@@ -117,12 +124,15 @@ static const struct arizona_micd_range micd_default_ranges[] = {
{ .max = 430, .key = BTN_5 },
};
+/* The number of levels in arizona_micd_levels valid for button thresholds */
+#define ARIZONA_NUM_MICD_BUTTON_LEVELS 64
+
static const int arizona_micd_levels[] = {
3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
- 1257,
+ 1257, 30000,
};
static const unsigned int arizona_cable[] = {
@@ -140,6 +150,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
{
struct arizona *arizona = info->arizona;
unsigned int mask = 0, val = 0;
+ unsigned int cap_sel = 0;
int ret;
switch (arizona->type) {
@@ -147,10 +158,21 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
case WM8280:
mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
ARIZONA_HP1L_SHRTI;
- if (clamp)
+ if (clamp) {
val = ARIZONA_HP1L_SHRTO;
- else
+ cap_sel = ARIZONA_TST_CAP_CLAMP;
+ } else {
val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
+ cap_sel = ARIZONA_TST_CAP_DEFAULT;
+ }
+
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_HP_TEST_CTRL_1,
+ ARIZONA_HP1_TST_CAP_SEL_MASK,
+ cap_sel);
+ if (ret != 0)
+ dev_warn(arizona->dev,
+ "Failed to set TST_CAP_SEL: %d\n", ret);
break;
default:
mask = ARIZONA_RMV_SHRT_HP1L;
@@ -270,6 +292,7 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
struct arizona *arizona = info->arizona;
bool change;
int ret;
+ unsigned int mode;
/* Microphone detection can't use idle mode */
pm_runtime_get(info->dev);
@@ -295,9 +318,14 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
regmap_write(arizona->regmap, 0x80, 0x0);
}
+ if (info->detecting && arizona->pdata.micd_software_compare)
+ mode = ARIZONA_ACCDET_MODE_ADC;
+ else
+ mode = ARIZONA_ACCDET_MODE_MIC;
+
regmap_update_bits(arizona->regmap,
ARIZONA_ACCESSORY_DETECT_MODE_1,
- ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
+ ARIZONA_ACCDET_MODE_MASK, mode);
arizona_extcon_pulse_micbias(info);
@@ -804,6 +832,37 @@ static void arizona_micd_detect(struct work_struct *work)
return;
}
+ if (info->detecting && arizona->pdata.micd_software_compare) {
+ /* Must disable MICD before we read the ADCVAL */
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA, 0);
+ ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
+ if (ret != 0) {
+ dev_err(arizona->dev,
+ "Failed to read MICDET_ADCVAL: %d\n",
+ ret);
+ mutex_unlock(&info->lock);
+ return;
+ }
+
+ dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
+
+ val &= ARIZONA_MICDET_ADCVAL_MASK;
+ if (val < ARRAY_SIZE(arizona_micd_levels))
+ val = arizona_micd_levels[val];
+ else
+ val = INT_MAX;
+
+ if (val <= QUICK_HEADPHONE_MAX_OHM)
+ val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
+ else if (val <= MICROPHONE_MIN_OHM)
+ val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
+ else if (val <= MICROPHONE_MAX_OHM)
+ val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
+ else
+ val = ARIZONA_MICD_LVL_8;
+ }
+
for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
if (ret != 0) {
@@ -932,10 +991,17 @@ static void arizona_micd_detect(struct work_struct *work)
}
handled:
- if (info->detecting)
+ if (info->detecting) {
+ if (arizona->pdata.micd_software_compare)
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA,
+ ARIZONA_MICD_ENA);
+
queue_delayed_work(system_power_efficient_wq,
&info->micd_timeout_work,
msecs_to_jiffies(info->micd_timeout));
+ }
pm_runtime_mark_last_busy(info->dev);
mutex_unlock(&info->lock);
@@ -991,12 +1057,9 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
mutex_lock(&info->lock);
- if (arizona->pdata.jd_gpio5) {
+ if (info->micd_clamp) {
mask = ARIZONA_MICD_CLAMP_STS;
- if (arizona->pdata.jd_invert)
- present = ARIZONA_MICD_CLAMP_STS;
- else
- present = 0;
+ present = 0;
} else {
mask = ARIZONA_JD1_STS;
if (arizona->pdata.jd_invert)
@@ -1055,9 +1118,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
msecs_to_jiffies(HPDET_DEBOUNCE));
}
- regmap_update_bits(arizona->regmap,
- ARIZONA_JACK_DETECT_DEBOUNCE,
- ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
+ if (info->micd_clamp || !arizona->pdata.jd_invert)
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB |
+ ARIZONA_JD1_DB, 0);
} else {
dev_dbg(arizona->dev, "Detected jack removal\n");
@@ -1259,6 +1324,10 @@ static int arizona_extcon_probe(struct platform_device *pdev)
info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
}
+ if (arizona->pdata.gpsw > 0)
+ regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
+ ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
+
if (arizona->pdata.micd_pol_gpio > 0) {
if (info->micd_modes[0].gpio)
mode = GPIOF_OUT_INIT_HIGH;
@@ -1335,7 +1404,8 @@ static int arizona_extcon_probe(struct platform_device *pdev)
break;
}
- BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
+ BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
+ ARIZONA_NUM_MICD_BUTTON_LEVELS);
if (arizona->pdata.num_micd_ranges) {
info->micd_ranges = pdata->micd_ranges;
@@ -1368,11 +1438,11 @@ static int arizona_extcon_probe(struct platform_device *pdev)
/* Set up all the buttons the user specified */
for (i = 0; i < info->num_micd_ranges; i++) {
- for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
+ for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
break;
- if (j == ARRAY_SIZE(arizona_micd_levels)) {
+ if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
dev_err(arizona->dev, "Unsupported MICD level %d\n",
info->micd_ranges[i].max);
ret = -EINVAL;
@@ -1436,7 +1506,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
pm_runtime_idle(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
- if (arizona->pdata.jd_gpio5) {
+ if (info->micd_clamp) {
jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
} else {
@@ -1541,7 +1611,7 @@ static int arizona_extcon_remove(struct platform_device *pdev)
ARIZONA_MICD_CLAMP_CONTROL,
ARIZONA_MICD_CLAMP_MODE_MASK, 0);
- if (arizona->pdata.jd_gpio5) {
+ if (info->micd_clamp) {
jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
} else {