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