cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hd44780.c (8563B)


      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
     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_NUM
     35};
     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(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
    313fail3:
    314	kfree(hd);
    315fail2:
    316	kfree(lcd);
    317fail1:
    318	kfree(hdc);
    319	return ret;
    320}
    321
    322static int hd44780_remove(struct platform_device *pdev)
    323{
    324	struct charlcd *lcd = platform_get_drvdata(pdev);
    325
    326	charlcd_unregister(lcd);
    327	kfree(lcd->drvdata);
    328
    329	kfree(lcd);
    330	return 0;
    331}
    332
    333static const struct of_device_id hd44780_of_match[] = {
    334	{ .compatible = "hit,hd44780" },
    335	{ /* sentinel */ }
    336};
    337MODULE_DEVICE_TABLE(of, hd44780_of_match);
    338
    339static struct platform_driver hd44780_driver = {
    340	.probe = hd44780_probe,
    341	.remove = hd44780_remove,
    342	.driver		= {
    343		.name	= "hd44780",
    344		.of_match_table = hd44780_of_match,
    345	},
    346};
    347
    348module_platform_driver(hd44780_driver);
    349MODULE_DESCRIPTION("HD44780 Character LCD driver");
    350MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
    351MODULE_LICENSE("GPL");