diff --git a/drivers/input/misc/qpnp_power_on_mmi/Android.mk b/drivers/input/misc/qpnp_power_on_mmi/Android.mk new file mode 100644 index 000000000000..f3ebef87b36f --- /dev/null +++ b/drivers/input/misc/qpnp_power_on_mmi/Android.mk @@ -0,0 +1,9 @@ +DLKM_DIR := motorola/kernel/modules +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := qpnp-power-on-mmi.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/AndroidKernelModule.mk + diff --git a/drivers/input/misc/qpnp_power_on_mmi/Kbuild b/drivers/input/misc/qpnp_power_on_mmi/Kbuild new file mode 100644 index 000000000000..6725e071c124 --- /dev/null +++ b/drivers/input/misc/qpnp_power_on_mmi/Kbuild @@ -0,0 +1,6 @@ +# add -Wall to try to catch everything we can. +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include + +obj-m += qpnp-power-on-mmi.o + diff --git a/drivers/input/misc/qpnp_power_on_mmi/Makefile b/drivers/input/misc/qpnp_power_on_mmi/Makefile new file mode 100644 index 000000000000..4191dea22679 --- /dev/null +++ b/drivers/input/misc/qpnp_power_on_mmi/Makefile @@ -0,0 +1,10 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean diff --git a/drivers/input/misc/qpnp_power_on_mmi/qpnp-power-on-mmi.c b/drivers/input/misc/qpnp_power_on_mmi/qpnp-power-on-mmi.c new file mode 100644 index 000000000000..53828197406c --- /dev/null +++ b/drivers/input/misc/qpnp_power_on_mmi/qpnp-power-on-mmi.c @@ -0,0 +1,140 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. 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 version 2 and + * only 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RESET_EXTRA_RESET_KUNPOW_REASON BIT(9) + +struct qpnp_pon_mmi { + struct platform_device *pdev; + struct delayed_work kpd_bark_work; + u32 kpd_bark_irq; +}; + + +static void kpd_bark_work_func(struct work_struct *work) +{ + struct qpnp_pon_mmi *pon = + container_of(work, struct qpnp_pon_mmi, kpd_bark_work.work); + + dev_err(&pon->pdev->dev, "HW User Reset! 2 sec to Reset!\n"); + qpnp_pon_store_extra_reset_info(RESET_EXTRA_RESET_KUNPOW_REASON, 0); + qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); + kernel_halt(); +} + +static irqreturn_t qpnp_kpdpwr_bark_irq(int irq, void *_pon) +{ + struct qpnp_pon_mmi *pon = _pon; + + schedule_delayed_work(&pon->kpd_bark_work, msecs_to_jiffies(0)); + + return IRQ_HANDLED; +} + +static int qpnp_pon_mmi_probe(struct platform_device *pdev) +{ + struct qpnp_pon_mmi *pon; + int rc; + + pon = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_pon_mmi), + GFP_KERNEL); + if (!pon) + return -ENOMEM; + + pon->pdev = pdev; + + dev_set_drvdata(&pdev->dev, pon); + + INIT_DELAYED_WORK(&pon->kpd_bark_work, kpd_bark_work_func); + pon->kpd_bark_irq = platform_get_irq_byname(pon->pdev, "kpdpwr-bark"); + if (pon->kpd_bark_irq < 0) { + dev_err(&pon->pdev->dev, + "Unable to get kpdpwr-bark irq\n"); + return -ENODEV; + } + + dev_info(&pon->pdev->dev, "Request %d kpdpwr-bark IRQ\n", + pon->kpd_bark_irq); + rc = devm_request_irq(&pon->pdev->dev, pon->kpd_bark_irq, + qpnp_kpdpwr_bark_irq, + IRQF_TRIGGER_RISING, + "qpnp_kpdpwr_bark", pon); + if (rc < 0) { + dev_err(&pon->pdev->dev, + "Can't request %d IRQ\n", + pon->kpd_bark_irq); + return rc; + } + + return 0; +} + +static int qpnp_pon_mmi_remove(struct platform_device *pdev) +{ + struct qpnp_pon_mmi *pon = dev_get_drvdata(&pdev->dev); + + cancel_delayed_work_sync(&pon->kpd_bark_work); + + return 0; +} + +static const struct of_device_id spmi_match_table[] = { + { .compatible = "qcom,qpnp-power-on-mmi", }, + {} +}; + +static struct platform_driver qpnp_pon_mmi_driver = { + .driver = { + .name = "qcom,qpnp-power-on-mmi", + .of_match_table = spmi_match_table, + }, + .probe = qpnp_pon_mmi_probe, + .remove = qpnp_pon_mmi_remove, +}; + +static int __init qpnp_pon_mmi_init(void) +{ + return platform_driver_register(&qpnp_pon_mmi_driver); +} +module_init(qpnp_pon_mmi_init); + +static void __exit qpnp_pon_mmi_exit(void) +{ + return platform_driver_unregister(&qpnp_pon_mmi_driver); +} +module_exit(qpnp_pon_mmi_exit); + +MODULE_DESCRIPTION("QPNP MMI PMIC POWER-ON driver"); +MODULE_LICENSE("GPL v2");