1 // SPDX-License-Identifier: GPL-2.0+
3 * HD44780 Character LCD driver for Linux
5 * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
6 * Copyright (C) 2016-2017 Glider bvba
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>
20 /* Order does matter due to writing to GPIO array subsets! */
21 PIN_DATA0
, /* Optional */
22 PIN_DATA1
, /* Optional */
23 PIN_DATA2
, /* Optional */
24 PIN_DATA3
, /* Optional */
30 PIN_CTRL_RW
, /* Optional */
32 PIN_CTRL_BL
, /* Optional */
37 struct gpio_desc
*pins
[PIN_NUM
];
40 static void hd44780_backlight(struct charlcd
*lcd
, int on
)
42 struct hd44780
*hd
= lcd
->drvdata
;
44 if (hd
->pins
[PIN_CTRL_BL
])
45 gpiod_set_value_cansleep(hd
->pins
[PIN_CTRL_BL
], on
);
48 static void hd44780_strobe_gpio(struct hd44780
*hd
)
50 /* Maintain the data during 20 us before the strobe */
53 gpiod_set_value_cansleep(hd
->pins
[PIN_CTRL_E
], 1);
55 /* Maintain the strobe during 40 us */
58 gpiod_set_value_cansleep(hd
->pins
[PIN_CTRL_E
], 0);
61 /* write to an LCD panel register in 8 bit GPIO mode */
62 static void hd44780_write_gpio8(struct hd44780
*hd
, u8 val
, unsigned int rs
)
64 DECLARE_BITMAP(values
, 10); /* for DATA[0-7], RS, RW */
68 __assign_bit(8, values
, rs
);
69 n
= hd
->pins
[PIN_CTRL_RW
] ? 10 : 9;
71 /* Present the data to the port */
72 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA0
], NULL
, values
);
74 hd44780_strobe_gpio(hd
);
77 /* write to an LCD panel register in 4 bit GPIO mode */
78 static void hd44780_write_gpio4(struct hd44780
*hd
, u8 val
, unsigned int rs
)
80 DECLARE_BITMAP(values
, 6); /* for DATA[4-7], RS, RW */
83 /* High nibble + RS, RW */
85 __assign_bit(4, values
, rs
);
86 n
= hd
->pins
[PIN_CTRL_RW
] ? 6 : 5;
88 /* Present the data to the port */
89 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA4
], NULL
, values
);
91 hd44780_strobe_gpio(hd
);
95 values
[0] |= val
& 0x0f;
97 /* Present the data to the port */
98 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA4
], NULL
, values
);
100 hd44780_strobe_gpio(hd
);
103 /* Send a command to the LCD panel in 8 bit GPIO mode */
104 static void hd44780_write_cmd_gpio8(struct charlcd
*lcd
, int cmd
)
106 struct hd44780
*hd
= lcd
->drvdata
;
108 hd44780_write_gpio8(hd
, cmd
, 0);
110 /* The shortest command takes at least 120 us */
114 /* Send data to the LCD panel in 8 bit GPIO mode */
115 static void hd44780_write_data_gpio8(struct charlcd
*lcd
, int data
)
117 struct hd44780
*hd
= lcd
->drvdata
;
119 hd44780_write_gpio8(hd
, data
, 1);
121 /* The shortest data takes at least 45 us */
125 static const struct charlcd_ops hd44780_ops_gpio8
= {
126 .write_cmd
= hd44780_write_cmd_gpio8
,
127 .write_data
= hd44780_write_data_gpio8
,
128 .backlight
= hd44780_backlight
,
131 /* Send a command to the LCD panel in 4 bit GPIO mode */
132 static void hd44780_write_cmd_gpio4(struct charlcd
*lcd
, int cmd
)
134 struct hd44780
*hd
= lcd
->drvdata
;
136 hd44780_write_gpio4(hd
, cmd
, 0);
138 /* The shortest command takes at least 120 us */
142 /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
143 static void hd44780_write_cmd_raw_gpio4(struct charlcd
*lcd
, int cmd
)
145 DECLARE_BITMAP(values
, 6); /* for DATA[4-7], RS, RW */
146 struct hd44780
*hd
= lcd
->drvdata
;
149 /* Command nibble + RS, RW */
150 values
[0] = cmd
& 0x0f;
151 n
= hd
->pins
[PIN_CTRL_RW
] ? 6 : 5;
153 /* Present the data to the port */
154 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA4
], NULL
, values
);
156 hd44780_strobe_gpio(hd
);
159 /* Send data to the LCD panel in 4 bit GPIO mode */
160 static void hd44780_write_data_gpio4(struct charlcd
*lcd
, int data
)
162 struct hd44780
*hd
= lcd
->drvdata
;
164 hd44780_write_gpio4(hd
, data
, 1);
166 /* The shortest data takes at least 45 us */
170 static const struct charlcd_ops hd44780_ops_gpio4
= {
171 .write_cmd
= hd44780_write_cmd_gpio4
,
172 .write_cmd_raw4
= hd44780_write_cmd_raw_gpio4
,
173 .write_data
= hd44780_write_data_gpio4
,
174 .backlight
= hd44780_backlight
,
177 static int hd44780_probe(struct platform_device
*pdev
)
179 struct device
*dev
= &pdev
->dev
;
180 unsigned int i
, base
;
186 ifwidth
= gpiod_count(dev
, "data");
201 lcd
= charlcd_alloc(sizeof(struct hd44780
));
207 for (i
= 0; i
< ifwidth
; i
++) {
208 hd
->pins
[base
+ i
] = devm_gpiod_get_index(dev
, "data", i
,
210 if (IS_ERR(hd
->pins
[base
+ i
])) {
211 ret
= PTR_ERR(hd
->pins
[base
+ i
]);
216 hd
->pins
[PIN_CTRL_E
] = devm_gpiod_get(dev
, "enable", GPIOD_OUT_LOW
);
217 if (IS_ERR(hd
->pins
[PIN_CTRL_E
])) {
218 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_E
]);
222 hd
->pins
[PIN_CTRL_RS
] = devm_gpiod_get(dev
, "rs", GPIOD_OUT_HIGH
);
223 if (IS_ERR(hd
->pins
[PIN_CTRL_RS
])) {
224 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_RS
]);
229 hd
->pins
[PIN_CTRL_RW
] = devm_gpiod_get_optional(dev
, "rw",
231 if (IS_ERR(hd
->pins
[PIN_CTRL_RW
])) {
232 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_RW
]);
236 hd
->pins
[PIN_CTRL_BL
] = devm_gpiod_get_optional(dev
, "backlight",
238 if (IS_ERR(hd
->pins
[PIN_CTRL_BL
])) {
239 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_BL
]);
243 /* Required properties */
244 ret
= device_property_read_u32(dev
, "display-height-chars",
248 ret
= device_property_read_u32(dev
, "display-width-chars", &lcd
->width
);
253 * On displays with more than two rows, the internal buffer width is
254 * usually equal to the display width
257 lcd
->bwidth
= lcd
->width
;
259 /* Optional properties */
260 device_property_read_u32(dev
, "internal-buffer-width", &lcd
->bwidth
);
262 lcd
->ifwidth
= ifwidth
;
263 lcd
->ops
= ifwidth
== 8 ? &hd44780_ops_gpio8
: &hd44780_ops_gpio4
;
265 ret
= charlcd_register(lcd
);
269 platform_set_drvdata(pdev
, lcd
);
277 static int hd44780_remove(struct platform_device
*pdev
)
279 struct charlcd
*lcd
= platform_get_drvdata(pdev
);
281 charlcd_unregister(lcd
);
287 static const struct of_device_id hd44780_of_match
[] = {
288 { .compatible
= "hit,hd44780" },
291 MODULE_DEVICE_TABLE(of
, hd44780_of_match
);
293 static struct platform_driver hd44780_driver
= {
294 .probe
= hd44780_probe
,
295 .remove
= hd44780_remove
,
298 .of_match_table
= hd44780_of_match
,
302 module_platform_driver(hd44780_driver
);
303 MODULE_DESCRIPTION("HD44780 Character LCD driver");
304 MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
305 MODULE_LICENSE("GPL");