2020-10-29 10:03:25

by Lars Poeschel

[permalink] [raw]
Subject: [PATCH 00/25] Make charlcd device independent

From: Lars Poeschel <[email protected]>

This tries to make charlcd device independent. At the moment hd44780
device specific code is contained deep in charlcd. This moves this out
into a hd44780_common module, where the two hd44780 drivers we have at
the moment (hd44780 and panel) can use this from. The goal is that at
the end other drivers can use the charlcd interface.
I add one such driver for a modtronix lcd displau with the last patch.
I submitted this already some time ago, where the wish was so split
this into smaller chunks what I try to do with this patchset.

This is v5 of the patchset. I address a few review comments with this.
I fixed some typos, but more importantly Miguel spotted that I reverted
commit 3f03b6498 ("auxdisplay: charlcd: Reuse hex_to_bin() instead of
custom code") during rebasing. This is corrected now.

As a note to patch 23:
This might slightly change behaviour.
On hd44780 displays with one or two lines the previous implementation
did still write characters to the buffer of the display even if they are
currently not visible. The shift_display command could be used so set
the "viewing window" to a new position in the buffer and then you could
see the characters previously written.
This described behaviour does not work for hd44780 displays with more
than two display lines. There simply is not enough buffer.
So the behaviour was a bit inconsistens across different displays.
The new behaviour is to stop writing character at the end of a visible
line, even if there would be room in the buffer. This allows us to have
an easy implementation, that should behave equal on all supported
displays. This is not hd44780 hardware dependent anymore.

Link: https://lore.kernel.org/lkml/[email protected]/
Link: https://lore.kernel.org/lkml/CANiq72kS-u_Xd_m+2CQVh-JCncPf1XNXrXAZ=4z+mze8fwv2kw@mail.gmail.com/

Changes in v5:
- patch 1: Fix a commit message typo: of -> on
- patch 2: Remove some unnecessary newlines
- patch 8: Fix some typos
- patch 14: Fix commit message typo: it's -> its
- patch 15: this patch is squashed together from the former individual
hd44780_common_ function patches
- patch 16: combined two cleanup patches
- patch 17: I did previously undo commit 3f03b6498 which was a mistake.
This is now corrected.
- patch 24: Picked up Robs Reviewed-by
- patch 25: use hex_to_bin like in commit 3f03b6498 but for the lcd2s.c
file

Changes in v4:
- modtronix -> Modtronix in new lcd2s driver
- Kconfig: remove "default n" in new lcd2s driver

Changes in v3:
- Fix some typos in Kconfig stuff
- Fix kernel test robot reported error: Missed EXPORT_SYMBOL_GPL
- new patch to reduce display timeout
- better patch description to why not move cursor beyond end of a line
- Fixed make dt_binding_doc errors

Changes in v2:
- split whole patch into many smaller chunks
- device tree doc in yaml

Lars Poeschel (25):
auxdisplay: Use an enum for charlcd backlight on/off ops
auxdisplay: Introduce hd44780_common.[ch]
auxdisplay: Move hwidth and bwidth to struct hd44780_common
auxdisplay: Move ifwidth to struct hd44780_common
auxdisplay: Move write_data pointer to hd44780_common
auxdisplay: Move write_cmd pointers to hd44780 drivers
auxdisplay: Move addr out of charlcd_priv
auxdisplay: hd44780_common_print
auxdisplay: provide hd44780_common_gotoxy
auxdisplay: add home to charlcd_ops
auxdisplay: Move clear_display to hd44780_common
auxdisplay: make charlcd_backlight visible to hd44780_common
auxdisplay: Make use of enum for backlight on / off
auxdisplay: Move init_display to hd44780_common
auxdisplay: implement various hd44780_common_ functions
auxdisplay: cleanup unnecessary hd44780 code in charlcd
auxdisplay: Move char redefine code to hd44780_common
auxdisplay: Call charlcd_backlight in place
auxdisplay: hd44780_common: Reduce clear_display timeout
auxdisplay: hd44780: Remove clear_fast
auxdisplay: charlcd: replace last device specific stuff
auxdisplay: Change gotoxy calling interface
auxdisplay: charlcd: Do not print chars at end of line
auxdisplay: lcd2s DT binding doc
auxdisplay: add a driver for lcd2s character display

.../bindings/auxdisplay/modtronix,lcd2s.yaml | 58 +++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
drivers/auxdisplay/Kconfig | 30 ++
drivers/auxdisplay/Makefile | 2 +
drivers/auxdisplay/charlcd.c | 412 +++++-------------
drivers/auxdisplay/charlcd.h | 86 +++-
drivers/auxdisplay/hd44780.c | 120 +++--
drivers/auxdisplay/hd44780_common.c | 361 +++++++++++++++
drivers/auxdisplay/hd44780_common.h | 33 ++
drivers/auxdisplay/lcd2s.c | 403 +++++++++++++++++
drivers/auxdisplay/panel.c | 180 ++++----
11 files changed, 1237 insertions(+), 450 deletions(-)
create mode 100644 Documentation/devicetree/bindings/auxdisplay/modtronix,lcd2s.yaml
create mode 100644 drivers/auxdisplay/hd44780_common.c
create mode 100644 drivers/auxdisplay/hd44780_common.h
create mode 100644 drivers/auxdisplay/lcd2s.c

--
2.28.0


2020-10-29 10:05:09

by Lars Poeschel

[permalink] [raw]
Subject: [PATCH v5 24/25] auxdisplay: lcd2s DT binding doc

From: Lars Poeschel <[email protected]>

Add a binding doc for the modtronix lcd2s auxdisplay driver. It also
adds modtronix to the list of known vendor-prefixes.

Reviewed-by: Willy Tarreau <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Lars Poeschel <[email protected]>
---
Changes in v5:
- Picked up Robs Reviewed-by
Changes in v3:
- Fixed make dt_binding_doc errors
Changes in v2:
- Adopted yaml based file format
---
.../bindings/auxdisplay/modtronix,lcd2s.yaml | 58 +++++++++++++++++++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
2 files changed, 60 insertions(+)
create mode 100644 Documentation/devicetree/bindings/auxdisplay/modtronix,lcd2s.yaml

diff --git a/Documentation/devicetree/bindings/auxdisplay/modtronix,lcd2s.yaml b/Documentation/devicetree/bindings/auxdisplay/modtronix,lcd2s.yaml
new file mode 100644
index 000000000000..a1d55a2634a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/auxdisplay/modtronix,lcd2s.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/auxdisplay/modtronix,lcd2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Modtronix engineering LCD2S Character LCD Display
+
+maintainers:
+ - Lars Poeschel <[email protected]>
+
+description:
+ The LCD2S is a Character LCD Display manufactured by Modtronix Engineering.
+ The display supports a serial I2C and SPI interface. The driver currently
+ only supports the I2C interface.
+
+properties:
+ compatible:
+ const: modtronix,lcd2s
+
+ reg:
+ maxItems: 1
+ description:
+ I2C bus address of the display.
+
+ display-height-chars:
+ description: Height of the display, in character cells.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 4
+
+ display-width-chars:
+ description: Width of the display, in character cells.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 16
+ maximum: 20
+
+required:
+ - compatible
+ - reg
+ - display-height-chars
+ - display-width-chars
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ lcd2s: auxdisplay@28 {
+ compatible = "modtronix,lcd2s";
+ reg = <0x28>;
+ display-height-chars = <4>;
+ display-width-chars = <20>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 2735be1a8470..65f40ab5a87f 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -681,6 +681,8 @@ patternProperties:
description: MiraMEMS Sensing Technology Co., Ltd.
"^mitsubishi,.*":
description: Mitsubishi Electric Corporation
+ "^modtronix,.*":
+ description: Modtronix Engineering
"^mosaixtech,.*":
description: Mosaix Technologies, Inc.
"^motorola,.*":
--
2.28.0

2020-10-29 10:05:47

by Lars Poeschel

[permalink] [raw]
Subject: Re: [PATCH 00/25] Make charlcd device independent

This series was sent wrong. Should be v5. Drop this one.

Sorry and thanks,
Lars

On Thu, Oct 29, 2020 at 10:50:07AM +0100, [email protected] wrote:
> From: Lars Poeschel <[email protected]>
>
> This tries to make charlcd device independent. At the moment hd44780
> device specific code is contained deep in charlcd. This moves this out
> into a hd44780_common module, where the two hd44780 drivers we have at
> the moment (hd44780 and panel) can use this from. The goal is that at
> the end other drivers can use the charlcd interface.
> I add one such driver for a modtronix lcd displau with the last patch.
> I submitted this already some time ago, where the wish was so split
> this into smaller chunks what I try to do with this patchset.
>
> This is v5 of the patchset. I address a few review comments with this.
> I fixed some typos, but more importantly Miguel spotted that I reverted
> commit 3f03b6498 ("auxdisplay: charlcd: Reuse hex_to_bin() instead of
> custom code") during rebasing. This is corrected now.
>
> As a note to patch 23:
> This might slightly change behaviour.
> On hd44780 displays with one or two lines the previous implementation
> did still write characters to the buffer of the display even if they are
> currently not visible. The shift_display command could be used so set
> the "viewing window" to a new position in the buffer and then you could
> see the characters previously written.
> This described behaviour does not work for hd44780 displays with more
> than two display lines. There simply is not enough buffer.
> So the behaviour was a bit inconsistens across different displays.
> The new behaviour is to stop writing character at the end of a visible
> line, even if there would be room in the buffer. This allows us to have
> an easy implementation, that should behave equal on all supported
> displays. This is not hd44780 hardware dependent anymore.
>
> Link: https://lore.kernel.org/lkml/[email protected]/
> Link: https://lore.kernel.org/lkml/CANiq72kS-u_Xd_m+2CQVh-JCncPf1XNXrXAZ=4z+mze8fwv2kw@mail.gmail.com/
>
> Changes in v5:
> - patch 1: Fix a commit message typo: of -> on
> - patch 2: Remove some unnecessary newlines
> - patch 8: Fix some typos
> - patch 14: Fix commit message typo: it's -> its
> - patch 15: this patch is squashed together from the former individual
> hd44780_common_ function patches
> - patch 16: combined two cleanup patches
> - patch 17: I did previously undo commit 3f03b6498 which was a mistake.
> This is now corrected.
> - patch 24: Picked up Robs Reviewed-by
> - patch 25: use hex_to_bin like in commit 3f03b6498 but for the lcd2s.c
> file
>
> Changes in v4:
> - modtronix -> Modtronix in new lcd2s driver
> - Kconfig: remove "default n" in new lcd2s driver
>
> Changes in v3:
> - Fix some typos in Kconfig stuff
> - Fix kernel test robot reported error: Missed EXPORT_SYMBOL_GPL
> - new patch to reduce display timeout
> - better patch description to why not move cursor beyond end of a line
> - Fixed make dt_binding_doc errors
>
> Changes in v2:
> - split whole patch into many smaller chunks
> - device tree doc in yaml
>
> Lars Poeschel (25):
> auxdisplay: Use an enum for charlcd backlight on/off ops
> auxdisplay: Introduce hd44780_common.[ch]
> auxdisplay: Move hwidth and bwidth to struct hd44780_common
> auxdisplay: Move ifwidth to struct hd44780_common
> auxdisplay: Move write_data pointer to hd44780_common
> auxdisplay: Move write_cmd pointers to hd44780 drivers
> auxdisplay: Move addr out of charlcd_priv
> auxdisplay: hd44780_common_print
> auxdisplay: provide hd44780_common_gotoxy
> auxdisplay: add home to charlcd_ops
> auxdisplay: Move clear_display to hd44780_common
> auxdisplay: make charlcd_backlight visible to hd44780_common
> auxdisplay: Make use of enum for backlight on / off
> auxdisplay: Move init_display to hd44780_common
> auxdisplay: implement various hd44780_common_ functions
> auxdisplay: cleanup unnecessary hd44780 code in charlcd
> auxdisplay: Move char redefine code to hd44780_common
> auxdisplay: Call charlcd_backlight in place
> auxdisplay: hd44780_common: Reduce clear_display timeout
> auxdisplay: hd44780: Remove clear_fast
> auxdisplay: charlcd: replace last device specific stuff
> auxdisplay: Change gotoxy calling interface
> auxdisplay: charlcd: Do not print chars at end of line
> auxdisplay: lcd2s DT binding doc
> auxdisplay: add a driver for lcd2s character display
>
> .../bindings/auxdisplay/modtronix,lcd2s.yaml | 58 +++
> .../devicetree/bindings/vendor-prefixes.yaml | 2 +
> drivers/auxdisplay/Kconfig | 30 ++
> drivers/auxdisplay/Makefile | 2 +
> drivers/auxdisplay/charlcd.c | 412 +++++-------------
> drivers/auxdisplay/charlcd.h | 86 +++-
> drivers/auxdisplay/hd44780.c | 120 +++--
> drivers/auxdisplay/hd44780_common.c | 361 +++++++++++++++
> drivers/auxdisplay/hd44780_common.h | 33 ++
> drivers/auxdisplay/lcd2s.c | 403 +++++++++++++++++
> drivers/auxdisplay/panel.c | 180 ++++----
> 11 files changed, 1237 insertions(+), 450 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/auxdisplay/modtronix,lcd2s.yaml
> create mode 100644 drivers/auxdisplay/hd44780_common.c
> create mode 100644 drivers/auxdisplay/hd44780_common.h
> create mode 100644 drivers/auxdisplay/lcd2s.c
>
> --
> 2.28.0
>

2020-10-29 10:06:12

by Lars Poeschel

[permalink] [raw]
Subject: [PATCH v5 25/25] auxdisplay: add a driver for lcd2s character display

From: Lars Poeschel <[email protected]>

This driver allows to use a lcd2s 20x4 character display from Modtronix
engineering as an auxdisplay charlcd device.

Signed-off-by: Lars Poeschel <[email protected]>
---
Changes in v5:
- use hex_to_bin like in commit 3f03b6498 but for this file
Changes in v4:
- modtronix -> Modtronix
- Kconfig: remove "default n"
---
drivers/auxdisplay/Kconfig | 10 +
drivers/auxdisplay/Makefile | 1 +
drivers/auxdisplay/lcd2s.c | 403 ++++++++++++++++++++++++++++++++++++
3 files changed, 414 insertions(+)
create mode 100644 drivers/auxdisplay/lcd2s.c

diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index a56171d1a1ba..96c8cdfce48d 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -173,6 +173,16 @@ config HT16K33
Say yes here to add support for Holtek HT16K33, RAM mapping 16*8
LED controller driver with keyscan.

+config LCD2S
+ tristate "lcd2s 20x4 character display over I2C console"
+ depends on I2C
+ select CHARLCD
+ help
+ This is a driver that lets you use the lcd2s 20x4 character display
+ from Modtronix engineering as a console output device. The display
+ is a simple single color character display. You have to connect it
+ to an I2C bus.
+
config ARM_CHARLCD
bool "ARM Ltd. Character LCD Driver"
depends on PLAT_VERSATILE
diff --git a/drivers/auxdisplay/Makefile b/drivers/auxdisplay/Makefile
index 7e8a8c3eb3c3..307771027c89 100644
--- a/drivers/auxdisplay/Makefile
+++ b/drivers/auxdisplay/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_IMG_ASCII_LCD) += img-ascii-lcd.o
obj-$(CONFIG_HD44780) += hd44780.o
obj-$(CONFIG_HT16K33) += ht16k33.o
obj-$(CONFIG_PARPORT_PANEL) += panel.o
+obj-$(CONFIG_LCD2S) += lcd2s.o
diff --git a/drivers/auxdisplay/lcd2s.c b/drivers/auxdisplay/lcd2s.c
new file mode 100644
index 000000000000..cfa5f86deeef
--- /dev/null
+++ b/drivers/auxdisplay/lcd2s.c
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * console driver for LCD2S 4x20 character displays connected through i2c.
+ * The display also has a spi interface, but the driver does not support
+ * this yet.
+ *
+ * This is a driver allowing you to use a LCD2S 4x20 from modtronix
+ * engineering as auxdisplay character device.
+ *
+ * (C) 2019 by Lemonage Software GmbH
+ * Author: Lars Pöschel <[email protected]>
+ * All rights reserved.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+
+#include "charlcd.h"
+
+#define LCD2S_CMD_CUR_MOVES_FWD 0x09
+#define LCD2S_CMD_CUR_BLINK_OFF 0x10
+#define LCD2S_CMD_CUR_UL_OFF 0x11
+#define LCD2S_CMD_DISPLAY_OFF 0x12
+#define LCD2S_CMD_CUR_BLINK_ON 0x18
+#define LCD2S_CMD_CUR_UL_ON 0x19
+#define LCD2S_CMD_DISPLAY_ON 0x1a
+#define LCD2S_CMD_BACKLIGHT_OFF 0x20
+#define LCD2S_CMD_BACKLIGHT_ON 0x28
+#define LCD2S_CMD_WRITE 0x80
+#define LCD2S_CMD_MOV_CUR_RIGHT 0x83
+#define LCD2S_CMD_MOV_CUR_LEFT 0x84
+#define LCD2S_CMD_SHIFT_RIGHT 0x85
+#define LCD2S_CMD_SHIFT_LEFT 0x86
+#define LCD2S_CMD_SHIFT_UP 0x87
+#define LCD2S_CMD_SHIFT_DOWN 0x88
+#define LCD2S_CMD_CUR_ADDR 0x89
+#define LCD2S_CMD_CUR_POS 0x8a
+#define LCD2S_CMD_CUR_RESET 0x8b
+#define LCD2S_CMD_CLEAR 0x8c
+#define LCD2S_CMD_DEF_CUSTOM_CHAR 0x92
+#define LCD2S_CMD_READ_STATUS 0xd0
+
+#define LCD2S_CHARACTER_SIZE 8
+
+#define LCD2S_STATUS_BUF_MASK 0x7f
+
+struct lcd2s_data {
+ struct i2c_client *i2c;
+ struct charlcd *charlcd;
+};
+
+static s32 lcd2s_wait_buf_free(const struct i2c_client *client, int count)
+{
+ s32 status;
+
+ status = i2c_smbus_read_byte_data(client, LCD2S_CMD_READ_STATUS);
+ if (status < 0)
+ return status;
+
+ while ((status & LCD2S_STATUS_BUF_MASK) < count) {
+ mdelay(1);
+ status = i2c_smbus_read_byte_data(client,
+ LCD2S_CMD_READ_STATUS);
+ if (status < 0)
+ return status;
+ }
+ return 0;
+}
+
+static int lcd2s_i2c_master_send(const struct i2c_client *client,
+ const char *buf, int count)
+{
+ s32 status;
+
+ status = lcd2s_wait_buf_free(client, count);
+ if (status < 0)
+ return status;
+
+ return i2c_master_send(client, buf, count);
+}
+
+static int lcd2s_i2c_smbus_write_byte(const struct i2c_client *client, u8 value)
+{
+ s32 status;
+
+ status = lcd2s_wait_buf_free(client, 1);
+ if (status < 0)
+ return status;
+
+ return i2c_smbus_write_byte(client, value);
+}
+
+static int lcd2s_print(struct charlcd *lcd, int c)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+ u8 buf[2] = { LCD2S_CMD_WRITE, c };
+
+ lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
+ return 0;
+}
+
+static int lcd2s_gotoxy(struct charlcd *lcd, unsigned int x, unsigned int y)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+ u8 buf[] = { LCD2S_CMD_CUR_POS, y + 1, x + 1};
+
+ lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
+
+ return 0;
+}
+
+static int lcd2s_home(struct charlcd *lcd)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_RESET);
+ return 0;
+}
+
+static int lcd2s_init_display(struct charlcd *lcd)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+
+ /* turn everything off, but display on */
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_DISPLAY_ON);
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_BACKLIGHT_OFF);
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_MOVES_FWD);
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_BLINK_OFF);
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_UL_OFF);
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CLEAR);
+
+ return 0;
+}
+
+static int lcd2s_shift_cursor(struct charlcd *lcd, enum charlcd_shift_dir dir)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+
+ if (dir == CHARLCD_SHIFT_LEFT)
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_MOV_CUR_LEFT);
+ else
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_MOV_CUR_RIGHT);
+
+ return 0;
+}
+
+static int lcd2s_shift_display(struct charlcd *lcd, enum charlcd_shift_dir dir)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+
+ if (dir == CHARLCD_SHIFT_LEFT)
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_SHIFT_LEFT);
+ else
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_SHIFT_RIGHT);
+
+ return 0;
+}
+
+static void lcd2s_backlight(struct charlcd *lcd, enum charlcd_onoff on)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+
+ if (on)
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_BACKLIGHT_ON);
+ else
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_BACKLIGHT_OFF);
+}
+
+static int lcd2s_display(struct charlcd *lcd, enum charlcd_onoff on)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+
+ if (on)
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_DISPLAY_ON);
+ else
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_DISPLAY_OFF);
+
+ return 0;
+}
+
+static int lcd2s_cursor(struct charlcd *lcd, enum charlcd_onoff on)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+
+ if (on)
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_UL_ON);
+ else
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_UL_OFF);
+
+ return 0;
+}
+
+static int lcd2s_blink(struct charlcd *lcd, enum charlcd_onoff on)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+
+ if (on)
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_BLINK_ON);
+ else
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_BLINK_OFF);
+
+ return 0;
+}
+
+static int lcd2s_fontsize(struct charlcd *lcd, enum charlcd_fontsize size)
+{
+ return 0;
+}
+
+static int lcd2s_lines(struct charlcd *lcd, enum charlcd_lines lines)
+{
+ return 0;
+}
+
+static int lcd2s_redefine_char(struct charlcd *lcd, char *esc)
+{
+ /* Generator : LGcxxxxx...xx; must have <c> between '0'
+ * and '7', representing the numerical ASCII code of the
+ * redefined character, and <xx...xx> a sequence of 16
+ * hex digits representing 8 bytes for each character.
+ * Most LCDs will only use 5 lower bits of the 7 first
+ * bytes.
+ */
+
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+ u8 buf[LCD2S_CHARACTER_SIZE + 2] = { LCD2S_CMD_DEF_CUSTOM_CHAR };
+ u8 value;
+ int shift, i;
+
+ if (!strchr(esc, ';'))
+ return 0;
+
+ esc++;
+
+ buf[1] = *(esc++) - '0';
+ if (buf[1] > 7)
+ return 1;
+
+ i = 0;
+ shift = 0;
+ value = 0;
+ while (*esc && i < LCD2S_CHARACTER_SIZE + 2) {
+ int half;
+
+ shift ^= 4;
+ half = hex_to_bin(*esc++);
+ if (half < 0)
+ continue;
+
+ value |= half << shift;
+ if (shift == 0) {
+ buf[i++] = value;
+ value = 0;
+ }
+ }
+
+ lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
+ return 1;
+}
+
+static int lcd2s_clear_display(struct charlcd *lcd)
+{
+ struct lcd2s_data *lcd2s = lcd->drvdata;
+
+ /* This implicitly sets cursor to first row and column */
+ lcd2s_i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CLEAR);
+ return 0;
+}
+
+static const struct charlcd_ops lcd2s_ops = {
+ .print = lcd2s_print,
+ .backlight = lcd2s_backlight,
+ .gotoxy = lcd2s_gotoxy,
+ .home = lcd2s_home,
+ .clear_display = lcd2s_clear_display,
+ .init_display = lcd2s_init_display,
+ .shift_cursor = lcd2s_shift_cursor,
+ .shift_display = lcd2s_shift_display,
+ .display = lcd2s_display,
+ .cursor = lcd2s_cursor,
+ .blink = lcd2s_blink,
+ .fontsize = lcd2s_fontsize,
+ .lines = lcd2s_lines,
+ .redefine_char = lcd2s_redefine_char,
+};
+
+static int lcd2s_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct charlcd *lcd;
+ struct lcd2s_data *lcd2s;
+ int err;
+
+ if (!i2c_check_functionality(i2c->adapter,
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
+ return -EIO;
+
+ /* Test, if the display is responding */
+ err = lcd2s_i2c_smbus_write_byte(i2c, LCD2S_CMD_DISPLAY_OFF);
+ if (err < 0)
+ return err;
+
+ lcd = charlcd_alloc();
+ if (!lcd)
+ return -ENOMEM;
+
+ lcd2s = kzalloc(sizeof(struct lcd2s_data), GFP_KERNEL);
+ if (!lcd2s) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ lcd->drvdata = lcd2s;
+ lcd2s->i2c = i2c;
+ lcd2s->charlcd = lcd;
+
+ /* Required properties */
+ err = device_property_read_u32(&i2c->dev, "display-height-chars",
+ &lcd->height);
+ if (err)
+ goto fail2;
+
+ err = device_property_read_u32(&i2c->dev, "display-width-chars",
+ &lcd->width);
+ if (err)
+ goto fail2;
+
+ lcd->ops = &lcd2s_ops;
+
+ err = charlcd_register(lcd2s->charlcd);
+ if (err)
+ goto fail2;
+
+ i2c_set_clientdata(i2c, lcd2s);
+ return 0;
+
+fail2:
+ kfree(lcd2s);
+fail1:
+ kfree(lcd);
+ return err;
+}
+
+static int lcd2s_i2c_remove(struct i2c_client *i2c)
+{
+ struct lcd2s_data *lcd2s = i2c_get_clientdata(i2c);
+
+ kfree(lcd2s->charlcd);
+ charlcd_unregister(lcd2s->charlcd);
+ return 0;
+}
+
+static const struct i2c_device_id lcd2s_i2c_id[] = {
+ { "lcd2s", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lcd2s_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id lcd2s_of_table[] = {
+ { .compatible = "modtronix,lcd2s" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lcd2s_of_table);
+#endif
+
+static struct i2c_driver lcd2s_i2c_driver = {
+ .driver = {
+ .name = "lcd2s",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = of_match_ptr(lcd2s_of_table),
+#endif
+ },
+ .probe = lcd2s_i2c_probe,
+ .remove = lcd2s_i2c_remove,
+ .id_table = lcd2s_i2c_id,
+};
+
+static int __init lcd2s_modinit(void)
+{
+ int ret = 0;
+
+ ret = i2c_add_driver(&lcd2s_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register lcd2s driver\n");
+
+ return ret;
+}
+module_init(lcd2s_modinit)
+
+static void __exit lcd2s_exit(void)
+{
+ i2c_del_driver(&lcd2s_i2c_driver);
+}
+module_exit(lcd2s_exit)
+
+MODULE_DESCRIPTION("LCD2S character display driver");
+MODULE_AUTHOR("Lars Poeschel");
+MODULE_LICENSE("GPL");
--
2.28.0

2020-10-31 09:32:04

by Miguel Ojeda

[permalink] [raw]
Subject: Re: [PATCH 00/25] Make charlcd device independent

Hi Lars,

On Thu, Oct 29, 2020 at 10:52 AM <[email protected]> wrote:
>
> Changes in v5:
> - patch 1: Fix a commit message typo: of -> on
> - patch 2: Remove some unnecessary newlines
> - patch 8: Fix some typos
> - patch 14: Fix commit message typo: it's -> its
> - patch 15: this patch is squashed together from the former individual
> hd44780_common_ function patches
> - patch 16: combined two cleanup patches
> - patch 17: I did previously undo commit 3f03b6498 which was a mistake.
> This is now corrected.
> - patch 24: Picked up Robs Reviewed-by
> - patch 25: use hex_to_bin like in commit 3f03b6498 but for the lcd2s.c
> file

Thanks a lot for all that! Please take a look at my other two messages
for v5. We are almost there...

Cheers,
Miguel