Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags   |
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OnKey device driver for DA9063, DA9062 and DA9061 PMICs
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/mfd/da9063/core.h>
#include <linux/mfd/da9063/registers.h>
#include <linux/mfd/da9062/core.h>
#include <linux/mfd/da9062/registers.h>
struct da906x_chip_config {
<------>/* REGS */
<------>int onkey_status;
<------>int onkey_pwr_signalling;
<------>int onkey_fault_log;
<------>int onkey_shutdown;
<------>/* MASKS */
<------>int onkey_nonkey_mask;
<------>int onkey_nonkey_lock_mask;
<------>int onkey_key_reset_mask;
<------>int onkey_shutdown_mask;
<------>/* NAMES */
<------>const char *name;
};
struct da9063_onkey {
<------>struct delayed_work work;
<------>struct input_dev *input;
<------>struct device *dev;
<------>struct regmap *regmap;
<------>const struct da906x_chip_config *config;
<------>char phys[32];
<------>bool key_power;
};
static const struct da906x_chip_config da9063_regs = {
<------>/* REGS */
<------>.onkey_status = DA9063_REG_STATUS_A,
<------>.onkey_pwr_signalling = DA9063_REG_CONTROL_B,
<------>.onkey_fault_log = DA9063_REG_FAULT_LOG,
<------>.onkey_shutdown = DA9063_REG_CONTROL_F,
<------>/* MASKS */
<------>.onkey_nonkey_mask = DA9063_NONKEY,
<------>.onkey_nonkey_lock_mask = DA9063_NONKEY_LOCK,
<------>.onkey_key_reset_mask = DA9063_KEY_RESET,
<------>.onkey_shutdown_mask = DA9063_SHUTDOWN,
<------>/* NAMES */
<------>.name = DA9063_DRVNAME_ONKEY,
};
static const struct da906x_chip_config da9062_regs = {
<------>/* REGS */
<------>.onkey_status = DA9062AA_STATUS_A,
<------>.onkey_pwr_signalling = DA9062AA_CONTROL_B,
<------>.onkey_fault_log = DA9062AA_FAULT_LOG,
<------>.onkey_shutdown = DA9062AA_CONTROL_F,
<------>/* MASKS */
<------>.onkey_nonkey_mask = DA9062AA_NONKEY_MASK,
<------>.onkey_nonkey_lock_mask = DA9062AA_NONKEY_LOCK_MASK,
<------>.onkey_key_reset_mask = DA9062AA_KEY_RESET_MASK,
<------>.onkey_shutdown_mask = DA9062AA_SHUTDOWN_MASK,
<------>/* NAMES */
<------>.name = "da9062-onkey",
};
static const struct of_device_id da9063_compatible_reg_id_table[] = {
<------>{ .compatible = "dlg,da9063-onkey", .data = &da9063_regs },
<------>{ .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
<------>{ },
};
MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
static void da9063_poll_on(struct work_struct *work)
{
<------>struct da9063_onkey *onkey = container_of(work,
<------><------><------><------><------><------>struct da9063_onkey,
<------><------><------><------><------><------>work.work);
<------>const struct da906x_chip_config *config = onkey->config;
<------>unsigned int val;
<------>int fault_log = 0;
<------>bool poll = true;
<------>int error;
<------>/* Poll to see when the pin is released */
<------>error = regmap_read(onkey->regmap,
<------><------><------> config->onkey_status,
<------><------><------> &val);
<------>if (error) {
<------><------>dev_err(onkey->dev,
<------><------><------>"Failed to read ON status: %d\n", error);
<------><------>goto err_poll;
<------>}
<------>if (!(val & config->onkey_nonkey_mask)) {
<------><------>error = regmap_update_bits(onkey->regmap,
<------><------><------><------><------> config->onkey_pwr_signalling,
<------><------><------><------><------> config->onkey_nonkey_lock_mask,
<------><------><------><------><------> 0);
<------><------>if (error) {
<------><------><------>dev_err(onkey->dev,
<------><------><------><------>"Failed to reset the Key Delay %d\n", error);
<------><------><------>goto err_poll;
<------><------>}
<------><------>input_report_key(onkey->input, KEY_POWER, 0);
<------><------>input_sync(onkey->input);
<------><------>poll = false;
<------>}
<------>/*
<------> * If the fault log KEY_RESET is detected, then clear it
<------> * and shut down the system.
<------> */
<------>error = regmap_read(onkey->regmap,
<------><------><------> config->onkey_fault_log,
<------><------><------> &fault_log);
<------>if (error) {
<------><------>dev_warn(&onkey->input->dev,
<------><------><------> "Cannot read FAULT_LOG: %d\n", error);
<------>} else if (fault_log & config->onkey_key_reset_mask) {
<------><------>error = regmap_write(onkey->regmap,
<------><------><------><------> config->onkey_fault_log,
<------><------><------><------> config->onkey_key_reset_mask);
<------><------>if (error) {
<------><------><------>dev_warn(&onkey->input->dev,
<------><------><------><------> "Cannot reset KEY_RESET fault log: %d\n",
<------><------><------><------> error);
<------><------>} else {
<------><------><------>/* at this point we do any S/W housekeeping
<------><------><------> * and then send shutdown command
<------><------><------> */
<------><------><------>dev_dbg(&onkey->input->dev,
<------><------><------><------>"Sending SHUTDOWN to PMIC ...\n");
<------><------><------>error = regmap_write(onkey->regmap,
<------><------><------><------><------> config->onkey_shutdown,
<------><------><------><------><------> config->onkey_shutdown_mask);
<------><------><------>if (error)
<------><------><------><------>dev_err(&onkey->input->dev,
<------><------><------><------><------>"Cannot SHUTDOWN PMIC: %d\n",
<------><------><------><------><------>error);
<------><------>}
<------>}
err_poll:
<------>if (poll)
<------><------>schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
}
static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
{
<------>struct da9063_onkey *onkey = data;
<------>const struct da906x_chip_config *config = onkey->config;
<------>unsigned int val;
<------>int error;
<------>error = regmap_read(onkey->regmap,
<------><------><------> config->onkey_status,
<------><------><------> &val);
<------>if (onkey->key_power && !error && (val & config->onkey_nonkey_mask)) {
<------><------>input_report_key(onkey->input, KEY_POWER, 1);
<------><------>input_sync(onkey->input);
<------><------>schedule_delayed_work(&onkey->work, 0);
<------><------>dev_dbg(onkey->dev, "KEY_POWER long press.\n");
<------>} else {
<------><------>input_report_key(onkey->input, KEY_POWER, 1);
<------><------>input_sync(onkey->input);
<------><------>input_report_key(onkey->input, KEY_POWER, 0);
<------><------>input_sync(onkey->input);
<------><------>dev_dbg(onkey->dev, "KEY_POWER short press.\n");
<------>}
<------>return IRQ_HANDLED;
}
static void da9063_cancel_poll(void *data)
{
<------>struct da9063_onkey *onkey = data;
<------>cancel_delayed_work_sync(&onkey->work);
}
static int da9063_onkey_probe(struct platform_device *pdev)
{
<------>struct da9063_onkey *onkey;
<------>const struct of_device_id *match;
<------>int irq;
<------>int error;
<------>match = of_match_node(da9063_compatible_reg_id_table,
<------><------><------> pdev->dev.of_node);
<------>if (!match)
<------><------>return -ENXIO;
<------>onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey),
<------><------><------> GFP_KERNEL);
<------>if (!onkey) {
<------><------>dev_err(&pdev->dev, "Failed to allocate memory.\n");
<------><------>return -ENOMEM;
<------>}
<------>onkey->config = match->data;
<------>onkey->dev = &pdev->dev;
<------>onkey->regmap = dev_get_regmap(pdev->dev.parent, NULL);
<------>if (!onkey->regmap) {
<------><------>dev_err(&pdev->dev, "Parent regmap unavailable.\n");
<------><------>return -ENXIO;
<------>}
<------>onkey->key_power = !of_property_read_bool(pdev->dev.of_node,
<------><------><------><------><------><------> "dlg,disable-key-power");
<------>onkey->input = devm_input_allocate_device(&pdev->dev);
<------>if (!onkey->input) {
<------><------>dev_err(&pdev->dev, "Failed to allocated input device.\n");
<------><------>return -ENOMEM;
<------>}
<------>onkey->input->name = onkey->config->name;
<------>snprintf(onkey->phys, sizeof(onkey->phys), "%s/input0",
<------><------> onkey->config->name);
<------>onkey->input->phys = onkey->phys;
<------>onkey->input->dev.parent = &pdev->dev;
<------>input_set_capability(onkey->input, EV_KEY, KEY_POWER);
<------>INIT_DELAYED_WORK(&onkey->work, da9063_poll_on);
<------>error = devm_add_action(&pdev->dev, da9063_cancel_poll, onkey);
<------>if (error) {
<------><------>dev_err(&pdev->dev,
<------><------><------>"Failed to add cancel poll action: %d\n",
<------><------><------>error);
<------><------>return error;
<------>}
<------>irq = platform_get_irq_byname(pdev, "ONKEY");
<------>if (irq < 0)
<------><------>return irq;
<------>error = devm_request_threaded_irq(&pdev->dev, irq,
<------><------><------><------><------> NULL, da9063_onkey_irq_handler,
<------><------><------><------><------> IRQF_TRIGGER_LOW | IRQF_ONESHOT,
<------><------><------><------><------> "ONKEY", onkey);
<------>if (error) {
<------><------>dev_err(&pdev->dev,
<------><------><------>"Failed to request IRQ %d: %d\n", irq, error);
<------><------>return error;
<------>}
<------>error = input_register_device(onkey->input);
<------>if (error) {
<------><------>dev_err(&pdev->dev,
<------><------><------>"Failed to register input device: %d\n", error);
<------><------>return error;
<------>}
<------>return 0;
}
static struct platform_driver da9063_onkey_driver = {
<------>.probe = da9063_onkey_probe,
<------>.driver = {
<------><------>.name = DA9063_DRVNAME_ONKEY,
<------><------>.of_match_table = da9063_compatible_reg_id_table,
<------>},
};
module_platform_driver(da9063_onkey_driver);
MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063, DA9062 and DA9061");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);