linux-leds.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Geert Uytterhoeven <geert@linux-m68k.org>
To: Robin van der Gracht <robin@protonic.nl>
Cc: Rob Herring <robh+dt@kernel.org>, Miguel Ojeda <ojeda@kernel.org>,
	Paul Burton <paulburton@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	"open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS" 
	<devicetree@vger.kernel.org>,
	"open list:BROADCOM NVRAM DRIVER" <linux-mips@vger.kernel.org>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	linux-leds <linux-leds@vger.kernel.org>,
	Pavel Machek <pavel@ucw.cz>, Dan Murphy <dmurphy@ti.com>
Subject: Re: [PATCH 17/17] auxdisplay: ht16k33: Add segment display LED support
Date: Tue, 23 Mar 2021 13:32:03 +0100	[thread overview]
Message-ID: <CAMuHMdXMQYoGbyLsbiZSEWKK0+iPZe7WELmtDUTjqK-VKMZURg@mail.gmail.com> (raw)
In-Reply-To: <543ec200931af3192541fef51bc8e96a@protonic.nl>

CC linux-leds (which I intended, but forgot to add)

cover letter at
https://lore.kernel.org/linux-devicetree/20210322144848.1065067-1-geert@linux-m68k.org/

On Tue, Mar 23, 2021 at 11:08 AM Robin van der Gracht <robin@protonic.nl> wrote:
>
> On 2021-03-22 15:48, Geert Uytterhoeven wrote:
> > 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.
> >
> > 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.
> > ---
> >  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 0b502a6039f89c6b..5821addd9aec5633 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;
> > @@ -578,11 +633,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,
> > +                     DRIVER_NAME ":%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;
>
> The LED class can pretty much do what the backlight class can and more.
>
> Maybe we can stop registering a backlight device in the fbdev case and
> register a led device for both. This makes the code cleaner and drops
> a dependency but will break backwards compatibility.
>
> I'd prefer a single solution that covers both use cases, but I'm not
> sure about the 'breaking backwards compatibility' consequence...
>
> Groetjes / Kind regards,
> Robin van der Gracht

       reply	other threads:[~2021-03-23 12:33 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20210322144848.1065067-1-geert@linux-m68k.org>
     [not found] ` <20210322144848.1065067-18-geert@linux-m68k.org>
     [not found]   ` <543ec200931af3192541fef51bc8e96a@protonic.nl>
2021-03-23 12:32     ` Geert Uytterhoeven [this message]
2021-03-23 20:40       ` [PATCH 17/17] auxdisplay: ht16k33: Add segment display LED support Pavel Machek
2021-03-24  8:31         ` Geert Uytterhoeven
2021-03-27 22:19           ` Pavel Machek
2021-06-25 12:39           ` 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=CAMuHMdXMQYoGbyLsbiZSEWKK0+iPZe7WELmtDUTjqK-VKMZURg@mail.gmail.com \
    --to=geert@linux-m68k.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dmurphy@ti.com \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).