projects/linux·blob master · refs

344 lines · 8.3 KiB

1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * HD44780 Character LCD driver for Linux
4 *
5 * Copyright (C) 2000-2008, Willy Tarreau <[email protected]>
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/platform_device.h>
13#include <linux/property.h>
14#include <linux/slab.h>
15
16#include "charlcd.h"
17#include "hd44780_common.h"
18
19enum hd44780_pin {
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 */
25 PIN_DATA4,
26 PIN_DATA5,
27 PIN_DATA6,
28 PIN_DATA7,
29 PIN_CTRL_RS,
30 PIN_CTRL_RW, /* Optional */
31 PIN_CTRL_E,
32 PIN_CTRL_BL, /* Optional */
33 PIN_NUM
34};
35
36struct hd44780 {
37 struct gpio_desc *pins[PIN_NUM];
38};
39
40static void hd44780_backlight(struct charlcd *lcd, enum charlcd_onoff on)
41{
42 struct hd44780_common *hdc = lcd->drvdata;
43 struct hd44780 *hd = hdc->hd44780;
44
45 if (hd->pins[PIN_CTRL_BL])
46 gpiod_set_value_cansleep(hd->pins[PIN_CTRL_BL], on);
47}
48
49static void hd44780_strobe_gpio(struct hd44780 *hd)
50{
51 /* Maintain the data during 20 us before the strobe */
52 udelay(20);
53
54 gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 1);
55
56 /* Maintain the strobe during 40 us */
57 udelay(40);
58
59 gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 0);
60}
61
62/* write to an LCD panel register in 8 bit GPIO mode */
63static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
64{
65 DECLARE_BITMAP(values, 10); /* for DATA[0-7], RS, RW */
66 unsigned int n;
67
68 values[0] = val;
69 __assign_bit(8, values, rs);
70 n = hd->pins[PIN_CTRL_RW] ? 10 : 9;
71
72 /* Present the data to the port */
73 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], NULL, values);
74
75 hd44780_strobe_gpio(hd);
76}
77
78/* write to an LCD panel register in 4 bit GPIO mode */
79static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs)
80{
81 DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
82 unsigned int n;
83
84 /* High nibble + RS, RW */
85 values[0] = val >> 4;
86 __assign_bit(4, values, rs);
87 n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
88
89 /* Present the data to the port */
90 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
91
92 hd44780_strobe_gpio(hd);
93
94 /* Low nibble */
95 values[0] &= ~0x0fUL;
96 values[0] |= val & 0x0f;
97
98 /* Present the data to the port */
99 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
100
101 hd44780_strobe_gpio(hd);
102}
103
104/* Send a command to the LCD panel in 8 bit GPIO mode */
105static void hd44780_write_cmd_gpio8(struct hd44780_common *hdc, int cmd)
106{
107 struct hd44780 *hd = hdc->hd44780;
108
109 hd44780_write_gpio8(hd, cmd, 0);
110
111 /* The shortest command takes at least 120 us */
112 udelay(120);
113}
114
115/* Send data to the LCD panel in 8 bit GPIO mode */
116static void hd44780_write_data_gpio8(struct hd44780_common *hdc, int data)
117{
118 struct hd44780 *hd = hdc->hd44780;
119
120 hd44780_write_gpio8(hd, data, 1);
121
122 /* The shortest data takes at least 45 us */
123 udelay(45);
124}
125
126static const struct charlcd_ops hd44780_ops_gpio8 = {
127 .backlight = hd44780_backlight,
128 .print = hd44780_common_print,
129 .gotoxy = hd44780_common_gotoxy,
130 .home = hd44780_common_home,
131 .clear_display = hd44780_common_clear_display,
132 .init_display = hd44780_common_init_display,
133 .shift_cursor = hd44780_common_shift_cursor,
134 .shift_display = hd44780_common_shift_display,
135 .display = hd44780_common_display,
136 .cursor = hd44780_common_cursor,
137 .blink = hd44780_common_blink,
138 .fontsize = hd44780_common_fontsize,
139 .lines = hd44780_common_lines,
140 .redefine_char = hd44780_common_redefine_char,
141};
142
143/* Send a command to the LCD panel in 4 bit GPIO mode */
144static void hd44780_write_cmd_gpio4(struct hd44780_common *hdc, int cmd)
145{
146 struct hd44780 *hd = hdc->hd44780;
147
148 hd44780_write_gpio4(hd, cmd, 0);
149
150 /* The shortest command takes at least 120 us */
151 udelay(120);
152}
153
154/* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
155static void hd44780_write_cmd_raw_gpio4(struct hd44780_common *hdc, int cmd)
156{
157 DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
158 struct hd44780 *hd = hdc->hd44780;
159 unsigned int n;
160
161 /* Command nibble + RS, RW */
162 values[0] = cmd & 0x0f;
163 n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
164
165 /* Present the data to the port */
166 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
167
168 hd44780_strobe_gpio(hd);
169}
170
171/* Send data to the LCD panel in 4 bit GPIO mode */
172static void hd44780_write_data_gpio4(struct hd44780_common *hdc, int data)
173{
174 struct hd44780 *hd = hdc->hd44780;
175
176 hd44780_write_gpio4(hd, data, 1);
177
178 /* The shortest data takes at least 45 us */
179 udelay(45);
180}
181
182static const struct charlcd_ops hd44780_ops_gpio4 = {
183 .backlight = hd44780_backlight,
184 .print = hd44780_common_print,
185 .gotoxy = hd44780_common_gotoxy,
186 .home = hd44780_common_home,
187 .clear_display = hd44780_common_clear_display,
188 .init_display = hd44780_common_init_display,
189 .shift_cursor = hd44780_common_shift_cursor,
190 .shift_display = hd44780_common_shift_display,
191 .display = hd44780_common_display,
192 .cursor = hd44780_common_cursor,
193 .blink = hd44780_common_blink,
194 .fontsize = hd44780_common_fontsize,
195 .lines = hd44780_common_lines,
196 .redefine_char = hd44780_common_redefine_char,
197};
198
199static int hd44780_probe(struct platform_device *pdev)
200{
201 struct device *dev = &pdev->dev;
202 unsigned int i, base;
203 struct charlcd *lcd;
204 struct hd44780_common *hdc;
205 struct hd44780 *hd;
206 int ifwidth, ret = -ENOMEM;
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 = hd44780_common_alloc();
225 if (!lcd)
226 return -ENOMEM;
227
228 hd = kzalloc_obj(*hd);
229 if (!hd)
230 goto fail2;
231
232 hdc = lcd->drvdata;
233 hdc->hd44780 = hd;
234
235 for (i = 0; i < ifwidth; i++) {
236 hd->pins[base + i] = devm_gpiod_get_index(dev, "data", i,
237 GPIOD_OUT_LOW);
238 if (IS_ERR(hd->pins[base + i])) {
239 ret = PTR_ERR(hd->pins[base + i]);
240 goto fail3;
241 }
242 }
243
244 hd->pins[PIN_CTRL_E] = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
245 if (IS_ERR(hd->pins[PIN_CTRL_E])) {
246 ret = PTR_ERR(hd->pins[PIN_CTRL_E]);
247 goto fail3;
248 }
249
250 hd->pins[PIN_CTRL_RS] = devm_gpiod_get(dev, "rs", GPIOD_OUT_HIGH);
251 if (IS_ERR(hd->pins[PIN_CTRL_RS])) {
252 ret = PTR_ERR(hd->pins[PIN_CTRL_RS]);
253 goto fail3;
254 }
255
256 /* Optional pins */
257 hd->pins[PIN_CTRL_RW] = devm_gpiod_get_optional(dev, "rw",
258 GPIOD_OUT_LOW);
259 if (IS_ERR(hd->pins[PIN_CTRL_RW])) {
260 ret = PTR_ERR(hd->pins[PIN_CTRL_RW]);
261 goto fail3;
262 }
263
264 hd->pins[PIN_CTRL_BL] = devm_gpiod_get_optional(dev, "backlight",
265 GPIOD_OUT_LOW);
266 if (IS_ERR(hd->pins[PIN_CTRL_BL])) {
267 ret = PTR_ERR(hd->pins[PIN_CTRL_BL]);
268 goto fail3;
269 }
270
271 /* Required properties */
272 ret = device_property_read_u32(dev, "display-height-chars",
273 &lcd->height);
274 if (ret)
275 goto fail3;
276 ret = device_property_read_u32(dev, "display-width-chars", &lcd->width);
277 if (ret)
278 goto fail3;
279
280 /*
281 * On displays with more than two rows, the internal buffer width is
282 * usually equal to the display width
283 */
284 if (lcd->height > 2)
285 hdc->bwidth = lcd->width;
286
287 /* Optional properties */
288 device_property_read_u32(dev, "internal-buffer-width", &hdc->bwidth);
289
290 hdc->ifwidth = ifwidth;
291 if (ifwidth == 8) {
292 lcd->ops = &hd44780_ops_gpio8;
293 hdc->write_data = hd44780_write_data_gpio8;
294 hdc->write_cmd = hd44780_write_cmd_gpio8;
295 } else {
296 lcd->ops = &hd44780_ops_gpio4;
297 hdc->write_data = hd44780_write_data_gpio4;
298 hdc->write_cmd = hd44780_write_cmd_gpio4;
299 hdc->write_cmd_raw4 = hd44780_write_cmd_raw_gpio4;
300 }
301
302 ret = charlcd_register(lcd);
303 if (ret)
304 goto fail3;
305
306 platform_set_drvdata(pdev, lcd);
307 return 0;
308
309fail3:
310 kfree(hd);
311fail2:
312 hd44780_common_free(lcd);
313 return ret;
314}
315
316static void hd44780_remove(struct platform_device *pdev)
317{
318 struct charlcd *lcd = platform_get_drvdata(pdev);
319 struct hd44780_common *hdc = lcd->drvdata;
320
321 charlcd_unregister(lcd);
322 kfree(hdc->hd44780);
323 hd44780_common_free(lcd);
324}
325
326static const struct of_device_id hd44780_of_match[] = {
327 { .compatible = "hit,hd44780" },
328 { /* sentinel */ }
329};
330MODULE_DEVICE_TABLE(of, hd44780_of_match);
331
332static struct platform_driver hd44780_driver = {
333 .probe = hd44780_probe,
334 .remove = hd44780_remove,
335 .driver = {
336 .name = "hd44780",
337 .of_match_table = hd44780_of_match,
338 },
339};
340
341module_platform_driver(hd44780_driver);
342MODULE_DESCRIPTION("HD44780 Character LCD driver");
343MODULE_AUTHOR("Geert Uytterhoeven <[email protected]>");
344MODULE_LICENSE("GPL");