@@ -956,4 +956,13 @@ config INPUT_STPMIC1_ONKEY
To compile this driver as a module, choose M here: the
module will be called stpmic1_onkey.
+config INPUT_AS1895
+ tristate "AS1895 hall sensor support"
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Say Y here if you have a as1895 hall sensor connected to a GPIO pin.
+
+ To compile this driver as a module, choose M here: the
+ module will be called as1895.
+
endif
@@ -92,3 +92,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o
+obj-$(CONFIG_INPUT_AS1895) += as1895.o
new file mode 100644
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ */
+
+#include <linux/extcon-provider.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_wakeup.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+/* Timeout value for processing the wakeup event */
+#define AS1895_WAKEUP_TIMEOUT_MS 100
+
+#define AS1895_DRV_NAME "AMZN-AS1895"
+
+struct as1895_dev {
+ struct input_dev *input;
+ struct extcon_dev *edev;
+ struct wakeup_source *ws;
+
+ /* the connected gpio pin number */
+ int gpio_pin;
+ int irq;
+};
+
+static const unsigned int as1895_cable[] = {
+ EXTCON_MECHANICAL,
+ EXTCON_NONE,
+};
+
+static irqreturn_t as1895_irq_thread_handler(int irq, void *data)
+{
+ struct as1895_dev *as1895 = (struct as1895_dev *)data;
+ struct input_dev *input = as1895->input;
+ int gpio_val;
+
+ /* allow user space to consume the event */
+ __pm_wakeup_event(as1895->ws, AS1895_WAKEUP_TIMEOUT_MS);
+
+ gpio_val = gpio_get_value(as1895->gpio_pin);
+
+ extcon_set_state_sync(as1895->edev, EXTCON_MECHANICAL,
+ gpio_val ? false : true);
+
+ input_report_switch(input, SW_LID, !gpio_val);
+
+ input_sync(input);
+
+ return IRQ_HANDLED;
+}
+
+static int as1895_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct as1895_dev *as1895;
+ unsigned long irqflags;
+ int ret, gpio_pin;
+ const char *name;
+
+ ret = of_property_read_string(node, "name", &name);
+ if (ret)
+ return ret;
+
+ gpio_pin = of_get_named_gpio(node, "int-gpio", 0);
+ if (!gpio_is_valid(gpio_pin))
+ return -EINVAL;
+
+ as1895 = devm_kzalloc(dev, sizeof(struct as1895_dev), GFP_KERNEL);
+ if (!as1895)
+ return -ENOMEM;
+
+ as1895->edev = devm_extcon_dev_allocate(dev, as1895_cable);
+ if (IS_ERR(as1895->edev))
+ return -ENOMEM;
+
+ /* register extcon device */
+ ret = devm_extcon_dev_register(dev, as1895->edev);
+ if (ret) {
+ dev_err(dev, "can't register extcon device: %d\n", ret);
+ return ret;
+ }
+
+ as1895->input = devm_input_allocate_device(dev);
+ if (!as1895->input)
+ return -ENOMEM;
+
+ as1895->input->name = name;
+ set_bit(EV_SW, as1895->input->evbit);
+ set_bit(SW_LID, as1895->input->swbit);
+
+ /* register input device */
+ ret = input_register_device(as1895->input);
+ if (ret) {
+ dev_err(dev, "can't register input device: %d\n", ret);
+ return ret;
+ }
+
+ as1895->ws = wakeup_source_register(NULL, name);
+ if (!as1895->ws)
+ return -ENOMEM;
+
+ as1895->gpio_pin = gpio_pin;
+ as1895->irq = gpio_to_irq(gpio_pin);
+
+ irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+
+ ret = request_threaded_irq(as1895->irq, NULL,
+ as1895_irq_thread_handler,
+ irqflags, name, as1895);
+ if (ret)
+ goto err_unregister_ws;
+
+ platform_set_drvdata(pdev, as1895);
+
+ device_init_wakeup(dev, true);
+
+ return 0;
+
+err_unregister_ws:
+ wakeup_source_unregister(as1895->ws);
+
+ return ret;
+}
+
+static void as1895_remove(struct platform_device *pdev)
+{
+ struct as1895_dev *as1895 = platform_get_drvdata(pdev);
+
+ device_init_wakeup(&pdev->dev, false);
+
+ free_irq(as1895->irq, as1895);
+
+ wakeup_source_unregister(as1895->ws);
+}
+
+static int as1895_suspend(struct device *dev)
+{
+ struct as1895_dev *as1895 = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(as1895->irq);
+
+ return 0;
+}
+
+static int as1895_resume(struct device *dev)
+{
+ struct as1895_dev *as1895 = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(as1895->irq);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(as1895_pm_ops, as1895_suspend, as1895_resume);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id as1895_of_match[] = {
+ { .compatible = "amazon,as1895-hall-sensor" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, as1895_of_match);
+#endif
+
+static struct platform_driver as1895_driver = {
+ .probe = as1895_probe,
+ .remove = as1895_remove,
+ .driver = {
+ .name = AS1895_DRV_NAME,
+ .pm = pm_sleep_ptr(&as1895_pm_ops),
+ .of_match_table = of_match_ptr(as1895_of_match),
+ }
+};
+
+module_platform_driver(as1895_driver);
+
+MODULE_AUTHOR("Wentong Wu <wentongw@amazon.com>");
+MODULE_AUTHOR("Zengjin Zhao <zzengjin@amazon.com>");
+MODULE_AUTHOR("Xinkai Liu <xinka@amazon.com>");
+MODULE_AUTHOR("Weihua Wu <wuweihua@amazon.com>");
+MODULE_DESCRIPTION("Amazon as1895 hall sensor driver");
+MODULE_LICENSE("GPL");