All of lore.kernel.org
 help / color / mirror / Atom feed
From: Geert Uytterhoeven <geert@linux-m68k.org>
To: Robin van der Gracht <robin@protonic.nl>,
	Rob Herring <robh+dt@kernel.org>, Miguel Ojeda <ojeda@kernel.org>,
	Paul Burton <paulburton@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Pavel Machek <pavel@ucw.cz>
Cc: devicetree@vger.kernel.org, linux-leds@vger.kernel.org,
	linux-mips@vger.kernel.org, linux-kernel@vger.kernel.org,
	Geert Uytterhoeven <geert@linux-m68k.org>
Subject: [PATCH v2 18/18] auxdisplay: ht16k33: Add segment display LED support
Date: Fri, 25 Jun 2021 14:59:02 +0200	[thread overview]
Message-ID: <20210625125902.1162428-19-geert@linux-m68k.org> (raw)
In-Reply-To: <20210625125902.1162428-1-geert@linux-m68k.org>

Instantiate a single LED for a segment display.  This allows the user to
control display brightness and blinking through the LED class API and
triggers, and exposes the display color.
The LED will be named "auxdisplay:<color>:backlight".

Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
For setting display brightness, this could use the existing backlight
support for frame buffer devices instantiated for dot-matrix displays.
However, using the leds subsystem instead has the advantage that the
driver can make use of the HT16K33's hardware blinking support, and can
expose the display color.  It can still be used with ledtrig-backlight.
Using "led-backlight", the backlight can no longer be controlled from
sysfs, precluding the use of other triggers incl. hardware blinking.

v2:
  - Use "auxdisplay" instead of DRIVER_NAME in LED name.
---
 drivers/auxdisplay/ht16k33.c | 81 ++++++++++++++++++++++++++++++++++--
 1 file changed, 77 insertions(+), 4 deletions(-)

diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c
index 28207517a4725250..cd88c7bcb1d713bf 100644
--- a/drivers/auxdisplay/ht16k33.c
+++ b/drivers/auxdisplay/ht16k33.c
@@ -29,6 +29,7 @@
 #include <asm/unaligned.h>
 
 #include "line-display.h"
+#include "../leds/leds.h"		/* for led_colors[] */
 
 /* Registers */
 #define REG_SYSTEM_SETUP		0x20
@@ -36,6 +37,10 @@
 
 #define REG_DISPLAY_SETUP		0x80
 #define REG_DISPLAY_SETUP_ON		BIT(0)
+#define REG_DISPLAY_SETUP_BLINK_OFF	(0 << 1)
+#define REG_DISPLAY_SETUP_BLINK_2HZ	(1 << 1)
+#define REG_DISPLAY_SETUP_BLINK_1HZ	(2 << 1)
+#define REG_DISPLAY_SETUP_BLINK_0HZ5	(3 << 1)
 
 #define REG_ROWINT_SET			0xA0
 #define REG_ROWINT_SET_INT_EN		BIT(0)
@@ -57,6 +62,8 @@
 #define BYTES_PER_ROW		(HT16K33_MATRIX_LED_MAX_ROWS / 8)
 #define HT16K33_FB_SIZE		(HT16K33_MATRIX_LED_MAX_COLS * BYTES_PER_ROW)
 
+#define COLOR_DEFAULT		LED_COLOR_ID_RED
+
 enum display_type {
 	DISP_MATRIX = 0,
 	DISP_QUAD_7SEG,
@@ -85,6 +92,7 @@ struct ht16k33_fbdev {
 
 struct ht16k33_seg {
 	struct linedisp linedisp;
+	struct led_classdev led;
 	union {
 		struct seg7_conversion_map seg7;
 		struct seg14_conversion_map seg14;
@@ -102,6 +110,7 @@ struct ht16k33_priv {
 		struct ht16k33_seg seg;
 	};
 	enum display_type type;
+	uint8_t blink;
 };
 
 static const struct fb_fix_screeninfo ht16k33_fb_fix = {
@@ -160,7 +169,7 @@ static DEVICE_ATTR(map_seg14, 0644, map_seg_show, map_seg_store);
 
 static int ht16k33_display_on(struct ht16k33_priv *priv)
 {
-	uint8_t data = REG_DISPLAY_SETUP | REG_DISPLAY_SETUP_ON;
+	uint8_t data = REG_DISPLAY_SETUP | REG_DISPLAY_SETUP_ON | priv->blink;
 
 	return i2c_smbus_write_byte(priv->client, data);
 }
@@ -175,8 +184,11 @@ static int ht16k33_brightness_set(struct ht16k33_priv *priv,
 {
 	int error;
 
-	if (brightness == 0)
+	if (brightness == 0) {
+		// Disable blink mode
+		priv->blink = REG_DISPLAY_SETUP_BLINK_OFF;
 		return ht16k33_display_off(priv);
+	}
 
 	error = ht16k33_display_on(priv);
 	if (error)
@@ -186,6 +198,49 @@ static int ht16k33_brightness_set(struct ht16k33_priv *priv,
 				    REG_BRIGHTNESS | (brightness - 1));
 }
 
+static int ht16k33_brightness_set_blocking(struct led_classdev *led_cdev,
+					   enum led_brightness brightness)
+{
+	struct ht16k33_priv *priv = container_of(led_cdev, struct ht16k33_priv,
+						 seg.led);
+
+	return ht16k33_brightness_set(priv, brightness);
+}
+
+static int ht16k33_blink_set(struct led_classdev *led_cdev,
+			     unsigned long *delay_on, unsigned long *delay_off)
+{
+	struct ht16k33_priv *priv = container_of(led_cdev, struct ht16k33_priv,
+						 seg.led);
+	unsigned int delay;
+	uint8_t blink;
+	int error;
+
+	if (!*delay_on && !*delay_off) {
+		blink = REG_DISPLAY_SETUP_BLINK_1HZ;
+		delay = 1000;
+	} else if (*delay_on <= 750) {
+		blink = REG_DISPLAY_SETUP_BLINK_2HZ;
+		delay = 500;
+	} else if (*delay_on <= 1500) {
+		blink = REG_DISPLAY_SETUP_BLINK_1HZ;
+		delay = 1000;
+	} else {
+		blink = REG_DISPLAY_SETUP_BLINK_0HZ5;
+		delay = 2000;
+	}
+
+	error = i2c_smbus_write_byte(priv->client,
+				     REG_DISPLAY_SETUP | REG_DISPLAY_SETUP_ON |
+				     blink);
+	if (error)
+		return error;
+
+	priv->blink = blink;
+	*delay_on = *delay_off = delay;
+	return 0;
+}
+
 static void ht16k33_fb_queue(struct ht16k33_priv *priv)
 {
 	struct ht16k33_fbdev *fbdev = &priv->fbdev;
@@ -576,11 +631,29 @@ static int ht16k33_fbdev_probe(struct i2c_client *client,
 static int ht16k33_seg_probe(struct i2c_client *client,
 			     struct ht16k33_priv *priv, uint32_t brightness)
 {
-	struct ht16k33_seg *seg = &priv->seg;
 	struct device *dev = &client->dev;
+	struct device_node *node = dev->of_node;
+	struct ht16k33_seg *seg = &priv->seg;
+	u32 color = COLOR_DEFAULT;
 	int err;
 
-	err = ht16k33_brightness_set(priv, MAX_BRIGHTNESS);
+	of_property_read_u32(node, "color", &color);
+	seg->led.name = devm_kasprintf(dev, GFP_KERNEL,
+			"auxdisplay:%s:" LED_FUNCTION_BACKLIGHT,
+			color < LED_COLOR_ID_MAX ? led_colors[color] : "");
+	seg->led.brightness_set_blocking = ht16k33_brightness_set_blocking;
+	seg->led.blink_set = ht16k33_blink_set;
+	seg->led.flags = LED_CORE_SUSPENDRESUME;
+	seg->led.brightness = brightness;
+	seg->led.max_brightness = MAX_BRIGHTNESS;
+
+	err = devm_led_classdev_register(dev, &seg->led);
+	if (err) {
+		dev_err(dev, "Failed to register LED\n");
+		return err;
+	}
+
+	err = ht16k33_brightness_set(priv, seg->led.brightness);
 	if (err)
 		return err;
 
-- 
2.25.1


  parent reply	other threads:[~2021-06-25 12:59 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-25 12:58 [PATCH v2 00/18] auxdisplay: ht16k33: Add character display support Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 01/18] uapi: Add <linux/map_to_14segment.h> Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 02/18] dt-bindings: auxdisplay: ht16k33: Document Adafruit segment displays Geert Uytterhoeven
2021-07-14 20:36   ` Rob Herring
2021-07-15  7:12     ` Geert Uytterhoeven
2021-07-15 14:32       ` Rob Herring
2021-07-15 15:06         ` Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 03/18] auxdisplay: img-ascii-lcd: Fix lock-up when displaying empty string Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 04/18] auxdisplay: img-ascii-lcd: Add helper variable dev Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 05/18] auxdisplay: img-ascii-lcd: Convert device attribute to sysfs_emit() Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 06/18] auxdisplay: Extract character line display core support Geert Uytterhoeven
2021-06-25 23:35   ` kernel test robot
2021-06-25 23:35     ` kernel test robot
2021-06-28 10:17     ` Geert Uytterhoeven
2021-06-28 10:17       ` Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 07/18] auxdisplay: linedisp: Use kmemdup_nul() helper Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 08/18] auxdisplay: linedisp: Add support for changing scroll rate Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 09/18] auxdisplay: ht16k33: Connect backlight to fbdev Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 10/18] auxdisplay: ht16k33: Use HT16K33_FB_SIZE in ht16k33_initialize() Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 11/18] auxdisplay: ht16k33: Remove unneeded error check in keypad probe() Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 12/18] auxdisplay: ht16k33: Convert to simple i2c probe function Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 13/18] auxdisplay: ht16k33: Add helper variable dev Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 14/18] auxdisplay: ht16k33: Move delayed work Geert Uytterhoeven
2021-06-25 12:58 ` [PATCH v2 15/18] auxdisplay: ht16k33: Extract ht16k33_brightness_set() Geert Uytterhoeven
2021-06-25 12:59 ` [PATCH v2 16/18] auxdisplay: ht16k33: Extract frame buffer probing Geert Uytterhoeven
2021-06-25 12:59 ` [PATCH v2 17/18] auxdisplay: ht16k33: Add support for segment displays Geert Uytterhoeven
2021-06-25 12:59 ` Geert Uytterhoeven [this message]
2021-06-25 20:39   ` [PATCH v2 18/18] auxdisplay: ht16k33: Add segment display LED support Marek Behun
2021-06-25 20:40     ` Marek Behun
2021-06-28  9:21       ` Geert Uytterhoeven
2021-06-28  9:21     ` Geert Uytterhoeven
2021-06-28 10:15       ` Marek Behun
2021-06-28 15:33         ` Geert Uytterhoeven

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210625125902.1162428-19-geert@linux-m68k.org \
    --to=geert@linux-m68k.org \
    --cc=devicetree@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=linux-mips@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=paulburton@kernel.org \
    --cc=pavel@ucw.cz \
    --cc=robh+dt@kernel.org \
    --cc=robin@protonic.nl \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.