2 * work_92105 display support
4 * (C) Copyright 2014 DENX Software Engineering GmbH
5 * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
7 * The work_92105 display is a HD44780-compatible module
8 * controlled through a MAX6957AAX SPI port expander, two
9 * MAX518 I2C DACs and native LPC32xx GPO 15.
11 * SPDX-License-Identifier: GPL-2.0+
15 #include <asm/arch/sys_proto.h>
16 #include <asm/arch/cpu.h>
17 #include <asm/arch/emc.h>
25 * GPO 15 in port 3 is gpio 3*32+15 = 111
31 * MAX6957AAX registers that we will be using
34 #define MAX6957_CONF 0x04
36 #define MAX6957_CONF_08_11 0x0A
37 #define MAX6957_CONF_12_15 0x0B
38 #define MAX6957_CONF_16_19 0x0C
41 * Individual gpio ports (one per gpio) to HD44780
44 #define MAX6957AAX_HD44780_RS 0x29
45 #define MAX6957AAX_HD44780_R_W 0x2A
46 #define MAX6957AAX_HD44780_EN 0x2B
47 #define MAX6957AAX_HD44780_DATA 0x4C
50 * Display controller instructions
53 /* Function set: eight bits, two lines, 8-dot font */
54 #define HD44780_FUNCTION_SET 0x38
56 /* Display ON / OFF: turn display on */
57 #define HD44780_DISPLAY_ON_OFF_CONTROL 0x0C
59 /* Entry mode: increment */
60 #define HD44780_ENTRY_MODE_SET 0x06
63 #define HD44780_CLEAR_DISPLAY 0x01
65 /* Set DDRAM addr (to be ORed with exact address) */
66 #define HD44780_SET_DDRAM_ADDR 0x80
68 /* Set CGRAM addr (to be ORed with exact address) */
69 #define HD44780_SET_CGRAM_ADDR 0x40
72 * Default value for contrats
75 #define CONTRAST_DEFAULT 25
78 * Define slave as a module-wide local to save passing it around,
79 * plus we will need it after init for the "hd44780" command.
82 static struct spi_slave
*slave
;
85 * Write a value into a MAX6957AAX register.
88 static void max6957aax_write(uint8_t reg
, uint8_t value
)
94 gpio_set_value(GPO_15
, 0);
95 /* do SPI read/write (passing din==dout is OK) */
96 spi_xfer(slave
, 16, dout
, dout
, SPI_XFER_BEGIN
| SPI_XFER_END
);
97 gpio_set_value(GPO_15
, 1);
101 * Read a value from a MAX6957AAX register.
103 * According to the MAX6957AAX datasheet, we should release the chip
104 * select halfway through the read sequence, when the actual register
105 * value is read; but the WORK_92105 hardware prevents the MAX6957AAX
106 * SPI OUT from reaching the LPC32XX SIP MISO if chip is not selected.
107 * so let's release the CS an hold it again while reading the result.
110 static uint8_t max6957aax_read(uint8_t reg
)
112 uint8_t dout
[2], din
[2];
114 /* send read command */
115 dout
[0] = reg
| 0x80; /* set bit 7 to indicate read */
117 gpio_set_value(GPO_15
, 0);
118 /* do SPI read/write (passing din==dout is OK) */
119 spi_xfer(slave
, 16, dout
, dout
, SPI_XFER_BEGIN
| SPI_XFER_END
);
120 /* latch read command */
121 gpio_set_value(GPO_15
, 1);
122 /* read register -- din = noop on xmit, din[1] = reg on recv */
125 gpio_set_value(GPO_15
, 0);
126 /* do SPI read/write (passing din==dout is OK) */
127 spi_xfer(slave
, 16, din
, din
, SPI_XFER_BEGIN
| SPI_XFER_END
);
129 gpio_set_value(GPO_15
, 1);
133 static void hd44780_instruction(unsigned long instruction
)
135 max6957aax_write(MAX6957AAX_HD44780_RS
, 0);
136 max6957aax_write(MAX6957AAX_HD44780_R_W
, 0);
137 max6957aax_write(MAX6957AAX_HD44780_EN
, 1);
138 max6957aax_write(MAX6957AAX_HD44780_DATA
, instruction
);
139 max6957aax_write(MAX6957AAX_HD44780_EN
, 0);
140 /* HD44780 takes 37 us for most instructions, 1520 for clear */
141 if (instruction
== HD44780_CLEAR_DISPLAY
)
147 static void hd44780_write_char(char c
)
149 max6957aax_write(MAX6957AAX_HD44780_RS
, 1);
150 max6957aax_write(MAX6957AAX_HD44780_R_W
, 0);
151 max6957aax_write(MAX6957AAX_HD44780_EN
, 1);
152 max6957aax_write(MAX6957AAX_HD44780_DATA
, c
);
153 max6957aax_write(MAX6957AAX_HD44780_EN
, 0);
154 /* HD44780 takes 37 us to write to DDRAM or CGRAM */
158 static void hd44780_write_str(char *s
)
160 max6957aax_write(MAX6957AAX_HD44780_RS
, 1);
161 max6957aax_write(MAX6957AAX_HD44780_R_W
, 0);
163 max6957aax_write(MAX6957AAX_HD44780_EN
, 1);
164 max6957aax_write(MAX6957AAX_HD44780_DATA
, *s
);
165 max6957aax_write(MAX6957AAX_HD44780_EN
, 0);
167 /* HD44780 takes 37 us to write to DDRAM or CGRAM */
173 * Existing user code might expect these custom characters to be
174 * recognized and displayed on the LCD
177 static u8 char_gen_chars
[] = {
178 /* #8, empty rectangle */
179 0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1F,
180 /* #9, filled right arrow */
181 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00,
182 /* #10, filled left arrow */
183 0x01, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x00,
184 /* #11, up and down arrow */
185 0x04, 0x0E, 0x1F, 0x00, 0x00, 0x1F, 0x0E, 0x04,
186 /* #12, plus/minus */
187 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00, 0x1F, 0x00,
188 /* #13, fat exclamation mark */
189 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00,
190 /* #14, empty square */
191 0x00, 0x1F, 0x11, 0x11, 0x11, 0x1F, 0x00, 0x00,
192 /* #15, struck out square */
193 0x00, 0x1F, 0x19, 0x15, 0x13, 0x1F, 0x00, 0x00,
196 static void hd44780_init_char_gen(void)
200 hd44780_instruction(HD44780_SET_CGRAM_ADDR
);
202 for (i
= 0; i
< sizeof(char_gen_chars
); i
++)
203 hd44780_write_char(char_gen_chars
[i
]);
205 hd44780_instruction(HD44780_SET_DDRAM_ADDR
);
208 void work_92105_display_init(void)
211 char *display_contrast_str
;
212 uint8_t display_contrast
= CONTRAST_DEFAULT
;
213 uint8_t enable_backlight
= 0x96;
215 slave
= spi_setup_slave(0, 0, 500000, 0);
218 printf("Failed to set up SPI slave\n");
222 claim_err
= spi_claim_bus(slave
);
225 debug("Failed to claim SPI bus: %d\n", claim_err
);
227 /* enable backlight */
228 i2c_write(0x2c, 0x01, 1, &enable_backlight
, 1);
230 /* set display contrast */
231 display_contrast_str
= getenv("fwopt_dispcontrast");
232 if (display_contrast_str
)
233 display_contrast
= simple_strtoul(display_contrast_str
,
235 i2c_write(0x2c, 0x00, 1, &display_contrast
, 1);
237 /* request GPO_15 as an output initially set to 1 */
238 gpio_request(GPO_15
, "MAX6957_nCS");
239 gpio_direction_output(GPO_15
, 1);
241 /* enable MAX6957 portexpander */
242 max6957aax_write(MAX6957_CONF
, 0x01);
243 /* configure pin 8 as input, pins 9..19 as outputs */
244 max6957aax_write(MAX6957_CONF_08_11
, 0x56);
245 max6957aax_write(MAX6957_CONF_12_15
, 0x55);
246 max6957aax_write(MAX6957_CONF_16_19
, 0x55);
248 /* initialize HD44780 */
249 max6957aax_write(MAX6957AAX_HD44780_EN
, 0);
250 hd44780_instruction(HD44780_FUNCTION_SET
);
251 hd44780_instruction(HD44780_DISPLAY_ON_OFF_CONTROL
);
252 hd44780_instruction(HD44780_ENTRY_MODE_SET
);
254 /* write custom character glyphs */
255 hd44780_init_char_gen();
257 /* Show U-Boot version, date and time as a sign-of-life */
258 hd44780_instruction(HD44780_CLEAR_DISPLAY
);
259 hd44780_instruction(HD44780_SET_DDRAM_ADDR
| 0);
260 hd44780_write_str(U_BOOT_VERSION
);
261 hd44780_instruction(HD44780_SET_DDRAM_ADDR
| 64);
262 hd44780_write_str(U_BOOT_DATE
);
263 hd44780_instruction(HD44780_SET_DDRAM_ADDR
| 64 | 20);
264 hd44780_write_str(U_BOOT_TIME
);
267 #ifdef CONFIG_CMD_MAX6957
269 static int do_max6957aax(cmd_tbl_t
*cmdtp
, int flag
, int argc
,
275 return CMD_RET_USAGE
;
276 switch (argv
[1][0]) {
279 reg
= simple_strtoul(argv
[2], NULL
, 0);
280 val
= max6957aax_read(reg
);
281 printf("MAX6957 reg 0x%02x read 0x%02x\n", reg
, val
);
284 reg
= simple_strtoul(argv
[1], NULL
, 0);
285 val
= simple_strtoul(argv
[2], NULL
, 0);
286 max6957aax_write(reg
, val
);
287 printf("MAX6957 reg 0x%02x wrote 0x%02x\n", reg
, val
);
293 #ifdef CONFIG_SYS_LONGHELP
294 static char max6957aax_help_text
[] =
295 "max6957aax - write or read display register:\n"
296 "\tmax6957aax R|r reg - read display register;\n"
297 "\tmax6957aax reg val - write display register.";
301 max6957aax
, 6, 1, do_max6957aax
,
302 "SPI MAX6957 display write/read",
305 #endif /* CONFIG_CMD_MAX6957 */
307 #ifdef CONFIG_CMD_HD44760
310 * We need the HUSH parser because we need string arguments, and
311 * only HUSH can understand them.
314 #if !defined(CONFIG_HUSH_PARSER)
315 #error CONFIG_CMD_HD44760 requires CONFIG_HUSH_PARSER
318 static int do_hd44780(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char *const argv
[])
323 return CMD_RET_USAGE
;
327 if (strcasecmp(cmd
, "cmd") == 0)
328 hd44780_instruction(simple_strtol(argv
[2], NULL
, 0));
329 else if (strcasecmp(cmd
, "data") == 0)
330 hd44780_write_char(simple_strtol(argv
[2], NULL
, 0));
331 else if (strcasecmp(cmd
, "str") == 0)
332 hd44780_write_str(argv
[2]);
336 #ifdef CONFIG_SYS_LONGHELP
337 static char hd44780_help_text
[] =
338 "hd44780 - control LCD driver:\n"
339 "\thd44780 cmd <val> - send command <val> to driver;\n"
340 "\thd44780 data <val> - send data <val> to driver;\n"
341 "\thd44780 str \"<text>\" - send \"<text>\" to driver.";
345 hd44780
, 6, 1, do_hd44780
,
346 "HD44780 LCD driver control",
349 #endif /* CONFIG_CMD_HD44760 */