162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci#include <linux/module.h> 362306a36Sopenharmony_ci#include <linux/sched.h> 462306a36Sopenharmony_ci#include <linux/slab.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "charlcd.h" 762306a36Sopenharmony_ci#include "hd44780_common.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* LCD commands */ 1062306a36Sopenharmony_ci#define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */ 1362306a36Sopenharmony_ci#define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */ 1662306a36Sopenharmony_ci#define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */ 1762306a36Sopenharmony_ci#define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */ 1862306a36Sopenharmony_ci#define LCD_CMD_BLINK_ON 0x01 /* Set blink on */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define LCD_CMD_SHIFT 0x10 /* Shift cursor/display */ 2162306a36Sopenharmony_ci#define LCD_CMD_DISPLAY_SHIFT 0x08 /* Shift display instead of cursor */ 2262306a36Sopenharmony_ci#define LCD_CMD_SHIFT_RIGHT 0x04 /* Shift display/cursor to the right */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define LCD_CMD_FUNCTION_SET 0x20 /* Set function */ 2562306a36Sopenharmony_ci#define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */ 2662306a36Sopenharmony_ci#define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */ 2762306a36Sopenharmony_ci#define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define LCD_CMD_SET_CGRAM_ADDR 0x40 /* Set char generator RAM address */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* sleeps that many milliseconds with a reschedule */ 3462306a36Sopenharmony_cistatic void long_sleep(int ms) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci schedule_timeout_interruptible(msecs_to_jiffies(ms)); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciint hd44780_common_print(struct charlcd *lcd, int c) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (lcd->addr.x < hdc->bwidth) { 4462306a36Sopenharmony_ci hdc->write_data(hdc, c); 4562306a36Sopenharmony_ci return 0; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci return 1; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_print); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ciint hd44780_common_gotoxy(struct charlcd *lcd, unsigned int x, unsigned int y) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 5562306a36Sopenharmony_ci unsigned int addr; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * we force the cursor to stay at the end of the 5962306a36Sopenharmony_ci * line if it wants to go farther 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci addr = x < hdc->bwidth ? x & (hdc->hwidth - 1) : hdc->bwidth - 1; 6262306a36Sopenharmony_ci if (y & 1) 6362306a36Sopenharmony_ci addr += hdc->hwidth; 6462306a36Sopenharmony_ci if (y & 2) 6562306a36Sopenharmony_ci addr += hdc->bwidth; 6662306a36Sopenharmony_ci hdc->write_cmd(hdc, LCD_CMD_SET_DDRAM_ADDR | addr); 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_gotoxy); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciint hd44780_common_home(struct charlcd *lcd) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci return hd44780_common_gotoxy(lcd, 0, 0); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_home); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* clears the display and resets X/Y */ 7862306a36Sopenharmony_ciint hd44780_common_clear_display(struct charlcd *lcd) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci hdc->write_cmd(hdc, LCD_CMD_DISPLAY_CLEAR); 8362306a36Sopenharmony_ci /* datasheet says to wait 1,64 milliseconds */ 8462306a36Sopenharmony_ci long_sleep(2); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * The Hitachi HD44780 controller (and compatible ones) reset the DDRAM 8862306a36Sopenharmony_ci * address when executing the DISPLAY_CLEAR command, thus the 8962306a36Sopenharmony_ci * following call is not required. However, other controllers do not 9062306a36Sopenharmony_ci * (e.g. NewHaven NHD-0220DZW-AG5), thus move the cursor to home 9162306a36Sopenharmony_ci * unconditionally to support both. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci return hd44780_common_home(lcd); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_clear_display); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciint hd44780_common_init_display(struct charlcd *lcd) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci void (*write_cmd_raw)(struct hd44780_common *hdc, int cmd); 10262306a36Sopenharmony_ci u8 init; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (hdc->ifwidth != 4 && hdc->ifwidth != 8) 10562306a36Sopenharmony_ci return -EINVAL; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci hdc->hd44780_common_flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | 10862306a36Sopenharmony_ci LCD_FLAG_D | LCD_FLAG_C | LCD_FLAG_B; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci long_sleep(20); /* wait 20 ms after power-up for the paranoid */ 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* 11362306a36Sopenharmony_ci * 8-bit mode, 1 line, small fonts; let's do it 3 times, to make sure 11462306a36Sopenharmony_ci * the LCD is in 8-bit mode afterwards 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci init = LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS; 11762306a36Sopenharmony_ci if (hdc->ifwidth == 4) { 11862306a36Sopenharmony_ci init >>= 4; 11962306a36Sopenharmony_ci write_cmd_raw = hdc->write_cmd_raw4; 12062306a36Sopenharmony_ci } else { 12162306a36Sopenharmony_ci write_cmd_raw = hdc->write_cmd; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci write_cmd_raw(hdc, init); 12462306a36Sopenharmony_ci long_sleep(10); 12562306a36Sopenharmony_ci write_cmd_raw(hdc, init); 12662306a36Sopenharmony_ci long_sleep(10); 12762306a36Sopenharmony_ci write_cmd_raw(hdc, init); 12862306a36Sopenharmony_ci long_sleep(10); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (hdc->ifwidth == 4) { 13162306a36Sopenharmony_ci /* Switch to 4-bit mode, 1 line, small fonts */ 13262306a36Sopenharmony_ci hdc->write_cmd_raw4(hdc, LCD_CMD_FUNCTION_SET >> 4); 13362306a36Sopenharmony_ci long_sleep(10); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* set font height and lines number */ 13762306a36Sopenharmony_ci hdc->write_cmd(hdc, 13862306a36Sopenharmony_ci LCD_CMD_FUNCTION_SET | 13962306a36Sopenharmony_ci ((hdc->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) | 14062306a36Sopenharmony_ci ((hdc->hd44780_common_flags & LCD_FLAG_F) ? 14162306a36Sopenharmony_ci LCD_CMD_FONT_5X10_DOTS : 0) | 14262306a36Sopenharmony_ci ((hdc->hd44780_common_flags & LCD_FLAG_N) ? 14362306a36Sopenharmony_ci LCD_CMD_TWO_LINES : 0)); 14462306a36Sopenharmony_ci long_sleep(10); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* display off, cursor off, blink off */ 14762306a36Sopenharmony_ci hdc->write_cmd(hdc, LCD_CMD_DISPLAY_CTRL); 14862306a36Sopenharmony_ci long_sleep(10); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci hdc->write_cmd(hdc, 15162306a36Sopenharmony_ci LCD_CMD_DISPLAY_CTRL | /* set display mode */ 15262306a36Sopenharmony_ci ((hdc->hd44780_common_flags & LCD_FLAG_D) ? 15362306a36Sopenharmony_ci LCD_CMD_DISPLAY_ON : 0) | 15462306a36Sopenharmony_ci ((hdc->hd44780_common_flags & LCD_FLAG_C) ? 15562306a36Sopenharmony_ci LCD_CMD_CURSOR_ON : 0) | 15662306a36Sopenharmony_ci ((hdc->hd44780_common_flags & LCD_FLAG_B) ? 15762306a36Sopenharmony_ci LCD_CMD_BLINK_ON : 0)); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci charlcd_backlight(lcd, 16062306a36Sopenharmony_ci (hdc->hd44780_common_flags & LCD_FLAG_L) ? 1 : 0); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci long_sleep(10); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* entry mode set : increment, cursor shifting */ 16562306a36Sopenharmony_ci hdc->write_cmd(hdc, LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci hd44780_common_clear_display(lcd); 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_init_display); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ciint hd44780_common_shift_cursor(struct charlcd *lcd, enum charlcd_shift_dir dir) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (dir == CHARLCD_SHIFT_LEFT) { 17762306a36Sopenharmony_ci /* back one char if not at end of line */ 17862306a36Sopenharmony_ci if (lcd->addr.x < hdc->bwidth) 17962306a36Sopenharmony_ci hdc->write_cmd(hdc, LCD_CMD_SHIFT); 18062306a36Sopenharmony_ci } else if (dir == CHARLCD_SHIFT_RIGHT) { 18162306a36Sopenharmony_ci /* allow the cursor to pass the end of the line */ 18262306a36Sopenharmony_ci if (lcd->addr.x < (hdc->bwidth - 1)) 18362306a36Sopenharmony_ci hdc->write_cmd(hdc, 18462306a36Sopenharmony_ci LCD_CMD_SHIFT | LCD_CMD_SHIFT_RIGHT); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_shift_cursor); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ciint hd44780_common_shift_display(struct charlcd *lcd, 19262306a36Sopenharmony_ci enum charlcd_shift_dir dir) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (dir == CHARLCD_SHIFT_LEFT) 19762306a36Sopenharmony_ci hdc->write_cmd(hdc, LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT); 19862306a36Sopenharmony_ci else if (dir == CHARLCD_SHIFT_RIGHT) 19962306a36Sopenharmony_ci hdc->write_cmd(hdc, LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT | 20062306a36Sopenharmony_ci LCD_CMD_SHIFT_RIGHT); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_shift_display); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic void hd44780_common_set_mode(struct hd44780_common *hdc) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci hdc->write_cmd(hdc, 20962306a36Sopenharmony_ci LCD_CMD_DISPLAY_CTRL | 21062306a36Sopenharmony_ci ((hdc->hd44780_common_flags & LCD_FLAG_D) ? 21162306a36Sopenharmony_ci LCD_CMD_DISPLAY_ON : 0) | 21262306a36Sopenharmony_ci ((hdc->hd44780_common_flags & LCD_FLAG_C) ? 21362306a36Sopenharmony_ci LCD_CMD_CURSOR_ON : 0) | 21462306a36Sopenharmony_ci ((hdc->hd44780_common_flags & LCD_FLAG_B) ? 21562306a36Sopenharmony_ci LCD_CMD_BLINK_ON : 0)); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciint hd44780_common_display(struct charlcd *lcd, enum charlcd_onoff on) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (on == CHARLCD_ON) 22362306a36Sopenharmony_ci hdc->hd44780_common_flags |= LCD_FLAG_D; 22462306a36Sopenharmony_ci else 22562306a36Sopenharmony_ci hdc->hd44780_common_flags &= ~LCD_FLAG_D; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci hd44780_common_set_mode(hdc); 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_display); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ciint hd44780_common_cursor(struct charlcd *lcd, enum charlcd_onoff on) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (on == CHARLCD_ON) 23762306a36Sopenharmony_ci hdc->hd44780_common_flags |= LCD_FLAG_C; 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci hdc->hd44780_common_flags &= ~LCD_FLAG_C; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci hd44780_common_set_mode(hdc); 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_cursor); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciint hd44780_common_blink(struct charlcd *lcd, enum charlcd_onoff on) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (on == CHARLCD_ON) 25162306a36Sopenharmony_ci hdc->hd44780_common_flags |= LCD_FLAG_B; 25262306a36Sopenharmony_ci else 25362306a36Sopenharmony_ci hdc->hd44780_common_flags &= ~LCD_FLAG_B; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci hd44780_common_set_mode(hdc); 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_blink); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic void hd44780_common_set_function(struct hd44780_common *hdc) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci hdc->write_cmd(hdc, 26362306a36Sopenharmony_ci LCD_CMD_FUNCTION_SET | 26462306a36Sopenharmony_ci ((hdc->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) | 26562306a36Sopenharmony_ci ((hdc->hd44780_common_flags & LCD_FLAG_F) ? 26662306a36Sopenharmony_ci LCD_CMD_FONT_5X10_DOTS : 0) | 26762306a36Sopenharmony_ci ((hdc->hd44780_common_flags & LCD_FLAG_N) ? 26862306a36Sopenharmony_ci LCD_CMD_TWO_LINES : 0)); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ciint hd44780_common_fontsize(struct charlcd *lcd, enum charlcd_fontsize size) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (size == CHARLCD_FONTSIZE_LARGE) 27662306a36Sopenharmony_ci hdc->hd44780_common_flags |= LCD_FLAG_F; 27762306a36Sopenharmony_ci else 27862306a36Sopenharmony_ci hdc->hd44780_common_flags &= ~LCD_FLAG_F; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci hd44780_common_set_function(hdc); 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_fontsize); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ciint hd44780_common_lines(struct charlcd *lcd, enum charlcd_lines lines) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (lines == CHARLCD_LINES_2) 29062306a36Sopenharmony_ci hdc->hd44780_common_flags |= LCD_FLAG_N; 29162306a36Sopenharmony_ci else 29262306a36Sopenharmony_ci hdc->hd44780_common_flags &= ~LCD_FLAG_N; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci hd44780_common_set_function(hdc); 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_lines); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ciint hd44780_common_redefine_char(struct charlcd *lcd, char *esc) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci /* Generator : LGcxxxxx...xx; must have <c> between '0' 30262306a36Sopenharmony_ci * and '7', representing the numerical ASCII code of the 30362306a36Sopenharmony_ci * redefined character, and <xx...xx> a sequence of 16 30462306a36Sopenharmony_ci * hex digits representing 8 bytes for each character. 30562306a36Sopenharmony_ci * Most LCDs will only use 5 lower bits of the 7 first 30662306a36Sopenharmony_ci * bytes. 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci struct hd44780_common *hdc = lcd->drvdata; 31062306a36Sopenharmony_ci unsigned char cgbytes[8]; 31162306a36Sopenharmony_ci unsigned char cgaddr; 31262306a36Sopenharmony_ci int cgoffset; 31362306a36Sopenharmony_ci int shift; 31462306a36Sopenharmony_ci char value; 31562306a36Sopenharmony_ci int addr; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (!strchr(esc, ';')) 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci esc++; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci cgaddr = *(esc++) - '0'; 32362306a36Sopenharmony_ci if (cgaddr > 7) 32462306a36Sopenharmony_ci return 1; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci cgoffset = 0; 32762306a36Sopenharmony_ci shift = 0; 32862306a36Sopenharmony_ci value = 0; 32962306a36Sopenharmony_ci while (*esc && cgoffset < 8) { 33062306a36Sopenharmony_ci int half; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci shift ^= 4; 33362306a36Sopenharmony_ci half = hex_to_bin(*esc++); 33462306a36Sopenharmony_ci if (half < 0) 33562306a36Sopenharmony_ci continue; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci value |= half << shift; 33862306a36Sopenharmony_ci if (shift == 0) { 33962306a36Sopenharmony_ci cgbytes[cgoffset++] = value; 34062306a36Sopenharmony_ci value = 0; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci hdc->write_cmd(hdc, LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8)); 34562306a36Sopenharmony_ci for (addr = 0; addr < cgoffset; addr++) 34662306a36Sopenharmony_ci hdc->write_data(hdc, cgbytes[addr]); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* ensures that we stop writing to CGRAM */ 34962306a36Sopenharmony_ci lcd->ops->gotoxy(lcd, lcd->addr.x, lcd->addr.y); 35062306a36Sopenharmony_ci return 1; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_redefine_char); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistruct hd44780_common *hd44780_common_alloc(void) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct hd44780_common *hd; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci hd = kzalloc(sizeof(*hd), GFP_KERNEL); 35962306a36Sopenharmony_ci if (!hd) 36062306a36Sopenharmony_ci return NULL; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci hd->ifwidth = 8; 36362306a36Sopenharmony_ci hd->bwidth = DEFAULT_LCD_BWIDTH; 36462306a36Sopenharmony_ci hd->hwidth = DEFAULT_LCD_HWIDTH; 36562306a36Sopenharmony_ci return hd; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hd44780_common_alloc); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 370