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 20 enum 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 37 struct hd44780 { 38 struct gpio_desc *pins[PIN_NUM]; 39 }; 40 41 static 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 50 static 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 */ 64 static 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 */ 80 static 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 */ 106 static 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 */ 117 static 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 127 static 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 }; 134 135 /* Send a command to the LCD panel in 4 bit GPIO mode */ 136 static void hd44780_write_cmd_gpio4(struct hd44780_common *hdc, int cmd) 137 { 138 struct hd44780 *hd = hdc->hd44780; 139 140 hd44780_write_gpio4(hd, cmd, 0); 141 142 /* The shortest command takes at least 120 us */ 143 udelay(120); 144 } 145 146 /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */ 147 static void hd44780_write_cmd_raw_gpio4(struct hd44780_common *hdc, int cmd) 148 { 149 DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */ 150 struct hd44780 *hd = hdc->hd44780; 151 unsigned int n; 152 153 /* Command nibble + RS, RW */ 154 values[0] = cmd & 0x0f; 155 n = hd->pins[PIN_CTRL_RW] ? 6 : 5; 156 157 /* Present the data to the port */ 158 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values); 159 160 hd44780_strobe_gpio(hd); 161 } 162 163 /* Send data to the LCD panel in 4 bit GPIO mode */ 164 static void hd44780_write_data_gpio4(struct hd44780_common *hdc, int data) 165 { 166 struct hd44780 *hd = hdc->hd44780; 167 168 hd44780_write_gpio4(hd, data, 1); 169 170 /* The shortest data takes at least 45 us */ 171 udelay(45); 172 } 173 174 static const struct charlcd_ops hd44780_ops_gpio4 = { 175 .backlight = hd44780_backlight, 176 .print = hd44780_common_print, 177 .gotoxy = hd44780_common_gotoxy, 178 .home = hd44780_common_home, 179 .clear_display = hd44780_common_clear_display, 180 }; 181 182 static int hd44780_probe(struct platform_device *pdev) 183 { 184 struct device *dev = &pdev->dev; 185 unsigned int i, base; 186 struct charlcd *lcd; 187 struct hd44780_common *hdc; 188 struct hd44780 *hd; 189 int ifwidth, ret = -ENOMEM; 190 191 /* Required pins */ 192 ifwidth = gpiod_count(dev, "data"); 193 if (ifwidth < 0) 194 return ifwidth; 195 196 switch (ifwidth) { 197 case 4: 198 base = PIN_DATA4; 199 break; 200 case 8: 201 base = PIN_DATA0; 202 break; 203 default: 204 return -EINVAL; 205 } 206 207 hdc = hd44780_common_alloc(); 208 if (!hdc) 209 return -ENOMEM; 210 211 lcd = charlcd_alloc(); 212 if (!lcd) 213 goto fail1; 214 215 hd = kzalloc(sizeof(struct hd44780), GFP_KERNEL); 216 if (!hd) 217 goto fail2; 218 219 hdc->hd44780 = hd; 220 lcd->drvdata = hdc; 221 for (i = 0; i < ifwidth; i++) { 222 hd->pins[base + i] = devm_gpiod_get_index(dev, "data", i, 223 GPIOD_OUT_LOW); 224 if (IS_ERR(hd->pins[base + i])) { 225 ret = PTR_ERR(hd->pins[base + i]); 226 goto fail3; 227 } 228 } 229 230 hd->pins[PIN_CTRL_E] = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 231 if (IS_ERR(hd->pins[PIN_CTRL_E])) { 232 ret = PTR_ERR(hd->pins[PIN_CTRL_E]); 233 goto fail3; 234 } 235 236 hd->pins[PIN_CTRL_RS] = devm_gpiod_get(dev, "rs", GPIOD_OUT_HIGH); 237 if (IS_ERR(hd->pins[PIN_CTRL_RS])) { 238 ret = PTR_ERR(hd->pins[PIN_CTRL_RS]); 239 goto fail3; 240 } 241 242 /* Optional pins */ 243 hd->pins[PIN_CTRL_RW] = devm_gpiod_get_optional(dev, "rw", 244 GPIOD_OUT_LOW); 245 if (IS_ERR(hd->pins[PIN_CTRL_RW])) { 246 ret = PTR_ERR(hd->pins[PIN_CTRL_RW]); 247 goto fail3; 248 } 249 250 hd->pins[PIN_CTRL_BL] = devm_gpiod_get_optional(dev, "backlight", 251 GPIOD_OUT_LOW); 252 if (IS_ERR(hd->pins[PIN_CTRL_BL])) { 253 ret = PTR_ERR(hd->pins[PIN_CTRL_BL]); 254 goto fail3; 255 } 256 257 /* Required properties */ 258 ret = device_property_read_u32(dev, "display-height-chars", 259 &lcd->height); 260 if (ret) 261 goto fail3; 262 ret = device_property_read_u32(dev, "display-width-chars", &lcd->width); 263 if (ret) 264 goto fail3; 265 266 /* 267 * On displays with more than two rows, the internal buffer width is 268 * usually equal to the display width 269 */ 270 if (lcd->height > 2) 271 hdc->bwidth = lcd->width; 272 273 /* Optional properties */ 274 device_property_read_u32(dev, "internal-buffer-width", &hdc->bwidth); 275 276 hdc->ifwidth = ifwidth; 277 if (ifwidth == 8) { 278 lcd->ops = &hd44780_ops_gpio8; 279 hdc->write_data = hd44780_write_data_gpio8; 280 hdc->write_cmd = hd44780_write_cmd_gpio8; 281 } else { 282 lcd->ops = &hd44780_ops_gpio4; 283 hdc->write_data = hd44780_write_data_gpio4; 284 hdc->write_cmd = hd44780_write_cmd_gpio4; 285 hdc->write_cmd_raw4 = hd44780_write_cmd_raw_gpio4; 286 } 287 288 ret = charlcd_register(lcd); 289 if (ret) 290 goto fail3; 291 292 platform_set_drvdata(pdev, lcd); 293 return 0; 294 295 fail3: 296 kfree(hd); 297 fail2: 298 kfree(lcd); 299 fail1: 300 kfree(hdc); 301 return ret; 302 } 303 304 static int hd44780_remove(struct platform_device *pdev) 305 { 306 struct charlcd *lcd = platform_get_drvdata(pdev); 307 308 kfree(lcd->drvdata); 309 charlcd_unregister(lcd); 310 311 kfree(lcd); 312 return 0; 313 } 314 315 static const struct of_device_id hd44780_of_match[] = { 316 { .compatible = "hit,hd44780" }, 317 { /* sentinel */ } 318 }; 319 MODULE_DEVICE_TABLE(of, hd44780_of_match); 320 321 static struct platform_driver hd44780_driver = { 322 .probe = hd44780_probe, 323 .remove = hd44780_remove, 324 .driver = { 325 .name = "hd44780", 326 .of_match_table = hd44780_of_match, 327 }, 328 }; 329 330 module_platform_driver(hd44780_driver); 331 MODULE_DESCRIPTION("HD44780 Character LCD driver"); 332 MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>"); 333 MODULE_LICENSE("GPL"); 334