diff options
| author | Geert Uytterhoeven <geert@linux-m68k.org> | 2017-03-10 09:15:18 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-03-17 02:10:49 -0400 |
| commit | ac201479cc695cb0140e425b9ca8ab2ecdcd2f0d (patch) | |
| tree | 78929b3866d2bc0af026c538cd20b72de477c5da | |
| parent | 39f8ea46724efbed3ca021863a22337c31be264c (diff) | |
auxdisplay: charlcd: Add support for 4-bit interfaces
In 4-bit mode, 8-bit commands and data are written using two raw writes
to the data interface: high nibble first, low nibble last. This must be
handled by the low-level driver.
However, as we don't know in which mode (4-bit or 8-bit) nor 4-bit phase
the LCD was left, initialization must always be handled using raw
writes, and needs to configure the LCD for 8-bit mode first.
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | drivers/auxdisplay/charlcd.c | 36 | ||||
| -rw-r--r-- | include/misc/charlcd.h | 2 |
2 files changed, 32 insertions, 6 deletions
diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c index 930ffb2fb317..b3a84e90a268 100644 --- a/drivers/auxdisplay/charlcd.c +++ b/drivers/auxdisplay/charlcd.c | |||
| @@ -223,24 +223,46 @@ static void charlcd_clear_display(struct charlcd *lcd) | |||
| 223 | 223 | ||
| 224 | static int charlcd_init_display(struct charlcd *lcd) | 224 | static int charlcd_init_display(struct charlcd *lcd) |
| 225 | { | 225 | { |
| 226 | void (*write_cmd_raw)(struct charlcd *lcd, int cmd); | ||
| 226 | struct charlcd_priv *priv = to_priv(lcd); | 227 | struct charlcd_priv *priv = to_priv(lcd); |
| 228 | u8 init; | ||
| 229 | |||
| 230 | if (lcd->ifwidth != 4 && lcd->ifwidth != 8) | ||
| 231 | return -EINVAL; | ||
| 227 | 232 | ||
| 228 | priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D | | 233 | priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D | |
| 229 | LCD_FLAG_C | LCD_FLAG_B; | 234 | LCD_FLAG_C | LCD_FLAG_B; |
| 230 | 235 | ||
| 231 | long_sleep(20); /* wait 20 ms after power-up for the paranoid */ | 236 | long_sleep(20); /* wait 20 ms after power-up for the paranoid */ |
| 232 | 237 | ||
| 233 | /* 8bits, 1 line, small fonts; let's do it 3 times */ | 238 | /* |
| 234 | lcd->ops->write_cmd(lcd, LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS); | 239 | * 8-bit mode, 1 line, small fonts; let's do it 3 times, to make sure |
| 240 | * the LCD is in 8-bit mode afterwards | ||
| 241 | */ | ||
| 242 | init = LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS; | ||
| 243 | if (lcd->ifwidth == 4) { | ||
| 244 | init >>= 4; | ||
| 245 | write_cmd_raw = lcd->ops->write_cmd_raw4; | ||
| 246 | } else { | ||
| 247 | write_cmd_raw = lcd->ops->write_cmd; | ||
| 248 | } | ||
| 249 | write_cmd_raw(lcd, init); | ||
| 235 | long_sleep(10); | 250 | long_sleep(10); |
| 236 | lcd->ops->write_cmd(lcd, LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS); | 251 | write_cmd_raw(lcd, init); |
| 237 | long_sleep(10); | 252 | long_sleep(10); |
| 238 | lcd->ops->write_cmd(lcd, LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS); | 253 | write_cmd_raw(lcd, init); |
| 239 | long_sleep(10); | 254 | long_sleep(10); |
| 240 | 255 | ||
| 256 | if (lcd->ifwidth == 4) { | ||
| 257 | /* Switch to 4-bit mode, 1 line, small fonts */ | ||
| 258 | lcd->ops->write_cmd_raw4(lcd, LCD_CMD_FUNCTION_SET >> 4); | ||
| 259 | long_sleep(10); | ||
| 260 | } | ||
| 261 | |||
| 241 | /* set font height and lines number */ | 262 | /* set font height and lines number */ |
| 242 | lcd->ops->write_cmd(lcd, | 263 | lcd->ops->write_cmd(lcd, |
| 243 | LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS | | 264 | LCD_CMD_FUNCTION_SET | |
| 265 | ((lcd->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) | | ||
| 244 | ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) | | 266 | ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) | |
| 245 | ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)); | 267 | ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)); |
| 246 | long_sleep(10); | 268 | long_sleep(10); |
| @@ -482,7 +504,8 @@ static inline int handle_lcd_special_code(struct charlcd *lcd) | |||
| 482 | /* check whether one of F,N flags was changed */ | 504 | /* check whether one of F,N flags was changed */ |
| 483 | else if ((oldflags ^ priv->flags) & (LCD_FLAG_F | LCD_FLAG_N)) | 505 | else if ((oldflags ^ priv->flags) & (LCD_FLAG_F | LCD_FLAG_N)) |
| 484 | lcd->ops->write_cmd(lcd, | 506 | lcd->ops->write_cmd(lcd, |
| 485 | LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS | | 507 | LCD_CMD_FUNCTION_SET | |
| 508 | ((lcd->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) | | ||
| 486 | ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) | | 509 | ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) | |
| 487 | ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)); | 510 | ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)); |
| 488 | /* check whether L flag was changed */ | 511 | /* check whether L flag was changed */ |
| @@ -716,6 +739,7 @@ struct charlcd *charlcd_alloc(unsigned int drvdata_size) | |||
| 716 | priv->esc_seq.len = -1; | 739 | priv->esc_seq.len = -1; |
| 717 | 740 | ||
| 718 | lcd = &priv->lcd; | 741 | lcd = &priv->lcd; |
| 742 | lcd->ifwidth = 8; | ||
| 719 | lcd->bwidth = DEFAULT_LCD_BWIDTH; | 743 | lcd->bwidth = DEFAULT_LCD_BWIDTH; |
| 720 | lcd->hwidth = DEFAULT_LCD_HWIDTH; | 744 | lcd->hwidth = DEFAULT_LCD_HWIDTH; |
| 721 | lcd->drvdata = priv->drvdata; | 745 | lcd->drvdata = priv->drvdata; |
diff --git a/include/misc/charlcd.h b/include/misc/charlcd.h index c40047b673c9..23f61850f363 100644 --- a/include/misc/charlcd.h +++ b/include/misc/charlcd.h | |||
| @@ -14,6 +14,7 @@ struct charlcd { | |||
| 14 | const struct charlcd_ops *ops; | 14 | const struct charlcd_ops *ops; |
| 15 | const unsigned char *char_conv; /* Optional */ | 15 | const unsigned char *char_conv; /* Optional */ |
| 16 | 16 | ||
| 17 | int ifwidth; /* 4-bit or 8-bit (default) */ | ||
| 17 | int height; | 18 | int height; |
| 18 | int width; | 19 | int width; |
| 19 | int bwidth; /* Default set by charlcd_alloc() */ | 20 | int bwidth; /* Default set by charlcd_alloc() */ |
| @@ -28,6 +29,7 @@ struct charlcd_ops { | |||
| 28 | void (*write_data)(struct charlcd *lcd, int data); | 29 | void (*write_data)(struct charlcd *lcd, int data); |
| 29 | 30 | ||
| 30 | /* Optional */ | 31 | /* Optional */ |
| 32 | void (*write_cmd_raw4)(struct charlcd *lcd, int cmd); /* 4-bit only */ | ||
| 31 | void (*clear_fast)(struct charlcd *lcd); | 33 | void (*clear_fast)(struct charlcd *lcd); |
| 32 | void (*backlight)(struct charlcd *lcd, int on); | 34 | void (*backlight)(struct charlcd *lcd, int on); |
| 33 | }; | 35 | }; |
