aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-10-28 15:54:04 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-28 15:54:04 -0700
commitb779b332d0e1ef68f40867948ae5526a3e925163 (patch)
treed2fc8bb455d696fbdb288055ce0a4f0cfcee31fd /drivers
parenta0cadc2777a71b1fde62e6417284b38e52128e88 (diff)
parent0f48285755991b73c14b6eeeee464590f490ac25 (diff)
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: (73 commits) power: Revert "power_supply: Mark twl4030_charger as broken" mfd: Fix a memory leak when unload mc13xxx-core module mfd: Fix resource reclaim for max8998 mfd: Remove unneeded ret value checking for max8998 register updates mfd: Add free max8998->ono irq in max8998_irq_exit() mfd: Fix resource reclaim in pcf50633_remove() omap4: pandaboard: fix up mmc card detect logic mfd: Fix ezx_pcap_probe error path mfd: Fix off-by-one value range checking for tps6507x mfd: Remove __devinitdata from tc6393xb_mmc_resources mfd: Add WM831x SPI support mfd: Factor out WM831x I2C I/O from the core driver mfd: Remove DEBUG defines from mc13xxx-core mfd: Fix jz4740_adc_set_enabled mfd: Add TPS658621C device ID mfd: Fix twl-irq function declaration warnings regulator: max8998 BUCK1/2 voltage change with use of GPIOs mfd: Voltages and GPIOs platform_data definitions for max8998 regulator: max8998 BUCK1/2 internal voltages and indexes defined mfd: Support for ICs compliant with max8998 ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig12
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/stmpe-gpio.c13
-rw-r--r--drivers/gpio/vx855_gpio.c332
-rw-r--r--drivers/gpio/wm8994-gpio.c1
-rw-r--r--drivers/input/misc/max8925_onkey.c72
-rw-r--r--drivers/leds/leds-88pm860x.c119
-rw-r--r--drivers/mfd/88pm860x-core.c51
-rw-r--r--drivers/mfd/Kconfig91
-rw-r--r--drivers/mfd/Makefile9
-rw-r--r--drivers/mfd/ab3100-core.c143
-rw-r--r--drivers/mfd/ab8500-core.c299
-rw-r--r--drivers/mfd/ab8500-debugfs.c652
-rw-r--r--drivers/mfd/ab8500-i2c.c105
-rw-r--r--drivers/mfd/ab8500-spi.c2
-rw-r--r--drivers/mfd/da903x.c8
-rw-r--r--drivers/mfd/ezx-pcap.c11
-rw-r--r--drivers/mfd/htc-pasic3.c7
-rw-r--r--drivers/mfd/jz4740-adc.c2
-rw-r--r--drivers/mfd/max8925-core.c11
-rw-r--r--drivers/mfd/max8998-irq.c258
-rw-r--r--drivers/mfd/max8998.c90
-rw-r--r--drivers/mfd/mc13783-core.c752
-rw-r--r--drivers/mfd/mc13xxx-core.c840
-rw-r--r--drivers/mfd/mfd-core.c18
-rw-r--r--drivers/mfd/pcf50633-core.c9
-rw-r--r--drivers/mfd/sh_mobile_sdhi.c19
-rw-r--r--drivers/mfd/stmpe.c32
-rw-r--r--drivers/mfd/tc6393xb.c2
-rw-r--r--drivers/mfd/timberdale.c14
-rw-r--r--drivers/mfd/tps6507x.c2
-rw-r--r--drivers/mfd/tps6586x.c225
-rw-r--r--drivers/mfd/twl-core.c40
-rw-r--r--drivers/mfd/twl-core.h10
-rw-r--r--drivers/mfd/twl4030-irq.c4
-rw-r--r--drivers/mfd/twl4030-power.c30
-rw-r--r--drivers/mfd/twl6030-irq.c75
-rw-r--r--drivers/mfd/vx855.c147
-rw-r--r--drivers/mfd/wm831x-core.c148
-rw-r--r--drivers/mfd/wm831x-i2c.c143
-rw-r--r--drivers/mfd/wm831x-spi.c232
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/ab8500-pwm.c168
-rw-r--r--drivers/mmc/host/omap_hsmmc.c4
-rw-r--r--drivers/mmc/host/sh_mmcif.c12
-rw-r--r--drivers/mmc/host/tmio_mmc.c30
-rw-r--r--drivers/power/Kconfig1
-rw-r--r--drivers/regulator/ab8500.c86
-rw-r--r--drivers/regulator/max8998.c270
-rw-r--r--drivers/rtc/Kconfig19
-rw-r--r--drivers/rtc/Makefile3
-rw-r--r--drivers/rtc/rtc-ab8500.c103
-rw-r--r--drivers/rtc/rtc-max8998.c300
-rw-r--r--drivers/rtc/rtc-mc13783.c428
-rw-r--r--drivers/rtc/rtc-mc13xxx.c437
-rw-r--r--drivers/usb/otg/twl4030-usb.c13
57 files changed, 5071 insertions, 1844 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index dd9b4ba8d32..3143ac795eb 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -116,6 +116,18 @@ config GPIO_SCH
This driver can also be built as a module. If so, the module
will be called sch-gpio.
+config GPIO_VX855
+ tristate "VIA VX855/VX875 GPIO"
+ depends on GPIOLIB
+ select MFD_CORE
+ select MFD_VX855
+ help
+ Support access to the VX855/VX875 GPIO lines through the gpio library.
+
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
comment "I2C GPIO expanders:"
config GPIO_MAX7300
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index da2ecde5abd..bdf3ddec065 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -40,3 +40,4 @@ obj-$(CONFIG_GPIO_SCH) += sch_gpio.o
obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o
obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o
obj-$(CONFIG_GPIO_SX150X) += sx150x.o
+obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o
diff --git a/drivers/gpio/stmpe-gpio.c b/drivers/gpio/stmpe-gpio.c
index 4e1f1b9d5e6..7c9e6a052c4 100644
--- a/drivers/gpio/stmpe-gpio.c
+++ b/drivers/gpio/stmpe-gpio.c
@@ -30,6 +30,7 @@ struct stmpe_gpio {
struct mutex irq_lock;
int irq_base;
+ unsigned norequest_mask;
/* Caches of interrupt control registers for bus_lock */
u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
@@ -103,6 +104,9 @@ static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
+ if (stmpe_gpio->norequest_mask & (1 << offset))
+ return -EINVAL;
+
return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO);
}
@@ -287,8 +291,6 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
int irq;
pdata = stmpe->pdata->gpio;
- if (!pdata)
- return -ENODEV;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -302,6 +304,7 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
stmpe_gpio->dev = &pdev->dev;
stmpe_gpio->stmpe = stmpe;
+ stmpe_gpio->norequest_mask = pdata ? pdata->norequest_mask : 0;
stmpe_gpio->chip = template_chip;
stmpe_gpio->chip.ngpio = stmpe->num_gpios;
@@ -312,11 +315,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
if (ret)
- return ret;
+ goto out_free;
ret = stmpe_gpio_irq_init(stmpe_gpio);
if (ret)
- goto out_free;
+ goto out_disable;
ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
"stmpe-gpio", stmpe_gpio);
@@ -342,6 +345,8 @@ out_freeirq:
free_irq(irq, stmpe_gpio);
out_removeirq:
stmpe_gpio_irq_remove(stmpe_gpio);
+out_disable:
+ stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
out_free:
kfree(stmpe_gpio);
return ret;
diff --git a/drivers/gpio/vx855_gpio.c b/drivers/gpio/vx855_gpio.c
new file mode 100644
index 00000000000..8a98ee5d5f6
--- /dev/null
+++ b/drivers/gpio/vx855_gpio.c
@@ -0,0 +1,332 @@
+/*
+ * Linux GPIOlib driver for the VIA VX855 integrated southbridge GPIO
+ *
+ * Copyright (C) 2009 VIA Technologies, Inc.
+ * Copyright (C) 2010 One Laptop per Child
+ * Author: Harald Welte <HaraldWelte@viatech.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#define MODULE_NAME "vx855_gpio"
+
+/* The VX855 south bridge has the following GPIO pins:
+ * GPI 0...13 General Purpose Input
+ * GPO 0...12 General Purpose Output
+ * GPIO 0...14 General Purpose I/O (Open-Drain)
+ */
+
+#define NR_VX855_GPI 14
+#define NR_VX855_GPO 13
+#define NR_VX855_GPIO 15
+
+#define NR_VX855_GPInO (NR_VX855_GPI + NR_VX855_GPO)
+#define NR_VX855_GP (NR_VX855_GPI + NR_VX855_GPO + NR_VX855_GPIO)
+
+struct vx855_gpio {
+ struct gpio_chip gpio;
+ spinlock_t lock;
+ u32 io_gpi;
+ u32 io_gpo;
+ bool gpi_reserved;
+ bool gpo_reserved;
+};
+
+/* resolve a GPIx into the corresponding bit position */
+static inline u_int32_t gpi_i_bit(int i)
+{
+ if (i < 10)
+ return 1 << i;
+ else
+ return 1 << (i + 14);
+}
+
+static inline u_int32_t gpo_o_bit(int i)
+{
+ if (i < 11)
+ return 1 << i;
+ else
+ return 1 << (i + 14);
+}
+
+static inline u_int32_t gpio_i_bit(int i)
+{
+ if (i < 14)
+ return 1 << (i + 10);
+ else
+ return 1 << (i + 14);
+}
+
+static inline u_int32_t gpio_o_bit(int i)
+{
+ if (i < 14)
+ return 1 << (i + 11);
+ else
+ return 1 << (i + 13);
+}
+
+/* Mapping betwee numeric GPIO ID and the actual GPIO hardware numbering:
+ * 0..13 GPI 0..13
+ * 14..26 GPO 0..12
+ * 27..41 GPIO 0..14
+ */
+
+static int vx855gpio_direction_input(struct gpio_chip *gpio,
+ unsigned int nr)
+{
+ struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+ unsigned long flags;
+ u_int32_t reg_out;
+
+ /* Real GPI bits are always in input direction */
+ if (nr < NR_VX855_GPI)
+ return 0;
+
+ /* Real GPO bits cannot be put in output direction */
+ if (nr < NR_VX855_GPInO)
+ return -EINVAL;
+
+ /* Open Drain GPIO have to be set to one */
+ spin_lock_irqsave(&vg->lock, flags);
+ reg_out = inl(vg->io_gpo);
+ reg_out |= gpio_o_bit(nr - NR_VX855_GPInO);
+ outl(reg_out, vg->io_gpo);
+ spin_unlock_irqrestore(&vg->lock, flags);
+
+ return 0;
+}
+
+static int vx855gpio_get(struct gpio_chip *gpio, unsigned int nr)
+{
+ struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+ u_int32_t reg_in;
+ int ret = 0;
+
+ if (nr < NR_VX855_GPI) {
+ reg_in = inl(vg->io_gpi);
+ if (reg_in & gpi_i_bit(nr))
+ ret = 1;
+ } else if (nr < NR_VX855_GPInO) {
+ /* GPO don't have an input bit, we need to read it
+ * back from the output register */
+ reg_in = inl(vg->io_gpo);
+ if (reg_in & gpo_o_bit(nr - NR_VX855_GPI))
+ ret = 1;
+ } else {
+ reg_in = inl(vg->io_gpi);
+ if (reg_in & gpio_i_bit(nr - NR_VX855_GPInO))
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static void vx855gpio_set(struct gpio_chip *gpio, unsigned int nr,
+ int val)
+{
+ struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+ unsigned long flags;
+ u_int32_t reg_out;
+
+ /* True GPI cannot be switched to output mode */
+ if (nr < NR_VX855_GPI)
+ return;
+
+ spin_lock_irqsave(&vg->lock, flags);
+ reg_out = inl(vg->io_gpo);
+ if (nr < NR_VX855_GPInO) {
+ if (val)
+ reg_out |= gpo_o_bit(nr - NR_VX855_GPI);
+ else
+ reg_out &= ~gpo_o_bit(nr - NR_VX855_GPI);
+ } else {
+ if (val)
+ reg_out |= gpio_o_bit(nr - NR_VX855_GPInO);
+ else
+ reg_out &= ~gpio_o_bit(nr - NR_VX855_GPInO);
+ }
+ outl(reg_out, vg->io_gpo);
+ spin_unlock_irqrestore(&vg->lock, flags);
+}
+
+static int vx855gpio_direction_output(struct gpio_chip *gpio,
+ unsigned int nr, int val)
+{
+ /* True GPI cannot be switched to output mode */
+ if (nr < NR_VX855_GPI)
+ return -EINVAL;
+
+ /* True GPO don't need to be switched to output mode,
+ * and GPIO are open-drain, i.e. also need no switching,
+ * so all we do is set the level */
+ vx855gpio_set(gpio, nr, val);
+
+ return 0;
+}
+
+static const char *vx855gpio_names[NR_VX855_GP] = {
+ "VX855_GPI0", "VX855_GPI1", "VX855_GPI2", "VX855_GPI3", "VX855_GPI4",
+ "VX855_GPI5", "VX855_GPI6", "VX855_GPI7", "VX855_GPI8", "VX855_GPI9",
+ "VX855_GPI10", "VX855_GPI11", "VX855_GPI12", "VX855_GPI13",
+ "VX855_GPO0", "VX855_GPO1", "VX855_GPO2", "VX855_GPO3", "VX855_GPO4",
+ "VX855_GPO5", "VX855_GPO6", "VX855_GPO7", "VX855_GPO8", "VX855_GPO9",
+ "VX855_GPO10", "VX855_GPO11", "VX855_GPO12",
+ "VX855_GPIO0", "VX855_GPIO1", "VX855_GPIO2", "VX855_GPIO3",
+ "VX855_GPIO4", "VX855_GPIO5", "VX855_GPIO6", "VX855_GPIO7",
+ "VX855_GPIO8", "VX855_GPIO9", "VX855_GPIO10", "VX855_GPIO11",
+ "VX855_GPIO12", "VX855_GPIO13", "VX855_GPIO14"
+};
+
+static void vx855gpio_gpio_setup(struct vx855_gpio *vg)
+{
+ struct gpio_chip *c = &vg->gpio;
+
+ c->label = "VX855 South Bridge";
+ c->owner = THIS_MODULE;
+ c->direction_input = vx855gpio_direction_input;
+ c->direction_output = vx855gpio_direction_output;
+ c->get = vx855gpio_get;
+ c->set = vx855gpio_set;
+ c->dbg_show = NULL;
+ c->base = 0;
+ c->ngpio = NR_VX855_GP;
+ c->can_sleep = 0;
+ c->names = vx855gpio_names;
+}
+
+/* This platform device is ordinarily registered by the vx855 mfd driver */
+static __devinit int vx855gpio_probe(struct platform_device *pdev)
+{
+ struct resource *res_gpi;
+ struct resource *res_gpo;
+ struct vx855_gpio *vg;
+ int ret;
+
+ res_gpi = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ res_gpo = platform_get_resource(pdev, IORESOURCE_IO, 1);
+ if (!res_gpi || !res_gpo)
+ return -EBUSY;
+
+ vg = kzalloc(sizeof(*vg), GFP_KERNEL);
+ if (!vg)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, vg);
+
+ dev_info(&pdev->dev, "found VX855 GPIO controller\n");
+ vg->io_gpi = res_gpi->start;
+ vg->io_gpo = res_gpo->start;
+ spin_lock_init(&vg->lock);
+
+ /*
+ * A single byte is used to control various GPIO ports on the VX855,
+ * and in the case of the OLPC XO-1.5, some of those ports are used
+ * for switches that are interpreted and exposed through ACPI. ACPI
+ * will have reserved the region, so our own reservation will not
+ * succeed. Ignore and continue.
+ */
+
+ if (!request_region(res_gpi->start, resource_size(res_gpi),
+ MODULE_NAME "_gpi"))
+ dev_warn(&pdev->dev,
+ "GPI I/O resource busy, probably claimed by ACPI\n");
+ else
+ vg->gpi_reserved = true;
+
+ if (!request_region(res_gpo->start, resource_size(res_gpo),
+ MODULE_NAME "_gpo"))
+ dev_warn(&pdev->dev,
+ "GPO I/O resource busy, probably claimed by ACPI\n");
+ else
+ vg->gpo_reserved = true;
+
+ vx855gpio_gpio_setup(vg);
+
+ ret = gpiochip_add(&vg->gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register GPIOs\n");
+ goto out_release;
+ }
+
+ return 0;
+
+out_release:
+ if (vg->gpi_reserved)
+ release_region(res_gpi->start, resource_size(res_gpi));
+ if (vg->gpo_reserved)
+ release_region(res_gpi->start, resource_size(res_gpo));
+ platform_set_drvdata(pdev, NULL);
+ kfree(vg);
+ return ret;
+}
+
+static int __devexit vx855gpio_remove(struct platform_device *pdev)
+{
+ struct vx855_gpio *vg = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ if (gpiochip_remove(&vg->gpio))
+ dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
+
+ if (vg->gpi_reserved) {
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, resource_size(res));
+ }
+ if (vg->gpo_reserved) {
+ res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+ release_region(res->start, resource_size(res));
+ }
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(vg);
+ return 0;
+}
+
+static struct platform_driver vx855gpio_driver = {
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = vx855gpio_probe,
+ .remove = __devexit_p(vx855gpio_remove),
+};
+
+static int vx855gpio_init(void)
+{
+ return platform_driver_register(&vx855gpio_driver);
+}
+module_init(vx855gpio_init);
+
+static void vx855gpio_exit(void)
+{
+ platform_driver_unregister(&vx855gpio_driver);
+}
+module_exit(vx855gpio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>");
+MODULE_DESCRIPTION("GPIO driver for the VIA VX855 chipset");
+MODULE_ALIAS("platform:vx855_gpio");
diff --git a/drivers/gpio/wm8994-gpio.c b/drivers/gpio/wm8994-gpio.c
index 2ac9a16d3da..618398e4ed8 100644
--- a/drivers/gpio/wm8994-gpio.c
+++ b/drivers/gpio/wm8994-gpio.c
@@ -140,6 +140,7 @@ static struct gpio_chip template_chip = {
.get = wm8994_gpio_get,
.direction_output = wm8994_gpio_direction_out,
.set = wm8994_gpio_set,
+ .to_irq = wm8994_gpio_to_irq,
.dbg_show = wm8994_gpio_dbg_show,
.can_sleep = 1,
};
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c
index 80af4460801..7de0ded4ccc 100644
--- a/drivers/input/misc/max8925_onkey.c
+++ b/drivers/input/misc/max8925_onkey.c
@@ -27,27 +27,37 @@
#include <linux/mfd/max8925.h>
#include <linux/slab.h>
+#define SW_INPUT (1 << 7) /* 0/1 -- up/down */
#define HARDRESET_EN (1 << 7)
#define PWREN_EN (1 << 7)
struct max8925_onkey_info {
struct input_dev *idev;
struct i2c_client *i2c;
- int irq;
+ struct device *dev;
+ int irq[2];
};
/*
- * MAX8925 gives us an interrupt when ONKEY is held for 3 seconds.
+ * MAX8925 gives us an interrupt when ONKEY is pressed or released.
* max8925_set_bits() operates I2C bus and may sleep. So implement
* it in thread IRQ handler.
*/
static irqreturn_t max8925_onkey_handler(int irq, void *data)
{
struct max8925_onkey_info *info = data;
-
- input_report_key(info->idev, KEY_POWER, 1);
+ int ret, event;
+
+ ret = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);
+ if (ret & SW_INPUT)
+ event = 1;
+ else
+ event = 0;
+ input_report_key(info->idev, KEY_POWER, event);
input_sync(info->idev);
+ dev_dbg(info->dev, "onkey event:%d\n", event);
+
/* Enable hardreset to halt if system isn't shutdown on time */
max8925_set_bits(info->i2c, MAX8925_SYSENSEL,
HARDRESET_EN, HARDRESET_EN);
@@ -59,14 +69,42 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
{
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct max8925_onkey_info *info;
- int error;
+ int irq[2], error;
+
+ irq[0] = platform_get_irq(pdev, 0);
+ if (irq[0] < 0) {
+ dev_err(&pdev->dev, "No IRQ resource!\n");
+ return -EINVAL;
+ }
+ irq[1] = platform_get_irq(pdev, 1);
+ if (irq[1] < 0) {
+ dev_err(&pdev->dev, "No IRQ resource!\n");
+ return -EINVAL;
+ }
info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->i2c = chip->i2c;
- info->irq = chip->irq_base + MAX8925_IRQ_GPM_SW_3SEC;
+ info->dev = &pdev->dev;
+ irq[0] += chip->irq_base;
+ irq[1] += chip->irq_base;
+
+ error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler,
+ IRQF_ONESHOT, "onkey-down", info);
+ if (error < 0) {
+ dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+ irq[0], error);
+ goto out;
+ }
+ error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler,
+ IRQF_ONESHOT, "onkey-up", info);
+ if (error < 0) {
+ dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+ irq[1], error);
+ goto out_irq;
+ }
info->idev = input_allocate_device();
if (!info->idev) {
@@ -79,32 +117,29 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
info->idev->phys = "max8925_on/input0";
info->idev->id.bustype = BUS_I2C;
info->idev->dev.parent = &pdev->dev;
+ info->irq[0] = irq[0];
+ info->irq[1] = irq[1];
info->idev->evbit[0] = BIT_MASK(EV_KEY);
info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
- error = request_threaded_irq(info->irq, NULL, max8925_onkey_handler,
- IRQF_ONESHOT, "onkey", info);
- if (error < 0) {
- dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
- info->irq, error);
- goto out_irq;
- }
error = input_register_device(info->idev);
if (error) {
dev_err(chip->dev, "Can't register input device: %d\n", error);
- goto out;
+ goto out_reg;
}
platform_set_drvdata(pdev, info);
return 0;
-out:
- free_irq(info->irq, info);
-out_irq:
+out_reg:
input_free_device(info->idev);
out_input:
+ free_irq(info->irq[1], info);
+out_irq:
+ free_irq(info->irq[0], info);
+out:
kfree(info);
return error;
}
@@ -113,7 +148,8 @@ static int __devexit max8925_onkey_remove(struct platform_device *pdev)
{
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
- free_irq(info->irq, info);
+ free_irq(info->irq[0], info);
+ free_irq(info->irq[1], info);
input_unregister_device(info->idev);
kfree(info);
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index b7677106cff..e672b44ee17 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -24,26 +24,17 @@
#define LED_CURRENT_MASK (0x07 << 5)
#define LED_BLINK_ON_MASK (0x07)
-#define LED_BLINK_PERIOD_MASK (0x0F << 3)
#define LED_BLINK_MASK (0x7F)
#define LED_BLINK_ON(x) ((x & 0x7) * 66 + 66)
-#define LED_BLINK_PERIOD(x) ((x & 0xF) * 530 + 930)
#define LED_BLINK_ON_MIN LED_BLINK_ON(0)
#define LED_BLINK_ON_MAX LED_BLINK_ON(0x7)
-#define LED_BLINK_PERIOD_MIN LED_BLINK_PERIOD(0)
-#define LED_BLINK_PERIOD_MAX LED_BLINK_PERIOD(0xE)
+#define LED_ON_CONTINUOUS (0x0F << 3)
#define LED_TO_ON(x) ((x - 66) / 66)
-#define LED_TO_PERIOD(x) ((x - 930) / 530)
#define LED1_BLINK_EN (1 << 1)
#define LED2_BLINK_EN (1 << 2)
-enum {
- SET_BRIGHTNESS,
- SET_BLINK,
-};
-
struct pm860x_led {
struct led_classdev cdev;
struct i2c_client *i2c;
@@ -54,8 +45,6 @@ struct pm860x_led {
int port;
int iset;
- int command;
- int offset;
unsigned char brightness;
unsigned char current_brightness;
@@ -95,10 +84,12 @@ static inline int __blink_off(int port)
case PM8606_LED1_GREEN:
case PM8606_LED1_BLUE:
ret = PM8606_RGB1A;
+ break;
case PM8606_LED2_RED:
case PM8606_LED2_GREEN:
case PM8606_LED2_BLUE:
ret = PM8606_RGB2A;
+ break;
}
return ret;
}
@@ -122,60 +113,35 @@ static inline int __blink_ctl_mask(int port)
return ret;
}
-static int __led_set(struct pm860x_led *led, int command)
+static void pm860x_led_work(struct work_struct *work)
{
- struct pm860x_chip *chip = led->chip;
- int mask, ret;
+ struct pm860x_led *led;
+ struct pm860x_chip *chip;
+ int