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