1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 25036cc41SMarek Vasut /* 35036cc41SMarek Vasut * lms283gf05.c -- support for Samsung LMS283GF05 LCD 45036cc41SMarek Vasut * 55036cc41SMarek Vasut * Copyright (c) 2009 Marek Vasut <marek.vasut@gmail.com> 65036cc41SMarek Vasut */ 75036cc41SMarek Vasut 85036cc41SMarek Vasut #include <linux/device.h> 95036cc41SMarek Vasut #include <linux/kernel.h> 105036cc41SMarek Vasut #include <linux/delay.h> 115a0e3ad6STejun Heo #include <linux/slab.h> 12*93cc26faSLinus Walleij #include <linux/gpio/consumer.h> 135036cc41SMarek Vasut #include <linux/lcd.h> 145036cc41SMarek Vasut 155036cc41SMarek Vasut #include <linux/spi/spi.h> 16355b200bSPaul Gortmaker #include <linux/module.h> 175036cc41SMarek Vasut 185036cc41SMarek Vasut struct lms283gf05_state { 195036cc41SMarek Vasut struct spi_device *spi; 205036cc41SMarek Vasut struct lcd_device *ld; 21*93cc26faSLinus Walleij struct gpio_desc *reset; 225036cc41SMarek Vasut }; 235036cc41SMarek Vasut 245036cc41SMarek Vasut struct lms283gf05_seq { 255036cc41SMarek Vasut unsigned char reg; 265036cc41SMarek Vasut unsigned short value; 275036cc41SMarek Vasut unsigned char delay; 285036cc41SMarek Vasut }; 295036cc41SMarek Vasut 305036cc41SMarek Vasut /* Magic sequences supplied by manufacturer, for details refer to datasheet */ 31c22e61b3SJingoo Han static const struct lms283gf05_seq disp_initseq[] = { 325036cc41SMarek Vasut /* REG, VALUE, DELAY */ 335036cc41SMarek Vasut { 0x07, 0x0000, 0 }, 345036cc41SMarek Vasut { 0x13, 0x0000, 10 }, 355036cc41SMarek Vasut 365036cc41SMarek Vasut { 0x11, 0x3004, 0 }, 375036cc41SMarek Vasut { 0x14, 0x200F, 0 }, 385036cc41SMarek Vasut { 0x10, 0x1a20, 0 }, 395036cc41SMarek Vasut { 0x13, 0x0040, 50 }, 405036cc41SMarek Vasut 415036cc41SMarek Vasut { 0x13, 0x0060, 0 }, 425036cc41SMarek Vasut { 0x13, 0x0070, 200 }, 435036cc41SMarek Vasut 445036cc41SMarek Vasut { 0x01, 0x0127, 0 }, 455036cc41SMarek Vasut { 0x02, 0x0700, 0 }, 465036cc41SMarek Vasut { 0x03, 0x1030, 0 }, 475036cc41SMarek Vasut { 0x08, 0x0208, 0 }, 485036cc41SMarek Vasut { 0x0B, 0x0620, 0 }, 495036cc41SMarek Vasut { 0x0C, 0x0110, 0 }, 505036cc41SMarek Vasut { 0x30, 0x0120, 0 }, 515036cc41SMarek Vasut { 0x31, 0x0127, 0 }, 525036cc41SMarek Vasut { 0x32, 0x0000, 0 }, 535036cc41SMarek Vasut { 0x33, 0x0503, 0 }, 545036cc41SMarek Vasut { 0x34, 0x0727, 0 }, 555036cc41SMarek Vasut { 0x35, 0x0124, 0 }, 565036cc41SMarek Vasut { 0x36, 0x0706, 0 }, 575036cc41SMarek Vasut { 0x37, 0x0701, 0 }, 585036cc41SMarek Vasut { 0x38, 0x0F00, 0 }, 595036cc41SMarek Vasut { 0x39, 0x0F00, 0 }, 605036cc41SMarek Vasut { 0x40, 0x0000, 0 }, 615036cc41SMarek Vasut { 0x41, 0x0000, 0 }, 625036cc41SMarek Vasut { 0x42, 0x013f, 0 }, 635036cc41SMarek Vasut { 0x43, 0x0000, 0 }, 645036cc41SMarek Vasut { 0x44, 0x013f, 0 }, 655036cc41SMarek Vasut { 0x45, 0x0000, 0 }, 665036cc41SMarek Vasut { 0x46, 0xef00, 0 }, 675036cc41SMarek Vasut { 0x47, 0x013f, 0 }, 685036cc41SMarek Vasut { 0x48, 0x0000, 0 }, 695036cc41SMarek Vasut { 0x07, 0x0015, 30 }, 705036cc41SMarek Vasut 715036cc41SMarek Vasut { 0x07, 0x0017, 0 }, 725036cc41SMarek Vasut 735036cc41SMarek Vasut { 0x20, 0x0000, 0 }, 745036cc41SMarek Vasut { 0x21, 0x0000, 0 }, 755036cc41SMarek Vasut { 0x22, 0x0000, 0 } 765036cc41SMarek Vasut }; 775036cc41SMarek Vasut 78c22e61b3SJingoo Han static const struct lms283gf05_seq disp_pdwnseq[] = { 795036cc41SMarek Vasut { 0x07, 0x0016, 30 }, 805036cc41SMarek Vasut 815036cc41SMarek Vasut { 0x07, 0x0004, 0 }, 825036cc41SMarek Vasut { 0x10, 0x0220, 20 }, 835036cc41SMarek Vasut 845036cc41SMarek Vasut { 0x13, 0x0060, 50 }, 855036cc41SMarek Vasut 865036cc41SMarek Vasut { 0x13, 0x0040, 50 }, 875036cc41SMarek Vasut 885036cc41SMarek Vasut { 0x13, 0x0000, 0 }, 895036cc41SMarek Vasut { 0x10, 0x0000, 0 } 905036cc41SMarek Vasut }; 915036cc41SMarek Vasut 925036cc41SMarek Vasut 93*93cc26faSLinus Walleij static void lms283gf05_reset(struct gpio_desc *gpiod) 945036cc41SMarek Vasut { 95*93cc26faSLinus Walleij gpiod_set_value(gpiod, 0); /* De-asserted */ 965036cc41SMarek Vasut mdelay(100); 97*93cc26faSLinus Walleij gpiod_set_value(gpiod, 1); /* Asserted */ 985036cc41SMarek Vasut mdelay(20); 99*93cc26faSLinus Walleij gpiod_set_value(gpiod, 0); /* De-asserted */ 1005036cc41SMarek Vasut mdelay(20); 1015036cc41SMarek Vasut } 1025036cc41SMarek Vasut 1035036cc41SMarek Vasut static void lms283gf05_toggle(struct spi_device *spi, 104c22e61b3SJingoo Han const struct lms283gf05_seq *seq, int sz) 1055036cc41SMarek Vasut { 1065036cc41SMarek Vasut char buf[3]; 1075036cc41SMarek Vasut int i; 1085036cc41SMarek Vasut 1095036cc41SMarek Vasut for (i = 0; i < sz; i++) { 1105036cc41SMarek Vasut buf[0] = 0x74; 1115036cc41SMarek Vasut buf[1] = 0x00; 1125036cc41SMarek Vasut buf[2] = seq[i].reg; 1135036cc41SMarek Vasut spi_write(spi, buf, 3); 1145036cc41SMarek Vasut 1155036cc41SMarek Vasut buf[0] = 0x76; 1165036cc41SMarek Vasut buf[1] = seq[i].value >> 8; 1175036cc41SMarek Vasut buf[2] = seq[i].value & 0xff; 1185036cc41SMarek Vasut spi_write(spi, buf, 3); 1195036cc41SMarek Vasut 1205036cc41SMarek Vasut mdelay(seq[i].delay); 1215036cc41SMarek Vasut } 1225036cc41SMarek Vasut } 1235036cc41SMarek Vasut 1245036cc41SMarek Vasut static int lms283gf05_power_set(struct lcd_device *ld, int power) 1255036cc41SMarek Vasut { 1265036cc41SMarek Vasut struct lms283gf05_state *st = lcd_get_data(ld); 1275036cc41SMarek Vasut struct spi_device *spi = st->spi; 1285036cc41SMarek Vasut 1296bde9082SMarek Vasut if (power <= FB_BLANK_NORMAL) { 130*93cc26faSLinus Walleij if (st->reset) 131*93cc26faSLinus Walleij lms283gf05_reset(st->reset); 1325036cc41SMarek Vasut lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq)); 1335036cc41SMarek Vasut } else { 1345036cc41SMarek Vasut lms283gf05_toggle(spi, disp_pdwnseq, ARRAY_SIZE(disp_pdwnseq)); 135*93cc26faSLinus Walleij if (st->reset) 136*93cc26faSLinus Walleij gpiod_set_value(st->reset, 1); /* Asserted */ 1375036cc41SMarek Vasut } 1385036cc41SMarek Vasut 1395036cc41SMarek Vasut return 0; 1405036cc41SMarek Vasut } 1415036cc41SMarek Vasut 1425036cc41SMarek Vasut static struct lcd_ops lms_ops = { 1435036cc41SMarek Vasut .set_power = lms283gf05_power_set, 1445036cc41SMarek Vasut .get_power = NULL, 1455036cc41SMarek Vasut }; 1465036cc41SMarek Vasut 1471b9e450dSBill Pemberton static int lms283gf05_probe(struct spi_device *spi) 1485036cc41SMarek Vasut { 1495036cc41SMarek Vasut struct lms283gf05_state *st; 1505036cc41SMarek Vasut struct lcd_device *ld; 1515036cc41SMarek Vasut 15226f2b35cSJingoo Han st = devm_kzalloc(&spi->dev, sizeof(struct lms283gf05_state), 15326f2b35cSJingoo Han GFP_KERNEL); 154e1094f9fSJingoo Han if (st == NULL) 15504e961fbSJingoo Han return -ENOMEM; 1565036cc41SMarek Vasut 157*93cc26faSLinus Walleij st->reset = gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); 158*93cc26faSLinus Walleij if (IS_ERR(st->reset)) 159*93cc26faSLinus Walleij return PTR_ERR(st->reset); 160*93cc26faSLinus Walleij gpiod_set_consumer_name(st->reset, "LMS283GF05 RESET"); 161*93cc26faSLinus Walleij 1620a1c55d0SJingoo Han ld = devm_lcd_device_register(&spi->dev, "lms283gf05", &spi->dev, st, 1630a1c55d0SJingoo Han &lms_ops); 16404e961fbSJingoo Han if (IS_ERR(ld)) 16504e961fbSJingoo Han return PTR_ERR(ld); 1665036cc41SMarek Vasut 1675036cc41SMarek Vasut st->spi = spi; 1685036cc41SMarek Vasut st->ld = ld; 1695036cc41SMarek Vasut 170b936fab0SJingoo Han spi_set_drvdata(spi, st); 1715036cc41SMarek Vasut 1725036cc41SMarek Vasut /* kick in the LCD */ 173*93cc26faSLinus Walleij if (st->reset) 174*93cc26faSLinus Walleij lms283gf05_reset(st->reset); 1755036cc41SMarek Vasut lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq)); 1765036cc41SMarek Vasut 1775036cc41SMarek Vasut return 0; 1785036cc41SMarek Vasut } 1795036cc41SMarek Vasut 1805036cc41SMarek Vasut static struct spi_driver lms283gf05_driver = { 1815036cc41SMarek Vasut .driver = { 1825036cc41SMarek Vasut .name = "lms283gf05", 1835036cc41SMarek Vasut }, 1845036cc41SMarek Vasut .probe = lms283gf05_probe, 1855036cc41SMarek Vasut }; 1865036cc41SMarek Vasut 187462dd838SAxel Lin module_spi_driver(lms283gf05_driver); 1885036cc41SMarek Vasut 1895036cc41SMarek Vasut MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); 1905036cc41SMarek Vasut MODULE_DESCRIPTION("LCD283GF05 LCD"); 1915036cc41SMarek Vasut MODULE_LICENSE("GPL v2"); 192