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>
17 #include <misc/charlcd.h>
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 */
31 PIN_CTRL_RW
, /* Optional */
33 PIN_CTRL_BL
, /* Optional */
38 struct gpio_desc
*pins
[PIN_NUM
];
41 static void hd44780_backlight(struct charlcd
*lcd
, int on
)
43 struct hd44780
*hd
= lcd
->drvdata
;
45 if (hd
->pins
[PIN_CTRL_BL
])
46 gpiod_set_value_cansleep(hd
->pins
[PIN_CTRL_BL
], on
);
49 static void hd44780_strobe_gpio(struct hd44780
*hd
)
51 /* Maintain the data during 20 us before the strobe */
54 gpiod_set_value_cansleep(hd
->pins
[PIN_CTRL_E
], 1);
56 /* Maintain the strobe during 40 us */
59 gpiod_set_value_cansleep(hd
->pins
[PIN_CTRL_E
], 0);
62 /* write to an LCD panel register in 8 bit GPIO mode */
63 static void hd44780_write_gpio8(struct hd44780
*hd
, u8 val
, unsigned int rs
)
65 int values
[10]; /* for DATA[0-7], RS, RW */
68 for (i
= 0; i
< 8; i
++)
69 values
[PIN_DATA0
+ i
] = !!(val
& BIT(i
));
70 values
[PIN_CTRL_RS
] = rs
;
72 if (hd
->pins
[PIN_CTRL_RW
]) {
73 values
[PIN_CTRL_RW
] = 0;
77 /* Present the data to the port */
78 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA0
], values
);
80 hd44780_strobe_gpio(hd
);
83 /* write to an LCD panel register in 4 bit GPIO mode */
84 static void hd44780_write_gpio4(struct hd44780
*hd
, u8 val
, unsigned int rs
)
86 int values
[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
89 /* High nibble + RS, RW */
90 for (i
= 4; i
< 8; i
++)
91 values
[PIN_DATA0
+ i
] = !!(val
& BIT(i
));
92 values
[PIN_CTRL_RS
] = rs
;
94 if (hd
->pins
[PIN_CTRL_RW
]) {
95 values
[PIN_CTRL_RW
] = 0;
99 /* Present the data to the port */
100 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA4
],
103 hd44780_strobe_gpio(hd
);
106 for (i
= 0; i
< 4; i
++)
107 values
[PIN_DATA4
+ i
] = !!(val
& BIT(i
));
109 /* Present the data to the port */
110 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA4
],
113 hd44780_strobe_gpio(hd
);
116 /* Send a command to the LCD panel in 8 bit GPIO mode */
117 static void hd44780_write_cmd_gpio8(struct charlcd
*lcd
, int cmd
)
119 struct hd44780
*hd
= lcd
->drvdata
;
121 hd44780_write_gpio8(hd
, cmd
, 0);
123 /* The shortest command takes at least 120 us */
127 /* Send data to the LCD panel in 8 bit GPIO mode */
128 static void hd44780_write_data_gpio8(struct charlcd
*lcd
, int data
)
130 struct hd44780
*hd
= lcd
->drvdata
;
132 hd44780_write_gpio8(hd
, data
, 1);
134 /* The shortest data takes at least 45 us */
138 static const struct charlcd_ops hd44780_ops_gpio8
= {
139 .write_cmd
= hd44780_write_cmd_gpio8
,
140 .write_data
= hd44780_write_data_gpio8
,
141 .backlight
= hd44780_backlight
,
144 /* Send a command to the LCD panel in 4 bit GPIO mode */
145 static void hd44780_write_cmd_gpio4(struct charlcd
*lcd
, int cmd
)
147 struct hd44780
*hd
= lcd
->drvdata
;
149 hd44780_write_gpio4(hd
, cmd
, 0);
151 /* The shortest command takes at least 120 us */
155 /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
156 static void hd44780_write_cmd_raw_gpio4(struct charlcd
*lcd
, int cmd
)
158 int values
[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
159 struct hd44780
*hd
= lcd
->drvdata
;
162 /* Command nibble + RS, RW */
163 for (i
= 0; i
< 4; i
++)
164 values
[PIN_DATA4
+ i
] = !!(cmd
& BIT(i
));
165 values
[PIN_CTRL_RS
] = 0;
167 if (hd
->pins
[PIN_CTRL_RW
]) {
168 values
[PIN_CTRL_RW
] = 0;
172 /* Present the data to the port */
173 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA4
],
176 hd44780_strobe_gpio(hd
);
179 /* Send data to the LCD panel in 4 bit GPIO mode */
180 static void hd44780_write_data_gpio4(struct charlcd
*lcd
, int data
)
182 struct hd44780
*hd
= lcd
->drvdata
;
184 hd44780_write_gpio4(hd
, data
, 1);
186 /* The shortest data takes at least 45 us */
190 static const struct charlcd_ops hd44780_ops_gpio4
= {
191 .write_cmd
= hd44780_write_cmd_gpio4
,
192 .write_cmd_raw4
= hd44780_write_cmd_raw_gpio4
,
193 .write_data
= hd44780_write_data_gpio4
,
194 .backlight
= hd44780_backlight
,
197 static int hd44780_probe(struct platform_device
*pdev
)
199 struct device
*dev
= &pdev
->dev
;
200 unsigned int i
, base
;
206 ifwidth
= gpiod_count(dev
, "data");
221 lcd
= charlcd_alloc(sizeof(struct hd44780
));
227 for (i
= 0; i
< ifwidth
; i
++) {
228 hd
->pins
[base
+ i
] = devm_gpiod_get_index(dev
, "data", i
,
230 if (IS_ERR(hd
->pins
[base
+ i
])) {
231 ret
= PTR_ERR(hd
->pins
[base
+ i
]);
236 hd
->pins
[PIN_CTRL_E
] = devm_gpiod_get(dev
, "enable", GPIOD_OUT_LOW
);
237 if (IS_ERR(hd
->pins
[PIN_CTRL_E
])) {
238 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_E
]);
242 hd
->pins
[PIN_CTRL_RS
] = devm_gpiod_get(dev
, "rs", GPIOD_OUT_HIGH
);
243 if (IS_ERR(hd
->pins
[PIN_CTRL_RS
])) {
244 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_RS
]);
249 hd
->pins
[PIN_CTRL_RW
] = devm_gpiod_get_optional(dev
, "rw",
251 if (IS_ERR(hd
->pins
[PIN_CTRL_RW
])) {
252 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_RW
]);
256 hd
->pins
[PIN_CTRL_BL
] = devm_gpiod_get_optional(dev
, "backlight",
258 if (IS_ERR(hd
->pins
[PIN_CTRL_BL
])) {
259 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_BL
]);
263 /* Required properties */
264 ret
= device_property_read_u32(dev
, "display-height-chars",
268 ret
= device_property_read_u32(dev
, "display-width-chars", &lcd
->width
);
273 * On displays with more than two rows, the internal buffer width is
274 * usually equal to the display width
277 lcd
->bwidth
= lcd
->width
;
279 /* Optional properties */
280 device_property_read_u32(dev
, "internal-buffer-width", &lcd
->bwidth
);
282 lcd
->ifwidth
= ifwidth
;
283 lcd
->ops
= ifwidth
== 8 ? &hd44780_ops_gpio8
: &hd44780_ops_gpio4
;
285 ret
= charlcd_register(lcd
);
289 platform_set_drvdata(pdev
, lcd
);
297 static int hd44780_remove(struct platform_device
*pdev
)
299 struct charlcd
*lcd
= platform_get_drvdata(pdev
);
301 charlcd_unregister(lcd
);
307 static const struct of_device_id hd44780_of_match
[] = {
308 { .compatible
= "hit,hd44780" },
311 MODULE_DEVICE_TABLE(of
, hd44780_of_match
);
313 static struct platform_driver hd44780_driver
= {
314 .probe
= hd44780_probe
,
315 .remove
= hd44780_remove
,
318 .of_match_table
= hd44780_of_match
,
322 module_platform_driver(hd44780_driver
);
323 MODULE_DESCRIPTION("HD44780 Character LCD driver");
324 MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
325 MODULE_LICENSE("GPL");