2020-10-05 13:05:43

by Lars Poeschel

[permalink] [raw]
Subject: [PATCH v4 13/32] auxdisplay: Make use of enum for backlight on / off

From: Lars Poeschel <[email protected]>

To turn the backlight on or off use our new enum CHARLCD_ON /
CHARLCD_OFF.

Reviewed-by: Willy Tarreau <[email protected]>
Signed-off-by: Lars Poeschel <[email protected]>
---
drivers/auxdisplay/charlcd.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 154419513186..9631f70e8128 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -115,7 +115,7 @@ static void charlcd_bl_off(struct work_struct *work)
if (priv->bl_tempo) {
priv->bl_tempo = false;
if (!(priv->flags & LCD_FLAG_L))
- priv->lcd.ops->backlight(&priv->lcd, 0);
+ priv->lcd.ops->backlight(&priv->lcd, CHARLCD_OFF);
}
mutex_unlock(&priv->bl_tempo_lock);
}
@@ -132,7 +132,7 @@ void charlcd_poke(struct charlcd *lcd)

mutex_lock(&priv->bl_tempo_lock);
if (!priv->bl_tempo && !(priv->flags & LCD_FLAG_L))
- lcd->ops->backlight(lcd, 1);
+ lcd->ops->backlight(lcd, CHARLCD_ON);
priv->bl_tempo = true;
schedule_delayed_work(&priv->bl_work, LCD_BL_TEMPO_PERIOD * HZ);
mutex_unlock(&priv->bl_tempo_lock);
@@ -829,7 +829,7 @@ int charlcd_unregister(struct charlcd *lcd)
the_charlcd = NULL;
if (lcd->ops->backlight) {
cancel_delayed_work_sync(&priv->bl_work);
- priv->lcd.ops->backlight(&priv->lcd, 0);
+ priv->lcd.ops->backlight(&priv->lcd, CHARLCD_OFF);
}

return 0;
--
2.28.0


2020-10-05 13:06:28

by Lars Poeschel

[permalink] [raw]
Subject: [PATCH v4 26/32] auxdisplay: hd44780_common: Reduce clear_display timeout

From: Lars Poeschel <[email protected]>

Digging in the hd44780 datasheet revealed that the timeout needed after
clearing the whole display is only 1,64ms not 15ms. So we can reduce
that timeout.

Link: https://lore.kernel.org/lkml/[email protected]/
Link: https://www.crystalfontz.com/controllers/Hitachi/HD44780/433/

Signed-off-by: Lars Poeschel <[email protected]>
---
Changes in v3:
- This patch is new in v3
---
drivers/auxdisplay/hd44780_common.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/auxdisplay/hd44780_common.c b/drivers/auxdisplay/hd44780_common.c
index 82afae78f46e..fbce8835a650 100644
--- a/drivers/auxdisplay/hd44780_common.c
+++ b/drivers/auxdisplay/hd44780_common.c
@@ -83,8 +83,8 @@ int hd44780_common_clear_display(struct charlcd *lcd)
struct hd44780_common *hdc = lcd->drvdata;

hdc->write_cmd(hdc, LCD_CMD_DISPLAY_CLEAR);
- /* we must wait a few milliseconds (15) */
- long_sleep(15);
+ /* datasheet says to wait 1,64 milliseconds */
+ long_sleep(2);
return 0;
}
EXPORT_SYMBOL_GPL(hd44780_common_clear_display);
--
2.28.0

2020-10-05 13:06:52

by Lars Poeschel

[permalink] [raw]
Subject: [PATCH v4 25/32] auxdisplay: Call charlcd_backlight in place

From: Lars Poeschel <[email protected]>

This moves the call to charlcd_backlight from the end of the switch
into the actual case statement that originates the change of the
backlight. This is more consistent to what is now found in this switch.

Reviewed-by: Willy Tarreau <[email protected]>
Signed-off-by: Lars Poeschel <[email protected]>
---
drivers/auxdisplay/charlcd.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index dca1b138a239..0f0568a4bd35 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -259,10 +259,16 @@ static inline int handle_lcd_special_code(struct charlcd *lcd)
break;
case '+': /* Back light ON */
priv->flags |= LCD_FLAG_L;
+ if (priv->flags != oldflags)
+ charlcd_backlight(lcd, CHARLCD_ON);
+
processed = 1;
break;
case '-': /* Back light OFF */
priv->flags &= ~LCD_FLAG_L;
+ if (priv->flags != oldflags)
+ charlcd_backlight(lcd, CHARLCD_OFF);
+
processed = 1;
break;
case '*': /* Flash back light */
@@ -363,14 +369,6 @@ static inline int handle_lcd_special_code(struct charlcd *lcd)
break;
}

- /* TODO: This indent party here got ugly, clean it! */
- /* Check whether one flag was changed */
- if (oldflags == priv->flags)
- return processed;
-
- if ((oldflags ^ priv->flags) & LCD_FLAG_L)
- charlcd_backlight(lcd, !!(priv->flags & LCD_FLAG_L));
-
return processed;
}

--
2.28.0

2020-10-05 13:07:21

by Lars Poeschel

[permalink] [raw]
Subject: [PATCH v4 27/32] auxdisplay: hd44780: Remove clear_fast

From: Lars Poeschel <[email protected]>

We remove the hd44780_clear_fast (display) clear implementation. With
the new timeout the normal clear_display is reasonably fast. So there is
no need for a clear_fast anymore.

Link: https://lore.kernel.org/lkml/[email protected]/

Signed-off-by: Lars Poeschel <[email protected]>
---
Changes in v3:
- This patch is squashed together from 26, 27 and 28 from previous patch
set:
Link: https://lore.kernel.org/lkml/[email protected]/
Link: https://lore.kernel.org/lkml/[email protected]/
Link: https://lore.kernel.org/lkml/[email protected]/

- Additionally this now removes clear_fast from charlcd_ops and from
panel driver.

---
drivers/auxdisplay/charlcd.c | 21 ++++-------
drivers/auxdisplay/charlcd.h | 6 ++--
drivers/auxdisplay/panel.c | 67 ------------------------------------
3 files changed, 8 insertions(+), 86 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 0f0568a4bd35..077c01e87127 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -125,20 +125,11 @@ static void charlcd_print(struct charlcd *lcd, char c)
lcd->ops->gotoxy(lcd);
}

-static void charlcd_clear_fast(struct charlcd *lcd)
+static void charlcd_clear_display(struct charlcd *lcd)
{
- struct hd44780_common *hdc = lcd->drvdata;
- int pos;
-
- charlcd_home(lcd);
-
- if (lcd->ops->clear_fast)
- lcd->ops->clear_fast(lcd);
- else
- for (pos = 0; pos < min(2, lcd->height) * hdc->hwidth; pos++)
- lcd->ops->print(lcd, ' ');
-
- charlcd_home(lcd);
+ lcd->ops->clear_display(lcd);
+ lcd->addr.x = 0;
+ lcd->addr.y = 0;
}

/*
@@ -409,7 +400,7 @@ static void charlcd_write_char(struct charlcd *lcd, char c)
break;
case '\f':
/* quickly clear the display */
- charlcd_clear_fast(lcd);
+ charlcd_clear_display(lcd);
break;
case '\n':
/*
@@ -448,7 +439,7 @@ static void charlcd_write_char(struct charlcd *lcd, char c)

if (!strcmp(priv->esc_seq.buf, "[2J")) {
/* clear the display */
- charlcd_clear_fast(lcd);
+ charlcd_clear_display(lcd);
processed = 1;
} else if (!strcmp(priv->esc_seq.buf, "[H")) {
/* cursor to home */
diff --git a/drivers/auxdisplay/charlcd.h b/drivers/auxdisplay/charlcd.h
index 83fa989d37fa..024f7188b5cc 100644
--- a/drivers/auxdisplay/charlcd.h
+++ b/drivers/auxdisplay/charlcd.h
@@ -55,7 +55,6 @@ struct charlcd {
/**
* struct charlcd_ops - Functions used by charlcd. Drivers have to implement
* these.
- * @clear_fast: Clear the whole display and set cursor to position 0, 0.
* @backlight: Turn backlight on or off. Optional.
* @print: just Print one character to the display at current cursor position.
* The buffered cursor position is advanced by charlcd. The cursor should not
@@ -64,8 +63,8 @@ struct charlcd {
* previously set in addr.x and addr.y by charlcd.
* @home: Set cursor to 0, 0. The values in addr.x and addr.y are set to 0, 0 by
* charlcd prior to calling this function.
- * @clear_display: Again clear the whole display, set the cursor to 0, 0. The
- * values in addr.x and addr.y are set to 0, 0 by charlcd prior to calling this
+ * @clear_display: Clear the whole display and set the cursor to 0, 0. The
+ * values in addr.x and addr.y are set to 0, 0 by charlcd after to calling this
* function.
* @init_display: Initialize the display.
* @shift_cursor: Shift cursor left or right one position.
@@ -77,7 +76,6 @@ struct charlcd {
* @redefine_char: Redefine the actual pixel matrix of character.
*/
struct charlcd_ops {
- void (*clear_fast)(struct charlcd *lcd);
void (*backlight)(struct charlcd *lcd, enum charlcd_onoff on);
int (*print)(struct charlcd *lcd, int c);
int (*gotoxy)(struct charlcd *lcd);
diff --git a/drivers/auxdisplay/panel.c b/drivers/auxdisplay/panel.c
index b0d2ae5b9be8..e07fadac281d 100644
--- a/drivers/auxdisplay/panel.c
+++ b/drivers/auxdisplay/panel.c
@@ -808,72 +808,7 @@ static void lcd_write_data_tilcd(struct hd44780_common *hdc, int data)
spin_unlock_irq(&pprt_lock);
}

-/* fills the display with spaces and resets X/Y */
-static void lcd_clear_fast_s(struct charlcd *charlcd)
-{
- struct hd44780_common *hdc = charlcd->drvdata;
- int pos;
-
- spin_lock_irq(&pprt_lock);
- for (pos = 0; pos < charlcd->height * hdc->hwidth; pos++) {
- lcd_send_serial(0x5F); /* R/W=W, RS=1 */
- lcd_send_serial(' ' & 0x0F);
- lcd_send_serial((' ' >> 4) & 0x0F);
- /* the shortest data takes at least 40 us */
- udelay(40);
- }
- spin_unlock_irq(&pprt_lock);
-}
-
-/* fills the display with spaces and resets X/Y */
-static void lcd_clear_fast_p8(struct charlcd *charlcd)
-{
- struct hd44780_common *hdc = charlcd->drvdata;
- int pos;
-
- spin_lock_irq(&pprt_lock);
- for (pos = 0; pos < charlcd->height * hdc->hwidth; pos++) {
- /* present the data to the data port */
- w_dtr(pprt, ' ');
-
- /* maintain the data during 20 us before the strobe */
- udelay(20);
-
- set_bit(LCD_BIT_E, bits);
- set_bit(LCD_BIT_RS, bits);
- clear_bit(LCD_BIT_RW, bits);
- set_ctrl_bits();
-
- /* maintain the strobe during 40 us */
- udelay(40);
-
- clear_bit(LCD_BIT_E, bits);
- set_ctrl_bits();
-
- /* the shortest data takes at least 45 us */
- udelay(45);
- }
- spin_unlock_irq(&pprt_lock);
-}
-
-/* fills the display with spaces and resets X/Y */
-static void lcd_clear_fast_tilcd(struct charlcd *charlcd)
-{
- struct hd44780_common *hdc = charlcd->drvdata;
- int pos;
-
- spin_lock_irq(&pprt_lock);
- for (pos = 0; pos < charlcd->height * hdc->hwidth; pos++) {
- /* present the data to the data port */
- w_dtr(pprt, ' ');
- udelay(60);
- }
-
- spin_unlock_irq(&pprt_lock);
-}
-
static const struct charlcd_ops charlcd_serial_ops = {
- .clear_fast = lcd_clear_fast_s,
.backlight = lcd_backlight,
.gotoxy = hd44780_common_gotoxy,
.home = hd44780_common_home,
@@ -890,7 +825,6 @@ static const struct charlcd_ops charlcd_serial_ops = {
};

static const struct charlcd_ops charlcd_parallel_ops = {
- .clear_fast = lcd_clear_fast_p8,
.backlight = lcd_backlight,
.gotoxy = hd44780_common_gotoxy,
.home = hd44780_common_home,
@@ -907,7 +841,6 @@ static const struct charlcd_ops charlcd_parallel_ops = {
};

static const struct charlcd_ops charlcd_tilcd_ops = {
- .clear_fast = lcd_clear_fast_tilcd,
.backlight = lcd_backlight,
.gotoxy = hd44780_common_gotoxy,
.home = hd44780_common_home,
--
2.28.0

2020-10-05 13:07:44

by Lars Poeschel

[permalink] [raw]
Subject: [PATCH v4 14/32] auxdisplay: Move init_display to hd44780_common

From: Lars Poeschel <[email protected]>

The init_display function is moved over to hd44780_common. charlcd uses
it via it's ops function pointer and drivers initialize the ops with the
common hd44780_common_init_display function.

Reviewed-by: Willy Tarreau <[email protected]>
Signed-off-by: Lars Poeschel <[email protected]>
---
drivers/auxdisplay/charlcd.c | 95 ++---------------------------
drivers/auxdisplay/charlcd.h | 9 +++
drivers/auxdisplay/hd44780.c | 2 +
drivers/auxdisplay/hd44780_common.c | 88 ++++++++++++++++++++++++++
drivers/auxdisplay/hd44780_common.h | 2 +
drivers/auxdisplay/panel.c | 3 +
6 files changed, 110 insertions(+), 89 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 9631f70e8128..94f6b0afab13 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -8,7 +8,6 @@

#include <linux/atomic.h>
#include <linux/ctype.h>
-#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
@@ -26,17 +25,7 @@
/* Keep the backlight on this many seconds for each flash */
#define LCD_BL_TEMPO_PERIOD 4

-#define LCD_FLAG_B 0x0004 /* Blink on */
-#define LCD_FLAG_C 0x0008 /* Cursor on */
-#define LCD_FLAG_D 0x0010 /* Display on */
-#define LCD_FLAG_F 0x0020 /* Large font mode */
-#define LCD_FLAG_N 0x0040 /* 2-rows mode */
-#define LCD_FLAG_L 0x0080 /* Backlight enabled */
-
/* LCD commands */
-#define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */
-#define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */
-
#define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */
#define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */
#define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */
@@ -84,12 +73,6 @@ struct charlcd_priv {
/* Device single-open policy control */
static atomic_t charlcd_available = ATOMIC_INIT(1);

-/* sleeps that many milliseconds with a reschedule */
-static void long_sleep(int ms)
-{
- schedule_timeout_interruptible(msecs_to_jiffies(ms));
-}
-
/* turn the backlight on or off */
void charlcd_backlight(struct charlcd *lcd, enum charlcd_onoff on)
{
@@ -177,76 +160,6 @@ static void charlcd_clear_fast(struct charlcd *lcd)
charlcd_home(lcd);
}

-static int charlcd_init_display(struct charlcd *lcd)
-{
- void (*write_cmd_raw)(struct hd44780_common *hdc, int cmd);
- struct charlcd_priv *priv = charlcd_to_priv(lcd);
- struct hd44780_common *hdc = lcd->drvdata;
- u8 init;
-
- if (hdc->ifwidth != 4 && hdc->ifwidth != 8)
- return -EINVAL;
-
- priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D |
- LCD_FLAG_C | LCD_FLAG_B;
-
- long_sleep(20); /* wait 20 ms after power-up for the paranoid */
-
- /*
- * 8-bit mode, 1 line, small fonts; let's do it 3 times, to make sure
- * the LCD is in 8-bit mode afterwards
- */
- init = LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS;
- if (hdc->ifwidth == 4) {
- init >>= 4;
- write_cmd_raw = hdc->write_cmd_raw4;
- } else {
- write_cmd_raw = hdc->write_cmd;
- }
- write_cmd_raw(hdc, init);
- long_sleep(10);
- write_cmd_raw(hdc, init);
- long_sleep(10);
- write_cmd_raw(hdc, init);
- long_sleep(10);
-
- if (hdc->ifwidth == 4) {
- /* Switch to 4-bit mode, 1 line, small fonts */
- hdc->write_cmd_raw4(hdc, LCD_CMD_FUNCTION_SET >> 4);
- long_sleep(10);
- }
-
- /* set font height and lines number */
- hdc->write_cmd(hdc,
- LCD_CMD_FUNCTION_SET |
- ((hdc->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) |
- ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) |
- ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0));
- long_sleep(10);
-
- /* display off, cursor off, blink off */
- hdc->write_cmd(hdc, LCD_CMD_DISPLAY_CTRL);
- long_sleep(10);
-
- hdc->write_cmd(hdc,
- LCD_CMD_DISPLAY_CTRL | /* set display mode */
- ((priv->flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) |
- ((priv->flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) |
- ((priv->flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0));
-
- charlcd_backlight(lcd, (priv->flags & LCD_FLAG_L) ? 1 : 0);
-
- long_sleep(10);
-
- /* entry mode set : increment, cursor shifting */
- hdc->write_cmd(hdc, LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC);
-
- lcd->ops->clear_display(lcd);
- lcd->addr.x = 0;
- lcd->addr.y = 0;
- return 0;
-}
-
/*
* Parses a movement command of the form "(.*);", where the group can be
* any number of subcommands of the form "(x|y)[0-9]+".
@@ -418,7 +331,9 @@ static inline int handle_lcd_special_code(struct charlcd *lcd)
break;
}
case 'I': /* reinitialize display */
- charlcd_init_display(lcd);
+ lcd->ops->init_display(lcd);
+ priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D |
+ LCD_FLAG_C | LCD_FLAG_B;
processed = 1;
break;
case 'G': {
@@ -727,6 +642,8 @@ static int charlcd_init(struct charlcd *lcd)
struct charlcd_priv *priv = charlcd_to_priv(lcd);
int ret;

+ priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D |
+ LCD_FLAG_C | LCD_FLAG_B;
if (lcd->ops->backlight) {
mutex_init(&priv->bl_tempo_lock);
INIT_DELAYED_WORK(&priv->bl_work, charlcd_bl_off);
@@ -737,7 +654,7 @@ static int charlcd_init(struct charlcd *lcd)
* Since charlcd_init_display() needs to write data, we have to
* enable mark the LCD initialized just before.
*/
- ret = charlcd_init_display(lcd);
+ ret = lcd->ops->init_display(lcd);
if (ret)
return ret;

diff --git a/drivers/auxdisplay/charlcd.h b/drivers/auxdisplay/charlcd.h
index e5b22e72fdc8..6281cf299a6d 100644
--- a/drivers/auxdisplay/charlcd.h
+++ b/drivers/auxdisplay/charlcd.h
@@ -9,6 +9,13 @@
#ifndef _CHARLCD_H
#define _CHARLCD_H

+#define LCD_FLAG_B 0x0004 /* Blink on */
+#define LCD_FLAG_C 0x0008 /* Cursor on */
+#define LCD_FLAG_D 0x0010 /* Display on */
+#define LCD_FLAG_F 0x0020 /* Large font mode */
+#define LCD_FLAG_N 0x0040 /* 2-rows mode */
+#define LCD_FLAG_L 0x0080 /* Backlight enabled */
+
enum charlcd_onoff {
CHARLCD_OFF = 0,
CHARLCD_ON,
@@ -45,6 +52,7 @@ struct charlcd {
* @clear_display: Again clear the whole display, set the cursor to 0, 0. The
* values in addr.x and addr.y are set to 0, 0 by charlcd prior to calling this
* function.
+ * @init_display: Initialize the display.
*/
struct charlcd_ops {
void (*clear_fast)(struct charlcd *lcd);
@@ -53,6 +61,7 @@ struct charlcd_ops {
int (*gotoxy)(struct charlcd *lcd);
int (*home)(struct charlcd *lcd);
int (*clear_display)(struct charlcd *lcd);
+ int (*init_display)(struct charlcd *lcd);
};

void charlcd_backlight(struct charlcd *lcd, enum charlcd_onoff on);
diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c
index 40ea6d25dbe1..5916da09f738 100644
--- a/drivers/auxdisplay/hd44780.c
+++ b/drivers/auxdisplay/hd44780.c
@@ -130,6 +130,7 @@ static const struct charlcd_ops hd44780_ops_gpio8 = {
.gotoxy = hd44780_common_gotoxy,
.home = hd44780_common_home,
.clear_display = hd44780_common_clear_display,
+ .init_display = hd44780_common_init_display,
};

/* Send a command to the LCD panel in 4 bit GPIO mode */
@@ -177,6 +178,7 @@ static const struct charlcd_ops hd44780_ops_gpio4 = {
.gotoxy = hd44780_common_gotoxy,
.home = hd44780_common_home,
.clear_display = hd44780_common_clear_display,
+ .init_display = hd44780_common_init_display,
};

static int hd44780_probe(struct platform_device *pdev)
diff --git a/drivers/auxdisplay/hd44780_common.c b/drivers/auxdisplay/hd44780_common.c
index 6bc2b3bf6139..8e64de2e44f2 100644
--- a/drivers/auxdisplay/hd44780_common.c
+++ b/drivers/auxdisplay/hd44780_common.c
@@ -9,6 +9,19 @@
/* LCD commands */
#define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */

+#define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */
+#define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */
+
+#define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */
+#define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */
+#define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */
+#define LCD_CMD_BLINK_ON 0x01 /* Set blink on */
+
+#define LCD_CMD_FUNCTION_SET 0x20 /* Set function */
+#define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */
+#define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */
+#define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */
+
#define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */

/* sleeps that many milliseconds with a reschedule */
@@ -70,6 +83,81 @@ int hd44780_common_clear_display(struct charlcd *lcd)
}
EXPORT_SYMBOL_GPL(hd44780_common_clear_display);

+int hd44780_common_init_display(struct charlcd *lcd)
+{
+ struct hd44780_common *hdc = lcd->drvdata;
+
+ void (*write_cmd_raw)(struct hd44780_common *hdc, int cmd);
+ u8 init;
+
+ if (hdc->ifwidth != 4 && hdc->ifwidth != 8)
+ return -EINVAL;
+
+ hdc->hd44780_common_flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) |
+ LCD_FLAG_D | LCD_FLAG_C | LCD_FLAG_B;
+
+ long_sleep(20); /* wait 20 ms after power-up for the paranoid */
+
+ /*
+ * 8-bit mode, 1 line, small fonts; let's do it 3 times, to make sure
+ * the LCD is in 8-bit mode afterwards
+ */
+ init = LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS;
+ if (hdc->ifwidth == 4) {
+ init >>= 4;
+ write_cmd_raw = hdc->write_cmd_raw4;
+ } else {
+ write_cmd_raw = hdc->write_cmd;
+ }
+ write_cmd_raw(hdc, init);
+ long_sleep(10);
+ write_cmd_raw(hdc, init);
+ long_sleep(10);
+ write_cmd_raw(hdc, init);
+ long_sleep(10);
+
+ if (hdc->ifwidth == 4) {
+ /* Switch to 4-bit mode, 1 line, small fonts */
+ hdc->write_cmd_raw4(hdc, LCD_CMD_FUNCTION_SET >> 4);
+ long_sleep(10);
+ }
+
+ /* set font height and lines number */
+ hdc->write_cmd(hdc,
+ LCD_CMD_FUNCTION_SET |
+ ((hdc->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) |
+ ((hdc->hd44780_common_flags & LCD_FLAG_F) ?
+ LCD_CMD_FONT_5X10_DOTS : 0) |
+ ((hdc->hd44780_common_flags & LCD_FLAG_N) ?
+ LCD_CMD_TWO_LINES : 0));
+ long_sleep(10);
+
+ /* display off, cursor off, blink off */
+ hdc->write_cmd(hdc, LCD_CMD_DISPLAY_CTRL);
+ long_sleep(10);
+
+ hdc->write_cmd(hdc,
+ LCD_CMD_DISPLAY_CTRL | /* set display mode */
+ ((hdc->hd44780_common_flags & LCD_FLAG_D) ?
+ LCD_CMD_DISPLAY_ON : 0) |
+ ((hdc->hd44780_common_flags & LCD_FLAG_C) ?
+ LCD_CMD_CURSOR_ON : 0) |
+ ((hdc->hd44780_common_flags & LCD_FLAG_B) ?
+ LCD_CMD_BLINK_ON : 0));
+
+ charlcd_backlight(lcd,
+ (hdc->hd44780_common_flags & LCD_FLAG_L) ? 1 : 0);
+
+ long_sleep(10);
+
+ /* entry mode set : increment, cursor shifting */
+ hdc->write_cmd(hdc, LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC);
+
+ hd44780_common_clear_display(lcd);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hd44780_common_init_display);
+
struct hd44780_common *hd44780_common_alloc(void)
{
struct hd44780_common *hd;
diff --git a/drivers/auxdisplay/hd44780_common.h b/drivers/auxdisplay/hd44780_common.h
index 11ec4baf6997..cefd78d67675 100644
--- a/drivers/auxdisplay/hd44780_common.h
+++ b/drivers/auxdisplay/hd44780_common.h
@@ -7,6 +7,7 @@ struct hd44780_common {
int ifwidth; /* 4-bit or 8-bit (default) */
int bwidth; /* Default set by hd44780_alloc() */
int hwidth; /* Default set by hd44780_alloc() */
+ unsigned long hd44780_common_flags;
void (*write_data)(struct hd44780_common *hdc, int data);
void (*write_cmd)(struct hd44780_common *hdc, int cmd);
/* write_cmd_raw4 is for 4-bit connected displays only */
@@ -18,5 +19,6 @@ int hd44780_common_print(struct charlcd *lcd, int c);
int hd44780_common_gotoxy(struct charlcd *lcd);
int hd44780_common_home(struct charlcd *lcd);
int hd44780_common_clear_display(struct charlcd *lcd);
+int hd44780_common_init_display(struct charlcd *lcd);
struct hd44780_common *hd44780_common_alloc(void);

diff --git a/drivers/auxdisplay/panel.c b/drivers/auxdisplay/panel.c
index 8adf627529f1..583bd22d3abd 100644
--- a/drivers/auxdisplay/panel.c
+++ b/drivers/auxdisplay/panel.c
@@ -878,6 +878,7 @@ static const struct charlcd_ops charlcd_serial_ops = {
.gotoxy = hd44780_common_gotoxy,
.home = hd44780_common_home,
.clear_display = hd44780_common_clear_display,
+ .init_display = hd44780_common_init_display,
};

static const struct charlcd_ops charlcd_parallel_ops = {
@@ -886,6 +887,7 @@ static const struct charlcd_ops charlcd_parallel_ops = {
.gotoxy = hd44780_common_gotoxy,
.home = hd44780_common_home,
.clear_display = hd44780_common_clear_display,
+ .init_display = hd44780_common_init_display,
};

static const struct charlcd_ops charlcd_tilcd_ops = {
@@ -894,6 +896,7 @@ static const struct charlcd_ops charlcd_tilcd_ops = {
.gotoxy = hd44780_common_gotoxy,
.home = hd44780_common_home,
.clear_display = hd44780_common_clear_display,
+ .init_display = hd44780_common_init_display,
};

/* initialize the LCD driver */
--
2.28.0

2020-10-16 04:31:59

by Miguel Ojeda

[permalink] [raw]
Subject: Re: [PATCH v4 14/32] auxdisplay: Move init_display to hd44780_common

On Mon, Oct 5, 2020 at 3:01 PM <[email protected]> wrote:
>
> The init_display function is moved over to hd44780_common. charlcd uses
> it via it's ops function pointer and drivers initialize the ops with the

it's -> its

(Already corrected in my queue)

Cheers,
Miguel