diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-12-15 14:52:16 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-12-15 14:52:16 -0300 |
commit | 8d91c1e411f55d7ea91b1183a2e9f8088fb4d5be (patch) | |
tree | e9891aa6c295060d065adffd610c4f49ecf884f3 /drivers/staging/fbtft | |
parent | a71852147516bc1cb5b0b3cbd13639bfd4022dc8 (diff) |
Linux-libre 4.3.2-gnu
Diffstat (limited to 'drivers/staging/fbtft')
-rw-r--r-- | drivers/staging/fbtft/Kconfig | 9 | ||||
-rw-r--r-- | drivers/staging/fbtft/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/fbtft/fb_uc1611.c | 350 | ||||
-rw-r--r-- | drivers/staging/fbtft/fb_watterott.c | 4 | ||||
-rw-r--r-- | drivers/staging/fbtft/fbtft-core.c | 27 | ||||
-rw-r--r-- | drivers/staging/fbtft/fbtft.h | 57 | ||||
-rw-r--r-- | drivers/staging/fbtft/fbtft_device.c | 31 | ||||
-rw-r--r-- | drivers/staging/fbtft/flexfb.c | 269 |
8 files changed, 578 insertions, 170 deletions
diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig index d4018780c..d473010fa 100644 --- a/drivers/staging/fbtft/Kconfig +++ b/drivers/staging/fbtft/Kconfig @@ -1,6 +1,7 @@ menuconfig FB_TFT tristate "Support for small TFT LCD display modules" - depends on FB && SPI && GPIOLIB + depends on FB && SPI + depends on GPIOLIB || COMPILE_TEST select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT @@ -152,6 +153,12 @@ config FB_TFT_TLS8204 help Generic Framebuffer support for TLS8204 +config FB_TFT_UC1611 + tristate "FB driver for the UC1611 LCD controller" + depends on FB_TFT + help + Generic Framebuffer support for UC1611 + config FB_TFT_UC1701 tristate "FB driver for the UC1701 LCD Controller" depends on FB_TFT diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile index 554b5260b..b26efdc87 100644 --- a/drivers/staging/fbtft/Makefile +++ b/drivers/staging/fbtft/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o +obj-$(CONFIG_FB_TFT_UC1611) += fb_uc1611.o obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o obj-$(CONFIG_FB_TFT_UPD161704) += fb_upd161704.o obj-$(CONFIG_FB_TFT_WATTEROTT) += fb_watterott.o diff --git a/drivers/staging/fbtft/fb_uc1611.c b/drivers/staging/fbtft/fb_uc1611.c new file mode 100644 index 000000000..5cafa50d1 --- /dev/null +++ b/drivers/staging/fbtft/fb_uc1611.c @@ -0,0 +1,350 @@ +/* + * FB driver for the UltraChip UC1611 LCD controller + * + * The display is 4-bit grayscale (16 shades) 240x160. + * + * Copyright (C) 2015 Henri Chain + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/spi/spi.h> +#include <linux/delay.h> + +#include "fbtft.h" + +#define DRVNAME "fb_uc1611" +#define WIDTH 240 +#define HEIGHT 160 +#define BPP 8 +#define FPS 40 + +/* + * LCD voltage is a combination of ratio, gain, pot and temp + * + * V_LCD = V_BIAS * ratio + * V_LCD = (C_V0 + C_PM × pot) * (1 + (T - 25) * temp) + * C_V0 and C_PM depend on ratio and gain + * T is ambient temperature + */ + +/* BR -> actual ratio: 0-3 -> 5, 10, 11, 13 */ +static unsigned ratio = 2; +module_param(ratio, uint, 0); +MODULE_PARM_DESC(ratio, "BR[1:0] Bias voltage ratio: 0-3 (default: 2)"); + +static unsigned gain = 3; +module_param(gain, uint, 0); +MODULE_PARM_DESC(gain, "GN[1:0] Bias voltage gain: 0-3 (default: 3)"); + +static unsigned pot = 16; +module_param(pot, uint, 0); +MODULE_PARM_DESC(pot, "PM[6:0] Bias voltage pot.: 0-63 (default: 16)"); + +/* TC -> % compensation per deg C: 0-3 -> -.05, -.10, -.015, -.20 */ +static unsigned temp; +module_param(temp, uint, 0); +MODULE_PARM_DESC(temp, "TC[1:0] Temperature compensation: 0-3 (default: 0)"); + +/* PC[1:0] -> LCD capacitance: 0-3 -> <20nF, 20-28 nF, 29-40 nF, 40-56 nF */ +static unsigned load = 1; +module_param(load, uint, 0); +MODULE_PARM_DESC(load, "PC[1:0] Panel Loading: 0-3 (default: 1)"); + +/* PC[3:2] -> V_LCD: 0, 1, 3 -> ext., int. with ratio = 5, int. standard */ +static unsigned pump = 3; +module_param(pump, uint, 0); +MODULE_PARM_DESC(pump, "PC[3:2] Pump control: 0,1,3 (default: 3)"); + +static int init_display(struct fbtft_par *par) +{ + int ret; + + fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); + + /* Set CS active high */ + par->spi->mode |= SPI_CS_HIGH; + ret = spi_setup(par->spi); + if (ret) { + dev_err(par->info->device, "Could not set SPI_CS_HIGH\n"); + return ret; + } + + /* Reset controller */ + write_reg(par, 0xE2); + + /* Set bias ratio */ + write_reg(par, 0xE8 | (ratio & 0x03)); + + /* Set bias gain and potentiometer */ + write_reg(par, 0x81); + write_reg(par, (gain & 0x03) << 6 | (pot & 0x3F)); + + /* Set temperature compensation */ + write_reg(par, 0x24 | (temp & 0x03)); + + /* Set panel loading */ + write_reg(par, 0x28 | (load & 0x03)); + + /* Set pump control */ + write_reg(par, 0x2C | (pump & 0x03)); + + /* Set inverse display */ + write_reg(par, 0xA6 | (0x01 & 0x01)); + + /* Set 4-bit grayscale mode */ + write_reg(par, 0xD0 | (0x02 & 0x03)); + + /* Set Display enable */ + write_reg(par, 0xA8 | 0x07); + + return 0; +} + +static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) +{ + fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, + "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", + __func__, xs, ys, xe, ye); + + switch (par->info->var.rotate) { + case 90: + case 270: + /* Set column address */ + write_reg(par, ys & 0x0F); + write_reg(par, 0x10 | (ys >> 4)); + + /* Set page address (divide xs by 2) (not used by driver) */ + write_reg(par, 0x60 | ((xs >> 1) & 0x0F)); + write_reg(par, 0x70 | (xs >> 5)); + break; + default: + /* Set column address (not used by driver) */ + write_reg(par, xs & 0x0F); + write_reg(par, 0x10 | (xs >> 4)); + + /* Set page address (divide ys by 2) */ + write_reg(par, 0x60 | ((ys >> 1) & 0x0F)); + write_reg(par, 0x70 | (ys >> 5)); + break; + } +} + +static int blank(struct fbtft_par *par, bool on) +{ + fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", + __func__, on ? "true" : "false"); + + if (on) + write_reg(par, 0xA8 | 0x00); + else + write_reg(par, 0xA8 | 0x07); + return 0; +} + +static int set_var(struct fbtft_par *par) +{ + fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); + + /* par->info->fix.visual = FB_VISUAL_PSEUDOCOLOR; */ + par->info->var.grayscale = 1; + par->info->var.red.offset = 0; + par->info->var.red.length = 8; + par->info->var.green.offset = 0; + par->info->var.green.length = 8; + par->info->var.blue.offset = 0; + par->info->var.blue.length = 8; + par->info->var.transp.offset = 0; + par->info->var.transp.length = 0; + + switch (par->info->var.rotate) { + case 90: + /* Set RAM address control */ + write_reg(par, 0x88 + | (0x0 & 0x1) << 2 /* Increment positively */ + | (0x1 & 0x1) << 1 /* Increment page first */ + | (0x1 & 0x1)); /* Wrap around (default) */ + + /* Set LCD mapping */ + write_reg(par, 0xC0 + | (0x0 & 0x1) << 2 /* Mirror Y OFF */ + | (0x0 & 0x1) << 1 /* Mirror X OFF */ + | (0x0 & 0x1)); /* MS nibble last (default) */ + break; + case 180: + /* Set RAM address control */ + write_reg(par, 0x88 + | (0x0 & 0x1) << 2 /* Increment positively */ + | (0x0 & 0x1) << 1 /* Increment column first */ + | (0x1 & 0x1)); /* Wrap around (default) */ + + /* Set LCD mapping */ + write_reg(par, 0xC0 + | (0x1 & 0x1) << 2 /* Mirror Y ON */ + | (0x0 & 0x1) << 1 /* Mirror X OFF */ + | (0x0 & 0x1)); /* MS nibble last (default) */ + break; + case 270: + /* Set RAM address control */ + write_reg(par, 0x88 + | (0x0 & 0x1) << 2 /* Increment positively */ + | (0x1 & 0x1) << 1 /* Increment page first */ + | (0x1 & 0x1)); /* Wrap around (default) */ + + /* Set LCD mapping */ + write_reg(par, 0xC0 + | (0x1 & 0x1) << 2 /* Mirror Y ON */ + | (0x1 & 0x1) << 1 /* Mirror X ON */ + | (0x0 & 0x1)); /* MS nibble last (default) */ + break; + default: + /* Set RAM address control */ + write_reg(par, 0x88 + | (0x0 & 0x1) << 2 /* Increment positively */ + | (0x0 & 0x1) << 1 /* Increment column first */ + | (0x1 & 0x1)); /* Wrap around (default) */ + + /* Set LCD mapping */ + write_reg(par, 0xC0 + | (0x0 & 0x1) << 2 /* Mirror Y OFF */ + | (0x1 & 0x1) << 1 /* Mirror X ON */ + | (0x0 & 0x1)); /* MS nibble last (default) */ + break; + } + + return 0; +} + +static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) +{ + u8 *vmem8 = (u8 *)(par->info->screen_base); + u8 *buf8 = (u8 *)(par->txbuf.buf); + u16 *buf16 = (u16 *)(par->txbuf.buf); + int line_length = par->info->fix.line_length; + int y_start = (offset / line_length); + int y_end = (offset + len - 1) / line_length; + int x, y, i; + int ret = 0; + + fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); + + switch (par->pdata->display.buswidth) { + case 8: + switch (par->info->var.rotate) { + case 90: + case 270: + i = y_start * line_length; + for (y = y_start; y <= y_end; y++) { + for (x = 0; x < line_length; x += 2) { + *buf8 = vmem8[i] >> 4; + *buf8 |= vmem8[i + 1] & 0xF0; + buf8++; + i += 2; + } + } + break; + default: + /* Must be even because pages are two lines */ + y_start &= 0xFE; + i = y_start * line_length; + for (y = y_start; y <= y_end; y += 2) { + for (x = 0; x < line_length; x++) { + *buf8 = vmem8[i] >> 4; + *buf8 |= vmem8[i + line_length] & 0xF0; + buf8++; + i++; + } + i += line_length; + } + break; + } + gpio_set_value(par->gpio.dc, 1); + + /* Write data */ + ret = par->fbtftops.write(par, par->txbuf.buf, len / 2); + break; + case 9: + switch (par->info->var.rotate) { + case 90: + case 270: + i = y_start * line_length; + for (y = y_start; y <= y_end; y++) { + for (x = 0; x < line_length; x += 2) { + *buf16 = 0x100; + *buf16 |= vmem8[i] >> 4; + *buf16 |= vmem8[i + 1] & 0xF0; + buf16++; + i += 2; + } + } + break; + default: + /* Must be even because pages are two lines */ + y_start &= 0xFE; + i = y_start * line_length; + for (y = y_start; y <= y_end; y += 2) { + for (x = 0; x < line_length; x++) { + *buf16 = 0x100; + *buf16 |= vmem8[i] >> 4; + *buf16 |= vmem8[i + line_length] & 0xF0; + buf16++; + i++; + } + i += line_length; + } + break; + } + + /* Write data */ + ret = par->fbtftops.write(par, par->txbuf.buf, len); + break; + default: + dev_err(par->info->device, "unsupported buswidth %d\n", + par->pdata->display.buswidth); + } + + if (ret < 0) + dev_err(par->info->device, "write failed and returned: %d\n", + ret); + + return ret; +} + +static struct fbtft_display display = { + .txbuflen = -1, + .regwidth = 8, + .width = WIDTH, + .height = HEIGHT, + .bpp = BPP, + .fps = FPS, + .fbtftops = { + .write_vmem = write_vmem, + .init_display = init_display, + .set_addr_win = set_addr_win, + .set_var = set_var, + .blank = blank, + }, +}; + +FBTFT_REGISTER_DRIVER(DRVNAME, "ultrachip,uc1611", &display); + +MODULE_ALIAS("spi:" DRVNAME); +MODULE_ALIAS("platform:" DRVNAME); +MODULE_ALIAS("spi:uc1611"); +MODULE_ALIAS("platform:uc1611"); + +MODULE_DESCRIPTION("FB driver for the UC1611 LCD controller"); +MODULE_AUTHOR("Henri Chain"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c index 88fb2c013..8eae6ef25 100644 --- a/drivers/staging/fbtft/fb_watterott.c +++ b/drivers/staging/fbtft/fb_watterott.c @@ -169,7 +169,7 @@ static int init_display(struct fbtft_par *par) /* enable SPI interface by having CS and MOSI low during reset */ save_mode = par->spi->mode; par->spi->mode |= SPI_CS_HIGH; - ret = par->spi->master->setup(par->spi); /* set CS inactive low */ + ret = spi_setup(par->spi); /* set CS inactive low */ if (ret) { dev_err(par->info->device, "Could not set SPI_CS_HIGH\n"); return ret; @@ -180,7 +180,7 @@ static int init_display(struct fbtft_par *par) par->fbtftops.reset(par); mdelay(1000); par->spi->mode = save_mode; - ret = par->spi->master->setup(par->spi); + ret = spi_setup(par->spi); if (ret) { dev_err(par->info->device, "Could not restore SPI mode\n"); return ret; diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 9cc81412b..7f5fa3d1c 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -677,13 +677,13 @@ static void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src) * */ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, - struct device *dev) + struct device *dev, + struct fbtft_platform_data *pdata) { struct fb_info *info; struct fbtft_par *par; struct fb_ops *fbops = NULL; struct fb_deferred_io *fbdefio = NULL; - struct fbtft_platform_data *pdata = dev->platform_data; u8 *vmem = NULL; void *txbuf = NULL; void *buf = NULL; @@ -828,7 +828,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, par = info->par; par->info = info; - par->pdata = dev->platform_data; + par->pdata = pdata; par->debug = display->debug; par->buf = buf; spin_lock_init(&par->dirty_lock); @@ -1076,6 +1076,11 @@ static int fbtft_init_display_dt(struct fbtft_par *par) p = of_prop_next_u32(prop, NULL, &val); if (!p) return -EINVAL; + + par->fbtftops.reset(par); + if (par->gpio.cs != -1) + gpio_set_value(par->gpio.cs, 0); /* Activate chip */ + while (p) { if (val & FBTFT_OF_INIT_CMD) { val &= 0xFFFF; @@ -1260,12 +1265,11 @@ EXPORT_SYMBOL(fbtft_init_display); */ static int fbtft_verify_gpios(struct fbtft_par *par) { - struct fbtft_platform_data *pdata; + struct fbtft_platform_data *pdata = par->pdata; int i; fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__); - pdata = par->info->device->platform_data; if (pdata->display.buswidth != 9 && par->startbyte == 0 && par->gpio.dc < 0) { dev_err(par->info->device, @@ -1383,10 +1387,9 @@ int fbtft_probe_common(struct fbtft_display *display, pdata = fbtft_probe_dt(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); - dev->platform_data = pdata; } - info = fbtft_framebuffer_alloc(display, dev); + info = fbtft_framebuffer_alloc(display, dev, pdata); if (!info) return -ENOMEM; @@ -1433,15 +1436,11 @@ int fbtft_probe_common(struct fbtft_display *display, /* 9-bit SPI setup */ if (par->spi && display->buswidth == 9) { - par->spi->bits_per_word = 9; - ret = par->spi->master->setup(par->spi); - if (ret) { + if (par->spi->master->bits_per_word_mask & SPI_BPW_MASK(9)) { + par->spi->bits_per_word = 9; + } else { dev_warn(&par->spi->dev, "9-bit SPI not available, emulating using 8-bit.\n"); - par->spi->bits_per_word = 8; - ret = par->spi->master->setup(par->spi); - if (ret) - goto out_release; /* allocate buffer with room for dc bits */ par->extra = devm_kzalloc(par->info->device, par->txbuf.len + (par->txbuf.len / 8) + 8, diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index 7d817eb26..7e9a506d6 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -262,39 +262,38 @@ struct fbtft_par { par->fbtftops.write_register(par, NUMARGS(__VA_ARGS__), __VA_ARGS__) /* fbtft-core.c */ -extern void fbtft_dbg_hex(const struct device *dev, - int groupsize, void *buf, size_t len, const char *fmt, ...); -extern struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, - struct device *dev); -extern void fbtft_framebuffer_release(struct fb_info *info); -extern int fbtft_register_framebuffer(struct fb_info *fb_info); -extern int fbtft_unregister_framebuffer(struct fb_info *fb_info); -extern void fbtft_register_backlight(struct fbtft_par *par); -extern void fbtft_unregister_backlight(struct fbtft_par *par); -extern int fbtft_init_display(struct fbtft_par *par); -extern int fbtft_probe_common(struct fbtft_display *display, - struct spi_device *sdev, struct platform_device *pdev); -extern int fbtft_remove_common(struct device *dev, struct fb_info *info); +void fbtft_dbg_hex(const struct device *dev, int groupsize, + void *buf, size_t len, const char *fmt, ...); +struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, + struct device *dev, + struct fbtft_platform_data *pdata); +void fbtft_framebuffer_release(struct fb_info *info); +int fbtft_register_framebuffer(struct fb_info *fb_info); +int fbtft_unregister_framebuffer(struct fb_info *fb_info); +void fbtft_register_backlight(struct fbtft_par *par); +void fbtft_unregister_backlight(struct fbtft_par *par); +int fbtft_init_display(struct fbtft_par *par); +int fbtft_probe_common(struct fbtft_display *display, struct spi_device *sdev, + struct platform_device *pdev); +int fbtft_remove_common(struct device *dev, struct fb_info *info); /* fbtft-io.c */ -extern int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len); -extern int fbtft_write_spi_emulate_9(struct fbtft_par *par, - void *buf, size_t len); -extern int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len); -extern int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len); -extern int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len); -extern int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, - void *buf, size_t len); +int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len); +int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len); +int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len); +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); /* fbtft-bus.c */ -extern int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len); -extern int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len); -extern int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len); -extern int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len); -extern void fbtft_write_reg8_bus8(struct fbtft_par *par, int len, ...); -extern void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...); -extern void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...); -extern void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...); +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); +int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len); +int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len); +void fbtft_write_reg8_bus8(struct fbtft_par *par, int len, ...); +void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...); +void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...); +void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...); #define FBTFT_REGISTER_DRIVER(_name, _compatible, _display) \ diff --git a/drivers/staging/fbtft/fbtft_device.c b/drivers/staging/fbtft/fbtft_device.c index 211d50490..fa916e88d 100644 --- a/drivers/staging/fbtft/fbtft_device.c +++ b/drivers/staging/fbtft/fbtft_device.c @@ -397,6 +397,37 @@ static struct fbtft_device_display displays[] = { } } }, { + .name = "ew24ha0", + .spi = &(struct spi_board_info) { + .modalias = "fb_uc1611", + .max_speed_hz = 32000000, + .mode = SPI_MODE_3, + .platform_data = &(struct fbtft_platform_data) { + .display = { + .buswidth = 8, + }, + .gpios = (const struct fbtft_gpio []) { + { "dc", 24 }, + {}, + }, + } + } + }, { + .name = "ew24ha0_9bit", + .spi = &(struct spi_board_info) { + .modalias = "fb_uc1611", + .max_speed_hz = 32000000, + .mode = SPI_MODE_3, + .platform_data = &(struct fbtft_platform_data) { + .display = { + .buswidth = 9, + }, + .gpios = (const struct fbtft_gpio []) { + {}, + }, + } + } + }, { .name = "flexfb", .spi = &(struct spi_board_info) { .modalias = "flexfb", diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c index 2c4ce07f5..3f380a008 100644 --- a/drivers/staging/fbtft/flexfb.c +++ b/drivers/staging/fbtft/flexfb.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> @@ -30,7 +26,6 @@ #define DRVNAME "flexfb" - static char *chip; module_param(chip, charp, 0); MODULE_PARM_DESC(chip, "LCD controller"); @@ -68,7 +63,6 @@ static bool latched; module_param(latched, bool, 0); MODULE_PARM_DESC(latched, "Use with latched 16-bit databus"); - static int *initp; static int initp_num; @@ -132,14 +126,115 @@ 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 }; +/** + * struct flexfb_lcd_controller - Describes the LCD controller properties + * @name: Model name of the chip + * @width: Width of display in pixels + * @height: Height of display in pixels + * @setaddrwin: Which set_addr_win() implementation to use + * @regwidth: LCD Controller Register width in bits + * @init_seq: LCD initialization sequence + * @init_seq_sz: Size of LCD initialization sequence + */ +struct flexfb_lcd_controller { + const char *name; + unsigned int width; + unsigned int height; + unsigned int setaddrwin; + unsigned int regwidth; + int *init_seq; + int init_seq_sz; +}; + +static const struct flexfb_lcd_controller flexfb_chip_table[] = { + { + .name = "st7735r", + .width = 120, + .height = 160, + .init_seq = st7735r_init, + .init_seq_sz = ARRAY_SIZE(st7735r_init), + }, + { + .name = "hx8340bn", + .width = 176, + .height = 220, + .init_seq = hx8340bn_init, + .init_seq_sz = ARRAY_SIZE(hx8340bn_init), + }, + { + .name = "ili9225", + .width = 176, + .height = 220, + .regwidth = 16, + .init_seq = ili9225_init, + .init_seq_sz = ARRAY_SIZE(ili9225_init), + }, + { + .name = "ili9225", + .width = 176, + .height = 220, + .regwidth = 16, + .init_seq = ili9225_init, + .init_seq_sz = ARRAY_SIZE(ili9225_init), + }, + { + .name = "ili9225", + .width = 176, + .height = 220, + .regwidth = 16, + .init_seq = ili9225_init, + .init_seq_sz = ARRAY_SIZE(ili9225_init), + }, + { + .name = "ili9320", + .width = 240, + .height = 320, + .setaddrwin = 1, + .regwidth = 16, + .init_seq = ili9320_init, + .init_seq_sz = ARRAY_SIZE(ili9320_init), + }, + { + .name = "ili9325", + .width = 240, + .height = 320, + .setaddrwin = 1, + .regwidth = 16, + .init_seq = ili9325_init, + .init_seq_sz = ARRAY_SIZE(ili9325_init), + }, + { + .name = "ili9341", + .width = 240, + .height = 320, + .init_seq = ili9341_init, + .init_seq_sz = ARRAY_SIZE(ili9341_init), + }, + { + .name = "ssd1289", + .width = 240, + .height = 320, + .setaddrwin = 2, + .regwidth = 16, + .init_seq = ssd1289_init, + .init_seq_sz = ARRAY_SIZE(ssd1289_init), + }, + { + .name = "ssd1351", + .width = 128, + .height = 128, + .setaddrwin = 3, + .init_seq = ssd1351_init, + .init_seq_sz = ARRAY_SIZE(ssd1351_init), + }, +}; /* ili9320, ili9325 */ static void flexfb_set_addr_win_1(struct fbtft_par *par, int xs, int ys, int xe, int ye) { - fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, - "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", - __func__, xs, ys, xe, ye); + fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", + __func__, xs, ys, xe, ye); switch (par->info->var.rotate) { /* R20h = Horizontal GRAM Start Address */ /* R21h = Vertical GRAM Start Address */ @@ -242,7 +337,7 @@ static int flexfb_verify_gpios_db(struct fbtft_par *par) return -EINVAL; } if (latched) - num_db = buswidth/2; + num_db = buswidth / 2; for (i = 0; i < num_db; i++) { if (par->gpio.db[i] < 0) { dev_err(par->info->device, @@ -255,8 +350,38 @@ static int flexfb_verify_gpios_db(struct fbtft_par *par) return 0; } +static void flexfb_chip_load_param(const struct flexfb_lcd_controller *chip) +{ + if (!width) + width = chip->width; + if (!height) + height = chip->height; + setaddrwin = chip->setaddrwin; + if (chip->regwidth) + regwidth = chip->regwidth; + if (!init_num) { + initp = chip->init_seq; + initp_num = chip->init_seq_sz; + } +} + static struct fbtft_display flex_display = { }; +static int flexfb_chip_init(const struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(flexfb_chip_table); i++) + if (!strcmp(chip, flexfb_chip_table[i].name)) { + flexfb_chip_load_param(&flexfb_chip_table[i]); + return 0; + } + + dev_err(dev, "chip=%s is not supported\n", chip); + + return -EINVAL; +} + static int flexfb_probe_common(struct spi_device *sdev, struct platform_device *pdev) { @@ -277,110 +402,9 @@ static int flexfb_probe_common(struct spi_device *sdev, sdev ? "'SPI device'" : "'Platform device'"); if (chip) { - - if (!strcmp(chip, "st7735r")) { - if (!width) - width = 128; - if (!height) - height = 160; - if (init_num == 0) { - initp = st7735r_init; - initp_num = ARRAY_SIZE(st7735r_init); - } - - - } else if (!strcmp(chip, "hx8340bn")) { - if (!width) - width = 176; - if (!height) - height = 220; - setaddrwin = 0; - if (init_num == 0) { - initp = hx8340bn_init; - initp_num = ARRAY_SIZE(hx8340bn_init); - } - - - } else if (!strcmp(chip, "ili9225")) { - if (!width) - width = 176; - if (!height) - height = 220; - setaddrwin = 0; - regwidth = 16; - if (init_num == 0) { - initp = ili9225_init; - initp_num = ARRAY_SIZE(ili9225_init); - } - - - - } else if (!strcmp(chip, "ili9320")) { - if (!width) - width = 240; - if (!height) - height = 320; - setaddrwin = 1; - regwidth = 16; - if (init_num == 0) { - initp = ili9320_init; - initp_num = ARRAY_SIZE(ili9320_init); - } - - - } else if (!strcmp(chip, "ili9325")) { - if (!width) - width = 240; - if (!height) - height = 320; - setaddrwin = 1; - regwidth = 16; - if (init_num == 0) { - initp = ili9325_init; - initp_num = ARRAY_SIZE(ili9325_init); - } - - } else if (!strcmp(chip, "ili9341")) { - if (!width) - width = 240; - if (!height) - height = 320; - setaddrwin = 0; - regwidth = 8; - if (init_num == 0) { - initp = ili9341_init; - initp_num = ARRAY_SIZE(ili9341_init); - } - - - } else if (!strcmp(chip, "ssd1289")) { - if (!width) - width = 240; - if (!height) - height = 320; - setaddrwin = 2; - regwidth = 16; - if (init_num == 0) { - initp = ssd1289_init; - initp_num = ARRAY_SIZE(ssd1289_init); - } - - - - } else if (!strcmp(chip, "ssd1351")) { - if (!width) - width = 128; - if (!height) - height = 128; - setaddrwin = 3; - if (init_num == 0) { - initp = ssd1351_init; - initp_num = ARRAY_SIZE(ssd1351_init); - } - } else { - dev_err(dev, "chip=%s is not supported\n", chip); - return -EINVAL; - } + ret = flexfb_chip_init(dev); + if (ret) + return ret; } if (width == 0 || height == 0) { @@ -395,7 +419,7 @@ static int flexfb_probe_common(struct spi_device *sdev, fbtft_init_dbg(dev, "regwidth = %d\n", regwidth); fbtft_init_dbg(dev, "buswidth = %d\n", buswidth); - info = fbtft_framebuffer_alloc(&flex_display, dev); + info = fbtft_framebuffer_alloc(&flex_display, dev, dev->platform_data); if (!info) return -ENOMEM; @@ -439,15 +463,12 @@ static int flexfb_probe_common(struct spi_device *sdev, } par->fbtftops.write_register = fbtft_write_reg8_bus9; par->fbtftops.write_vmem = fbtft_write_vmem16_bus9; - sdev->bits_per_word = 9; - ret = sdev->master->setup(sdev); - if (ret) { + if (par->spi->master->bits_per_word_mask + & SPI_BPW_MASK(9)) { + par->spi->bits_per_word = 9; + } else { dev_warn(dev, "9-bit SPI not available, emulating using 8-bit.\n"); - sdev->bits_per_word = 8; - ret = sdev->master->setup(sdev); - if (ret) - goto out_release; /* allocate buffer with room for dc bits */ par->extra = devm_kzalloc(par->info->device, par->txbuf.len + (par->txbuf.len / 8) + 8, @@ -527,8 +548,8 @@ static int flexfb_remove_common(struct device *dev, struct fb_info *info) return -EINVAL; par = info->par; if (par) - fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, - "%s()\n", __func__); + fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, "%s()\n", + __func__); fbtft_unregister_framebuffer(info); fbtft_framebuffer_release(info); |