[PATCH 1/4] drivers: Introduce vibrator uclass
Samuel Dionne-Riel
samuel at dionne-riel.com
Wed Dec 22 23:36:04 CET 2021
Signed-off-by: Samuel Dionne-Riel <samuel at dionne-riel.com>
---
arch/sandbox/dts/test.dts | 10 +++
configs/sandbox_defconfig | 2 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/vibrator/Kconfig | 21 +++++++
drivers/vibrator/Makefile | 5 ++
drivers/vibrator/vibrator-uclass.c | 62 +++++++++++++++++++
include/dm/uclass-id.h | 1 +
include/vibrator.h | 87 +++++++++++++++++++++++++++
test/dm/Makefile | 1 +
test/dm/vibrator.c | 97 ++++++++++++++++++++++++++++++
11 files changed, 289 insertions(+)
create mode 100644 drivers/vibrator/Kconfig
create mode 100644 drivers/vibrator/Makefile
create mode 100644 drivers/vibrator/vibrator-uclass.c
create mode 100644 include/vibrator.h
create mode 100644 test/dm/vibrator.c
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 2cea4a43c8..3633b8fb9f 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1608,6 +1608,16 @@
compatible = "sandbox,regmap_test";
};
};
+
+ vibrator_left {
+ compatible = "gpio-vibrator";
+ enable-gpios = <&gpio_a 1 0 GPIO_ACTIVE_HIGH>;
+ };
+
+ vibrator_right {
+ compatible = "gpio-vibrator";
+ enable-gpios = <&gpio_a 2 0 GPIO_ACTIVE_HIGH>;
+ };
};
#include "sandbox_pmic.dtsi"
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index c390afe9de..43f9972178 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -273,6 +273,8 @@ CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_USB_ETHER=y
CONFIG_USB_ETH_CDC=y
+CONFIG_VIBRATOR=y
+CONFIG_VIBRATOR_GPIO=y
CONFIG_DM_VIDEO=y
CONFIG_VIDEO_COPY=y
CONFIG_CONSOLE_ROTATION=y
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b26ca8cf70..a15674f22c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -134,6 +134,8 @@ source "drivers/usb/Kconfig"
source "drivers/ufs/Kconfig"
+source "drivers/vibrator/Kconfig"
+
source "drivers/video/Kconfig"
source "drivers/virtio/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 4e7cf28440..2290d4a5d8 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_$(SPL_TPL_)RTC) += rtc/
obj-$(CONFIG_$(SPL_TPL_)SERIAL) += serial/
obj-$(CONFIG_$(SPL_TPL_)SPI) += spi/
obj-$(CONFIG_$(SPL_TPL_)TIMER) += timer/
+obj-$(CONFIG_$(SPL_TPL_)VIBRATOR) += vibrator/
obj-$(CONFIG_$(SPL_TPL_)VIRTIO) += virtio/
obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/
obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/
diff --git a/drivers/vibrator/Kconfig b/drivers/vibrator/Kconfig
new file mode 100644
index 0000000000..f988aa63b9
--- /dev/null
+++ b/drivers/vibrator/Kconfig
@@ -0,0 +1,21 @@
+menu "Vibrator Feedback Support"
+
+config VIBRATOR
+ bool "Enable vibration motor support"
+ depends on DM
+ help
+ Many boards have vibration motorss which can be used to signal status or
+ alerts. U-Boot provides a uclass API to implement this feature. Vibration
+ motor drivers can provide access to board-specific vibration motors. Use
+ of the device tree for configuration is encouraged.
+
+config SPL_VIBRATOR
+ bool "Enable vibration motor support in SPL"
+ depends on SPL && SPL_DM
+ help
+ The vibration motor subsystem adds a small amount of overhead to the image.
+ If this is acceptable and you have a need to use vibration motors in SPL,
+ enable this option. You will need to enable device tree in SPL
+ for this to work.
+
+endmenu
diff --git a/drivers/vibrator/Makefile b/drivers/vibrator/Makefile
new file mode 100644
index 0000000000..326838ff7a
--- /dev/null
+++ b/drivers/vibrator/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2021 Samuel Dionne-Riel <samuel at dionne-riel.com>
+
+obj-y += vibrator-uclass.o
diff --git a/drivers/vibrator/vibrator-uclass.c b/drivers/vibrator/vibrator-uclass.c
new file mode 100644
index 0000000000..ffb6522a19
--- /dev/null
+++ b/drivers/vibrator/vibrator-uclass.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Samuel Dionne-Riel <samuel at dionne-riel.com>
+ * Copyright (c) 2015 Google, Inc
+ * Largely derived from `drivers/led/led-uclass.c`
+ * Original written by Simon Glass <sjg at chromium.org>
+ */
+
+#define LOG_CATEGORY UCLASS_VIBRATOR
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <vibrator.h>
+#include <dm/device-internal.h>
+#include <dm/root.h>
+#include <dm/uclass-internal.h>
+
+int vibrator_get_by_label(const char *label, struct udevice **devp)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_VIBRATOR, &uc);
+ if (ret)
+ return ret;
+ uclass_foreach_dev(dev, uc) {
+ struct vibrator_uc_plat *uc_plat = dev_get_uclass_plat(dev);
+
+ if (uc_plat->label && strcmp(label, uc_plat->label) == 0)
+ return uclass_get_device_tail(dev, 0, devp);
+ }
+
+ return -ENODEV;
+}
+
+int vibrator_set_state(struct udevice *dev, enum vibrator_state_t state)
+{
+ struct vibrator_ops *ops = vibrator_get_ops(dev);
+
+ if (!ops->set_state)
+ return -ENOSYS;
+
+ return ops->set_state(dev, state);
+}
+
+enum vibrator_state_t vibrator_get_state(struct udevice *dev)
+{
+ struct vibrator_ops *ops = vibrator_get_ops(dev);
+
+ if (!ops->get_state)
+ return -ENOSYS;
+
+ return ops->get_state(dev);
+}
+
+UCLASS_DRIVER(vibrator) = {
+ .id = UCLASS_VIBRATOR,
+ .name = "vibrator",
+ .per_device_plat_auto = sizeof(struct vibrator_uc_plat),
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 0e26e1d138..265369d07b 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -125,6 +125,7 @@ enum uclass_id {
UCLASS_USB_DEV_GENERIC, /* USB generic device */
UCLASS_USB_HUB, /* USB hub */
UCLASS_USB_GADGET_GENERIC, /* USB generic device */
+ UCLASS_VIBRATOR, /* Vibration feedback devices (phone vibration) */
UCLASS_VIDEO, /* Video or LCD device */
UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */
UCLASS_VIDEO_CONSOLE, /* Text console driver for video device */
diff --git a/include/vibrator.h b/include/vibrator.h
new file mode 100644
index 0000000000..9b04c7303a
--- /dev/null
+++ b/include/vibrator.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2021 Samuel Dionne-Riel <samuel at dionne-riel.com>
+ * Copyright (c) 2015 Google, Inc
+ * Largely derived from `include/led.h`
+ * Original written by Simon Glass <sjg at chromium.org>
+ */
+
+#ifndef __VIBRATOR_H
+#define __VIBRATOR_H
+
+struct udevice;
+
+/**
+ * struct vibrator_uc_plat - Platform data the uclass stores about each device
+ *
+ * @label: VIBRATOR label
+ */
+struct vibrator_uc_plat {
+ const char *label;
+};
+
+/**
+ * struct vibrator_uc_priv - Private data the uclass stores about each device
+ *
+ * @period_ms: Flash period in milliseconds
+ */
+struct vibrator_uc_priv {
+ int period_ms;
+};
+
+enum vibrator_state_t {
+ VIBRATOR_STATE_OFF = 0,
+ VIBRATOR_STATE_ON = 1,
+ VIBRATOR_STATE_TOGGLE,
+
+ VIBRATOR_STATE_COUNT,
+};
+
+struct vibrator_ops {
+ /**
+ * set_state() - set the state of an VIBRATOR
+ *
+ * @dev: VIBRATOR device to change
+ * @state: VIBRATOR state to set
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_state)(struct udevice *dev, enum vibrator_state_t state);
+
+ /**
+ * vibrator_get_state() - get the state of an VIBRATOR
+ *
+ * @dev: VIBRATOR device to change
+ * @return VIBRATOR state vibrator_state_t, or -ve on error
+ */
+ enum vibrator_state_t (*get_state)(struct udevice *dev);
+};
+
+#define vibrator_get_ops(dev) ((struct vibrator_ops *)(dev)->driver->ops)
+
+/**
+ * vibrator_get_by_label() - Find an VIBRATOR device by label
+ *
+ * @label: VIBRATOR label to look up
+ * @devp: Returns the associated device, if found
+ * @return 0 if found, -ENODEV if not found, other -ve on error
+ */
+int vibrator_get_by_label(const char *label, struct udevice **devp);
+
+/**
+ * vibrator_set_state() - set the state of an VIBRATOR
+ *
+ * @dev: VIBRATOR device to change
+ * @state: VIBRATOR state to set
+ * @return 0 if OK, -ve on error
+ */
+int vibrator_set_state(struct udevice *dev, enum vibrator_state_t state);
+
+/**
+ * vibrator_get_state() - get the state of an VIBRATOR
+ *
+ * @dev: VIBRATOR device to change
+ * @return VIBRATOR state vibrator_state_t, or -ve on error
+ */
+enum vibrator_state_t vibrator_get_state(struct udevice *dev);
+
+#endif
diff --git a/test/dm/Makefile b/test/dm/Makefile
index d46552fbf3..dffed0e7fc 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_TEE) += tee.o
obj-$(CONFIG_TIMER) += timer.o
obj-$(CONFIG_DM_USB) += usb.o
obj-$(CONFIG_DM_VIDEO) += video.o
+obj-$(CONFIG_VIBRATOR) += vibrator.o
obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o
ifeq ($(CONFIG_WDT_GPIO)$(CONFIG_WDT_SANDBOX),yy)
obj-y += wdt.o
diff --git a/test/dm/vibrator.c b/test/dm/vibrator.c
new file mode 100644
index 0000000000..ab5b548431
--- /dev/null
+++ b/test/dm/vibrator.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Samuel Dionne-Riel <samuel at dionne-riel.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <vibrator.h>
+#include <asm/gpio.h>
+#include <dm/test.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+/* Base test of the vibrator uclass */
+static int dm_test_vibrator_base(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+
+ ut_assertok(uclass_get_device(UCLASS_VIBRATOR, 0, &dev));
+ ut_assertok(uclass_get_device(UCLASS_VIBRATOR, 1, &dev));
+ ut_asserteq(-ENODEV, uclass_get_device(UCLASS_VIBRATOR, 2, &dev));
+
+ return 0;
+}
+DM_TEST(dm_test_vibrator_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* Test of the vibrator uclass using the vibrator_gpio driver */
+static int dm_test_vibrator_gpio(struct unit_test_state *uts)
+{
+ const int offset = 1;
+ struct udevice *dev, *gpio;
+
+ /*
+ * Check that we can manipulate a vibration motor. Vibrator 1 is connected to GPIO
+ * bank gpio_a, offset 1.
+ */
+ ut_assertok(uclass_get_device(UCLASS_VIBRATOR, 0, &dev));
+ ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio));
+ ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
+ ut_assertok(vibrator_set_state(dev, VIBRATOR_STATE_ON));
+ ut_asserteq(1, sandbox_gpio_get_value(gpio, offset));
+ ut_asserteq(VIBRATOR_STATE_ON, vibrator_get_state(dev));
+
+ ut_assertok(vibrator_set_state(dev, VIBRATOR_STATE_OFF));
+ ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
+ ut_asserteq(VIBRATOR_STATE_OFF, vibrator_get_state(dev));
+
+ return 0;
+}
+DM_TEST(dm_test_vibrator_gpio, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* Test that we can toggle vibration motors */
+static int dm_test_vibrator_toggle(struct unit_test_state *uts)
+{
+ const int offset = 1;
+ struct udevice *dev, *gpio;
+
+ /*
+ * Check that we can manipulate a vibration motor. Vibrator 1 is connected to GPIO
+ * bank gpio_a, offset 1.
+ */
+ ut_assertok(uclass_get_device(UCLASS_VIBRATOR, 0, &dev));
+ ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio));
+ ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
+ ut_assertok(vibrator_set_state(dev, VIBRATOR_STATE_TOGGLE));
+ ut_asserteq(1, sandbox_gpio_get_value(gpio, offset));
+ ut_asserteq(VIBRATOR_STATE_ON, vibrator_get_state(dev));
+
+ ut_assertok(vibrator_set_state(dev, VIBRATOR_STATE_TOGGLE));
+ ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
+ ut_asserteq(VIBRATOR_STATE_OFF, vibrator_get_state(dev));
+
+ return 0;
+}
+DM_TEST(dm_test_vibrator_toggle, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* Test obtaining a vibration motor by label */
+static int dm_test_vibrator_label(struct unit_test_state *uts)
+{
+ struct udevice *dev, *cmp;
+
+ ut_assertok(vibrator_get_by_label("vibrator_left", &dev));
+ ut_asserteq(1, device_active(dev));
+ ut_assertok(uclass_get_device(UCLASS_VIBRATOR, 0, &cmp));
+ ut_asserteq_ptr(dev, cmp);
+
+ ut_assertok(vibrator_get_by_label("vibrator_right", &dev));
+ ut_asserteq(1, device_active(dev));
+ ut_assertok(uclass_get_device(UCLASS_VIBRATOR, 1, &cmp));
+ ut_asserteq_ptr(dev, cmp);
+
+ ut_asserteq(-ENODEV, vibrator_get_by_label("doesnotexist", &dev));
+
+ return 0;
+}
+DM_TEST(dm_test_vibrator_label, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
--
2.34.0
More information about the U-Boot
mailing list