summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/auxdisplay/Kconfig20
-rw-r--r--drivers/auxdisplay/Makefile1
-rw-r--r--drivers/auxdisplay/hd44780.c43
-rw-r--r--drivers/auxdisplay/hd44780_common.c19
-rw-r--r--drivers/auxdisplay/hd44780_common.h7
-rw-r--r--drivers/auxdisplay/panel.c18
6 files changed, 91 insertions, 17 deletions
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index 81757eeded68..aaf2d66357a1 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -16,10 +16,29 @@ menuconfig AUXDISPLAY
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).
@@ -168,6 +187,7 @@ menuconfig PARPORT_PANEL
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
diff --git a/drivers/auxdisplay/Makefile b/drivers/auxdisplay/Makefile
index cf54b5efb07e..7e8a8c3eb3c3 100644
--- a/drivers/auxdisplay/Makefile
+++ b/drivers/auxdisplay/Makefile
@@ -4,6 +4,7 @@
#
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
diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c
index 5982158557bb..271dba9cd108 100644
--- a/drivers/auxdisplay/hd44780.c
+++ b/drivers/auxdisplay/hd44780.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include "charlcd.h"
+#include "hd44780_common.h"
enum hd44780_pin {
/* Order does matter due to writing to GPIO array subsets! */
@@ -179,8 +180,9 @@ static int hd44780_probe(struct platform_device *pdev)
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");
@@ -198,31 +200,39 @@ static int hd44780_probe(struct platform_device *pdev)
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 */
@@ -230,24 +240,24 @@ static int hd44780_probe(struct platform_device *pdev)
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
@@ -264,13 +274,17 @@ static int hd44780_probe(struct platform_device *pdev)
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;
}
@@ -278,9 +292,10 @@ static int hd44780_remove(struct platform_device *pdev)
{
struct charlcd *lcd = platform_get_drvdata(pdev);
+ kfree(lcd->drvdata);
charlcd_unregister(lcd);
- charlcd_free(lcd);
+ kfree(lcd);
return 0;
}
diff --git a/drivers/auxdisplay/hd44780_common.c b/drivers/auxdisplay/hd44780_common.c
new file mode 100644
index 000000000000..2fdea29d6a8f
--- /dev/null
+++ b/drivers/auxdisplay/hd44780_common.c
@@ -0,0 +1,19 @@
+// 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");
diff --git a/drivers/auxdisplay/hd44780_common.h b/drivers/auxdisplay/hd44780_common.h
new file mode 100644
index 000000000000..974868f7529c
--- /dev/null
+++ b/drivers/auxdisplay/hd44780_common.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+struct hd44780_common {
+ void *hd44780;
+};
+
+struct hd44780_common *hd44780_common_alloc(void);
diff --git a/drivers/auxdisplay/panel.c b/drivers/auxdisplay/panel.c
index de623ae219f1..c3a60e190a7a 100644
--- a/drivers/auxdisplay/panel.c
+++ b/drivers/auxdisplay/panel.c
@@ -56,6 +56,7 @@
#include <linux/uaccess.h>
#include "charlcd.h"
+#include "hd44780_common.h"
#define LCD_MAXBYTES 256 /* max burst write */
@@ -895,10 +896,20 @@ static const struct charlcd_ops charlcd_tilcd_ops = {
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
@@ -1620,7 +1631,7 @@ err_lcd_unreg:
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;
@@ -1647,7 +1658,8 @@ static void panel_detach(struct parport *port)
if (lcd.enabled) {
charlcd_unregister(lcd.charlcd);
lcd.initialized = false;
- charlcd_free(lcd.charlcd);
+ kfree(lcd.charlcd->drvdata);
+ kfree(lcd.charlcd);
lcd.charlcd = NULL;
}