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 DECLARE_BITMAP(values
, 10); /* for DATA[0-7], RS, RW */
69 __assign_bit(8, values
, rs
);
70 n
= hd
->pins
[PIN_CTRL_RW
] ? 10 : 9;
72 /* Present the data to the port */
73 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA0
], NULL
, values
);
75 hd44780_strobe_gpio(hd
);
78 /* write to an LCD panel register in 4 bit GPIO mode */
79 static void hd44780_write_gpio4(struct hd44780
*hd
, u8 val
, unsigned int rs
)
81 DECLARE_BITMAP(values
, 6); /* for DATA[4-7], RS, RW */
84 /* High nibble + RS, RW */
86 __assign_bit(4, values
, rs
);
87 n
= hd
->pins
[PIN_CTRL_RW
] ? 6 : 5;
89 /* Present the data to the port */
90 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA4
], NULL
, values
);
92 hd44780_strobe_gpio(hd
);
96 values
[0] |= val
& 0x0f;
98 /* Present the data to the port */
99 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA4
], NULL
, values
);
101 hd44780_strobe_gpio(hd
);
104 /* Send a command to the LCD panel in 8 bit GPIO mode */
105 static void hd44780_write_cmd_gpio8(struct charlcd
*lcd
, int cmd
)
107 struct hd44780
*hd
= lcd
->drvdata
;
109 hd44780_write_gpio8(hd
, cmd
, 0);
111 /* The shortest command takes at least 120 us */
115 /* Send data to the LCD panel in 8 bit GPIO mode */
116 static void hd44780_write_data_gpio8(struct charlcd
*lcd
, int data
)
118 struct hd44780
*hd
= lcd
->drvdata
;
120 hd44780_write_gpio8(hd
, data
, 1);
122 /* The shortest data takes at least 45 us */
126 static const struct charlcd_ops hd44780_ops_gpio8
= {
127 .write_cmd
= hd44780_write_cmd_gpio8
,
128 .write_data
= hd44780_write_data_gpio8
,
129 .backlight
= hd44780_backlight
,
132 /* Send a command to the LCD panel in 4 bit GPIO mode */
133 static void hd44780_write_cmd_gpio4(struct charlcd
*lcd
, int cmd
)
135 struct hd44780
*hd
= lcd
->drvdata
;
137 hd44780_write_gpio4(hd
, cmd
, 0);
139 /* The shortest command takes at least 120 us */
143 /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
144 static void hd44780_write_cmd_raw_gpio4(struct charlcd
*lcd
, int cmd
)
146 DECLARE_BITMAP(values
, 6); /* for DATA[4-7], RS, RW */
147 struct hd44780
*hd
= lcd
->drvdata
;
150 /* Command nibble + RS, RW */
151 values
[0] = cmd
& 0x0f;
152 n
= hd
->pins
[PIN_CTRL_RW
] ? 6 : 5;
154 /* Present the data to the port */
155 gpiod_set_array_value_cansleep(n
, &hd
->pins
[PIN_DATA4
], NULL
, values
);
157 hd44780_strobe_gpio(hd
);
160 /* Send data to the LCD panel in 4 bit GPIO mode */
161 static void hd44780_write_data_gpio4(struct charlcd
*lcd
, int data
)
163 struct hd44780
*hd
= lcd
->drvdata
;
165 hd44780_write_gpio4(hd
, data
, 1);
167 /* The shortest data takes at least 45 us */
171 static const struct charlcd_ops hd44780_ops_gpio4
= {
172 .write_cmd
= hd44780_write_cmd_gpio4
,
173 .write_cmd_raw4
= hd44780_write_cmd_raw_gpio4
,
174 .write_data
= hd44780_write_data_gpio4
,
175 .backlight
= hd44780_backlight
,
178 static int hd44780_probe(struct platform_device
*pdev
)
180 struct device
*dev
= &pdev
->dev
;
181 unsigned int i
, base
;
187 ifwidth
= gpiod_count(dev
, "data");
202 lcd
= charlcd_alloc(sizeof(struct hd44780
));
208 for (i
= 0; i
< ifwidth
; i
++) {
209 hd
->pins
[base
+ i
] = devm_gpiod_get_index(dev
, "data", i
,
211 if (IS_ERR(hd
->pins
[base
+ i
])) {
212 ret
= PTR_ERR(hd
->pins
[base
+ i
]);
217 hd
->pins
[PIN_CTRL_E
] = devm_gpiod_get(dev
, "enable", GPIOD_OUT_LOW
);
218 if (IS_ERR(hd
->pins
[PIN_CTRL_E
])) {
219 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_E
]);
223 hd
->pins
[PIN_CTRL_RS
] = devm_gpiod_get(dev
, "rs", GPIOD_OUT_HIGH
);
224 if (IS_ERR(hd
->pins
[PIN_CTRL_RS
])) {
225 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_RS
]);
230 hd
->pins
[PIN_CTRL_RW
] = devm_gpiod_get_optional(dev
, "rw",
232 if (IS_ERR(hd
->pins
[PIN_CTRL_RW
])) {
233 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_RW
]);
237 hd
->pins
[PIN_CTRL_BL
] = devm_gpiod_get_optional(dev
, "backlight",
239 if (IS_ERR(hd
->pins
[PIN_CTRL_BL
])) {
240 ret
= PTR_ERR(hd
->pins
[PIN_CTRL_BL
]);
244 /* Required properties */
245 ret
= device_property_read_u32(dev
, "display-height-chars",
249 ret
= device_property_read_u32(dev
, "display-width-chars", &lcd
->width
);
254 * On displays with more than two rows, the internal buffer width is
255 * usually equal to the display width
258 lcd
->bwidth
= lcd
->width
;
260 /* Optional properties */
261 device_property_read_u32(dev
, "internal-buffer-width", &lcd
->bwidth
);
263 lcd
->ifwidth
= ifwidth
;
264 lcd
->ops
= ifwidth
== 8 ? &hd44780_ops_gpio8
: &hd44780_ops_gpio4
;
266 ret
= charlcd_register(lcd
);
270 platform_set_drvdata(pdev
, lcd
);
278 static int hd44780_remove(struct platform_device
*pdev
)
280 struct charlcd
*lcd
= platform_get_drvdata(pdev
);
282 charlcd_unregister(lcd
);
288 static const struct of_device_id hd44780_of_match
[] = {
289 { .compatible
= "hit,hd44780" },
292 MODULE_DEVICE_TABLE(of
, hd44780_of_match
);
294 static struct platform_driver hd44780_driver
= {
295 .probe
= hd44780_probe
,
296 .remove
= hd44780_remove
,
299 .of_match_table
= hd44780_of_match
,
303 module_platform_driver(hd44780_driver
);
304 MODULE_DESCRIPTION("HD44780 Character LCD driver");
305 MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
306 MODULE_LICENSE("GPL");