Commit 8f7a16aa authored by Tom Rini's avatar Tom Rini

Merge tag 'u-boot-amlogic-20210222' of https://gitlab.denx.de/u-boot/custodians/u-boot-amlogic

- adds adc-keys button driver
- fix meson-saradc driver to get reference voltage
- add adc-keys test for sandbox
- enable adc-keys for VIM3 & VIM3L boards
- fix button.h build
parents bced796e 2d339efb
......@@ -2,6 +2,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/gpio/sandbox-gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/pinctrl/sandbox-pinmux.h>
#include <dt-bindings/mux/mux.h>
......@@ -69,6 +70,30 @@
};
};
buttons2 {
compatible = "adc-keys";
io-channels = <&adc 3>;
keyup-threshold-microvolt = <3000000>;
button-up {
label = "button3";
linux,code = <KEY_F3>;
press-threshold-microvolt = <1500000>;
};
button-down {
label = "button4";
linux,code = <KEY_F4>;
press-threshold-microvolt = <1000000>;
};
button-enter {
label = "button5";
linux,code = <KEY_F5>;
press-threshold-microvolt = <500000>;
};
};
cros_ec: cros-ec {
reg = <0 0>;
compatible = "google,cros-ec-sandbox";
......@@ -608,8 +633,9 @@
i2c-eeprom = <&bootcount_i2c>;
};
adc@0 {
adc: adc@0 {
compatible = "sandbox,adc";
#io-channel-cells = <1>;
vdd-supply = <&buck2>;
vss-microvolts = <0>;
};
......
......@@ -31,6 +31,8 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_ADC=y
CONFIG_SARADC_MESON=y
CONFIG_BUTTON=y
CONFIG_BUTTON_ADC=y
CONFIG_DM_I2C=y
CONFIG_SYS_I2C_MESON=y
CONFIG_DM_MMC=y
......
......@@ -31,6 +31,8 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_ADC=y
CONFIG_SARADC_MESON=y
CONFIG_BUTTON=y
CONFIG_BUTTON_ADC=y
CONFIG_DM_I2C=y
CONFIG_SYS_I2C_MESON=y
CONFIG_DM_MMC=y
......
......@@ -123,6 +123,7 @@ CONFIG_DM_BOOTCOUNT=y
CONFIG_DM_BOOTCOUNT_RTC=y
CONFIG_DM_BOOTCOUNT_I2C_EEPROM=y
CONFIG_BUTTON=y
CONFIG_BUTTON_ADC=y
CONFIG_BUTTON_GPIO=y
CONFIG_CLK=y
CONFIG_CLK_COMPOSITE_CCF=y
......
ADC attached resistor ladder buttons
------------------------------------
Required properties:
- compatible: "adc-keys"
- io-channels: Phandle to an ADC channel
- io-channel-names = "buttons";
- keyup-threshold-microvolt: Voltage above or equal to which all the keys are
considered up.
Optional properties:
- poll-interval: Poll interval time in milliseconds
- autorepeat: Boolean, Enable auto repeat feature of Linux input
subsystem.
Each button (key) is represented as a sub-node of "adc-keys":
Required subnode-properties:
- label: Descriptive name of the key.
- linux,code: Keycode to emit.
- press-threshold-microvolt: voltage above or equal to which this key is
considered pressed.
No two values of press-threshold-microvolt may be the same.
All values of press-threshold-microvolt must be less than
keyup-threshold-microvolt.
Example:
#include <dt-bindings/input/input.h>
adc-keys {
compatible = "adc-keys";
io-channels = <&lradc 0>;
io-channel-names = "buttons";
keyup-threshold-microvolt = <2000000>;
button-up {
label = "Volume Up";
linux,code = <KEY_VOLUMEUP>;
press-threshold-microvolt = <1500000>;
};
button-down {
label = "Volume Down";
linux,code = <KEY_VOLUMEDOWN>;
press-threshold-microvolt = <1000000>;
};
button-enter {
label = "Enter";
linux,code = <KEY_ENTER>;
press-threshold-microvolt = <500000>;
};
};
+--------------------------------+------------------------+
| 2.000.000 <= value | no key pressed |
+--------------------------------+------------------------+
| 1.500.000 <= value < 2.000.000 | KEY_VOLUMEUP pressed |
+--------------------------------+------------------------+
| 1.000.000 <= value < 1.500.000 | KEY_VOLUMEDOWN pressed |
+--------------------------------+------------------------+
| 500.000 <= value < 1.000.000 | KEY_ENTER pressed |
+--------------------------------+------------------------+
| value < 500.000 | no key pressed |
+--------------------------------+------------------------+
......@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/math64.h>
#include <linux/bitfield.h>
#include <power/regulator.h>
#define MESON_SAR_ADC_REG0 0x00
#define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31)
......@@ -656,7 +657,10 @@ static int meson_saradc_stop(struct udevice *dev)
static int meson_saradc_probe(struct udevice *dev)
{
struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
struct meson_saradc_priv *priv = dev_get_priv(dev);
struct udevice *vref;
int vref_uv;
int ret;
ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
......@@ -675,6 +679,23 @@ static int meson_saradc_probe(struct udevice *dev)
priv->active_channel = -1;
ret = device_get_supply_regulator(dev, "vref-supply", &vref);
if (ret) {
printf("can't get vref-supply: %d\n", ret);
return ret;
}
vref_uv = regulator_get_value(vref);
if (vref_uv < 0) {
printf("can't get vref-supply value: %d\n", vref_uv);
return vref_uv;
}
/* VDD supplied by common vref pin */
uc_pdata->vdd_supply = vref;
uc_pdata->vdd_microvolts = vref_uv;
uc_pdata->vss_microvolts = 0;
return 0;
}
......
......@@ -9,6 +9,14 @@ config BUTTON
can provide access to board-specific buttons. Use of the device tree
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
bool "Button gpio"
depends on BUTTON
......
......@@ -3,4 +3,5 @@
# Copyright (C) 2020 Philippe Reynes <philippe.reynes@softathome.com>
obj-$(CONFIG_BUTTON) += button-uclass.o
obj-$(CONFIG_BUTTON_ADC) += button-adc.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,
};
......@@ -6,6 +6,8 @@
#ifndef __BUTTON_H
#define __BUTTON_H
struct udevice;
/**
* struct button_uc_plat - Platform data the uclass stores about each device
*
......
......@@ -7,7 +7,10 @@
#include <common.h>
#include <dm.h>
#include <adc.h>
#include <button.h>
#include <power/regulator.h>
#include <power/sandbox_pmic.h>
#include <asm/gpio.h>
#include <dm/test.h>
#include <test/ut.h>
......@@ -17,11 +20,20 @@ static int dm_test_button_base(struct unit_test_state *uts)
{
struct udevice *dev;
/* Get the top-level device */
/* Get the top-level gpio buttons device */
ut_assertok(uclass_get_device(UCLASS_BUTTON, 0, &dev));
/* Get the 2 gpio buttons */
ut_assertok(uclass_get_device(UCLASS_BUTTON, 1, &dev));
ut_assertok(uclass_get_device(UCLASS_BUTTON, 2, &dev));
ut_asserteq(-ENODEV, uclass_get_device(UCLASS_BUTTON, 3, &dev));
/* Get the top-level adc buttons device */
ut_assertok(uclass_get_device(UCLASS_BUTTON, 3, &dev));
/* Get the 3 adc buttons */
ut_assertok(uclass_get_device(UCLASS_BUTTON, 4, &dev));
ut_assertok(uclass_get_device(UCLASS_BUTTON, 5, &dev));
ut_assertok(uclass_get_device(UCLASS_BUTTON, 6, &dev));
ut_asserteq(-ENODEV, uclass_get_device(UCLASS_BUTTON, 7, &dev));
return 0;
}
......@@ -72,3 +84,37 @@ static int dm_test_button_label(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_button_label, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
/* Test adc-keys driver */
static int dm_test_button_keys_adc(struct unit_test_state *uts)
{
struct udevice *supply;
struct udevice *dev;
int uV;
ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc@0", &dev));
ut_assertok(regulator_get_by_devname(SANDBOX_BUCK2_DEVNAME, &supply));
ut_assertok(regulator_set_value(supply, SANDBOX_BUCK2_SET_UV));
ut_asserteq(SANDBOX_BUCK2_SET_UV, regulator_get_value(supply));
/* Update ADC plat and get new Vdd value */
ut_assertok(adc_vdd_value(dev, &uV));
ut_asserteq(SANDBOX_BUCK2_SET_UV, uV);
/*
* sandbox-adc returns constant value on channel 3, is used by adc-keys:
* SANDBOX_ADC_CHANNEL3_DATA * SANDBOX_BUCK2_SET_UV / SANDBOX_ADC_DATA_MASK =
* 0x3000 * 3300000 / 0xffff = 618759uV
* This means that button3 and button4 are released and button5
* is pressed.
*/
ut_assertok(button_get_by_label("button3", &dev));
ut_asserteq(BUTTON_OFF, button_get_state(dev));
ut_assertok(button_get_by_label("button4", &dev));
ut_asserteq(BUTTON_OFF, button_get_state(dev));
ut_assertok(button_get_by_label("button5", &dev));
ut_asserteq(BUTTON_ON, button_get_state(dev));
return 0;
}
DM_TEST(dm_test_button_keys_adc, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment