[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