brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · 025dc68 Raw
353 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * HD44780 Character LCD driver for Linux4 *5 * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>6 * Copyright (C) 2016-2017 Glider bvba7 */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 20enum 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_NUM35};36 37struct hd44780 {38	struct gpio_desc *pins[PIN_NUM];39};40 41static 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 50static 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 */64static 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 */80static 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 */106static 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 */117static 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 127static 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 */145static 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 */156static 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 */173static 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 183static 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 200static 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(*hd), 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 is286	 * usually equal to the display width287	 */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 313fail3:314	kfree(hd);315fail2:316	kfree(lcd);317fail1:318	kfree(hdc);319	return ret;320}321 322static void 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}333 334static const struct of_device_id hd44780_of_match[] = {335	{ .compatible = "hit,hd44780" },336	{ /* sentinel */ }337};338MODULE_DEVICE_TABLE(of, hd44780_of_match);339 340static struct platform_driver hd44780_driver = {341	.probe = hd44780_probe,342	.remove_new = hd44780_remove,343	.driver		= {344		.name	= "hd44780",345		.of_match_table = hd44780_of_match,346	},347};348 349module_platform_driver(hd44780_driver);350MODULE_DESCRIPTION("HD44780 Character LCD driver");351MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");352MODULE_LICENSE("GPL");353