Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * HD44780 Character LCD driver for Linux
0004  *
0005  * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
0006  * Copyright (C) 2016-2017 Glider bvba
0007  */
0008 
0009 #include <linux/delay.h>
0010 #include <linux/gpio/consumer.h>
0011 #include <linux/module.h>
0012 #include <linux/mod_devicetable.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/property.h>
0015 #include <linux/slab.h>
0016 
0017 #include "charlcd.h"
0018 #include "hd44780_common.h"
0019 
0020 enum hd44780_pin {
0021     /* Order does matter due to writing to GPIO array subsets! */
0022     PIN_DATA0,  /* Optional */
0023     PIN_DATA1,  /* Optional */
0024     PIN_DATA2,  /* Optional */
0025     PIN_DATA3,  /* Optional */
0026     PIN_DATA4,
0027     PIN_DATA5,
0028     PIN_DATA6,
0029     PIN_DATA7,
0030     PIN_CTRL_RS,
0031     PIN_CTRL_RW,    /* Optional */
0032     PIN_CTRL_E,
0033     PIN_CTRL_BL,   /* Optional */
0034     PIN_NUM
0035 };
0036 
0037 struct hd44780 {
0038     struct gpio_desc *pins[PIN_NUM];
0039 };
0040 
0041 static void hd44780_backlight(struct charlcd *lcd, enum charlcd_onoff on)
0042 {
0043     struct hd44780_common *hdc = lcd->drvdata;
0044     struct hd44780 *hd = hdc->hd44780;
0045 
0046     if (hd->pins[PIN_CTRL_BL])
0047         gpiod_set_value_cansleep(hd->pins[PIN_CTRL_BL], on);
0048 }
0049 
0050 static void hd44780_strobe_gpio(struct hd44780 *hd)
0051 {
0052     /* Maintain the data during 20 us before the strobe */
0053     udelay(20);
0054 
0055     gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 1);
0056 
0057     /* Maintain the strobe during 40 us */
0058     udelay(40);
0059 
0060     gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 0);
0061 }
0062 
0063 /* write to an LCD panel register in 8 bit GPIO mode */
0064 static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
0065 {
0066     DECLARE_BITMAP(values, 10); /* for DATA[0-7], RS, RW */
0067     unsigned int n;
0068 
0069     values[0] = val;
0070     __assign_bit(8, values, rs);
0071     n = hd->pins[PIN_CTRL_RW] ? 10 : 9;
0072 
0073     /* Present the data to the port */
0074     gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], NULL, values);
0075 
0076     hd44780_strobe_gpio(hd);
0077 }
0078 
0079 /* write to an LCD panel register in 4 bit GPIO mode */
0080 static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs)
0081 {
0082     DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
0083     unsigned int n;
0084 
0085     /* High nibble + RS, RW */
0086     values[0] = val >> 4;
0087     __assign_bit(4, values, rs);
0088     n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
0089 
0090     /* Present the data to the port */
0091     gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
0092 
0093     hd44780_strobe_gpio(hd);
0094 
0095     /* Low nibble */
0096     values[0] &= ~0x0fUL;
0097     values[0] |= val & 0x0f;
0098 
0099     /* Present the data to the port */
0100     gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
0101 
0102     hd44780_strobe_gpio(hd);
0103 }
0104 
0105 /* Send a command to the LCD panel in 8 bit GPIO mode */
0106 static void hd44780_write_cmd_gpio8(struct hd44780_common *hdc, int cmd)
0107 {
0108     struct hd44780 *hd = hdc->hd44780;
0109 
0110     hd44780_write_gpio8(hd, cmd, 0);
0111 
0112     /* The shortest command takes at least 120 us */
0113     udelay(120);
0114 }
0115 
0116 /* Send data to the LCD panel in 8 bit GPIO mode */
0117 static void hd44780_write_data_gpio8(struct hd44780_common *hdc, int data)
0118 {
0119     struct hd44780 *hd = hdc->hd44780;
0120 
0121     hd44780_write_gpio8(hd, data, 1);
0122 
0123     /* The shortest data takes at least 45 us */
0124     udelay(45);
0125 }
0126 
0127 static const struct charlcd_ops hd44780_ops_gpio8 = {
0128     .backlight  = hd44780_backlight,
0129     .print      = hd44780_common_print,
0130     .gotoxy     = hd44780_common_gotoxy,
0131     .home       = hd44780_common_home,
0132     .clear_display  = hd44780_common_clear_display,
0133     .init_display   = hd44780_common_init_display,
0134     .shift_cursor   = hd44780_common_shift_cursor,
0135     .shift_display  = hd44780_common_shift_display,
0136     .display    = hd44780_common_display,
0137     .cursor     = hd44780_common_cursor,
0138     .blink      = hd44780_common_blink,
0139     .fontsize   = hd44780_common_fontsize,
0140     .lines      = hd44780_common_lines,
0141     .redefine_char  = hd44780_common_redefine_char,
0142 };
0143 
0144 /* Send a command to the LCD panel in 4 bit GPIO mode */
0145 static void hd44780_write_cmd_gpio4(struct hd44780_common *hdc, int cmd)
0146 {
0147     struct hd44780 *hd = hdc->hd44780;
0148 
0149     hd44780_write_gpio4(hd, cmd, 0);
0150 
0151     /* The shortest command takes at least 120 us */
0152     udelay(120);
0153 }
0154 
0155 /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
0156 static void hd44780_write_cmd_raw_gpio4(struct hd44780_common *hdc, int cmd)
0157 {
0158     DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
0159     struct hd44780 *hd = hdc->hd44780;
0160     unsigned int n;
0161 
0162     /* Command nibble + RS, RW */
0163     values[0] = cmd & 0x0f;
0164     n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
0165 
0166     /* Present the data to the port */
0167     gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
0168 
0169     hd44780_strobe_gpio(hd);
0170 }
0171 
0172 /* Send data to the LCD panel in 4 bit GPIO mode */
0173 static void hd44780_write_data_gpio4(struct hd44780_common *hdc, int data)
0174 {
0175     struct hd44780 *hd = hdc->hd44780;
0176 
0177     hd44780_write_gpio4(hd, data, 1);
0178 
0179     /* The shortest data takes at least 45 us */
0180     udelay(45);
0181 }
0182 
0183 static const struct charlcd_ops hd44780_ops_gpio4 = {
0184     .backlight  = hd44780_backlight,
0185     .print      = hd44780_common_print,
0186     .gotoxy     = hd44780_common_gotoxy,
0187     .home       = hd44780_common_home,
0188     .clear_display  = hd44780_common_clear_display,
0189     .init_display   = hd44780_common_init_display,
0190     .shift_cursor   = hd44780_common_shift_cursor,
0191     .shift_display  = hd44780_common_shift_display,
0192     .display    = hd44780_common_display,
0193     .cursor     = hd44780_common_cursor,
0194     .blink      = hd44780_common_blink,
0195     .fontsize   = hd44780_common_fontsize,
0196     .lines      = hd44780_common_lines,
0197     .redefine_char  = hd44780_common_redefine_char,
0198 };
0199 
0200 static int hd44780_probe(struct platform_device *pdev)
0201 {
0202     struct device *dev = &pdev->dev;
0203     unsigned int i, base;
0204     struct charlcd *lcd;
0205     struct hd44780_common *hdc;
0206     struct hd44780 *hd;
0207     int ifwidth, ret = -ENOMEM;
0208 
0209     /* Required pins */
0210     ifwidth = gpiod_count(dev, "data");
0211     if (ifwidth < 0)
0212         return ifwidth;
0213 
0214     switch (ifwidth) {
0215     case 4:
0216         base = PIN_DATA4;
0217         break;
0218     case 8:
0219         base = PIN_DATA0;
0220         break;
0221     default:
0222         return -EINVAL;
0223     }
0224 
0225     hdc = hd44780_common_alloc();
0226     if (!hdc)
0227         return -ENOMEM;
0228 
0229     lcd = charlcd_alloc();
0230     if (!lcd)
0231         goto fail1;
0232 
0233     hd = kzalloc(sizeof(struct hd44780), GFP_KERNEL);
0234     if (!hd)
0235         goto fail2;
0236 
0237     hdc->hd44780 = hd;
0238     lcd->drvdata = hdc;
0239     for (i = 0; i < ifwidth; i++) {
0240         hd->pins[base + i] = devm_gpiod_get_index(dev, "data", i,
0241                               GPIOD_OUT_LOW);
0242         if (IS_ERR(hd->pins[base + i])) {
0243             ret = PTR_ERR(hd->pins[base + i]);
0244             goto fail3;
0245         }
0246     }
0247 
0248     hd->pins[PIN_CTRL_E] = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
0249     if (IS_ERR(hd->pins[PIN_CTRL_E])) {
0250         ret = PTR_ERR(hd->pins[PIN_CTRL_E]);
0251         goto fail3;
0252     }
0253 
0254     hd->pins[PIN_CTRL_RS] = devm_gpiod_get(dev, "rs", GPIOD_OUT_HIGH);
0255     if (IS_ERR(hd->pins[PIN_CTRL_RS])) {
0256         ret = PTR_ERR(hd->pins[PIN_CTRL_RS]);
0257         goto fail3;
0258     }
0259 
0260     /* Optional pins */
0261     hd->pins[PIN_CTRL_RW] = devm_gpiod_get_optional(dev, "rw",
0262                             GPIOD_OUT_LOW);
0263     if (IS_ERR(hd->pins[PIN_CTRL_RW])) {
0264         ret = PTR_ERR(hd->pins[PIN_CTRL_RW]);
0265         goto fail3;
0266     }
0267 
0268     hd->pins[PIN_CTRL_BL] = devm_gpiod_get_optional(dev, "backlight",
0269                             GPIOD_OUT_LOW);
0270     if (IS_ERR(hd->pins[PIN_CTRL_BL])) {
0271         ret = PTR_ERR(hd->pins[PIN_CTRL_BL]);
0272         goto fail3;
0273     }
0274 
0275     /* Required properties */
0276     ret = device_property_read_u32(dev, "display-height-chars",
0277                        &lcd->height);
0278     if (ret)
0279         goto fail3;
0280     ret = device_property_read_u32(dev, "display-width-chars", &lcd->width);
0281     if (ret)
0282         goto fail3;
0283 
0284     /*
0285      * On displays with more than two rows, the internal buffer width is
0286      * usually equal to the display width
0287      */
0288     if (lcd->height > 2)
0289         hdc->bwidth = lcd->width;
0290 
0291     /* Optional properties */
0292     device_property_read_u32(dev, "internal-buffer-width", &hdc->bwidth);
0293 
0294     hdc->ifwidth = ifwidth;
0295     if (ifwidth == 8) {
0296         lcd->ops = &hd44780_ops_gpio8;
0297         hdc->write_data = hd44780_write_data_gpio8;
0298         hdc->write_cmd = hd44780_write_cmd_gpio8;
0299     } else {
0300         lcd->ops = &hd44780_ops_gpio4;
0301         hdc->write_data = hd44780_write_data_gpio4;
0302         hdc->write_cmd = hd44780_write_cmd_gpio4;
0303         hdc->write_cmd_raw4 = hd44780_write_cmd_raw_gpio4;
0304     }
0305 
0306     ret = charlcd_register(lcd);
0307     if (ret)
0308         goto fail3;
0309 
0310     platform_set_drvdata(pdev, lcd);
0311     return 0;
0312 
0313 fail3:
0314     kfree(hd);
0315 fail2:
0316     kfree(lcd);
0317 fail1:
0318     kfree(hdc);
0319     return ret;
0320 }
0321 
0322 static int hd44780_remove(struct platform_device *pdev)
0323 {
0324     struct charlcd *lcd = platform_get_drvdata(pdev);
0325 
0326     charlcd_unregister(lcd);
0327     kfree(lcd->drvdata);
0328 
0329     kfree(lcd);
0330     return 0;
0331 }
0332 
0333 static const struct of_device_id hd44780_of_match[] = {
0334     { .compatible = "hit,hd44780" },
0335     { /* sentinel */ }
0336 };
0337 MODULE_DEVICE_TABLE(of, hd44780_of_match);
0338 
0339 static struct platform_driver hd44780_driver = {
0340     .probe = hd44780_probe,
0341     .remove = hd44780_remove,
0342     .driver     = {
0343         .name   = "hd44780",
0344         .of_match_table = hd44780_of_match,
0345     },
0346 };
0347 
0348 module_platform_driver(hd44780_driver);
0349 MODULE_DESCRIPTION("HD44780 Character LCD driver");
0350 MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
0351 MODULE_LICENSE("GPL");