diff options
Diffstat (limited to 'kernel/drivers/staging/fbtft/fbtft-core.c')
-rw-r--r-- | kernel/drivers/staging/fbtft/fbtft-core.c | 196 |
1 files changed, 80 insertions, 116 deletions
diff --git a/kernel/drivers/staging/fbtft/fbtft-core.c b/kernel/drivers/staging/fbtft/fbtft-core.c index 53b748be2..b1e45161e 100644 --- a/kernel/drivers/staging/fbtft/fbtft-core.c +++ b/kernel/drivers/staging/fbtft/fbtft-core.c @@ -14,10 +14,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> @@ -47,10 +43,11 @@ static unsigned long debug; module_param(debug, ulong, 0); MODULE_PARM_DESC(debug, "override device debug level"); +#ifdef CONFIG_HAS_DMA static bool dma = true; module_param(dma, bool, 0); MODULE_PARM_DESC(dma, "Use DMA buffer"); - +#endif void fbtft_dbg_hex(const struct device *dev, int groupsize, void *buf, size_t len, const char *fmt, ...) @@ -125,33 +122,34 @@ static int fbtft_request_gpios(struct fbtft_par *par) unsigned long flags; int ret; - if (pdata && pdata->gpios) { - gpio = pdata->gpios; - while (gpio->name[0]) { - flags = FBTFT_GPIO_NO_MATCH; - /* if driver provides match function, try it first, - if no match use our own */ - if (par->fbtftops.request_gpios_match) - flags = par->fbtftops.request_gpios_match(par, gpio); - if (flags == FBTFT_GPIO_NO_MATCH) - flags = fbtft_request_gpios_match(par, gpio); - if (flags != FBTFT_GPIO_NO_MATCH) { - ret = devm_gpio_request_one(par->info->device, - gpio->gpio, flags, - par->info->device->driver->name); - if (ret < 0) { - dev_err(par->info->device, - "%s: gpio_request_one('%s'=%d) failed with %d\n", - __func__, gpio->name, - gpio->gpio, ret); - return ret; - } - fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, - "%s: '%s' = GPIO%d\n", - __func__, gpio->name, gpio->gpio); + if (!(pdata && pdata->gpios)) + return 0; + + gpio = pdata->gpios; + while (gpio->name[0]) { + flags = FBTFT_GPIO_NO_MATCH; + /* if driver provides match function, try it first, + if no match use our own */ + if (par->fbtftops.request_gpios_match) + flags = par->fbtftops.request_gpios_match(par, gpio); + if (flags == FBTFT_GPIO_NO_MATCH) + flags = fbtft_request_gpios_match(par, gpio); + if (flags != FBTFT_GPIO_NO_MATCH) { + ret = devm_gpio_request_one(par->info->device, + gpio->gpio, flags, + par->info->device->driver->name); + if (ret < 0) { + dev_err(par->info->device, + "%s: gpio_request_one('%s'=%d) failed with %d\n", + __func__, gpio->name, + gpio->gpio, ret); + return ret; } - gpio++; + fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, + "%s: '%s' = GPIO%d\n", + __func__, gpio->name, gpio->gpio); } + gpio++; } return 0; @@ -268,26 +266,23 @@ static int fbtft_backlight_get_brightness(struct backlight_device *bd) void fbtft_unregister_backlight(struct fbtft_par *par) { - const struct backlight_ops *bl_ops; - - fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); - if (par->info->bl_dev) { par->info->bl_dev->props.power = FB_BLANK_POWERDOWN; backlight_update_status(par->info->bl_dev); - bl_ops = par->info->bl_dev->ops; backlight_device_unregister(par->info->bl_dev); par->info->bl_dev = NULL; } } +static const struct backlight_ops fbtft_bl_ops = { + .get_brightness = fbtft_backlight_get_brightness, + .update_status = fbtft_backlight_update_status, +}; + void fbtft_register_backlight(struct fbtft_par *par) { struct backlight_device *bd; struct backlight_properties bl_props = { 0, }; - struct backlight_ops *bl_ops; - - fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); if (par->gpio.led[0] == -1) { fbtft_par_dbg(DEBUG_BACKLIGHT, par, @@ -295,13 +290,6 @@ void fbtft_register_backlight(struct fbtft_par *par) return; } - bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops), - GFP_KERNEL); - if (!bl_ops) - return; - - bl_ops->get_brightness = fbtft_backlight_get_brightness; - bl_ops->update_status = fbtft_backlight_update_status; bl_props.type = BACKLIGHT_RAW; /* Assume backlight is off, get polarity from current state of pin */ bl_props.power = FB_BLANK_POWERDOWN; @@ -309,7 +297,7 @@ void fbtft_register_backlight(struct fbtft_par *par) bl_props.state |= BL_CORE_DRIVER1; bd = backlight_device_register(dev_driver_string(par->info->device), - par->info->device, par, bl_ops, &bl_props); + par->info->device, par, &fbtft_bl_ops, &bl_props); if (IS_ERR(bd)) { dev_err(par->info->device, "cannot register backlight device (%ld)\n", @@ -331,9 +319,6 @@ EXPORT_SYMBOL(fbtft_unregister_backlight); static void fbtft_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); - /* Column address set */ write_reg(par, 0x2A, (xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF); @@ -346,7 +331,6 @@ static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, write_reg(par, 0x2C); } - static void fbtft_reset(struct fbtft_par *par) { if (par->gpio.reset == -1) @@ -358,13 +342,11 @@ static void fbtft_reset(struct fbtft_par *par) mdelay(120); } - static void fbtft_update_display(struct fbtft_par *par, unsigned start_line, unsigned end_line) { size_t offset, len; - struct timespec ts_start, ts_end, ts_fps, ts_duration; - long fps_ms, fps_us, duration_ms, duration_us; + ktime_t ts_start, ts_end; long fps, throughput; bool timeit = false; int ret = 0; @@ -372,7 +354,7 @@ static void fbtft_update_display(struct fbtft_par *par, unsigned start_line, if (unlikely(par->debug & (DEBUG_TIME_FIRST_UPDATE | DEBUG_TIME_EACH_UPDATE))) { if ((par->debug & DEBUG_TIME_EACH_UPDATE) || ((par->debug & DEBUG_TIME_FIRST_UPDATE) && !par->first_update_done)) { - getnstimeofday(&ts_start); + ts_start = ktime_get(); timeit = true; } } @@ -398,7 +380,7 @@ static void fbtft_update_display(struct fbtft_par *par, unsigned start_line, if (par->fbtftops.set_addr_win) par->fbtftops.set_addr_win(par, 0, start_line, - par->info->var.xres-1, end_line); + par->info->var.xres - 1, end_line); offset = start_line * par->info->fix.line_length; len = (end_line - start_line + 1) * par->info->fix.line_length; @@ -409,35 +391,25 @@ static void fbtft_update_display(struct fbtft_par *par, unsigned start_line, __func__); if (unlikely(timeit)) { - getnstimeofday(&ts_end); - if (par->update_time.tv_nsec == 0 && par->update_time.tv_sec == 0) { - par->update_time.tv_sec = ts_start.tv_sec; - par->update_time.tv_nsec = ts_start.tv_nsec; - } - ts_fps = timespec_sub(ts_start, par->update_time); - par->update_time.tv_sec = ts_start.tv_sec; - par->update_time.tv_nsec = ts_start.tv_nsec; - fps_ms = (ts_fps.tv_sec * 1000) + ((ts_fps.tv_nsec / 1000000) % 1000); - fps_us = (ts_fps.tv_nsec / 1000) % 1000; - fps = fps_ms * 1000 + fps_us; + ts_end = ktime_get(); + if (ktime_to_ns(par->update_time)) + par->update_time = ts_start; + + par->update_time = ts_start; + fps = ktime_us_delta(ts_start, par->update_time); fps = fps ? 1000000 / fps : 0; - ts_duration = timespec_sub(ts_end, ts_start); - duration_ms = (ts_duration.tv_sec * 1000) + ((ts_duration.tv_nsec / 1000000) % 1000); - duration_us = (ts_duration.tv_nsec / 1000) % 1000; - throughput = duration_ms * 1000 + duration_us; + throughput = ktime_us_delta(ts_end, ts_start); throughput = throughput ? (len * 1000) / throughput : 0; throughput = throughput * 1000 / 1024; dev_info(par->info->device, - "Display update: %ld kB/s (%ld.%.3ld ms), fps=%ld (%ld.%.3ld ms)\n", - throughput, duration_ms, duration_us, - fps, fps_ms, fps_us); + "Display update: %ld kB/s, fps=%ld\n", + throughput, fps); par->first_update_done = true; } } - static void fbtft_mkdirty(struct fb_info *info, int y, int height) { struct fbtft_par *par = info->par; @@ -484,7 +456,7 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) index = page->index << PAGE_SHIFT; y_low = index / info->fix.line_length; y_high = (index + PAGE_SIZE - 1) / info->fix.line_length; - fbtft_dev_dbg(DEBUG_DEFERRED_IO, par, info->device, + dev_dbg(info->device, "page->index=%lu y_low=%d y_high=%d\n", page->index, y_low, y_high); if (y_high > info->var.yres - 1) @@ -499,13 +471,12 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) dirty_lines_start, dirty_lines_end); } - static void fbtft_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct fbtft_par *par = info->par; - fbtft_dev_dbg(DEBUG_FB_FILLRECT, par, info->dev, + dev_dbg(info->dev, "%s: dx=%d, dy=%d, width=%d, height=%d\n", __func__, rect->dx, rect->dy, rect->width, rect->height); sys_fillrect(info, rect); @@ -518,7 +489,7 @@ static void fbtft_fb_copyarea(struct fb_info *info, { struct fbtft_par *par = info->par; - fbtft_dev_dbg(DEBUG_FB_COPYAREA, par, info->dev, + dev_dbg(info->dev, "%s: dx=%d, dy=%d, width=%d, height=%d\n", __func__, area->dx, area->dy, area->width, area->height); sys_copyarea(info, area); @@ -531,7 +502,7 @@ static void fbtft_fb_imageblit(struct fb_info *info, { struct fbtft_par *par = info->par; - fbtft_dev_dbg(DEBUG_FB_IMAGEBLIT, par, info->dev, + dev_dbg(info->dev, "%s: dx=%d, dy=%d, width=%d, height=%d\n", __func__, image->dx, image->dy, image->width, image->height); sys_imageblit(info, image); @@ -545,7 +516,7 @@ static ssize_t fbtft_fb_write(struct fb_info *info, const char __user *buf, struct fbtft_par *par = info->par; ssize_t res; - fbtft_dev_dbg(DEBUG_FB_WRITE, par, info->dev, + dev_dbg(info->dev, "%s: count=%zd, ppos=%llu\n", __func__, count, *ppos); res = fb_sys_write(info, buf, count, ppos); @@ -568,11 +539,10 @@ static int fbtft_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - struct fbtft_par *par = info->par; unsigned val; int ret = 1; - fbtft_dev_dbg(DEBUG_FB_SETCOLREG, par, info->dev, + dev_dbg(info->dev, "%s(regno=%u, red=0x%X, green=0x%X, blue=0x%X, trans=0x%X)\n", __func__, regno, red, green, blue, transp); @@ -599,7 +569,7 @@ static int fbtft_fb_blank(int blank, struct fb_info *info) struct fbtft_par *par = info->par; int ret = -EINVAL; - fbtft_dev_dbg(DEBUG_FB_BLANK, par, info->dev, "%s(blank=%d)\n", + dev_dbg(info->dev, "%s(blank=%d)\n", __func__, blank); if (!par->fbtftops.blank) @@ -676,13 +646,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; @@ -778,7 +748,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, if (!info) goto alloc_fail; - info->screen_base = (u8 __force __iomem *)vmem; + info->screen_buffer = vmem; info->fbops = fbops; info->fbdefio = fbdefio; @@ -801,7 +771,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, info->fix.xpanstep = 0; info->fix.ypanstep = 0; info->fix.ywrapstep = 0; - info->fix.line_length = width*bpp/8; + info->fix.line_length = width * bpp / 8; info->fix.accel = FB_ACCEL_NONE; info->fix.smem_len = vmem_size; @@ -827,7 +797,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); @@ -856,10 +826,13 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, #endif if (txbuflen > 0) { +#ifdef CONFIG_HAS_DMA if (dma) { dev->coherent_dma_mask = ~0; txbuf = dmam_alloc_coherent(dev, txbuflen, &par->txbuf.dma, GFP_DMA); - } else { + } else +#endif + { txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL); } if (!txbuf) @@ -915,7 +888,7 @@ EXPORT_SYMBOL(fbtft_framebuffer_alloc); void fbtft_framebuffer_release(struct fb_info *info) { fb_deferred_io_cleanup(info); - vfree(info->screen_base); + vfree(info->screen_buffer); framebuffer_release(info); } EXPORT_SYMBOL(fbtft_framebuffer_release); @@ -994,12 +967,12 @@ int fbtft_register_framebuffer(struct fb_info *fb_info) par->txbuf.len >> 10, par->txbuf.dma ? "DMA " : ""); if (spi) sprintf(text2, ", spi%d.%d at %d MHz", spi->master->bus_num, - spi->chip_select, spi->max_speed_hz/1000000); + spi->chip_select, spi->max_speed_hz / 1000000); dev_info(fb_info->dev, "%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n", fb_info->fix.id, fb_info->var.xres, fb_info->var.yres, fb_info->fix.smem_len >> 10, text1, - HZ/fb_info->fbdefio->delay, text2); + HZ / fb_info->fbdefio->delay, text2); #ifdef CONFIG_FB_BACKLIGHT /* Turn on backlight if available */ @@ -1062,10 +1035,6 @@ static int fbtft_init_display_dt(struct fbtft_par *par) const __be32 *p; u32 val; int buf[64], i, j; - char msg[128]; - char str[16]; - - fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); if (!node) return -EINVAL; @@ -1074,6 +1043,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; @@ -1089,13 +1063,11 @@ static int fbtft_init_display_dt(struct fbtft_par *par) p = of_prop_next_u32(prop, p, &val); } /* make debug message */ - msg[0] = '\0'; - for (j = 0; j < i; j++) { - snprintf(str, 128, " %02X", buf[j]); - strcat(msg, str); - } fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, - "init: write_register:%s\n", msg); + "init: write_register:\n"); + for (j = 0; j < i; j++) + fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, + "buf[%d] = %02X\n", j, buf[j]); par->fbtftops.write_register(par, i, buf[0], buf[1], buf[2], buf[3], @@ -1146,8 +1118,6 @@ int fbtft_init_display(struct fbtft_par *par) int i = 0; int j; - fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); - /* sanity check */ if (!par->init_sequence) { dev_err(par->info->device, @@ -1180,7 +1150,7 @@ int fbtft_init_display(struct fbtft_par *par) "missing delimiter at position %d\n", i); return -EINVAL; } - if (par->init_sequence[i+1] < 0) { + if (par->init_sequence[i + 1] < 0) { dev_err(par->info->device, "missing value after delimiter %d at position %d\n", par->init_sequence[i], i); @@ -1260,12 +1230,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 +1352,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 +1401,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, |