mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-09-19 12:51:23 +02:00
When bringing in the series 'arm: dts: am62-beagleplay: Fix Beagleplay Ethernet"' I failed to notice that b4 noticed it was based on next and so took that as the base commit and merged that part of next to master. This reverts commit c8ffd1356d42223cbb8c86280a083cc3c93e6426, reversing changes made to 2ee6f3a5f7550de3599faef9704e166e5dcace35. Reported-by: Jonas Karlman <jonas@kwiboo.se> Signed-off-by: Tom Rini <trini@konsulko.com>
158 lines
3.6 KiB
C
158 lines
3.6 KiB
C
// 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 down_threshold = 0, up_threshold, voltage, 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_threshold);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = ofnode_read_u32(dev_ofnode(dev), "press-threshold-microvolt",
|
|
&voltage);
|
|
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 > voltage && t < up_threshold)
|
|
up_threshold = t;
|
|
else if (t < voltage && t > down_threshold)
|
|
down_threshold = t;
|
|
}
|
|
|
|
priv->channel = args.args[0];
|
|
|
|
/*
|
|
* Define the voltage range such that the button is only pressed
|
|
* when the voltage is closest to its own press-threshold-microvolt
|
|
*/
|
|
if (down_threshold == 0)
|
|
priv->min = 0;
|
|
else
|
|
priv->min = down_threshold + (voltage - down_threshold) / 2;
|
|
|
|
priv->max = voltage + (up_threshold - voltage) / 2;
|
|
|
|
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,
|
|
};
|