if AUXDISPLAY
+config CHARLCD
+ tristate "Character LCD core support" if COMPILE_TEST
+ help
+ This is the base system for character-based LCD displays.
+ It makes no sense to have this alone, you select your display driver
+ and if it needs the charlcd core, it will select it automatically.
+ This is some character LCD core interface that multiple drivers can
+ use.
+
+config HD44780_COMMON
+ tristate "Common functions for HD44780 (and compatibles) LCD displays" if COMPILE_TEST
+ help
+ This is a module with the common symbols for HD44780 (and compatibles)
+ displays. This is the code that multiple other modules use. It is not
+ useful alone. If you have some sort of HD44780 compatible display,
+ you very likely use this. It is selected automatically by selecting
+ your concrete display.
+
config HD44780
tristate "HD44780 Character LCD support"
depends on GPIOLIB || COMPILE_TEST
select CHARLCD
+ select HD44780_COMMON
help
Enable support for Character LCDs using a HD44780 controller.
The LCD is accessible through the /dev/lcd char device (10, 156).
tristate "Parallel port LCD/Keypad Panel support"
depends on PARPORT
select CHARLCD
+ select HD44780_COMMON
help
Say Y here if you have an HD44780 or KS-0074 LCD connected to your
parallel port. This driver also features 4 and 6-key keypads. The LCD
#
obj-$(CONFIG_CHARLCD) += charlcd.o
+obj-$(CONFIG_HD44780_COMMON) += hd44780_common.o
obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
obj-$(CONFIG_KS0108) += ks0108.o
obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o
#include <linux/slab.h>
#include "charlcd.h"
+#include "hd44780_common.h"
enum hd44780_pin {
/* Order does matter due to writing to GPIO array subsets! */
struct device *dev = &pdev->dev;
unsigned int i, base;
struct charlcd *lcd;
+ struct hd44780_common *hdc;
struct hd44780 *hd;
- int ifwidth, ret;
+ int ifwidth, ret = -ENOMEM;
/* Required pins */
ifwidth = gpiod_count(dev, "data");
return -EINVAL;
}
+ hdc = hd44780_common_alloc();
+ if (!hdc)
+ return -ENOMEM;
+
lcd = charlcd_alloc(sizeof(struct hd44780));
if (!lcd)
- return -ENOMEM;
+ goto fail1;
- hd = lcd->drvdata;
+ hd = kzalloc(sizeof(struct hd44780), GFP_KERNEL);
+ if (!hd)
+ goto fail2;
+ hdc->hd44780 = hd;
+ lcd->drvdata = hdc;
for (i = 0; i < ifwidth; i++) {
hd->pins[base + i] = devm_gpiod_get_index(dev, "data", i,
GPIOD_OUT_LOW);
if (IS_ERR(hd->pins[base + i])) {
ret = PTR_ERR(hd->pins[base + i]);
- goto fail;
+ goto fail3;
}
}
hd->pins[PIN_CTRL_E] = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(hd->pins[PIN_CTRL_E])) {
ret = PTR_ERR(hd->pins[PIN_CTRL_E]);
- goto fail;
+ goto fail3;
}
hd->pins[PIN_CTRL_RS] = devm_gpiod_get(dev, "rs", GPIOD_OUT_HIGH);
if (IS_ERR(hd->pins[PIN_CTRL_RS])) {
ret = PTR_ERR(hd->pins[PIN_CTRL_RS]);
- goto fail;
+ goto fail3;
}
/* Optional pins */
GPIOD_OUT_LOW);
if (IS_ERR(hd->pins[PIN_CTRL_RW])) {
ret = PTR_ERR(hd->pins[PIN_CTRL_RW]);
- goto fail;
+ goto fail3;
}
hd->pins[PIN_CTRL_BL] = devm_gpiod_get_optional(dev, "backlight",
GPIOD_OUT_LOW);
if (IS_ERR(hd->pins[PIN_CTRL_BL])) {
ret = PTR_ERR(hd->pins[PIN_CTRL_BL]);
- goto fail;
+ goto fail3;
}
/* Required properties */
ret = device_property_read_u32(dev, "display-height-chars",
&lcd->height);
if (ret)
- goto fail;
+ goto fail3;
ret = device_property_read_u32(dev, "display-width-chars", &lcd->width);
if (ret)
- goto fail;
+ goto fail3;
/*
* On displays with more than two rows, the internal buffer width is
ret = charlcd_register(lcd);
if (ret)
- goto fail;
+ goto fail3;
platform_set_drvdata(pdev, lcd);
return 0;
-fail:
- charlcd_free(lcd);
+fail3:
+ kfree(hd);
+fail2:
+ kfree(lcd);
+fail1:
+ kfree(hdc);
return ret;
}
{
struct charlcd *lcd = platform_get_drvdata(pdev);
+ kfree(lcd->drvdata);
charlcd_unregister(lcd);
- charlcd_free(lcd);
+ kfree(lcd);
return 0;
}
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "hd44780_common.h"
+
+struct hd44780_common *hd44780_common_alloc(void)
+{
+ struct hd44780_common *hd;
+
+ hd = kzalloc(sizeof(*hd), GFP_KERNEL);
+ if (!hd)
+ return NULL;
+
+ return hd;
+}
+EXPORT_SYMBOL_GPL(hd44780_common_alloc);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+struct hd44780_common {
+ void *hd44780;
+};
+
+struct hd44780_common *hd44780_common_alloc(void);
#include <linux/uaccess.h>
#include "charlcd.h"
+#include "hd44780_common.h"
#define LCD_MAXBYTES 256 /* max burst write */
static void lcd_init(void)
{
struct charlcd *charlcd;
+ struct hd44780_common *hdc;
+
+ hdc = hd44780_common_alloc();
+ if (!hdc)
+ return;
charlcd = charlcd_alloc(0);
- if (!charlcd)
+ if (!charlcd) {
+ kfree(hdc);
return;
+ }
+
+ hdc->hd44780 = &lcd;
+ charlcd->drvdata = hdc;
/*
* Init lcd struct with load-time values to preserve exact
if (lcd.enabled)
charlcd_unregister(lcd.charlcd);
err_unreg_device:
- charlcd_free(lcd.charlcd);
+ kfree(lcd.charlcd);
lcd.charlcd = NULL;
parport_unregister_device(pprt);
pprt = NULL;
if (lcd.enabled) {
charlcd_unregister(lcd.charlcd);
lcd.initialized = false;
- charlcd_free(lcd.charlcd);
+ kfree(lcd.charlcd->drvdata);
+ kfree(lcd.charlcd);
lcd.charlcd = NULL;
}