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