linux/drivers/auxdisplay/hd44780.c
<<
>>
Prefs
   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 <misc/charlcd.h>
  18
  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, int on)
  42{
  43        struct hd44780 *hd = lcd->drvdata;
  44
  45        if (hd->pins[PIN_CTRL_BL])
  46                gpiod_set_value_cansleep(hd->pins[PIN_CTRL_BL], on);
  47}
  48
  49static void hd44780_strobe_gpio(struct hd44780 *hd)
  50{
  51        /* Maintain the data during 20 us before the strobe */
  52        udelay(20);
  53
  54        gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 1);
  55
  56        /* Maintain the strobe during 40 us */
  57        udelay(40);
  58
  59        gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 0);
  60}
  61
  62/* write to an LCD panel register in 8 bit GPIO mode */
  63static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
  64{
  65        DECLARE_BITMAP(values, 10); /* for DATA[0-7], RS, RW */
  66        unsigned int n;
  67
  68        values[0] = val;
  69        __assign_bit(8, values, rs);
  70        n = hd->pins[PIN_CTRL_RW] ? 10 : 9;
  71
  72        /* Present the data to the port */
  73        gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], NULL, values);
  74
  75        hd44780_strobe_gpio(hd);
  76}
  77
  78/* write to an LCD panel register in 4 bit GPIO mode */
  79static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs)
  80{
  81        DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
  82        unsigned int n;
  83
  84        /* High nibble + RS, RW */
  85        values[0] = val >> 4;
  86        __assign_bit(4, values, rs);
  87        n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
  88
  89        /* Present the data to the port */
  90        gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
  91
  92        hd44780_strobe_gpio(hd);
  93
  94        /* Low nibble */
  95        values[0] &= ~0x0fUL;
  96        values[0] |= val & 0x0f;
  97
  98        /* Present the data to the port */
  99        gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
 100
 101        hd44780_strobe_gpio(hd);
 102}
 103
 104/* Send a command to the LCD panel in 8 bit GPIO mode */
 105static void hd44780_write_cmd_gpio8(struct charlcd *lcd, int cmd)
 106{
 107        struct hd44780 *hd = lcd->drvdata;
 108
 109        hd44780_write_gpio8(hd, cmd, 0);
 110
 111        /* The shortest command takes at least 120 us */
 112        udelay(120);
 113}
 114
 115/* Send data to the LCD panel in 8 bit GPIO mode */
 116static void hd44780_write_data_gpio8(struct charlcd *lcd, int data)
 117{
 118        struct hd44780 *hd = lcd->drvdata;
 119
 120        hd44780_write_gpio8(hd, data, 1);
 121
 122        /* The shortest data takes at least 45 us */
 123        udelay(45);
 124}
 125
 126static const struct charlcd_ops hd44780_ops_gpio8 = {
 127        .write_cmd      = hd44780_write_cmd_gpio8,
 128        .write_data     = hd44780_write_data_gpio8,
 129        .backlight      = hd44780_backlight,
 130};
 131
 132/* Send a command to the LCD panel in 4 bit GPIO mode */
 133static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd)
 134{
 135        struct hd44780 *hd = lcd->drvdata;
 136
 137        hd44780_write_gpio4(hd, cmd, 0);
 138
 139        /* The shortest command takes at least 120 us */
 140        udelay(120);
 141}
 142
 143/* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
 144static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd)
 145{
 146        DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
 147        struct hd44780 *hd = lcd->drvdata;
 148        unsigned int n;
 149
 150        /* Command nibble + RS, RW */
 151        values[0] = cmd & 0x0f;
 152        n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
 153
 154        /* Present the data to the port */
 155        gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
 156
 157        hd44780_strobe_gpio(hd);
 158}
 159
 160/* Send data to the LCD panel in 4 bit GPIO mode */
 161static void hd44780_write_data_gpio4(struct charlcd *lcd, int data)
 162{
 163        struct hd44780 *hd = lcd->drvdata;
 164
 165        hd44780_write_gpio4(hd, data, 1);
 166
 167        /* The shortest data takes at least 45 us */
 168        udelay(45);
 169}
 170
 171static const struct charlcd_ops hd44780_ops_gpio4 = {
 172        .write_cmd      = hd44780_write_cmd_gpio4,
 173        .write_cmd_raw4 = hd44780_write_cmd_raw_gpio4,
 174        .write_data     = hd44780_write_data_gpio4,
 175        .backlight      = hd44780_backlight,
 176};
 177
 178static int hd44780_probe(struct platform_device *pdev)
 179{
 180        struct device *dev = &pdev->dev;
 181        unsigned int i, base;
 182        struct charlcd *lcd;
 183        struct hd44780 *hd;
 184        int ifwidth, ret;
 185
 186        /* Required pins */
 187        ifwidth = gpiod_count(dev, "data");
 188        if (ifwidth < 0)
 189                return ifwidth;
 190
 191        switch (ifwidth) {
 192        case 4:
 193                base = PIN_DATA4;
 194                break;
 195        case 8:
 196                base = PIN_DATA0;
 197                break;
 198        default:
 199                return -EINVAL;
 200        }
 201
 202        lcd = charlcd_alloc(sizeof(struct hd44780));
 203        if (!lcd)
 204                return -ENOMEM;
 205
 206        hd = lcd->drvdata;
 207
 208        for (i = 0; i < ifwidth; i++) {
 209                hd->pins[base + i] = devm_gpiod_get_index(dev, "data", i,
 210                                                          GPIOD_OUT_LOW);
 211                if (IS_ERR(hd->pins[base + i])) {
 212                        ret = PTR_ERR(hd->pins[base + i]);
 213                        goto fail;
 214                }
 215        }
 216
 217        hd->pins[PIN_CTRL_E] = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
 218        if (IS_ERR(hd->pins[PIN_CTRL_E])) {
 219                ret = PTR_ERR(hd->pins[PIN_CTRL_E]);
 220                goto fail;
 221        }
 222
 223        hd->pins[PIN_CTRL_RS] = devm_gpiod_get(dev, "rs", GPIOD_OUT_HIGH);
 224        if (IS_ERR(hd->pins[PIN_CTRL_RS])) {
 225                ret = PTR_ERR(hd->pins[PIN_CTRL_RS]);
 226                goto fail;
 227        }
 228
 229        /* Optional pins */
 230        hd->pins[PIN_CTRL_RW] = devm_gpiod_get_optional(dev, "rw",
 231                                                        GPIOD_OUT_LOW);
 232        if (IS_ERR(hd->pins[PIN_CTRL_RW])) {
 233                ret = PTR_ERR(hd->pins[PIN_CTRL_RW]);
 234                goto fail;
 235        }
 236
 237        hd->pins[PIN_CTRL_BL] = devm_gpiod_get_optional(dev, "backlight",
 238                                                        GPIOD_OUT_LOW);
 239        if (IS_ERR(hd->pins[PIN_CTRL_BL])) {
 240                ret = PTR_ERR(hd->pins[PIN_CTRL_BL]);
 241                goto fail;
 242        }
 243
 244        /* Required properties */
 245        ret = device_property_read_u32(dev, "display-height-chars",
 246                                       &lcd->height);
 247        if (ret)
 248                goto fail;
 249        ret = device_property_read_u32(dev, "display-width-chars", &lcd->width);
 250        if (ret)
 251                goto fail;
 252
 253        /*
 254         * On displays with more than two rows, the internal buffer width is
 255         * usually equal to the display width
 256         */
 257        if (lcd->height > 2)
 258                lcd->bwidth = lcd->width;
 259
 260        /* Optional properties */
 261        device_property_read_u32(dev, "internal-buffer-width", &lcd->bwidth);
 262
 263        lcd->ifwidth = ifwidth;
 264        lcd->ops = ifwidth == 8 ? &hd44780_ops_gpio8 : &hd44780_ops_gpio4;
 265
 266        ret = charlcd_register(lcd);
 267        if (ret)
 268                goto fail;
 269
 270        platform_set_drvdata(pdev, lcd);
 271        return 0;
 272
 273fail:
 274        kfree(lcd);
 275        return ret;
 276}
 277
 278static int hd44780_remove(struct platform_device *pdev)
 279{
 280        struct charlcd *lcd = platform_get_drvdata(pdev);
 281
 282        charlcd_unregister(lcd);
 283        return 0;
 284}
 285
 286static const struct of_device_id hd44780_of_match[] = {
 287        { .compatible = "hit,hd44780" },
 288        { /* sentinel */ }
 289};
 290MODULE_DEVICE_TABLE(of, hd44780_of_match);
 291
 292static struct platform_driver hd44780_driver = {
 293        .probe = hd44780_probe,
 294        .remove = hd44780_remove,
 295        .driver         = {
 296                .name   = "hd44780",
 297                .of_match_table = hd44780_of_match,
 298        },
 299};
 300
 301module_platform_driver(hd44780_driver);
 302MODULE_DESCRIPTION("HD44780 Character LCD driver");
 303MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
 304MODULE_LICENSE("GPL");
 305