diff options
Diffstat (limited to 'board/fusb307bgevb/lcd.c')
-rw-r--r-- | board/fusb307bgevb/lcd.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/board/fusb307bgevb/lcd.c b/board/fusb307bgevb/lcd.c new file mode 100644 index 0000000000..892888329e --- /dev/null +++ b/board/fusb307bgevb/lcd.c @@ -0,0 +1,166 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * LCD driver for I2C LCD 2004. + */ + +#include "i2c.h" +#include "lcd.h" +#include "timer.h" + +struct lcd_state_info { + uint8_t addr; + uint8_t displayfunction; + uint8_t displaycontrol; + uint8_t backlightval; +}; + +static struct lcd_state_info state = { + .addr = LCD_SLAVE_ADDR, + .backlightval = LCD_BACKLIGHT, + .displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5X8DOTS, +}; + +/************ low level data pushing commands **********/ +/* write either command or data */ +static void expander_write(uint8_t data) +{ + i2c_write8(I2C_PORT_TCPC, LCD_SLAVE_ADDR, 0x00, data | + state.backlightval); +} + +static void pulse_enable(uint8_t data) +{ + expander_write(data | LCD_EN);/* En high */ + usleep(1); /* enable pulse must be >450ns */ + + expander_write(data & ~LCD_EN);/* En low */ + usleep(50); /* commands need > 37us to settle */ +} + +static void write_4bits(uint8_t value) +{ + expander_write(value); + pulse_enable(value); +} + +static void send(uint8_t value, uint8_t mode) +{ + uint8_t highnib = value & 0xf0; + uint8_t lownib = (value << 4) & 0xf0; + + write_4bits(highnib | mode); + write_4bits(lownib | mode); +} + +/*********** mid level commands, for sending data/cmds */ +static void command(uint8_t value) +{ + send(value, 0); +} + +/********** high level commands, for the user! */ +void lcd_clear(void) +{ + command(LCD_CLEAR_DISPLAY);/* clear display, set cursor to zero */ + usleep(2000); /* this command takes a long time! */ +} + +void lcd_set_cursor(uint8_t col, uint8_t row) +{ + int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; + + command(LCD_SET_DDRAMADDR | (col + row_offsets[row])); +} + +void lcd_print_char(char data) +{ + send(data, LCD_RS); +} + +void lcd_print_string(const char *str) +{ + while (*str) + lcd_print_char(*str++); +} + +/* Turn the display on/off (quickly) */ +void lcd_disable_display(void) +{ + state.displaycontrol &= ~LCD_DISPLAY_ON; + command(LCD_DISPLAY_CONTROL | state.displaycontrol); +} +void lcd_enable_display(void) +{ + state.displaycontrol |= LCD_DISPLAY_ON; + command(LCD_DISPLAY_CONTROL | state.displaycontrol); +} + +/* Turn the (optional) backlight off/on */ +void lcd_disable_backlight(void) +{ + state.backlightval = LCD_NO_BACKLIGHT; + expander_write(0); +} + +void lcd_enable_backlight(void) +{ + state.backlightval = LCD_BACKLIGHT; + expander_write(0); +} + +void lcd_init(uint8_t cols, uint8_t rows, uint8_t dotsize) +{ + if (rows > 1) + state.displayfunction |= LCD_2LINE; + + /* for some 1 line displays you can select a 10 pixel high font */ + if ((dotsize != 0) && (rows == 1)) + state.displayfunction |= LCD_5X10DOTS; + + /* SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! + * according to datasheet, we need at least 40ms after power rises + * above 2.7V before sending commands. Arduino can turn on way + * before 4.5V so we'll wait 50 + */ + usleep(50); + + /* Now we pull both RS and R/W low to begin commands */ + /* reset expanderand turn backlight off (Bit 8 =1) */ + expander_write(state.backlightval); + usleep(1000); + + /* put the LCD into 4 bit mode + * this is according to the hitachi HD44780 datasheet + * figure 24, pg 46 + * we start in 8bit mode, try to set 4 bit mode + */ + write_4bits(0x03 << 4); + usleep(4500); /* wait min 4.1ms */ + /*second try */ + write_4bits(0x03 << 4); + usleep(4500); /* wait min 4.1ms */ + /* third go! */ + write_4bits(0x03 << 4); + usleep(150); + /* finally, set to 4-bit interface */ + write_4bits(0x02 << 4); + + /* set # lines, font size, etc. */ + command(LCD_FUNCTION_SET | state.displayfunction); + + /* turn the display on with no cursor or blinking default */ + state.displaycontrol = LCD_DISPLAY_ON | LCD_CURSOR_OFF | LCD_BLINK_OFF; + lcd_enable_display(); + + /* clear it off */ + lcd_clear(); + + /* Initialize to default text direction (for roman languages) + * and set the entry mode + */ + command(LCD_ENTRYMODE_SET | LCD_ENTRY_LEFT | LCD_ENTRY_SHIFT_DECREMENT); + + lcd_set_cursor(0, 0); +} |