Skip to content

Commit

Permalink
extcon: arizona: Implement button detection support
Browse files Browse the repository at this point in the history
As well as identifying accessories the accessory detection hardware on
Arizona class devices can also detect a number of buttons which we should
report via the input API.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Mark Brown authored and Greg Kroah-Hartman committed Aug 16, 2012
1 parent 689ae23 commit 34efe4d
Showing 1 changed file with 65 additions and 7 deletions.
72 changes: 65 additions & 7 deletions drivers/extcon/extcon-arizona.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
Expand All @@ -30,11 +31,14 @@
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>

#define ARIZONA_NUM_BUTTONS 6

struct arizona_extcon_info {
struct device *dev;
struct arizona *arizona;
struct mutex lock;
struct regulator *micvdd;
struct input_dev *input;

int micd_mode;
const struct arizona_micd_config *micd_modes;
Expand All @@ -54,6 +58,18 @@ static const struct arizona_micd_config micd_default_modes[] = {
{ 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
};

static struct {
u16 status;
int report;
} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = {
{ 0x1, BTN_0 },
{ 0x2, BTN_1 },
{ 0x4, BTN_2 },
{ 0x8, BTN_3 },
{ 0x10, BTN_4 },
{ 0x20, BTN_5 },
};

#define ARIZONA_CABLE_MECHANICAL 0
#define ARIZONA_CABLE_MICROPHONE 1
#define ARIZONA_CABLE_HEADPHONE 2
Expand Down Expand Up @@ -133,6 +149,7 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)

if (change) {
regulator_disable(info->micvdd);
pm_runtime_mark_last_busy(info->dev);
pm_runtime_put_autosuspend(info->dev);
}
}
Expand All @@ -141,8 +158,8 @@ static irqreturn_t arizona_micdet(int irq, void *data)
{
struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona;
unsigned int val;
int ret;
unsigned int val, lvl;
int ret, i;

mutex_lock(&info->lock);

Expand Down Expand Up @@ -219,13 +236,22 @@ static irqreturn_t arizona_micdet(int irq, void *data)

/*
* If we're still detecting and we detect a short then we've
* got a headphone. Otherwise it's a button press, the
* button reporting is stubbed out for now.
* got a headphone. Otherwise it's a button press.
*/
if (val & 0x3fc) {
if (info->mic) {
dev_dbg(arizona->dev, "Mic button detected\n");

lvl = val & ARIZONA_MICD_LVL_MASK;
lvl >>= ARIZONA_MICD_LVL_SHIFT;

for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
if (lvl & arizona_lvl_to_key[i].status)
input_report_key(info->input,
arizona_lvl_to_key[i].report,
1);
input_sync(info->input);

} else if (info->detecting) {
dev_dbg(arizona->dev, "Headphone detected\n");
info->detecting = false;
Expand All @@ -244,6 +270,10 @@ static irqreturn_t arizona_micdet(int irq, void *data)
}
} else {
dev_dbg(arizona->dev, "Mic button released\n");
for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
input_report_key(info->input,
arizona_lvl_to_key[i].report, 0);
input_sync(info->input);
}

handled:
Expand All @@ -258,7 +288,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona;
unsigned int val;
int ret;
int ret, i;

pm_runtime_get_sync(info->dev);

Expand Down Expand Up @@ -288,6 +318,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)

arizona_stop_mic(info);

for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
input_report_key(info->input,
arizona_lvl_to_key[i].report, 0);
input_sync(info->input);

ret = extcon_update_state(&info->edev, 0xffffffff, 0);
if (ret != 0)
dev_err(arizona->dev, "Removal report failed: %d\n",
Expand All @@ -307,7 +342,7 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
struct arizona_pdata *pdata;
struct arizona_extcon_info *info;
int ret, mode;
int ret, mode, i;

pdata = dev_get_platdata(arizona->dev);

Expand Down Expand Up @@ -382,6 +417,20 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)

arizona_extcon_set_mode(info, 0);

info->input = input_allocate_device();
if (!info->input) {
dev_err(arizona->dev, "Can't allocate input dev\n");
ret = -ENOMEM;
goto err_register;
}

for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
input_set_capability(info->input, EV_KEY,
arizona_lvl_to_key[i].report);
info->input->name = "Headset";
info->input->phys = "arizona/extcon";
info->input->dev.parent = &pdev->dev;

pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
Expand All @@ -391,7 +440,7 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
ret);
goto err_register;
goto err_input;
}

ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 1);
Expand Down Expand Up @@ -436,6 +485,12 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)

pm_runtime_put(&pdev->dev);

ret = input_register_device(info->input);
if (ret) {
dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
goto err_fall_wake;
}

return 0;

err_fall_wake:
Expand All @@ -446,6 +501,8 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0);
err_rise:
arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
err_input:
input_free_device(info->input);
err_register:
pm_runtime_disable(&pdev->dev);
extcon_dev_unregister(&info->edev);
Expand All @@ -468,6 +525,7 @@ static int __devexit arizona_extcon_remove(struct platform_device *pdev)
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
ARIZONA_JD1_ENA, 0);
arizona_clk32k_disable(arizona);
input_unregister_device(info->input);
extcon_dev_unregister(&info->edev);

return 0;
Expand Down

0 comments on commit 34efe4d

Please sign in to comment.