linux/drivers/auxdisplay/hd44780.c
<<
>>
Prefs
   1/*
   2 * HD44780 Character LCD driver for Linux
   3 *
   4 * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
   5 * Copyright (C) 2016-2017 Glider bvba
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License
   9 * as published by the Free Software Foundation; either version
  10 * 2 of the License, or (at your option) any later version.
  11 */
  12
  13#include <linux/delay.h>
  14#include <linux/gpio/consumer.h>
  15#include <linux/module.h>
  16#include <linux/platform_device.h>
  17#include <linux/property.h>
  18#include <linux/slab.h>
  19
  20#include <misc/charlcd.h>
  21
  22
  23enum hd44780_pin {
  24        /* Order does matter due to writing to GPIO array subsets! */
  25        PIN_DATA0,      /* Optional */
  26        PIN_DATA1,      /* Optional */
  27        PIN_DATA2,      /* Optional */
  28        PIN_DATA3,      /* Optional */
  29        PIN_DATA4,
  30        PIN_DATA5,
  31        PIN_DATA6,
  32        PIN_DATA7,
  33        PIN_CTRL_RS,
  34        PIN_CTRL_RW,    /* Optional */
  35        PIN_CTRL_E,
  36        PIN_CTRL_BL,   /* Optional */
  37        PIN_NUM
  38};
  39
  40struct hd44780 {
  41        struct gpio_desc *pins[PIN_NUM];
  42};
  43
  44static void hd44780_backlight(struct charlcd *lcd, int on)
  45{
  46        struct hd44780 *hd = lcd->drvdata;
  47
  48        if (hd->pins[PIN_CTRL_BL])
  49                gpiod_set_value_cansleep(hd->pins[PIN_CTRL_BL], on);
  50}
  51
  52static void hd44780_strobe_gpio(struct hd44780 *hd)
  53{
  54        /* Maintain the data during 20 us before the strobe */
  55        udelay(20);
  56
  57        gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 1);
  58
  59        /* Maintain the strobe during 40 us */
  60        udelay(40);
  61
  62        gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 0);
  63}
  64
  65/* write to an LCD panel register in 8 bit GPIO mode */
  66static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
  67{
  68        int values[10]; /* for DATA[0-7], RS, RW */
  69        unsigned int i, n;
  70
  71        for (i = 0; i < 8; i++)
  72                values[PIN_DATA0 + i] = !!(val & BIT(i));
  73        values[PIN_CTRL_RS] = rs;
  74        n = 9;
  75        if (hd->pins[PIN_CTRL_RW]) {
  76                values[PIN_CTRL_RW] = 0;
  77                n++;
  78        }
  79
  80        /* Present the data to the port */
  81        gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], values);
  82
  83        hd44780_strobe_gpio(hd);
  84}
  85
  86/* write to an LCD panel register in 4 bit GPIO mode */
  87static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs)
  88{
  89        int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
  90        unsigned int i, n;
  91
  92        /* High nibble + RS, RW */
  93        for (i = 4; i < 8; i++)
  94                values[PIN_DATA0 + i] = !!(val & BIT(i));
  95        values[PIN_CTRL_RS] = rs;
  96        n = 5;
  97        if (hd->pins[PIN_CTRL_RW]) {
  98                values[PIN_CTRL_RW] = 0;
  99                n++;
 100        }
 101
 102        /* Present the data to the port */
 103        gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
 104                                       &values[PIN_DATA4]);
 105
 106        hd44780_strobe_gpio(hd);
 107
 108        /* Low nibble */
 109        for (i = 0; i < 4; i++)
 110                values[PIN_DATA4 + i] = !!(val & BIT(i));
 111
 112        /* Present the data to the port */
 113        gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
 114                                       &values[PIN_DATA4]);
 115
 116        hd44780_strobe_gpio(hd);
 117}
 118
 119/* Send a command to the LCD panel in 8 bit GPIO mode */
 120static void hd44780_write_cmd_gpio8(struct charlcd *lcd, int cmd)
 121{
 122        struct hd44780 *hd = lcd->drvdata;
 123
 124        hd44780_write_gpio8(hd, cmd, 0);
 125
 126        /* The shortest command takes at least 120 us */
 127        udelay(120);
 128}
 129
 130/* Send data to the LCD panel in 8 bit GPIO mode */
 131static void hd44780_write_data_gpio8(struct charlcd *lcd, int data)
 132{
 133        struct hd44780 *hd = lcd->drvdata;
 134
 135        hd44780_write_gpio8(hd, data, 1);
 136
 137        /* The shortest data takes at least 45 us */
 138        udelay(45);
 139}
 140
 141static const struct charlcd_ops hd44780_ops_gpio8 = {
 142        .write_cmd      = hd44780_write_cmd_gpio8,
 143        .write_data     = hd44780_write_data_gpio8,
 144        .backlight      = hd44780_backlight,
 145};
 146
 147/* Send a command to the LCD panel in 4 bit GPIO mode */
 148static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd)
 149{
 150        struct hd44780 *hd = lcd->drvdata;
 151
 152        hd44780_write_gpio4(hd, cmd, 0);
 153
 154        /* The shortest command takes at least 120 us */
 155        udelay(120);
 156}
 157
 158/* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
 159static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd)
 160{
 161        int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
 162        struct hd44780 *hd = lcd->drvdata;
 163        unsigned int i, n;
 164
 165        /* Command nibble + RS, RW */
 166        for (i = 0; i < 4; i++)
 167                values[PIN_DATA4 + i] = !!(cmd & BIT(i));
 168        values[PIN_CTRL_RS] = 0;
 169        n = 5;
 170        if (hd->pins[PIN_CTRL_RW]) {
 171                values[PIN_CTRL_RW] = 0;
 172                n++;
 173        }
 174
 175        /* Present the data to the port */
 176        gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
 177                                       &values[PIN_DATA4]);
 178
 179        hd44780_strobe_gpio(hd);
 180}
 181
 182/* Send data to the LCD panel in 4 bit GPIO mode */
 183static void hd44780_write_data_gpio4(struct charlcd *lcd, int data)
 184{
 185        struct hd44780 *hd = lcd->drvdata;
 186
 187        hd44780_write_gpio4(hd, data, 1);
 188
 189        /* The shortest data takes at least 45 us */
 190        udelay(45);
 191}
 192
 193static const struct charlcd_ops hd44780_ops_gpio4 = {
 194        .write_cmd      = hd44780_write_cmd_gpio4,
 195        .write_cmd_raw4 = hd44780_write_cmd_raw_gpio4,
 196        .write_data     = hd44780_write_data_gpio4,
 197        .backlight      = hd44780_backlight,
 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 *hd;
 206        int ifwidth, ret;
 207
 208        /* Required pins */
 209        ifwidth = gpiod_count(dev, "data");
 210        if (ifwidth < 0)
 211                return ifwidth;
 212
 213        switch (ifwidth) {
 214        case 4:
 215                base = PIN_DATA4;
 216                break;
 217        case 8:
 218                base = PIN_DATA0;
 219                break;
 220        default:
 221                return -EINVAL;
 222        }
 223
 224        lcd = charlcd_alloc(sizeof(struct hd44780));
 225        if (!lcd)
 226                return -ENOMEM;
 227
 228        hd = lcd->drvdata;
 229
 230        for (i = 0; i < ifwidth; i++) {
 231                hd->pins[base + i] = devm_gpiod_get_index(dev, "data", i,
 232                                                          GPIOD_OUT_LOW);
 233                if (IS_ERR(hd->pins[base + i])) {
 234                        ret = PTR_ERR(hd->pins[base + i]);
 235                        goto fail;
 236                }
 237        }
 238
 239        hd->pins[PIN_CTRL_E] = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
 240        if (IS_ERR(hd->pins[PIN_CTRL_E])) {
 241                ret = PTR_ERR(hd->pins[PIN_CTRL_E]);
 242                goto fail;
 243        }
 244
 245        hd->pins[PIN_CTRL_RS] = devm_gpiod_get(dev, "rs", GPIOD_OUT_HIGH);
 246        if (IS_ERR(hd->pins[PIN_CTRL_RS])) {
 247                ret = PTR_ERR(hd->pins[PIN_CTRL_RS]);
 248                goto fail;
 249        }
 250
 251        /* Optional pins */
 252        hd->pins[PIN_CTRL_RW] = devm_gpiod_get_optional(dev, "rw",
 253                                                        GPIOD_OUT_LOW);
 254        if (IS_ERR(hd->pins[PIN_CTRL_RW])) {
 255                ret = PTR_ERR(hd->pins[PIN_CTRL_RW]);
 256                goto fail;
 257        }
 258
 259        hd->pins[PIN_CTRL_BL] = devm_gpiod_get_optional(dev, "backlight",
 260                                                        GPIOD_OUT_LOW);
 261        if (IS_ERR(hd->pins[PIN_CTRL_BL])) {
 262                ret = PTR_ERR(hd->pins[PIN_CTRL_BL]);
 263                goto fail;
 264        }
 265
 266        /* Required properties */
 267        ret = device_property_read_u32(dev, "display-height-chars",
 268                                       &lcd->height);
 269        if (ret)
 270                goto fail;
 271        ret = device_property_read_u32(dev, "display-width-chars", &lcd->width);
 272        if (ret)
 273                goto fail;
 274
 275        /*
 276         * On displays with more than two rows, the internal buffer width is
 277         * usually equal to the display width
 278         */
 279        if (lcd->height > 2)
 280                lcd->bwidth = lcd->width;
 281
 282        /* Optional properties */
 283        device_property_read_u32(dev, "internal-buffer-width", &lcd->bwidth);
 284
 285        lcd->ifwidth = ifwidth;
 286        lcd->ops = ifwidth == 8 ? &hd44780_ops_gpio8 : &hd44780_ops_gpio4;
 287
 288        ret = charlcd_register(lcd);
 289        if (ret)
 290                goto fail;
 291
 292        platform_set_drvdata(pdev, lcd);
 293        return 0;
 294
 295fail:
 296        kfree(lcd);
 297        return ret;
 298}
 299
 300static int hd44780_remove(struct platform_device *pdev)
 301{
 302        struct charlcd *lcd = platform_get_drvdata(pdev);
 303
 304        charlcd_unregister(lcd);
 305        return 0;
 306}
 307
 308static const struct of_device_id hd44780_of_match[] = {
 309        { .compatible = "hit,hd44780" },
 310        { /* sentinel */ }
 311};
 312MODULE_DEVICE_TABLE(of, hd44780_of_match);
 313
 314static struct platform_driver hd44780_driver = {
 315        .probe = hd44780_probe,
 316        .remove = hd44780_remove,
 317        .driver         = {
 318                .name   = "hd44780",
 319                .of_match_table = hd44780_of_match,
 320        },
 321};
 322
 323module_platform_driver(hd44780_driver);
 324MODULE_DESCRIPTION("HD44780 Character LCD driver");
 325MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
 326MODULE_LICENSE("GPL");
 327