summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authora1205z <a1205z@motorola.com>2013-12-13 10:02:53 -0600
committerJames Wylder <jwylder@motorola.com>2014-03-05 17:46:58 -0600
commit25372d59ec0eddc27d6025be01e0f402657c96c6 (patch)
treeb2b88b109a9b8bd401b442132571e674c3ed72bb
parentc4d75a7ed02adc3dc7fd471f4b1c63df6d3b227a (diff)
downloadolio-linux-3.10-25372d59ec0eddc27d6025be01e0f402657c96c6.tar.xz
olio-linux-3.10-25372d59ec0eddc27d6025be01e0f402657c96c6.zip
IKXCLOCK-50: Bring up PMIC TPS interrupt
Bring up PMIC TPS interrupt for power key detection Change-Id: I405c19c04ab0d9308308f41377f9ce25deb732e8 Signed-off-by: a1205z <a1205z@motorola.com> Reviewed-on: http://gerrit.pcs.mot.com/590472 SLTApproved: Slta Waiver <sltawvr@motorola.com> Tested-by: Jira Key <jirakey@motorola.com> Reviewed-by: Douglas Zobel <dzobel1@motorola.com> Submit-Approved: Jira Key <jirakey@motorola.com>
-rw-r--r--arch/arm/boot/dts/omap3-minnow-p0.dts2
-rw-r--r--arch/arm/mach-omap2/board-minnow-spi.c2
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/tps65912-core.c37
-rw-r--r--drivers/mfd/tps65912-irq.c51
-rw-r--r--drivers/mfd/tps65912-key.c132
-rw-r--r--include/linux/mfd/tps65912.h14
7 files changed, 232 insertions, 8 deletions
diff --git a/arch/arm/boot/dts/omap3-minnow-p0.dts b/arch/arm/boot/dts/omap3-minnow-p0.dts
index 0b0f2ccdfa0..917a7a2e70e 100644
--- a/arch/arm/boot/dts/omap3-minnow-p0.dts
+++ b/arch/arm/boot/dts/omap3-minnow-p0.dts
@@ -27,6 +27,8 @@
dcdc1_avs;
dcdc4_avs;
+ tps_irq_gpio = <0>;
+
regulators {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/mach-omap2/board-minnow-spi.c b/arch/arm/mach-omap2/board-minnow-spi.c
index bc0a1abd38c..5d0f2815c8d 100644
--- a/arch/arm/mach-omap2/board-minnow-spi.c
+++ b/arch/arm/mach-omap2/board-minnow-spi.c
@@ -114,7 +114,7 @@ unsigned short cpcap_regulator_off_mode_values[CPCAP_NUM_REGULATORS] = {
[CPCAP_VAUDIO] = 0x0000,
};
-#define CPCAP_GPIO 0
+#define CPCAP_GPIO 1
struct regulator_consumer_supply cpcap_sw4_consumers[] = {
REGULATOR_SUPPLY("sw4", NULL /* DSP */),
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b11b8bf992f..254ffaabdb4 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -60,7 +60,7 @@ obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_TPS6507X) += tps6507x.o
obj-$(CONFIG_MFD_TPS65217) += tps65217.o
obj-$(CONFIG_MFD_TPS65910) += tps65910.o
-tps65912-objs := tps65912-core.o tps65912-irq.o
+tps65912-objs := tps65912-core.o tps65912-irq.o tps65912-key.o
obj-$(CONFIG_MFD_TPS65912) += tps65912.o
obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o
obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o
diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c
index 6165c1fc36d..f0bcdce6df2 100644
--- a/drivers/mfd/tps65912-core.c
+++ b/drivers/mfd/tps65912-core.c
@@ -21,6 +21,7 @@
#include <linux/mfd/core.h>
#include <linux/mfd/tps65912.h>
#include <linux/of_device.h>
+#include <linux/irq.h>
static struct mfd_cell tps65912s[] = {
{
@@ -28,6 +29,12 @@ static struct mfd_cell tps65912s[] = {
},
};
+static struct platform_device tps65912_key_device = {
+ .name = "tps65912_key",
+ .id = -1,
+ .dev.platform_data = NULL,
+};
+
int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask)
{
u8 data;
@@ -127,6 +134,7 @@ static struct tps65912_board *tps65912_parse_dt(struct tps65912 *tps65912)
{
struct device_node *np = tps65912->dev->of_node;
struct tps65912_board *board_info;
+ int tps_irq_gpio, ret;
board_info = kzalloc(sizeof(struct tps65912_board), GFP_KERNEL);
if (!board_info) {
@@ -154,9 +162,25 @@ static struct tps65912_board *tps65912_parse_dt(struct tps65912 *tps65912)
pr_info("dcdc4_avs is 1\n");
}
- board_info->irq = tps65912->irq_num;
- board_info->irq_base = 0;
+ if (!of_property_read_u32(np,"tps_irq_gpio",&tps_irq_gpio)) {
+ ret = gpio_request(tps_irq_gpio, "tps65912-irq");
+ if (ret)
+ goto err;
+ ret = gpio_direction_input(tps_irq_gpio);
+ if (ret) {
+ gpio_free(tps_irq_gpio);
+ goto err;
+ }
+
+ board_info->irq = __gpio_to_irq(tps_irq_gpio);
+ pr_info("tps_irq_gpio:%d irq:%d\n", tps_irq_gpio, board_info->irq);
+ }
+ board_info->irq_base = irq_alloc_descs(-1, 0, TPS65912_NUM_IRQ, 0);
+ pr_info("irq_base:%d\n", board_info->irq_base);
return board_info;
+err:
+ kfree(board_info);
+ return NULL;
}
#else
static inline
@@ -207,11 +231,16 @@ int tps65912_device_init(struct tps65912 *tps65912)
if (ret < 0)
goto err;
+ tps65912_key_device.dev.platform_data = tps65912;
+ ret = platform_device_register(&tps65912_key_device);
+ if (ret < 0)
+ goto err;
+
init_data->irq = pmic_plat_data->irq;
init_data->irq_base = pmic_plat_data->irq_base;
ret = tps65912_irq_init(tps65912, init_data->irq, init_data);
if (ret < 0)
- goto err;
+ goto err_irq;
#ifdef CONFIG_MFD_TPS65912_DEBUGFS
ret = tps65912_debugfs_create(tps65912);
@@ -226,6 +255,8 @@ int tps65912_device_init(struct tps65912 *tps65912)
err_debugfs:
#endif
tps65912_irq_exit(tps65912);
+err_irq:
+ platform_device_unregister(&tps65912_key_device);
err:
kfree(init_data);
kfree(pmic_plat_data);
diff --git a/drivers/mfd/tps65912-irq.c b/drivers/mfd/tps65912-irq.c
index d360a83a273..0e696c41bfe 100644
--- a/drivers/mfd/tps65912-irq.c
+++ b/drivers/mfd/tps65912-irq.c
@@ -22,6 +22,13 @@
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/mfd/tps65912.h>
+#include <linux/input.h>
+
+enum pwrkey_states {
+ PWRKEY_RELEASE, /* Power key released state. */
+ PWRKEY_PRESS, /* Power key pressed state. */
+ PWRKEY_UNKNOWN, /* Unknown power key state. */
+};
static inline int irq_to_tps65912_irq(struct tps65912 *tps65912,
int irq)
@@ -29,6 +36,30 @@ static inline int irq_to_tps65912_irq(struct tps65912 *tps65912,
return irq - tps65912->irq_base;
}
+/* this powerkey_handler runs in process contextt, not in interrupt context*/
+static irqreturn_t powerkey_handler(int irq, void *irq_data)
+{
+ struct tps65912 *tps65912 = irq_data;
+ u32 new_state;
+
+ if (irq - tps65912->irq_base == TPS65912_IRQ_GPIO3_R) {
+ new_state = PWRKEY_RELEASE;
+ } else if (irq - tps65912->irq_base == TPS65912_IRQ_GPIO3_F) {
+ new_state = PWRKEY_PRESS;
+ } else {
+ pr_info("incorrect interrupt %d for power key\n",
+ irq - tps65912->irq_base);
+ return IRQ_HANDLED;
+ }
+
+ mutex_lock(&tps65912->irq_lock);
+ if (new_state != tps65912->powerkey_state) {
+ tps65912_broadcast_key_event(tps65912, KEY_END, new_state);
+ tps65912->powerkey_state = new_state;
+ }
+ mutex_unlock(&tps65912->irq_lock);
+ return IRQ_HANDLED;
+}
/*
* This is a threaded IRQ handler so can access I2C/SPI. Since the
* IRQ handler explicitly clears the IRQ it handles the IRQ line
@@ -158,7 +189,7 @@ int tps65912_irq_init(struct tps65912 *tps65912, int irq,
struct tps65912_platform_data *pdata)
{
int ret, cur_irq;
- int flags = IRQF_ONESHOT;
+ int flags = IRQF_ONESHOT|IRQF_TRIGGER_RISING;
u8 reg;
if (!irq) {
@@ -171,6 +202,8 @@ int tps65912_irq_init(struct tps65912 *tps65912, int irq,
return 0;
}
+ tps65912->powerkey_state = PWRKEY_RELEASE;
+
/* Clear unattended interrupts */
tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg);
tps65912->write(tps65912, TPS65912_INT_STS, 1, &reg);
@@ -207,10 +240,22 @@ int tps65912_irq_init(struct tps65912 *tps65912, int irq,
#endif
}
+ ret = request_threaded_irq(tps65912->irq_base + TPS65912_IRQ_GPIO3_R,
+ NULL, powerkey_handler, flags, "tps65912_key_rel", tps65912);
+
+ if (ret != 0)
+ dev_err(tps65912->dev,
+ "Failed to request sub-IRQ for power key rel: %d\n", ret);
+
+ ret = request_threaded_irq(tps65912->irq_base + TPS65912_IRQ_GPIO3_F,
+ NULL, powerkey_handler, flags, "tps65912_key_press", tps65912);
+
+ if (ret != 0)
+ dev_err(tps65912->dev,
+ "Failed to request sub-IRQ for power key press: %d\n", ret);
+
ret = request_threaded_irq(irq, NULL, tps65912_irq, flags,
"tps65912", tps65912);
-
- irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
if (ret != 0)
dev_err(tps65912->dev, "Failed to request IRQ: %d\n", ret);
diff --git a/drivers/mfd/tps65912-key.c b/drivers/mfd/tps65912-key.c
new file mode 100644
index 00000000000..5b0b0ebb2c4
--- /dev/null
+++ b/drivers/mfd/tps65912-key.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013 Motorola, Inc.
+ *
+ * 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.
+ *
+ * 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/slab.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65912.h>
+
+struct tps65912_key_data {
+ struct input_dev *input_dev;
+ struct tps65912 *tps65912;
+};
+
+static int __init tps65912_key_probe(struct platform_device *pdev)
+{
+ int err;
+ struct tps65912_key_data *key;
+
+ pr_info("tps65912_key_probe begin\n");
+
+ if (pdev->dev.platform_data == NULL) {
+ dev_err(&pdev->dev, "no platform_data\n");
+ return -EINVAL;
+ }
+
+ key = kzalloc(sizeof(*key), GFP_KERNEL);
+ if (!key)
+ return -ENOMEM;
+
+ key->tps65912 = pdev->dev.platform_data;
+
+ key->input_dev = input_allocate_device();
+ if (key->input_dev == NULL) {
+ dev_err(&pdev->dev, "can't allocate input device\n");
+ err = -ENOMEM;
+ goto err0;
+ }
+
+ set_bit(EV_KEY, key->input_dev->evbit);
+ set_bit(KEY_MEDIA, key->input_dev->keybit);
+ set_bit(KEY_END, key->input_dev->keybit);
+ set_bit(KEY_POWER_DOUBLE, key->input_dev->keybit);
+
+ key->input_dev->name = "tps65912-key";
+
+ err = input_register_device(key->input_dev);
+ if (err < 0) {
+ dev_err(&pdev->dev, "could not register input device.\n");
+ goto err1;
+ }
+
+ platform_set_drvdata(pdev, key);
+ tps65912_set_keydata(key->tps65912, key);
+
+ dev_info(&pdev->dev, "tps65912 key device probed\n");
+
+ return 0;
+
+err1:
+ input_free_device(key->input_dev);
+err0:
+ kfree(key);
+ return err;
+}
+
+static int __exit tps65912_key_remove(struct platform_device *pdev)
+{
+ struct tps65912_key_data *key = platform_get_drvdata(pdev);
+
+ input_unregister_device(key->input_dev);
+ input_free_device(key->input_dev);
+ kfree(key);
+
+ return 0;
+}
+
+void tps65912_broadcast_key_event(struct tps65912 *tps65912,
+ unsigned int code, int value)
+{
+ struct tps65912_key_data *key = tps65912_get_keydata(tps65912);
+
+ if (key && key->input_dev) {
+ input_report_key(key->input_dev, code, value);
+ /*sync with input subsystem to solve the key cached problem*/
+ input_sync(key->input_dev);
+ }
+}
+EXPORT_SYMBOL(tps65912_broadcast_key_event);
+
+static struct platform_driver tps65912_key_driver = {
+ .probe = tps65912_key_probe,
+ .remove = __exit_p(tps65912_key_remove),
+ .driver = {
+ .name = "tps65912_key",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init tps65912_key_init(void)
+{
+ return platform_driver_register(&tps65912_key_driver);
+}
+module_init(tps65912_key_init);
+
+static void __exit tps65912_key_exit(void)
+{
+ platform_driver_unregister(&tps65912_key_driver);
+}
+module_exit(tps65912_key_exit);
+
+MODULE_ALIAS("platform:tps65912_key");
+MODULE_DESCRIPTION("TPS65912 KEY driver");
+MODULE_AUTHOR("Motorola");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/tps65912.h b/include/linux/mfd/tps65912.h
index 16375fe5132..7b38617e041 100644
--- a/include/linux/mfd/tps65912.h
+++ b/include/linux/mfd/tps65912.h
@@ -317,6 +317,8 @@ struct tps65912 {
int irq_num;
u32 irq_mask;
void *debugfs_data;
+ void *keydata;
+ u32 powerkey_state;
};
struct tps65912_platform_data {
@@ -324,6 +326,16 @@ struct tps65912_platform_data {
int irq_base;
};
+static inline void tps65912_set_keydata(struct tps65912 *tps65912, void *data)
+{
+ tps65912->keydata = data;
+}
+
+static inline void *tps65912_get_keydata(struct tps65912 *tps65912)
+{
+ return tps65912->keydata;
+}
+
unsigned int tps_chip(void);
int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask);
@@ -338,5 +350,7 @@ int tps65912_irq_exit(struct tps65912 *tps65912);
int tps65912_debugfs_create(struct tps65912 *tps65912);
void tps65912_debugfs_remove(struct tps65912 *tps65912);
void tps65912_dump_registers(struct tps65912 *tps65912);
+void tps65912_broadcast_key_event(struct tps65912 *tps65912,
+ unsigned int code, int value);
#endif /* __LINUX_MFD_TPS65912_H */