root/drivers/auxdisplay/hd44780.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hd44780_backlight
  2. hd44780_strobe_gpio
  3. hd44780_write_gpio8
  4. hd44780_write_gpio4
  5. hd44780_write_cmd_gpio8
  6. hd44780_write_data_gpio8
  7. hd44780_write_cmd_gpio4
  8. hd44780_write_cmd_raw_gpio4
  9. hd44780_write_data_gpio4
  10. hd44780_probe
  11. hd44780_remove

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

/* [<][>][^][v][top][bottom][index][help] */