Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (55 commits)
  regulator: Voltage count for AB3100
  mfd: Convert WM8350 to use request_threaded_irq()
  mfd: Update MAINTAINERS patterns for WM831x
  mfd: Fix twl4030-power warnings
  regulator: AB3100 support
  rtc: AB3100 RTC support
  mfd: Fix ab3100-otp build failure
  mfd: OMAP: Board-specifc twl4030 DPS scripts for RX51 board
  mfd: Print warning for twl4030 out-of-order script loading
  mfd: Add support for TWL4030/5030 dynamic power switching
  mfd: AB3100 OTP readout
  regulator: Add Freescale MC13783 driver
  mfd: Add Freescale MC13783 driver
  mfd: AB3100 disable irq nosync
  mfd: AB3100 alter default setting
  mfd: AB3100 propagate error
  mfd: AB3100 accessor function cleanups
  rtc: Add support for RTCs on Wolfson WM831x devices
  regulator: get pcap data from the parent device
  input: PCAP2 misc input driver
  ...
This commit is contained in:
Linus Torvalds
2009-09-18 09:22:36 -07:00
65 changed files with 12775 additions and 124 deletions

View File

@@ -279,4 +279,24 @@ config INPUT_BFIN_ROTARY
To compile this driver as a module, choose M here: the
module will be called bfin-rotary.
config INPUT_WM831X_ON
tristate "WM831X ON pin"
depends on MFD_WM831X
help
Support the ON pin of WM831X PMICs as an input device
reporting power button status.
To compile this driver as a module, choose M here: the module
will be called wm831x_on.
config INPUT_PCAP
tristate "Motorola EZX PCAP misc input events"
depends on EZX_PCAP
help
Say Y here if you want to use Power key and Headphone button
on Motorola EZX phones.
To compile this driver as a module, choose M here: the
module will be called pcap_keys.
endif

View File

@@ -16,6 +16,7 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
@@ -26,4 +27,6 @@ obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o

View File

@@ -0,0 +1,144 @@
/*
* Input driver for PCAP events:
* * Power key
* * Headphone button
*
* Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/mfd/ezx-pcap.h>
struct pcap_keys {
struct pcap_chip *pcap;
struct input_dev *input;
};
/* PCAP2 interrupts us on keypress */
static irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys)
{
struct pcap_keys *pcap_keys = _pcap_keys;
int pirq = irq_to_pcap(pcap_keys->pcap, irq);
u32 pstat;
ezx_pcap_read(pcap_keys->pcap, PCAP_REG_PSTAT, &pstat);
pstat &= 1 << pirq;
switch (pirq) {
case PCAP_IRQ_ONOFF:
input_report_key(pcap_keys->input, KEY_POWER, !pstat);
break;
case PCAP_IRQ_MIC:
input_report_key(pcap_keys->input, KEY_HP, !pstat);
break;
}
input_sync(pcap_keys->input);
return IRQ_HANDLED;
}
static int __devinit pcap_keys_probe(struct platform_device *pdev)
{
int err = -ENOMEM;
struct pcap_keys *pcap_keys;
struct input_dev *input_dev;
pcap_keys = kmalloc(sizeof(struct pcap_keys), GFP_KERNEL);
if (!pcap_keys)
return err;
pcap_keys->pcap = dev_get_drvdata(pdev->dev.parent);
input_dev = input_allocate_device();
if (!input_dev)
goto fail;
pcap_keys->input = input_dev;
platform_set_drvdata(pdev, pcap_keys);
input_dev->name = pdev->name;
input_dev->phys = "pcap-keys/input0";
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(KEY_POWER, input_dev->keybit);
__set_bit(KEY_HP, input_dev->keybit);
err = input_register_device(input_dev);
if (err)
goto fail_allocate;
err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF),
pcap_keys_handler, 0, "Power key", pcap_keys);
if (err)
goto fail_register;
err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC),
pcap_keys_handler, 0, "Headphone button", pcap_keys);
if (err)
goto fail_pwrkey;
return 0;
fail_pwrkey:
free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys);
fail_register:
input_unregister_device(input_dev);
goto fail;
fail_allocate:
input_free_device(input_dev);
fail:
kfree(pcap_keys);
return err;
}
static int __devexit pcap_keys_remove(struct platform_device *pdev)
{
struct pcap_keys *pcap_keys = platform_get_drvdata(pdev);
free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys);
free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), pcap_keys);
input_unregister_device(pcap_keys->input);
kfree(pcap_keys);
return 0;
}
static struct platform_driver pcap_keys_device_driver = {
.probe = pcap_keys_probe,
.remove = __devexit_p(pcap_keys_remove),
.driver = {
.name = "pcap-keys",
.owner = THIS_MODULE,
}
};
static int __init pcap_keys_init(void)
{
return platform_driver_register(&pcap_keys_device_driver);
};
static void __exit pcap_keys_exit(void)
{
platform_driver_unregister(&pcap_keys_device_driver);
};
module_init(pcap_keys_init);
module_exit(pcap_keys_exit);
MODULE_DESCRIPTION("Motorola PCAP2 input events driver");
MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pcap_keys");

View File

@@ -0,0 +1,163 @@
/**
* wm831x-on.c - WM831X ON pin driver
*
* Copyright (C) 2009 Wolfson Microelectronics plc
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file "COPYING" in the main directory of this
* archive for more details.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/mfd/wm831x/core.h>
struct wm831x_on {
struct input_dev *dev;
struct delayed_work work;
struct wm831x *wm831x;
};
/*
* The chip gives us an interrupt when the ON pin is asserted but we
* then need to poll to see when the pin is deasserted.
*/
static void wm831x_poll_on(struct work_struct *work)
{
struct wm831x_on *wm831x_on = container_of(work, struct wm831x_on,
work.work);
struct wm831x *wm831x = wm831x_on->wm831x;
int poll, ret;
ret = wm831x_reg_read(wm831x, WM831X_ON_PIN_CONTROL);
if (ret >= 0) {
poll = !(ret & WM831X_ON_PIN_STS);
input_report_key(wm831x_on->dev, KEY_POWER, poll);
input_sync(wm831x_on->dev);
} else {
dev_err(wm831x->dev, "Failed to read ON status: %d\n", ret);
poll = 1;
}
if (poll)
schedule_delayed_work(&wm831x_on->work, 100);
}
static irqreturn_t wm831x_on_irq(int irq, void *data)
{
struct wm831x_on *wm831x_on = data;
schedule_delayed_work(&wm831x_on->work, 0);
return IRQ_HANDLED;
}
static int __devinit wm831x_on_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_on *wm831x_on;
int irq = platform_get_irq(pdev, 0);
int ret;
wm831x_on = kzalloc(sizeof(struct wm831x_on), GFP_KERNEL);
if (!wm831x_on) {
dev_err(&pdev->dev, "Can't allocate data\n");
return -ENOMEM;
}
wm831x_on->wm831x = wm831x;
INIT_DELAYED_WORK(&wm831x_on->work, wm831x_poll_on);
wm831x_on->dev = input_allocate_device();
if (!wm831x_on->dev) {
dev_err(&pdev->dev, "Can't allocate input dev\n");
ret = -ENOMEM;
goto err;
}
wm831x_on->dev->evbit[0] = BIT_MASK(EV_KEY);
wm831x_on->dev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
wm831x_on->dev->name = "wm831x_on";
wm831x_on->dev->phys = "wm831x_on/input0";
wm831x_on->dev->dev.parent = &pdev->dev;
ret = wm831x_request_irq(wm831x, irq, wm831x_on_irq,
IRQF_TRIGGER_RISING, "wm831x_on", wm831x_on);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to request IRQ: %d\n", ret);
goto err_input_dev;
}
ret = input_register_device(wm831x_on->dev);
if (ret) {
dev_dbg(&pdev->dev, "Can't register input device: %d\n", ret);
goto err_irq;
}
platform_set_drvdata(pdev, wm831x_on);
return 0;
err_irq:
wm831x_free_irq(wm831x, irq, NULL);
err_input_dev:
input_free_device(wm831x_on->dev);
err:
kfree(wm831x_on);
return ret;
}
static int __devexit wm831x_on_remove(struct platform_device *pdev)
{
struct wm831x_on *wm831x_on = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
wm831x_free_irq(wm831x_on->wm831x, irq, wm831x_on);
cancel_delayed_work_sync(&wm831x_on->work);
input_unregister_device(wm831x_on->dev);
kfree(wm831x_on);
return 0;
}
static struct platform_driver wm831x_on_driver = {
.probe = wm831x_on_probe,
.remove = __devexit_p(wm831x_on_remove),
.driver = {
.name = "wm831x-on",
.owner = THIS_MODULE,
},
};
static int __init wm831x_on_init(void)
{
return platform_driver_register(&wm831x_on_driver);
}
module_init(wm831x_on_init);
static void __exit wm831x_on_exit(void)
{
platform_driver_unregister(&wm831x_on_driver);
}
module_exit(wm831x_on_exit);
MODULE_ALIAS("platform:wm831x-on");
MODULE_DESCRIPTION("WM831x ON pin");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");

View File

@@ -510,4 +510,13 @@ config TOUCHSCREEN_W90X900
To compile this driver as a module, choose M here: the
module will be called w90p910_ts.
config TOUCHSCREEN_PCAP
tristate "Motorola PCAP touchscreen"
depends on EZX_PCAP
help
Say Y here if you have a Motorola EZX telephone and
want to enable support for the built-in touchscreen.
To compile this driver as a module, choose M here: the
module will be called pcap_ts.
endif

View File

@@ -40,3 +40,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o

View File

@@ -0,0 +1,271 @@
/*
* Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform.
*
* Copyright (C) 2006 Harald Welte <laforge@openezx.org>
* Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/pm.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/mfd/ezx-pcap.h>
struct pcap_ts {
struct pcap_chip *pcap;
struct input_dev *input;
struct delayed_work work;
u16 x, y;
u16 pressure;
u8 read_state;
};
#define SAMPLE_DELAY 20 /* msecs */
#define X_AXIS_MIN 0
#define X_AXIS_MAX 1023
#define Y_AXIS_MAX X_AXIS_MAX
#define Y_AXIS_MIN X_AXIS_MIN
#define PRESSURE_MAX X_AXIS_MAX
#define PRESSURE_MIN X_AXIS_MIN
static void pcap_ts_read_xy(void *data, u16 res[2])
{
struct pcap_ts *pcap_ts = data;
switch (pcap_ts->read_state) {
case PCAP_ADC_TS_M_PRESSURE:
/* pressure reading is unreliable */
if (res[0] > PRESSURE_MIN && res[0] < PRESSURE_MAX)
pcap_ts->pressure = res[0];
pcap_ts->read_state = PCAP_ADC_TS_M_XY;
schedule_delayed_work(&pcap_ts->work, 0);
break;
case PCAP_ADC_TS_M_XY:
pcap_ts->y = res[0];
pcap_ts->x = res[1];
if (pcap_ts->x <= X_AXIS_MIN || pcap_ts->x >= X_AXIS_MAX ||
pcap_ts->y <= Y_AXIS_MIN || pcap_ts->y >= Y_AXIS_MAX) {
/* pen has been released */
input_report_abs(pcap_ts->input, ABS_PRESSURE, 0);
input_report_key(pcap_ts->input, BTN_TOUCH, 0);
pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY;
schedule_delayed_work(&pcap_ts->work, 0);
} else {
/* pen is touching the screen */
input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x);
input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y);
input_report_key(pcap_ts->input, BTN_TOUCH, 1);
input_report_abs(pcap_ts->input, ABS_PRESSURE,
pcap_ts->pressure);
/* switch back to pressure read mode */
pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE;
schedule_delayed_work(&pcap_ts->work,
msecs_to_jiffies(SAMPLE_DELAY));
}
input_sync(pcap_ts->input);
break;
default:
dev_warn(&pcap_ts->input->dev,
"pcap_ts: Warning, unhandled read_state %d\n",
pcap_ts->read_state);
break;
}
}
static void pcap_ts_work(struct work_struct *work)
{
struct delayed_work *dw = container_of(work, struct delayed_work, work);
struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work);
u8 ch[2];
pcap_set_ts_bits(pcap_ts->pcap,
pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY)
return;
/* start adc conversion */
ch[0] = PCAP_ADC_CH_TS_X1;
ch[1] = PCAP_ADC_CH_TS_Y1;
pcap_adc_async(pcap_ts->pcap, PCAP_ADC_BANK_1, 0, ch,
pcap_ts_read_xy, pcap_ts);
}
static irqreturn_t pcap_ts_event_touch(int pirq, void *data)
{
struct pcap_ts *pcap_ts = data;
if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) {
pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE;
schedule_delayed_work(&pcap_ts->work, 0);
}
return IRQ_HANDLED;
}
static int pcap_ts_open(struct input_dev *dev)
{
struct pcap_ts *pcap_ts = input_get_drvdata(dev);
pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY;
schedule_delayed_work(&pcap_ts->work, 0);
return 0;
}
static void pcap_ts_close(struct input_dev *dev)
{
struct pcap_ts *pcap_ts = input_get_drvdata(dev);
cancel_delayed_work_sync(&pcap_ts->work);
pcap_ts->read_state = PCAP_ADC_TS_M_NONTS;
pcap_set_ts_bits(pcap_ts->pcap,
pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
}
static int __devinit pcap_ts_probe(struct platform_device *pdev)
{
struct input_dev *input_dev;
struct pcap_ts *pcap_ts;
int err = -ENOMEM;
pcap_ts = kzalloc(sizeof(*pcap_ts), GFP_KERNEL);
if (!pcap_ts)
return err;
pcap_ts->pcap = dev_get_drvdata(pdev->dev.parent);
platform_set_drvdata(pdev, pcap_ts);
input_dev = input_allocate_device();
if (!input_dev)
goto fail;
INIT_DELAYED_WORK(&pcap_ts->work, pcap_ts_work);
pcap_ts->read_state = PCAP_ADC_TS_M_NONTS;
pcap_set_ts_bits(pcap_ts->pcap,
pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
pcap_ts->input = input_dev;
input_set_drvdata(input_dev, pcap_ts);
input_dev->name = "pcap-touchscreen";
input_dev->phys = "pcap_ts/input0";
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0002;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &pdev->dev;
input_dev->open = pcap_ts_open;
input_dev->close = pcap_ts_close;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN,
PRESSURE_MAX, 0, 0);
err = input_register_device(pcap_ts->input);
if (err)
goto fail_allocate;
err = request_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS),
pcap_ts_event_touch, 0, "Touch Screen", pcap_ts);
if (err)
goto fail_register;
return 0;
fail_register:
input_unregister_device(input_dev);
goto fail;
fail_allocate:
input_free_device(input_dev);
fail:
kfree(pcap_ts);
return err;
}
static int __devexit pcap_ts_remove(struct platform_device *pdev)
{
struct pcap_ts *pcap_ts = platform_get_drvdata(pdev);
free_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), pcap_ts);
cancel_delayed_work_sync(&pcap_ts->work);
input_unregister_device(pcap_ts->input);
kfree(pcap_ts);
return 0;
}
#ifdef CONFIG_PM
static int pcap_ts_suspend(struct device *dev)
{
struct pcap_ts *pcap_ts = dev_get_drvdata(dev);
pcap_set_ts_bits(pcap_ts->pcap, PCAP_ADC_TS_REF_LOWPWR);
return 0;
}
static int pcap_ts_resume(struct device *dev)
{
struct pcap_ts *pcap_ts = dev_get_drvdata(dev);
pcap_set_ts_bits(pcap_ts->pcap,
pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
return 0;
}
static struct dev_pm_ops pcap_ts_pm_ops = {
.suspend = pcap_ts_suspend,
.resume = pcap_ts_resume,
};
#define PCAP_TS_PM_OPS (&pcap_ts_pm_ops)
#else
#define PCAP_TS_PM_OPS NULL
#endif
static struct platform_driver pcap_ts_driver = {
.probe = pcap_ts_probe,
.remove = __devexit_p(pcap_ts_remove),
.driver = {
.name = "pcap-ts",
.owner = THIS_MODULE,
.pm = PCAP_TS_PM_OPS,
},
};
static int __init pcap_ts_init(void)
{
return platform_driver_register(&pcap_ts_driver);
}
static void __exit pcap_ts_exit(void)
{
platform_driver_unregister(&pcap_ts_driver);
}
module_init(pcap_ts_init);
module_exit(pcap_ts_exit);
MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver");
MODULE_AUTHOR("Daniel Ribeiro / Harald Welte");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pcap_ts");