summaryrefslogtreecommitdiff
path: root/drivers/extcon
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2013-02-24 21:02:38 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:01:50 -0700
commita918093cee4c24603d799b9a4ecf6d51c9e91e9f (patch)
treedabc25d49b8d3339b725c2f995630a7e7ef6e819 /drivers/extcon
parent1fa85ce950c12c616f3baf1e0f2c930c2fd8fb81 (diff)
extcon: palma: add vbus detection through extcon notification
Add VBUS detection on palmas and notify the state through extcon framework. Bug 1238096 Change-Id: Ic5bb577aa66330e93b909df7dfc297aaf55fa0e6 Signed-off-by: Mallikarjun Kasoju <mkasoju@nvidia.com> Reviewed-on: http://git-master/r/203655 (cherry picked from commit b5e45af19fd91e8c54c17c1f21deee0afb8d6fd4) Reviewed-on: http://git-master/r/204692 (cherry picked from commit 222d6e830ab6bb3253d18066ba5dc6f820d7a040) Reviewed-on: http://git-master/r/206549 Reviewed-by: Automatic_Commit_Validation_User Tested-by: Seema Khowala <seemaj@nvidia.com> Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Diffstat (limited to 'drivers/extcon')
-rw-r--r--drivers/extcon/Kconfig7
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-palmas.c204
3 files changed, 212 insertions, 0 deletions
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index da6ff5767207..1482d27e55a9 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -52,6 +52,13 @@ config EXTCON_MAX8997
Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory
detector and switch.
+config EXTCON_PALMAS
+ tristate "PALMAS EXTCON Support"
+ depends on MFD_PALMAS
+ help
+ If you say yes here you get support for the VBUS detection and notification
+ through extcon framework from Palmas PMIC.
+
config EXTCON_ARIZONA
tristate "Wolfson Arizona EXTCON support"
depends on MFD_ARIZONA && INPUT && SND_SOC
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 064584bdf986..fd9b31e93548 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
obj-$(CONFIG_EXTCON_MAX77665) += extcon-max77665.o
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
+obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o
obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
new file mode 100644
index 000000000000..5977836b32de
--- /dev/null
+++ b/drivers/extcon/extcon-palmas.c
@@ -0,0 +1,204 @@
+/*
+ * palmas-extcon.c -- Palmas VBUS detection in extcon framework.
+ *
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; 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/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/pm.h>
+#include <linux/extcon.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/palmas.h>
+
+struct palmas_extcon {
+ struct device *dev;
+ struct palmas *palmas;
+ struct extcon_dev *edev;
+ int vbus_irq;
+ int id_irq;
+};
+
+const char *palmas_excon_cable[] = {
+ [0] = "USB",
+ NULL,
+};
+
+static int palmas_extcon_cable_update(
+ struct palmas_extcon *palma_econ)
+{
+ int ret;
+ unsigned int status;
+
+ ret = palmas_read(palma_econ->palmas, PALMAS_INTERRUPT_BASE,
+ PALMAS_INT3_LINE_STATE, &status);
+ if (ret < 0) {
+ dev_err(palma_econ->dev,
+ "INT3_LINE_STATE read failed: %d\n", ret);
+ return ret;
+ }
+
+ if (status & PALMAS_INT3_LINE_STATE_VBUS)
+ extcon_set_cable_state(palma_econ->edev, "USB", true);
+ else
+ extcon_set_cable_state(palma_econ->edev, "USB", false);
+
+ dev_info(palma_econ->dev, "VBUS %s status: 0x%02x\n",
+ (status & PALMAS_INT3_LINE_STATE_VBUS) ? "Valid" : "Invalid",
+ status);
+
+ return 0;
+}
+
+static irqreturn_t palmas_extcon_irq(int irq, void *data)
+{
+ struct palmas_extcon *palma_econ = data;
+
+ if (irq == palma_econ->vbus_irq)
+ palmas_extcon_cable_update(palma_econ);
+ else
+ dev_err(palma_econ->dev, "Unknown interrupt %d\n", irq);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit palmas_extcon_probe(struct platform_device *pdev)
+{
+ struct palmas_extcon *palma_econ;
+ struct extcon_dev *edev;
+ int ret;
+
+ palma_econ = devm_kzalloc(&pdev->dev, sizeof(*palma_econ), GFP_KERNEL);
+ if (!palma_econ) {
+ dev_err(&pdev->dev, "Memory allocation failed for palma_econ\n");
+ return -ENOMEM;
+ }
+
+ edev = devm_kzalloc(&pdev->dev, sizeof(*edev), GFP_KERNEL);
+ if (!edev) {
+ dev_err(&pdev->dev, "Memory allocation failed for edev\n");
+ return -ENOMEM;
+ }
+ palma_econ->edev = edev;
+ palma_econ->edev->name = dev_name(&pdev->dev);
+ palma_econ->edev->supported_cable = palmas_excon_cable;
+
+ palma_econ->dev = &pdev->dev;
+ palma_econ->palmas = dev_get_drvdata(pdev->dev.parent);
+ dev_set_drvdata(&pdev->dev, palma_econ);
+
+ palma_econ->vbus_irq = platform_get_irq(pdev, 0);
+ palma_econ->id_irq = platform_get_irq(pdev, 1);
+
+ ret = extcon_dev_register(palma_econ->edev, NULL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register extcon device\n");
+ return ret;
+ }
+
+ /* Set initial state */
+ ret = palmas_extcon_cable_update(palma_econ);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Cable init failed: %d\n", ret);
+ goto out;
+ }
+
+ ret = request_threaded_irq(palma_econ->vbus_irq, NULL,
+ palmas_extcon_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ dev_name(palma_econ->dev), palma_econ);
+ if (ret < 0) {
+ dev_err(palma_econ->dev, "request irq %d failed: %dn",
+ palma_econ->vbus_irq, ret);
+ goto out;
+ }
+
+ device_set_wakeup_capable(&pdev->dev, 1);
+ return 0;
+
+out:
+ extcon_dev_unregister(palma_econ->edev);
+ return ret;
+}
+
+static int __devexit palmas_extcon_remove(struct platform_device *pdev)
+{
+ struct palmas_extcon *palma_econ = dev_get_drvdata(&pdev->dev);
+
+ extcon_dev_unregister(palma_econ->edev);
+ free_irq(palma_econ->vbus_irq, palma_econ);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int palmas_extcon_suspend(struct device *dev)
+{
+ struct palmas_extcon *palma_econ = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(palma_econ->vbus_irq);
+ return 0;
+}
+
+static int palmas_extcon_resume(struct device *dev)
+{
+ struct palmas_extcon *palma_econ = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(palma_econ->vbus_irq);
+ return 0;
+};
+#endif
+
+static const struct dev_pm_ops palmas_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(palmas_extcon_suspend,
+ palmas_extcon_resume)
+};
+
+static struct platform_driver palmas_extcon_driver = {
+ .probe = palmas_extcon_probe,
+ .remove = __devexit_p(palmas_extcon_remove),
+ .driver = {
+ .name = "palmas-extcon",
+ .owner = THIS_MODULE,
+ .pm = &palmas_pm_ops,
+ },
+};
+
+static int __init palmas_extcon_driver_init(void)
+{
+ return platform_driver_register(&palmas_extcon_driver);
+}
+subsys_initcall_sync(palmas_extcon_driver_init);
+
+static void __exit palmas_extcon_driver_exit(void)
+{
+ platform_driver_unregister(&palmas_extcon_driver);
+}
+module_exit(palmas_extcon_driver_exit);
+
+MODULE_DESCRIPTION("palmas extcon driver");
+MODULE_AUTHOR("Laxman Dewangan<ldewangan@nvidia.com>");
+MODULE_ALIAS("platform:palmas-extcon");
+MODULE_LICENSE("GPL v2");