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