Skip to content
Snippets Groups Projects
Commit c0165c85 authored by Marek Szyprowski's avatar Marek Szyprowski Committed by Neil Armstrong
Browse files

button: add a simple Analog to Digital Converter device based button driver


Add a simple Analog to Digital Converter device based button driver. This
driver binds to the 'adc-keys' device tree node.

Signed-off-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: default avatarSimon Glass <sjg@chromium.org>
Signed-off-by: default avatarNeil Armstrong <narmstrong@baylibre.com>
parent e1b03d6b
No related branches found
No related tags found
No related merge requests found
...@@ -9,6 +9,14 @@ config BUTTON ...@@ -9,6 +9,14 @@ config BUTTON
can provide access to board-specific buttons. Use of the device tree can provide access to board-specific buttons. Use of the device tree
for configuration is encouraged. for configuration is encouraged.
config BUTTON_ADC
bool "Button adc"
depends on BUTTON
help
Enable support for buttons which are connected to Analog to Digital
Converter device. The ADC driver must use driver model. Buttons are
configured using the device tree.
config BUTTON_GPIO config BUTTON_GPIO
bool "Button gpio" bool "Button gpio"
depends on BUTTON depends on BUTTON
......
...@@ -3,4 +3,5 @@ ...@@ -3,4 +3,5 @@
# Copyright (C) 2020 Philippe Reynes <philippe.reynes@softathome.com> # Copyright (C) 2020 Philippe Reynes <philippe.reynes@softathome.com>
obj-$(CONFIG_BUTTON) += button-uclass.o obj-$(CONFIG_BUTTON) += button-uclass.o
obj-$(CONFIG_BUTTON_ADC) += button-adc.o
obj-$(CONFIG_BUTTON_GPIO) += button-gpio.o obj-$(CONFIG_BUTTON_GPIO) += button-gpio.o
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Samsung Electronics Co., Ltd.
* http://www.samsung.com
* Author: Marek Szyprowski <m.szyprowski@samsung.com>
*/
#include <common.h>
#include <adc.h>
#include <button.h>
#include <log.h>
#include <dm.h>
#include <dm/lists.h>
#include <dm/of_access.h>
#include <dm/uclass-internal.h>
/**
* struct button_adc_priv - private data for button-adc driver.
*
* @adc: Analog to Digital Converter device to which button is connected.
* @channel: channel of the ADC device to probe the button state.
* @min: minimal uV value to consider button as pressed.
* @max: maximal uV value to consider button as pressed.
*/
struct button_adc_priv {
struct udevice *adc;
int channel;
int min;
int max;
};
static enum button_state_t button_adc_get_state(struct udevice *dev)
{
struct button_adc_priv *priv = dev_get_priv(dev);
unsigned int val;
int ret, uV;
ret = adc_start_channel(priv->adc, priv->channel);
if (ret)
return ret;
ret = adc_channel_data(priv->adc, priv->channel, &val);
if (ret)
return ret;
ret = adc_raw_to_uV(priv->adc, val, &uV);
if (ret)
return ret;
return (uV >= priv->min && uV < priv->max) ? BUTTON_ON : BUTTON_OFF;
}
static int button_adc_of_to_plat(struct udevice *dev)
{
struct button_uc_plat *uc_plat = dev_get_uclass_plat(dev);
struct button_adc_priv *priv = dev_get_priv(dev);
struct ofnode_phandle_args args;
u32 treshold, up_treshold, t;
ofnode node;
int ret;
/* Ignore the top-level button node */
if (!uc_plat->label)
return 0;
ret = dev_read_phandle_with_args(dev->parent, "io-channels",
"#io-channel-cells", 0, 0, &args);
if (ret)
return ret;
ret = uclass_get_device_by_ofnode(UCLASS_ADC, args.node, &priv->adc);
if (ret)
return ret;
ret = ofnode_read_u32(dev_ofnode(dev->parent),
"keyup-threshold-microvolt", &up_treshold);
if (ret)
return ret;
ret = ofnode_read_u32(dev_ofnode(dev), "press-threshold-microvolt",
&treshold);
if (ret)
return ret;
dev_for_each_subnode(node, dev->parent) {
ret = ofnode_read_u32(node, "press-threshold-microvolt", &t);
if (ret)
return ret;
if (t > treshold)
up_treshold = t;
}
priv->channel = args.args[0];
priv->min = treshold;
priv->max = up_treshold;
return ret;
}
static int button_adc_bind(struct udevice *parent)
{
struct udevice *dev;
ofnode node;
int ret;
dev_for_each_subnode(node, parent) {
struct button_uc_plat *uc_plat;
const char *label;
label = ofnode_read_string(node, "label");
if (!label) {
debug("%s: node %s has no label\n", __func__,
ofnode_get_name(node));
return -EINVAL;
}
ret = device_bind_driver_to_node(parent, "button_adc",
ofnode_get_name(node),
node, &dev);
if (ret)
return ret;
uc_plat = dev_get_uclass_plat(dev);
uc_plat->label = label;
}
return 0;
}
static const struct button_ops button_adc_ops = {
.get_state = button_adc_get_state,
};
static const struct udevice_id button_adc_ids[] = {
{ .compatible = "adc-keys" },
{ }
};
U_BOOT_DRIVER(button_adc) = {
.name = "button_adc",
.id = UCLASS_BUTTON,
.of_match = button_adc_ids,
.ops = &button_adc_ops,
.priv_auto = sizeof(struct button_adc_priv),
.bind = button_adc_bind,
.of_to_plat = button_adc_of_to_plat,
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment