lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <tencent_3AC818B2FE367BA7DD8940E08827CB146806@qq.com>
Date: Wed, 21 Jan 2026 03:59:14 -0500
From: 756271518@...com
To: dmitry.torokhov@...il.com
Cc: linusw@...nel.org,
	brgl@...nel.org,
	linux-kernel@...r.kernel.org,
	linux-input@...r.kernel.org,
	linux-gpio@...r.kernel.org,
	xuchen <756271518@...com>
Subject: [PATCH] Add common hall sensor drivers

From: xuchen <756271518@...com>

This patch adds support for common hall sensor ICs used in Qualcomm
reference designs. The driver handles both rising and falling edges
to detect magnetic field changes.

Signed-off-by: xuchen <756271518@...com>
---
 drivers/input/keyboard/pogo_switch.c | 323 +++++++++++++++++++++++++++
 1 file changed, 323 insertions(+)
 create mode 100644 drivers/input/keyboard/pogo_switch.c

diff --git a/drivers/input/keyboard/pogo_switch.c b/drivers/input/keyboard/pogo_switch.c
new file mode 100644
index 000000000000..ea91037caeb3
--- /dev/null
+++ b/drivers/input/keyboard/pogo_switch.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Pogo switch/hall sensor driver
+ *
+ * Copyright (c) 2024 faiot.com
+ *
+ * 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 <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/spinlock.h>
+#include <dt-bindings/input/gpio-keys.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+
+#define LID_DEV_NAME	"hall_sensor"
+#define HALL_INPUT	"/dev/input/hall_dev"
+#define KEY_HALL	84
+
+struct hall_data {
+	int gpio;			/* device use gpio number */
+	int irq;			/* device request irq number */
+	int active_low;			/* gpio active high or low for valid value */
+	bool wakeup;			/* device can wakeup system or not */
+	struct input_dev *hall_dev;
+	struct device *dev;
+	int detect_irq;
+	struct workqueue_struct *hall_wq;
+	struct delayed_work hall_debounce_work_det;
+};
+
+static struct hall_data *p_hall_data;
+static struct class extbd_ctrl_class;
+static int g_extbd_status;
+
+static void hall_driver_remove(struct platform_device *dev);
+
+static int hall_parse_dt(struct device *dev, struct hall_data *data)
+{
+	struct device_node *np = dev->of_node;
+
+	data->gpio = of_get_named_gpio(np, "faiot,hall-int", 0);
+	if (!gpio_is_valid(data->gpio)) {
+		dev_err(dev, "hall gpio is not valid\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static irqreturn_t hall_interrupt_handler(int irq, void *dev)
+{
+	if (p_hall_data == NULL || p_hall_data->hall_wq == NULL) {
+		pr_err("zy : irq resource not rdy\n");
+		return IRQ_HANDLED;
+	}
+
+	queue_delayed_work(p_hall_data->hall_wq,
+			   &p_hall_data->hall_debounce_work_det,
+			   msecs_to_jiffies(50));
+	return IRQ_HANDLED;
+}
+
+static void hall_det_debounce_work_func(struct work_struct *work)
+{
+	int value;
+
+	value = (gpio_get_value_cansleep(p_hall_data->gpio) ? 1 : 0) ^
+		p_hall_data->active_low;
+	if (value) {
+		input_report_key(p_hall_data->hall_dev, KEY_HALL, 0);
+		input_sync(p_hall_data->hall_dev);
+		dev_info(&p_hall_data->hall_dev->dev,
+			 "hall_interrupt_handler near\n");
+	} else {
+		input_report_key(p_hall_data->hall_dev, KEY_HALL, 1);
+		input_sync(p_hall_data->hall_dev);
+		dev_info(&p_hall_data->hall_dev->dev,
+			 "hall_interrupt_handler far\n");
+	}
+}
+
+static int hall_input_init(struct platform_device *pdev,
+			   struct hall_data *data)
+{
+	int err;
+
+	data->hall_dev = devm_input_allocate_device(&pdev->dev);
+	if (!data->hall_dev) {
+		dev_err(&pdev->dev, "input device allocation failed\n");
+		return -EINVAL;
+	}
+
+	data->hall_dev->name = LID_DEV_NAME;
+	data->hall_dev->phys = HALL_INPUT;
+	set_bit(EV_KEY, data->hall_dev->evbit);
+	set_bit(KEY_HALL, data->hall_dev->keybit);
+
+	err = input_register_device(data->hall_dev);
+	if (err < 0) {
+		dev_err(&pdev->dev, "unable to register input device %s\n",
+			LID_DEV_NAME);
+		return err;
+	}
+
+	return 0;
+}
+
+static ssize_t extbd_status_store(const struct class *c,
+				  const struct class_attribute *attr,
+				  const char *buf, size_t count)
+{
+	if (kstrtoint(buf, 0, &g_extbd_status))
+		return -EINVAL;
+
+	return count;
+}
+
+static ssize_t extbd_status_show(const struct class *c,
+				 const struct class_attribute *attr,
+				 char *buf)
+{
+	g_extbd_status = (gpio_get_value_cansleep(p_hall_data->gpio) ? 1 : 0) ^
+			 p_hall_data->active_low;
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", g_extbd_status);
+}
+
+static CLASS_ATTR_RW(extbd_status);
+
+static struct attribute *extbd_ctrl_class_attrs[] = {
+	&class_attr_extbd_status.attr,
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(extbd_ctrl_class);
+
+static int hall_driver_probe(struct platform_device *dev)
+{
+	struct hall_data *data;
+	int err;
+	int irq_flags;
+
+	dev_info(&dev->dev, "hall_driver probe\n");
+
+	data = devm_kzalloc(&dev->dev, sizeof(struct hall_data), GFP_KERNEL);
+	if (data == NULL) {
+		err = -ENOMEM;
+		dev_err(&dev->dev, "failed to allocate memory %d\n", err);
+		goto exit;
+	}
+
+	data->dev = &dev->dev;
+	dev_set_drvdata(&dev->dev, data);
+
+	err = hall_parse_dt(&dev->dev, data);
+	if (err < 0) {
+		dev_err(&dev->dev, "Failed to parse device tree\n");
+		goto exit;
+	}
+
+	err = hall_input_init(dev, data);
+	if (err < 0) {
+		dev_err(&dev->dev, "input init failed\n");
+		goto exit;
+	}
+
+	if (!gpio_is_valid(data->gpio)) {
+		dev_err(&dev->dev, "gpio is not valid\n");
+		err = -EINVAL;
+		goto free_gpio;
+	}
+
+	irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+	err = gpio_request_one(data->gpio, GPIOF_IN, "hall_sensor_irq");
+	if (err) {
+		dev_err(&dev->dev, "unable to request gpio %d\n", data->gpio);
+		goto exit;
+	}
+
+	data->irq = gpio_to_irq(data->gpio);
+	err = devm_request_threaded_irq(&dev->dev, data->irq, NULL,
+					hall_interrupt_handler,
+					irq_flags, "hall_sensor", data);
+	if (err < 0)
+		goto free_irq;
+
+	data->hall_wq = create_singlethread_workqueue("hall_wq");
+	if (!data->hall_wq)
+		return -EINVAL;
+
+	INIT_DELAYED_WORK(&data->hall_debounce_work_det,
+			  hall_det_debounce_work_func);
+
+	/*
+	 * err = sysfs_create_group(&data->dev->kobj, &hall_attr_group);
+	 * if (err) {
+	 *     printk(KERN_ERR "%s sysfs_create_group fail\n", __func__);
+	 *     return err;
+	 * }
+	 */
+
+	extbd_ctrl_class.name = "extbd_ctrl";
+	extbd_ctrl_class.class_groups = extbd_ctrl_class_groups;
+	err = class_register(&extbd_ctrl_class);
+	if (err < 0)
+		dev_err(&dev->dev, "Failed to create extbd_ctrl_class rc=%d\n",
+			err);
+
+	p_hall_data = data;
+	device_init_wakeup(&dev->dev, data->wakeup);
+	enable_irq_wake(data->irq);
+
+	dev_info(&dev->dev, "guh hall probe end");
+
+	return 0;
+
+free_irq:
+	disable_irq_wake(data->irq);
+	device_init_wakeup(&dev->dev, 0);
+free_gpio:
+	gpio_free(data->gpio);
+exit:
+	return err;
+}
+
+static void hall_driver_remove(struct platform_device *dev)
+{
+	struct hall_data *data = dev_get_drvdata(&dev->dev);
+
+	disable_irq_wake(data->irq);
+	device_init_wakeup(&dev->dev, 0);
+	if (data->gpio)
+		gpio_free(data->gpio);
+}
+
+static int hall_driver_suspend(struct platform_device *dev,
+			       pm_message_t state)
+{
+	/*
+	 * struct hall_data *data = dev_get_drvdata(&dev->dev);
+	 * gpio_direction_output(data->extbd_power, 0);
+	 */
+
+	return 0;
+}
+
+static int hall_driver_resume(struct platform_device *dev)
+{
+	/*
+	 * struct hall_data *data = dev_get_drvdata(&dev->dev);
+	 * gpio_direction_output(data->extbd_power, 1);
+	 */
+
+	return 0;
+}
+
+static struct platform_device_id hall_id[] = {
+	{ LID_DEV_NAME, 0 },
+	{ },
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id hall_match_table[] = {
+	{ .compatible = "hall-switch", },
+	{ },
+};
+#endif
+
+static struct platform_driver hall_driver = {
+	.driver = {
+		.name = LID_DEV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(hall_match_table),
+	},
+	.probe = hall_driver_probe,
+	.remove = hall_driver_remove,
+	.suspend = hall_driver_suspend,
+	.resume = hall_driver_resume,
+	.id_table = hall_id,
+};
+
+static int __init hall_init(void)
+{
+	return platform_driver_register(&hall_driver);
+}
+
+static void __exit hall_exit(void)
+{
+	platform_driver_unregister(&hall_driver);
+}
+
+module_init(hall_init);
+module_exit(hall_exit);
+
+MODULE_DESCRIPTION("Hall sensor driver");
+MODULE_LICENSE("GPL");


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ