From 6431989c1f0c4fed3e4f63ecd663a9f6fe97bea9 Mon Sep 17 00:00:00 2001 From: "charles.park" Date: Mon, 31 Dec 2018 12:01:01 +0900 Subject: [PATCH] ODROID-N2: fbtft ili9488 lcd module added. Change-Id: I701bf93801c55f9e28395bc8ee7c9b88e6859a09 --- drivers/staging/fbtft/fbtft-io.c | 57 ++++++++++++++++++ drivers/staging/fbtft/fbtft.h | 14 +++++ drivers/staging/fbtft/fbtft_device.c | 19 ++++++ drivers/staging/fbtft/flexfb.c | 87 ++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+) diff --git a/drivers/staging/fbtft/fbtft-io.c b/drivers/staging/fbtft/fbtft-io.c index 4dcea2e0b3ae..fd133e0ecc75 100644 --- a/drivers/staging/fbtft/fbtft-io.c +++ b/drivers/staging/fbtft/fbtft-io.c @@ -236,3 +236,60 @@ int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) return -1; } EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched); + +#if defined(CONFIG_ARCH_MESON64_ODROID_COMMON) +union reg_bitfield { + unsigned int wvalue; + struct { + unsigned int db02: 1; /* GPIOX.0 */ + unsigned int db00: 1; /* GPIOX.1 */ + unsigned int db01: 1; /* GPIOX.2 */ + unsigned int bit3: 1; /* GPIOX.3 */ + unsigned int db07: 1; /* GPIOX.4 */ + unsigned int bit5: 1; /* GPIOX.5 */ + unsigned int bit6: 1; /* GPIOX.6 */ + unsigned int db06: 1; /* GPIOX.7 */ + unsigned int db05: 1; /* GPIOX.8 */ + unsigned int db04: 1; /* GPIOX.9 */ + unsigned int wr: 1; /* GPIOX.10 */ + unsigned int db03: 1; /* GPIOX.11 */ + /* GPIOX.12 ~ GPIOX.31 */ + unsigned int bit12_bit31 : 20; + } bits; +}; + +int fbtft_write_reg_wr(struct fbtft_par *par, void *buf, size_t len) +{ + u8 data; + union reg_bitfield dbus; + + if (!par->reg_gpiox) { + pr_err("%s : ioremap gpio register fail!\n", __func__); + return 0; + } + + dbus.wvalue = ioread32(par->reg_gpiox + OFFSET_GPIOX_IN); + + while (len--) { + data = *buf; + dbus.bits.db00 = (data & 0x01) ? 1 : 0; + dbus.bits.db01 = (data & 0x02) ? 1 : 0; + dbus.bits.db02 = (data & 0x04) ? 1 : 0; + dbus.bits.db03 = (data & 0x08) ? 1 : 0; + dbus.bits.db04 = (data & 0x10) ? 1 : 0; + dbus.bits.db05 = (data & 0x20) ? 1 : 0; + dbus.bits.db06 = (data & 0x40) ? 1 : 0; + dbus.bits.db07 = (data & 0x80) ? 1 : 0; + /* Start writing by pulling down /WR */ + dbus.bits.wr = 0; + iowrite32(dbus.wvalue, par->reg_gpiox + OFFSET_GPIOX_OUT); + dbus.bits.wr = 1; + iowrite32(dbus.wvalue, par->reg_gpiox + OFFSET_GPIOX_OUT); + + buf++; + } + + return 0; +} + +#endif /* #if defined(CONFIG_ARCH_MESON64_ODROID_COMMON) */ diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index 89c4b5b76ce6..06128aa082bf 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -241,8 +241,18 @@ struct fbtft_par { ktime_t update_time; bool bgr; void *extra; +#if defined(CONFIG_ARCH_MESON64_ODROID_COMMON) + void __iomem *reg_gpiox; +#endif }; +#if defined(CONFIG_ARCH_MESON64_ODROID_COMMON) + #define ODROIDN2_GPIO_START 0xff634400 + #define ODROIDN2_GPIOX_START (ODROIDN2_GPIO_START + 0x50) + #define OFFSET_GPIOX_OUT 0x0C + #define OFFSET_GPIOX_IN 0x10 +#endif + #define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int)) #define write_reg(par, ...) \ @@ -272,6 +282,10 @@ int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len); int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len); int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len); +#if defined(CONFIG_ARCH_MESON64_ODROID_COMMON) +int fbtft_write_reg_wr(struct fbtft_par *par, void *buf, size_t len); +#endif + /* fbtft-bus.c */ int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len); int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len); diff --git a/drivers/staging/fbtft/fbtft_device.c b/drivers/staging/fbtft/fbtft_device.c index 9d031a98c3bc..1c37fe0f6b03 100644 --- a/drivers/staging/fbtft/fbtft_device.c +++ b/drivers/staging/fbtft/fbtft_device.c @@ -544,6 +544,24 @@ static struct fbtft_device_display displays[] = { .release = fbtft_device_pdev_release, .platform_data = &(struct fbtft_platform_data) { .gpios = (const struct fbtft_gpio []) { +#if defined(CONFIG_ARCH_MESON64_ODROID_COMMON) + { "reset", 479 }, /* GPX.3 */ + { "dc", 490 }, /* GPX.14 */ + { "wr", 486 }, /* GPX.10 */ + { "cs", 492 }, /* GPX.16 */ + { "db00", 477 }, /* GPX.1 */ + { "db01", 478 }, /* GPX.2 */ + { "db02", 476 }, /* GPX.0 */ + { "db03", 487 }, /* GPX.11 */ + { "db04", 485 }, /* GPX.9 */ + { "db05", 484 }, /* GPX.8 */ + { "db06", 483 }, /* GPX.7 */ + { "db07", 480 }, /* GPX.4 */ + { "led", 481 }, /* GPX.5 */ + {}, + +#else + { "reset", 17 }, { "dc", 1 }, { "wr", 0 }, @@ -558,6 +576,7 @@ static struct fbtft_device_display displays[] = { { "db07", 7 }, { "led", 4 }, {}, +#endif }, }, } diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c index ce0d254148e4..bc68bd0c2adc 100644 --- a/drivers/staging/fbtft/flexfb.c +++ b/drivers/staging/fbtft/flexfb.c @@ -126,6 +126,24 @@ 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 }; +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 @@ -210,6 +228,13 @@ static const struct flexfb_lcd_controller flexfb_chip_table[] = { .init_seq = ili9341_init, .init_seq_sz = ARRAY_SIZE(ili9341_init), }, + { + .name = "ili9488", + .width = 320, + .height = 480, + .init_seq = ili9488_init, + .init_seq_sz = ARRAY_SIZE(ili9488_init), + }, { .name = "ssd1289", .width = 240, @@ -229,6 +254,53 @@ static const struct flexfb_lcd_controller flexfb_chip_table[] = { }, }; +#if defined(CONFIG_ARCH_MESON64_ODROID_COMMON) +static void set_addr_win_odroid(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 address */ + 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_odroid(struct fbtft_par *par) +{ + u8 val; + + fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); + + 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; +} + +#endif + /* ili9320, ili9325 */ static void flexfb_set_addr_win_1(struct fbtft_par *par, int xs, int ys, int xe, int ye) @@ -518,6 +590,17 @@ static int flexfb_probe_common(struct spi_device *sdev, if (!nobacklight) par->fbtftops.register_backlight = fbtft_register_backlight; +#if defined(CONFIG_ARCH_MESON64_ODROID_COMMON) + par->reg_gpiox = ioremap(ODROIDN2_GPIOX_START, 64); + if (!par->reg_gpiox) { + pr_err("%s : ioremap gpiox register error!\n", __func__); + } else { + par->fbtftops.write = fbtft_write_reg_wr; + par->fbtftops.set_addr_win = set_addr_win_odroid; + par->fbtftops.set_var = set_var_odroid; + } +#endif + ret = fbtft_register_framebuffer(info); if (ret < 0) goto out_release; @@ -540,6 +623,10 @@ 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 defined(CONFIG_ARCH_MESON64_ODROID_COMMON) + if (par->reg_gpiox) + iounmap(par->reg_gpiox); +#endif fbtft_unregister_framebuffer(info); fbtft_framebuffer_release(info);