extcon: arizona: Implement button detection support
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>
This commit is contained in:
parent
689ae231af
commit
34efe4dc47
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -446,6 +501,8 @@ err_rise_wake:
|
|||
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);
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue