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.
Unified · Split
| @@ -223,24 +223,46 @@ static void charlcd_clear_display(struct charlcd *lcd) · 222 unmodified lines | |||
| 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) · 235 unmodified lines | |||
| 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) · 227 unmodified lines | |||
| 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; |
| @@ -14,6 +14,7 @@ struct charlcd { · 13 unmodified lines | |||
| 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 { · 8 unmodified lines | |||
| 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 | }; |