hd44780.c (8563B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * HD44780 Character LCD driver for Linux 4 * 5 * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu> 6 * Copyright (C) 2016-2017 Glider bvba 7 */ 8 9#include <linux/delay.h> 10#include <linux/gpio/consumer.h> 11#include <linux/module.h> 12#include <linux/mod_devicetable.h> 13#include <linux/platform_device.h> 14#include <linux/property.h> 15#include <linux/slab.h> 16 17#include "charlcd.h" 18#include "hd44780_common.h" 19 20enum hd44780_pin { 21 /* Order does matter due to writing to GPIO array subsets! */ 22 PIN_DATA0, /* Optional */ 23 PIN_DATA1, /* Optional */ 24 PIN_DATA2, /* Optional */ 25 PIN_DATA3, /* Optional */ 26 PIN_DATA4, 27 PIN_DATA5, 28 PIN_DATA6, 29 PIN_DATA7, 30 PIN_CTRL_RS, 31 PIN_CTRL_RW, /* Optional */ 32 PIN_CTRL_E, 33 PIN_CTRL_BL, /* Optional */ 34 PIN_NUM 35}; 36 37struct hd44780 { 38 struct gpio_desc *pins[PIN_NUM]; 39}; 40 41static void hd44780_backlight(struct charlcd *lcd, enum charlcd_onoff on) 42{ 43 struct hd44780_common *hdc = lcd->drvdata; 44 struct hd44780 *hd = hdc->hd44780; 45 46 if (hd->pins[PIN_CTRL_BL]) 47 gpiod_set_value_cansleep(hd->pins[PIN_CTRL_BL], on); 48} 49 50static void hd44780_strobe_gpio(struct hd44780 *hd) 51{ 52 /* Maintain the data during 20 us before the strobe */ 53 udelay(20); 54 55 gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 1); 56 57 /* Maintain the strobe during 40 us */ 58 udelay(40); 59 60 gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 0); 61} 62 63/* write to an LCD panel register in 8 bit GPIO mode */ 64static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs) 65{ 66 DECLARE_BITMAP(values, 10); /* for DATA[0-7], RS, RW */ 67 unsigned int n; 68 69 values[0] = val; 70 __assign_bit(8, values, rs); 71 n = hd->pins[PIN_CTRL_RW] ? 10 : 9; 72 73 /* Present the data to the port */ 74 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], NULL, values); 75 76 hd44780_strobe_gpio(hd); 77} 78 79/* write to an LCD panel register in 4 bit GPIO mode */ 80static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs) 81{ 82 DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */ 83 unsigned int n; 84 85 /* High nibble + RS, RW */ 86 values[0] = val >> 4; 87 __assign_bit(4, values, rs); 88 n = hd->pins[PIN_CTRL_RW] ? 6 : 5; 89 90 /* Present the data to the port */ 91 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values); 92 93 hd44780_strobe_gpio(hd); 94 95 /* Low nibble */ 96 values[0] &= ~0x0fUL; 97 values[0] |= val & 0x0f; 98 99 /* Present the data to the port */ 100 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values); 101 102 hd44780_strobe_gpio(hd); 103} 104 105/* Send a command to the LCD panel in 8 bit GPIO mode */ 106static void hd44780_write_cmd_gpio8(struct hd44780_common *hdc, int cmd) 107{ 108 struct hd44780 *hd = hdc->hd44780; 109 110 hd44780_write_gpio8(hd, cmd, 0); 111 112 /* The shortest command takes at least 120 us */ 113 udelay(120); 114} 115 116/* Send data to the LCD panel in 8 bit GPIO mode */ 117static void hd44780_write_data_gpio8(struct hd44780_common *hdc, int data) 118{ 119 struct hd44780 *hd = hdc->hd44780; 120 121 hd44780_write_gpio8(hd, data, 1); 122 123 /* The shortest data takes at least 45 us */ 124 udelay(45); 125} 126 127static const struct charlcd_ops hd44780_ops_gpio8 = { 128 .backlight = hd44780_backlight, 129 .print = hd44780_common_print, 130 .gotoxy = hd44780_common_gotoxy, 131 .home = hd44780_common_home, 132 .clear_display = hd44780_common_clear_display, 133 .init_display = hd44780_common_init_display, 134 .shift_cursor = hd44780_common_shift_cursor, 135 .shift_display = hd44780_common_shift_display, 136 .display = hd44780_common_display, 137 .cursor = hd44780_common_cursor, 138 .blink = hd44780_common_blink, 139 .fontsize = hd44780_common_fontsize, 140 .lines = hd44780_common_lines, 141 .redefine_char = hd44780_common_redefine_char, 142}; 143 144/* Send a command to the LCD panel in 4 bit GPIO mode */ 145static void hd44780_write_cmd_gpio4(struct hd44780_common *hdc, int cmd) 146{ 147 struct hd44780 *hd = hdc->hd44780; 148 149 hd44780_write_gpio4(hd, cmd, 0); 150 151 /* The shortest command takes at least 120 us */ 152 udelay(120); 153} 154 155/* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */ 156static void hd44780_write_cmd_raw_gpio4(struct hd44780_common *hdc, int cmd) 157{ 158 DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */ 159 struct hd44780 *hd = hdc->hd44780; 160 unsigned int n; 161 162 /* Command nibble + RS, RW */ 163 values[0] = cmd & 0x0f; 164 n = hd->pins[PIN_CTRL_RW] ? 6 : 5; 165 166 /* Present the data to the port */ 167 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values); 168 169 hd44780_strobe_gpio(hd); 170} 171 172/* Send data to the LCD panel in 4 bit GPIO mode */ 173static void hd44780_write_data_gpio4(struct hd44780_common *hdc, int data) 174{ 175 struct hd44780 *hd = hdc->hd44780; 176 177 hd44780_write_gpio4(hd, data, 1); 178 179 /* The shortest data takes at least 45 us */ 180 udelay(45); 181} 182 183static const struct charlcd_ops hd44780_ops_gpio4 = { 184 .backlight = hd44780_backlight, 185 .print = hd44780_common_print, 186 .gotoxy = hd44780_common_gotoxy, 187 .home = hd44780_common_home, 188 .clear_display = hd44780_common_clear_display, 189 .init_display = hd44780_common_init_display, 190 .shift_cursor = hd44780_common_shift_cursor, 191 .shift_display = hd44780_common_shift_display, 192 .display = hd44780_common_display, 193 .cursor = hd44780_common_cursor, 194 .blink = hd44780_common_blink, 195 .fontsize = hd44780_common_fontsize, 196 .lines = hd44780_common_lines, 197 .redefine_char = hd44780_common_redefine_char, 198}; 199 200static int hd44780_probe(struct platform_device *pdev) 201{ 202 struct device *dev = &pdev->dev; 203 unsigned int i, base; 204 struct charlcd *lcd; 205 struct hd44780_common *hdc; 206 struct hd44780 *hd; 207 int ifwidth, ret = -ENOMEM; 208 209 /* Required pins */ 210 ifwidth = gpiod_count(dev, "data"); 211 if (ifwidth < 0) 212 return ifwidth; 213 214 switch (ifwidth) { 215 case 4: 216 base = PIN_DATA4; 217 break; 218 case 8: 219 base = PIN_DATA0; 220 break; 221 default: 222 return -EINVAL; 223 } 224 225 hdc = hd44780_common_alloc(); 226 if (!hdc) 227 return -ENOMEM; 228 229 lcd = charlcd_alloc(); 230 if (!lcd) 231 goto fail1; 232 233 hd = kzalloc(sizeof(struct hd44780), GFP_KERNEL); 234 if (!hd) 235 goto fail2; 236 237 hdc->hd44780 = hd; 238 lcd->drvdata = hdc; 239 for (i = 0; i < ifwidth; i++) { 240 hd->pins[base + i] = devm_gpiod_get_index(dev, "data", i, 241 GPIOD_OUT_LOW); 242 if (IS_ERR(hd->pins[base + i])) { 243 ret = PTR_ERR(hd->pins[base + i]); 244 goto fail3; 245 } 246 } 247 248 hd->pins[PIN_CTRL_E] = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 249 if (IS_ERR(hd->pins[PIN_CTRL_E])) { 250 ret = PTR_ERR(hd->pins[PIN_CTRL_E]); 251 goto fail3; 252 } 253 254 hd->pins[PIN_CTRL_RS] = devm_gpiod_get(dev, "rs", GPIOD_OUT_HIGH); 255 if (IS_ERR(hd->pins[PIN_CTRL_RS])) { 256 ret = PTR_ERR(hd->pins[PIN_CTRL_RS]); 257 goto fail3; 258 } 259 260 /* Optional pins */ 261 hd->pins[PIN_CTRL_RW] = devm_gpiod_get_optional(dev, "rw", 262 GPIOD_OUT_LOW); 263 if (IS_ERR(hd->pins[PIN_CTRL_RW])) { 264 ret = PTR_ERR(hd->pins[PIN_CTRL_RW]); 265 goto fail3; 266 } 267 268 hd->pins[PIN_CTRL_BL] = devm_gpiod_get_optional(dev, "backlight", 269 GPIOD_OUT_LOW); 270 if (IS_ERR(hd->pins[PIN_CTRL_BL])) { 271 ret = PTR_ERR(hd->pins[PIN_CTRL_BL]); 272 goto fail3; 273 } 274 275 /* Required properties */ 276 ret = device_property_read_u32(dev, "display-height-chars", 277 &lcd->height); 278 if (ret) 279 goto fail3; 280 ret = device_property_read_u32(dev, "display-width-chars", &lcd->width); 281 if (ret) 282 goto fail3; 283 284 /* 285 * On displays with more than two rows, the internal buffer width is 286 * usually equal to the display width 287 */ 288 if (lcd->height > 2) 289 hdc->bwidth = lcd->width; 290 291 /* Optional properties */ 292 device_property_read_u32(dev, "internal-buffer-width", &hdc->bwidth); 293 294 hdc->ifwidth = ifwidth; 295 if (ifwidth == 8) { 296 lcd->ops = &hd44780_ops_gpio8; 297 hdc->write_data = hd44780_write_data_gpio8; 298 hdc->write_cmd = hd44780_write_cmd_gpio8; 299 } else { 300 lcd->ops = &hd44780_ops_gpio4; 301 hdc->write_data = hd44780_write_data_gpio4; 302 hdc->write_cmd = hd44780_write_cmd_gpio4; 303 hdc->write_cmd_raw4 = hd44780_write_cmd_raw_gpio4; 304 } 305 306 ret = charlcd_register(lcd); 307 if (ret) 308 goto fail3; 309 310 platform_set_drvdata(pdev, lcd); 311 return 0; 312 313fail3: 314 kfree(hd); 315fail2: 316 kfree(lcd); 317fail1: 318 kfree(hdc); 319 return ret; 320} 321 322static int hd44780_remove(struct platform_device *pdev) 323{ 324 struct charlcd *lcd = platform_get_drvdata(pdev); 325 326 charlcd_unregister(lcd); 327 kfree(lcd->drvdata); 328 329 kfree(lcd); 330 return 0; 331} 332 333static const struct of_device_id hd44780_of_match[] = { 334 { .compatible = "hit,hd44780" }, 335 { /* sentinel */ } 336}; 337MODULE_DEVICE_TABLE(of, hd44780_of_match); 338 339static struct platform_driver hd44780_driver = { 340 .probe = hd44780_probe, 341 .remove = hd44780_remove, 342 .driver = { 343 .name = "hd44780", 344 .of_match_table = hd44780_of_match, 345 }, 346}; 347 348module_platform_driver(hd44780_driver); 349MODULE_DESCRIPTION("HD44780 Character LCD driver"); 350MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>"); 351MODULE_LICENSE("GPL");