From 2147eecf3f36c10e3d45ec1977f8d0f3b9bea736 Mon Sep 17 00:00:00 2001 From: "charles.park" Date: Thu, 19 Jan 2017 17:18:35 +0900 Subject: [PATCH] ODROID-XU4: add fbtft_device(ODROID TFT35 driver) Change-Id: I5acded855e96b83eeae7d98a30c789a07c1d8044 --- drivers/staging/fbtft/fbtft_device.c | 28 ++--- drivers/staging/fbtft/flexfb.c | 149 +++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 13 deletions(-) mode change 100644 => 100755 drivers/staging/fbtft/flexfb.c diff --git a/drivers/staging/fbtft/fbtft_device.c b/drivers/staging/fbtft/fbtft_device.c index 37cabda2e8fd..e1c1ee0ef429 100755 --- a/drivers/staging/fbtft/fbtft_device.c +++ b/drivers/staging/fbtft/fbtft_device.c @@ -549,20 +549,22 @@ static struct fbtft_device_display displays[] = { .dev = { .release = fbtft_device_pdev_release, .platform_data = &(struct fbtft_platform_data) { + /* for ODROID TFT35(ili9488) */ + .bgr = true, .gpios = (const struct fbtft_gpio []) { - { "reset", 17 }, - { "dc", 1 }, - { "wr", 0 }, - { "cs", 21 }, - { "db00", 9 }, - { "db01", 11 }, - { "db02", 18 }, - { "db03", 23 }, - { "db04", 24 }, - { "db05", 25 }, - { "db06", 8 }, - { "db07", 7 }, - { "led", 4 }, + { "reset", 174 }, /* GPA0.3 */ + { "dc", 28 }, /* GPX2.4 */ + { "wr", 190 }, /* GPA2.5 */ + { "cs", 173 }, /* GPA0.2 */ + { "db00", 23 }, /* GPX1.7 */ + { "db01", 24 }, /* GPX2.0 */ + { "db02", 19 }, /* GPX1.3 */ + { "db03", 189 }, /* GPA2.4 */ + { "db04", 191 }, /* GPA2.6 */ + { "db05", 192 }, /* GPA2.7 */ + { "db06", 22 }, /* GPX1.6 */ + { "db07", 21 }, /* GPX1.5 */ + { "led", 31 }, /* GPX2.7 */ {}, }, }, diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c old mode 100644 new mode 100755 index ce0d254148e4..efc901eb60a3 --- a/drivers/staging/fbtft/flexfb.c +++ b/drivers/staging/fbtft/flexfb.c @@ -126,6 +126,23 @@ static int ssd1351_init[] = { -1, 0xfd, 0x12, -1, 0xfd, 0xb1, -1, 0xae, -1, 0xb3 -1, 0xab, 0x01, -1, 0xb1, 0x32, -1, 0xb4, 0xa0, 0xb5, 0x55, -1, 0xbb, 0x17, -1, 0xbe, 0x05, -1, 0xc1, 0xc8, 0x80, 0xc8, -1, 0xc7, 0x0f, -1, 0xb6, 0x01, -1, 0xa6, -1, 0xaf, -3 }; +/* for ODROID TFT35 LCD */ +static int ili9488_init[] = { + -1, 0xB0,0x00, + -1, 0x11, + -2, 120, + -1, 0x3A,0x55, + -1, 0xC2,0x33, + -1, 0xC5,0x00,0x1E,0x80, + -1, 0x36,0x28, + -1, 0xB1,0xB0, + -1, 0xE0,0x00,0x04,0x0E,0x08,0x17,0x0A,0x40,0x79,0x4D,0x07,0x0E,0x0A,0x1A,0x1D,0x0F, + -1, 0xE1,0x00,0x1B,0x1F,0x02,0x10,0x05,0x32,0x34,0x43,0x02,0x0A,0x09,0x33,0x37,0x0F, + -1, 0x11, + -1, 0x29, + -3 +}; + /** * struct flexfb_lcd_controller - Describes the LCD controller properties * @name: Model name of the chip @@ -227,8 +244,118 @@ static const struct flexfb_lcd_controller flexfb_chip_table[] = { .init_seq = ssd1351_init, .init_seq_sz = ARRAY_SIZE(ssd1351_init), }, + /* for ODROID TFT35 LCD */ + { + .name = "ili9488", + .width = 320, + .height = 480, + .setaddrwin = 0, + .init_seq = ili9488_init, + .init_seq_sz = ARRAY_SIZE(ili9488_init), + }, }; +/* for ODROID TFT32 LCD(ili9488) */ +#define ODROIDXU3_GPX1_REG 0x13400C24 +#define ODROIDXU3_GPX2_REG 0x13400C44 +#define ODROIDXU3_GPA2_REG 0x14010044 + +union reg_bitfield { + unsigned int wvalue; + struct { + unsigned int bit0 : 1; + unsigned int bit1 : 1; + unsigned int bit2 : 1; + unsigned int bit3 : 1; + unsigned int bit4 : 1; + unsigned int bit5 : 1; + unsigned int bit6 : 1; + unsigned int bit7 : 1; + unsigned int bit8_bit31 : 24; + } bits; +}; + +volatile void __iomem *reg_gpx1; +volatile void __iomem *reg_gpx2; +volatile void __iomem *reg_gpa2; + +static int write_reg_wr_ili9488(struct fbtft_par *par, void *buf, size_t len) +{ + u8 data; + union reg_bitfield gpx1, gpx2, gpa2; + + if ((reg_gpx1 == NULL) || (reg_gpx2 == NULL) || (reg_gpa2 == NULL)) { + pr_err("%s : ioremap gpio register fail!\n", __func__); + return 0; + } + + gpx1.wvalue = ioread32(reg_gpx1); + gpx2.wvalue = ioread32(reg_gpx2); + gpa2.wvalue = ioread32(reg_gpa2); + + while (len--) { + data = *(u8 *) buf; + gpx1.bits.bit7 = (data & 0x01) ? 1 : 0; + gpx2.bits.bit0 = (data & 0x02) ? 1 : 0; + gpx1.bits.bit3 = (data & 0x04) ? 1 : 0; + gpa2.bits.bit4 = (data & 0x08) ? 1 : 0; + gpa2.bits.bit6 = (data & 0x10) ? 1 : 0; + gpa2.bits.bit7 = (data & 0x20) ? 1 : 0; + gpx1.bits.bit6 = (data & 0x40) ? 1 : 0; + gpx1.bits.bit5 = (data & 0x80) ? 1 : 0; + /* Start writing by pulling down /WR */ + gpa2.bits.bit5 = 0; + iowrite32(gpx1.wvalue, reg_gpx1); + iowrite32(gpx2.wvalue, reg_gpx2); + iowrite32(gpa2.wvalue, reg_gpa2); + gpa2.bits.bit5 = 1; + iowrite32(gpa2.wvalue, reg_gpa2); + + buf++; + } + + return 0; +} + +static void set_addr_win_ili9488(struct fbtft_par *par, int xs, int ys, int xe, int ye) +{ + /* Column address */ + write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); + + /* Row adress */ + write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); + + /* Memory write */ + write_reg(par, 0x2C); +} + +#define ODROID_TFT35_MACTL_MV 0x20 +#define ODROID_TFT35_MACTL_MX 0x40 +#define ODROID_TFT35_MACTL_MY 0x80 + +static int set_var_ili9488(struct fbtft_par *par) +{ + u8 val; + + switch (par->info->var.rotate) { + case 270: + val = ODROID_TFT35_MACTL_MV; + break; + case 180: + val = ODROID_TFT35_MACTL_MY; + break; + case 90: + val = ODROID_TFT35_MACTL_MV | ODROID_TFT35_MACTL_MX | ODROID_TFT35_MACTL_MY; + break; + default: + val = ODROID_TFT35_MACTL_MX; + break; + } + /* Memory Access Control */ + write_reg(par, 0x36, val | (par->bgr << 3)); + return 0; +} + /* ili9320, ili9325 */ static void flexfb_set_addr_win_1(struct fbtft_par *par, int xs, int ys, int xe, int ye) @@ -518,6 +645,21 @@ static int flexfb_probe_common(struct spi_device *sdev, if (!nobacklight) par->fbtftops.register_backlight = fbtft_register_backlight; + /* for ODROID TFT35 LCD(ili9488) */ + if (!strcmp(chip, "ili9488")) { + reg_gpx1 = ioremap(ODROIDXU3_GPX1_REG, 4); + reg_gpx2 = ioremap(ODROIDXU3_GPX2_REG, 4); + reg_gpa2 = ioremap(ODROIDXU3_GPA2_REG, 4); + if ((reg_gpx1 == NULL) || (reg_gpx2 == NULL) || (reg_gpa2 == NULL)) + pr_err("%s : ioremap gpiox register error!\n", __func__); + else { + pr_err("%s : ioremap gpiox register success!\n", __func__); + par->fbtftops.write = write_reg_wr_ili9488; + par->fbtftops.set_addr_win = set_addr_win_ili9488; + par->fbtftops.set_var = set_var_ili9488; + } + } + ret = fbtft_register_framebuffer(info); if (ret < 0) goto out_release; @@ -540,6 +682,13 @@ static int flexfb_remove_common(struct device *dev, struct fb_info *info) if (par) fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, "%s()\n", __func__); + + if (!strcmp(chip, "ili9488")) { + if (reg_gpx1) iounmap(reg_gpx1); + if (reg_gpx2) iounmap(reg_gpx2); + if (reg_gpa2) iounmap(reg_gpa2); + } + fbtft_unregister_framebuffer(info); fbtft_framebuffer_release(info);