0001
0002
0003
0004
0005
0006
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
0022 PIN_DATA0,
0023 PIN_DATA1,
0024 PIN_DATA2,
0025 PIN_DATA3,
0026 PIN_DATA4,
0027 PIN_DATA5,
0028 PIN_DATA6,
0029 PIN_DATA7,
0030 PIN_CTRL_RS,
0031 PIN_CTRL_RW,
0032 PIN_CTRL_E,
0033 PIN_CTRL_BL,
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
0053 udelay(20);
0054
0055 gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 1);
0056
0057
0058 udelay(40);
0059
0060 gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 0);
0061 }
0062
0063
0064 static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
0065 {
0066 DECLARE_BITMAP(values, 10);
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
0074 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], NULL, values);
0075
0076 hd44780_strobe_gpio(hd);
0077 }
0078
0079
0080 static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs)
0081 {
0082 DECLARE_BITMAP(values, 6);
0083 unsigned int n;
0084
0085
0086 values[0] = val >> 4;
0087 __assign_bit(4, values, rs);
0088 n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
0089
0090
0091 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
0092
0093 hd44780_strobe_gpio(hd);
0094
0095
0096 values[0] &= ~0x0fUL;
0097 values[0] |= val & 0x0f;
0098
0099
0100 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
0101
0102 hd44780_strobe_gpio(hd);
0103 }
0104
0105
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
0113 udelay(120);
0114 }
0115
0116
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
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
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
0152 udelay(120);
0153 }
0154
0155
0156 static void hd44780_write_cmd_raw_gpio4(struct hd44780_common *hdc, int cmd)
0157 {
0158 DECLARE_BITMAP(values, 6);
0159 struct hd44780 *hd = hdc->hd44780;
0160 unsigned int n;
0161
0162
0163 values[0] = cmd & 0x0f;
0164 n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
0165
0166
0167 gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
0168
0169 hd44780_strobe_gpio(hd);
0170 }
0171
0172
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
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
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
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
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
0286
0287
0288 if (lcd->height > 2)
0289 hdc->bwidth = lcd->width;
0290
0291
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 { }
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");