Update source to Armbian-dev-202610.A311Y3

This commit is contained in:
2026-11-11 08:50:43 +08:00
parent 3428a94f6b
commit f459ef6a9e
12514 changed files with 2264376 additions and 468481 deletions
@@ -5,3 +5,14 @@ config AMLOGIC_INPUT_FILTER
default n
help
Say Y here if you want to use the Input Filter.
config AMLOGIC_HALL_SENSOR
bool "Amlogic hall sensor support"
default n
help
Hall sensor driver monitors the hall switch gpio and reports
the cover state as EV_SW/SW_LID input event, which can be
used to wake up or turn off the screen when the smart cover
is opened/closed.
Say Y here if you want to use the amlogic hall sensor.
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
$(MODULE_NAME)-$(CONFIG_AMLOGIC_INPUT_FILTER) += misc/input_filter.o
$(MODULE_NAME)-$(CONFIG_AMLOGIC_HALL_SENSOR) += misc/hall_sensor.o
@@ -0,0 +1,265 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2026 Amlogic, Inc. All rights reserved.
*/
/*
* Hall Sensor driver for smart cover detection.
*
* This driver handles a hall switch like SDC1211 whose OUT pin is
* connected to a SoC GPIO. The hall switch pulls the GPIO level when
* the cover magnet is near, the driver reports the state as an
* EV_SW/SW_LID input event so that user space can turn off/wake up
* the screen when the cover is closed/opened.
*
* DT properties:
* - hall-gpios : the gpio the hall switch OUT pin connects to,
* the gpio polarity flags describe the active
* (cover closed) level.
* - linux,code : the switch code to report, default SW_LID.
* - debounce-ms : debounce time in ms, default 30ms.
* - wakeup-source : enable the hall irq as a wakeup source, the
* irq is also registered to bl31 so that it can
* wake up the system from deep suspend.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/pm_wakeup.h>
#include <linux/amlogic/power_domain.h>
#define DEFAULT_DEBOUNCE_MS 30
#define HALL_SENSOR_NAME "hall_sensor"
struct hall_sensor {
struct device *dev;
struct input_dev *input;
struct gpio_desc *desc;
int irq;
u32 code;
u32 debounce_ms;
int last_state;
struct delayed_work work;
};
static void hall_sensor_work(struct work_struct *work)
{
struct hall_sensor *hall =
container_of(work, struct hall_sensor, work.work);
int state;
state = gpiod_get_value(hall->desc);
if (state < 0) {
dev_err(hall->dev, "failed to get hall gpio value\n");
return;
}
if (state != hall->last_state) {
hall->last_state = state;
input_report_switch(hall->input, hall->code, state);
input_sync(hall->input);
dev_info(hall->dev,
"cover %s\n", state ? "closed" : "opened");
}
}
static irqreturn_t hall_sensor_irq_handler(int irq, void *data)
{
struct hall_sensor *hall = data;
/*
* Do not disable the irq here, just refresh the debounce
* window so that the irq stays enabled for wakeup.
*/
mod_delayed_work(system_wq, &hall->work,
msecs_to_jiffies(hall->debounce_ms));
return IRQ_HANDLED;
}
static ssize_t hall_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct hall_sensor *hall = dev_get_drvdata(dev);
return sysfs_emit(buf, "%d\n", hall->last_state);
}
static DEVICE_ATTR_RO(hall_state);
static int hall_sensor_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct hall_sensor *hall;
bool wakeup_source;
struct irq_desc *desc;
unsigned long number;
int ret;
if (!dev->of_node) {
dev_err(dev, "device node is NULL\n");
return -EINVAL;
}
hall = devm_kzalloc(dev, sizeof(*hall), GFP_KERNEL);
if (!hall)
return -ENOMEM;
hall->dev = dev;
platform_set_drvdata(pdev, hall);
hall->desc = devm_gpiod_get(dev, "hall", GPIOD_IN);
if (IS_ERR(hall->desc)) {
dev_err(dev, "failed to get hall gpio\n");
return PTR_ERR(hall->desc);
}
if (of_property_read_u32(dev->of_node, "linux,code", &hall->code))
hall->code = SW_LID;
if (of_property_read_u32(dev->of_node,
"debounce-ms", &hall->debounce_ms))
hall->debounce_ms = DEFAULT_DEBOUNCE_MS;
hall->irq = gpiod_to_irq(hall->desc);
if (hall->irq < 0) {
dev_err(dev, "failed to get hall irq\n");
return hall->irq;
}
hall->input = devm_input_allocate_device(dev);
if (!hall->input)
return -ENOMEM;
hall->input->name = HALL_SENSOR_NAME;
hall->input->phys = HALL_SENSOR_NAME "/input0";
hall->input->dev.parent = dev;
hall->input->id.bustype = BUS_ISA;
hall->input->id.vendor = 0x0001;
hall->input->id.product = 0x0001;
hall->input->id.version = 0x0100;
input_set_capability(hall->input, EV_SW, hall->code);
ret = input_register_device(hall->input);
if (ret) {
dev_err(dev, "failed to register input device\n");
return ret;
}
/* Report the current cover state at boot. */
hall->last_state = gpiod_get_value(hall->desc);
if (hall->last_state < 0)
hall->last_state = 0;
input_report_switch(hall->input, hall->code, hall->last_state);
input_sync(hall->input);
dev_info(dev, "hall cover %s at probe\n",
hall->last_state ? "closed" : "opened");
INIT_DELAYED_WORK(&hall->work, hall_sensor_work);
ret = devm_request_irq(dev, hall->irq, hall_sensor_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
HALL_SENSOR_NAME, hall);
if (ret) {
dev_err(dev, "failed to request hall irq\n");
return ret;
}
ret = device_create_file(dev, &dev_attr_hall_state);
if (ret) {
dev_err(dev, "failed to create hall_state sysfs node\n");
return ret;
}
wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source");
if (wakeup_source) {
device_init_wakeup(dev, true);
/*
* Register the hall irq to bl31 as a wakeup source,
* refer to the gpio_keypad driver.
*/
desc = irq_to_desc(hall->irq);
if (desc && desc->irq_data.parent_data) {
number = desc->irq_data.parent_data->hwirq - 32;
pwr_ctrl_irq_set(number, 1, 0);
dev_dbg(dev, "register wakeup irq %lu\n", number);
} else {
dev_err(dev, "failed to get hall parent irq\n");
}
}
dev_info(dev, "hall sensor probed, code=%u debounce=%ums\n",
hall->code, hall->debounce_ms);
return 0;
}
static void hall_sensor_remove(struct platform_device *pdev)
{
struct hall_sensor *hall = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&hall->work);
device_remove_file(&pdev->dev, &dev_attr_hall_state);
}
static int hall_sensor_suspend(struct device *dev)
{
struct hall_sensor *hall = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(hall->irq);
return 0;
}
static int hall_sensor_resume(struct device *dev)
{
struct hall_sensor *hall = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(hall->irq);
/*
* The cover state may change during suspend, report it
* after resume.
*/
mod_delayed_work(system_wq, &hall->work, 0);
return 0;
}
static const struct dev_pm_ops hall_sensor_pm_ops = {
.suspend = hall_sensor_suspend,
.resume = hall_sensor_resume,
};
static const struct of_device_id hall_sensor_dt_match[] = {
{ .compatible = "amlogic,hall-sensor", },
{}
};
MODULE_DEVICE_TABLE(of, hall_sensor_dt_match);
static struct platform_driver hall_sensor_driver = {
.probe = hall_sensor_probe,
.remove = hall_sensor_remove,
.driver = {
.name = "hall-sensor",
.pm = &hall_sensor_pm_ops,
.of_match_table = hall_sensor_dt_match,
},
};
int __init meson_hall_sensor_init(void)
{
return platform_driver_register(&hall_sensor_driver);
}
void __exit meson_hall_sensor_exit(void)
{
platform_driver_unregister(&hall_sensor_driver);
}
MODULE_LICENSE("GPL v2");
@@ -216,6 +216,10 @@ static int input_filter_connect(struct input_handler *handler,
if (error)
goto err_unregister_handle;
/*
* struct input_handle *handle will be freed in input_filter_disconnect()
*/
// coverity[RESOURCE_LEAK]
return 0;
err_unregister_handle: