Commit | Line | Data |
---|---|---|
c296d5f9 TP |
1 | /* |
2 | * Copyright (C) 2013 Noralf Tronnes | |
3 | * | |
4 | * This driver is inspired by: | |
5 | * st7735fb.c, Copyright (C) 2011, Matt Porter | |
6 | * broadsheetfb.c, Copyright (C) 2008, Jaya Kumar | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
c296d5f9 TP |
17 | */ |
18 | ||
19 | #include <linux/module.h> | |
20 | #include <linux/kernel.h> | |
21 | #include <linux/errno.h> | |
22 | #include <linux/string.h> | |
23 | #include <linux/mm.h> | |
24 | #include <linux/vmalloc.h> | |
25 | #include <linux/slab.h> | |
26 | #include <linux/init.h> | |
27 | #include <linux/fb.h> | |
28 | #include <linux/gpio.h> | |
29 | #include <linux/spi/spi.h> | |
30 | #include <linux/delay.h> | |
31 | #include <linux/uaccess.h> | |
32 | #include <linux/backlight.h> | |
33 | #include <linux/platform_device.h> | |
34 | #include <linux/spinlock.h> | |
35 | #include <linux/dma-mapping.h> | |
36 | #include <linux/of.h> | |
37 | #include <linux/of_gpio.h> | |
a79cb390 | 38 | #include <video/mipi_display.h> |
c296d5f9 TP |
39 | |
40 | #include "fbtft.h" | |
d9fabbde | 41 | #include "internal.h" |
c296d5f9 TP |
42 | |
43 | static unsigned long debug; | |
7e059db6 | 44 | module_param(debug, ulong, 0); |
c296d5f9 TP |
45 | MODULE_PARM_DESC(debug, "override device debug level"); |
46 | ||
8e1a4c7f | 47 | #ifdef CONFIG_HAS_DMA |
c296d5f9 TP |
48 | static bool dma = true; |
49 | module_param(dma, bool, 0); | |
50 | MODULE_PARM_DESC(dma, "Use DMA buffer"); | |
8e1a4c7f | 51 | #endif |
c296d5f9 | 52 | |
c296d5f9 TP |
53 | void fbtft_dbg_hex(const struct device *dev, int groupsize, |
54 | void *buf, size_t len, const char *fmt, ...) | |
55 | { | |
56 | va_list args; | |
57 | static char textbuf[512]; | |
58 | char *text = textbuf; | |
59 | size_t text_len; | |
60 | ||
61 | va_start(args, fmt); | |
62 | text_len = vscnprintf(text, sizeof(textbuf), fmt, args); | |
63 | va_end(args); | |
64 | ||
65 | hex_dump_to_buffer(buf, len, 32, groupsize, text + text_len, | |
66 | 512 - text_len, false); | |
67 | ||
68 | if (len > 32) | |
69 | dev_info(dev, "%s ...\n", text); | |
70 | else | |
71 | dev_info(dev, "%s\n", text); | |
72 | } | |
73 | EXPORT_SYMBOL(fbtft_dbg_hex); | |
74 | ||
ed208436 | 75 | static unsigned long fbtft_request_gpios_match(struct fbtft_par *par, |
c296d5f9 TP |
76 | const struct fbtft_gpio *gpio) |
77 | { | |
78 | int ret; | |
79 | long val; | |
80 | ||
81 | fbtft_par_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, "%s('%s')\n", | |
82 | __func__, gpio->name); | |
83 | ||
84 | if (strcasecmp(gpio->name, "reset") == 0) { | |
85 | par->gpio.reset = gpio->gpio; | |
86 | return GPIOF_OUT_INIT_HIGH; | |
87 | } else if (strcasecmp(gpio->name, "dc") == 0) { | |
88 | par->gpio.dc = gpio->gpio; | |
89 | return GPIOF_OUT_INIT_LOW; | |
90 | } else if (strcasecmp(gpio->name, "cs") == 0) { | |
91 | par->gpio.cs = gpio->gpio; | |
92 | return GPIOF_OUT_INIT_HIGH; | |
93 | } else if (strcasecmp(gpio->name, "wr") == 0) { | |
94 | par->gpio.wr = gpio->gpio; | |
95 | return GPIOF_OUT_INIT_HIGH; | |
96 | } else if (strcasecmp(gpio->name, "rd") == 0) { | |
97 | par->gpio.rd = gpio->gpio; | |
98 | return GPIOF_OUT_INIT_HIGH; | |
99 | } else if (strcasecmp(gpio->name, "latch") == 0) { | |
100 | par->gpio.latch = gpio->gpio; | |
101 | return GPIOF_OUT_INIT_LOW; | |
102 | } else if (gpio->name[0] == 'd' && gpio->name[1] == 'b') { | |
103 | ret = kstrtol(&gpio->name[2], 10, &val); | |
104 | if (ret == 0 && val < 16) { | |
105 | par->gpio.db[val] = gpio->gpio; | |
106 | return GPIOF_OUT_INIT_LOW; | |
107 | } | |
108 | } else if (strcasecmp(gpio->name, "led") == 0) { | |
109 | par->gpio.led[0] = gpio->gpio; | |
110 | return GPIOF_OUT_INIT_LOW; | |
111 | } else if (strcasecmp(gpio->name, "led_") == 0) { | |
112 | par->gpio.led[0] = gpio->gpio; | |
113 | return GPIOF_OUT_INIT_HIGH; | |
114 | } | |
115 | ||
116 | return FBTFT_GPIO_NO_MATCH; | |
117 | } | |
118 | ||
ed208436 | 119 | static int fbtft_request_gpios(struct fbtft_par *par) |
c296d5f9 TP |
120 | { |
121 | struct fbtft_platform_data *pdata = par->pdata; | |
122 | const struct fbtft_gpio *gpio; | |
123 | unsigned long flags; | |
124 | int ret; | |
125 | ||
ed20c6fb MR |
126 | if (!(pdata && pdata->gpios)) |
127 | return 0; | |
128 | ||
129 | gpio = pdata->gpios; | |
130 | while (gpio->name[0]) { | |
131 | flags = FBTFT_GPIO_NO_MATCH; | |
132 | /* if driver provides match function, try it first, | |
e4d1bff1 AJ |
133 | * if no match use our own |
134 | */ | |
ed20c6fb MR |
135 | if (par->fbtftops.request_gpios_match) |
136 | flags = par->fbtftops.request_gpios_match(par, gpio); | |
137 | if (flags == FBTFT_GPIO_NO_MATCH) | |
138 | flags = fbtft_request_gpios_match(par, gpio); | |
139 | if (flags != FBTFT_GPIO_NO_MATCH) { | |
140 | ret = devm_gpio_request_one(par->info->device, | |
141 | gpio->gpio, flags, | |
142 | par->info->device->driver->name); | |
143 | if (ret < 0) { | |
144 | dev_err(par->info->device, | |
145 | "%s: gpio_request_one('%s'=%d) failed with %d\n", | |
146 | __func__, gpio->name, | |
147 | gpio->gpio, ret); | |
148 | return ret; | |
c296d5f9 | 149 | } |
ed20c6fb MR |
150 | fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, |
151 | "%s: '%s' = GPIO%d\n", | |
152 | __func__, gpio->name, gpio->gpio); | |
c296d5f9 | 153 | } |
ed20c6fb | 154 | gpio++; |
c296d5f9 TP |
155 | } |
156 | ||
157 | return 0; | |
158 | } | |
159 | ||
160 | #ifdef CONFIG_OF | |
161 | static int fbtft_request_one_gpio(struct fbtft_par *par, | |
162 | const char *name, int index, int *gpiop) | |
163 | { | |
164 | struct device *dev = par->info->device; | |
165 | struct device_node *node = dev->of_node; | |
166 | int gpio, flags, ret = 0; | |
167 | enum of_gpio_flags of_flags; | |
168 | ||
169 | if (of_find_property(node, name, NULL)) { | |
170 | gpio = of_get_named_gpio_flags(node, name, index, &of_flags); | |
171 | if (gpio == -ENOENT) | |
172 | return 0; | |
173 | if (gpio == -EPROBE_DEFER) | |
174 | return gpio; | |
175 | if (gpio < 0) { | |
176 | dev_err(dev, | |
177 | "failed to get '%s' from DT\n", name); | |
178 | return gpio; | |
179 | } | |
180 | ||
181 | /* active low translates to initially low */ | |
182 | flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW : | |
183 | GPIOF_OUT_INIT_HIGH; | |
184 | ret = devm_gpio_request_one(dev, gpio, flags, | |
185 | dev->driver->name); | |
186 | if (ret) { | |
187 | dev_err(dev, | |
188 | "gpio_request_one('%s'=%d) failed with %d\n", | |
189 | name, gpio, ret); | |
190 | return ret; | |
191 | } | |
192 | if (gpiop) | |
193 | *gpiop = gpio; | |
194 | fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n", | |
195 | __func__, name, gpio); | |
196 | } | |
197 | ||
198 | return ret; | |
199 | } | |
200 | ||
201 | static int fbtft_request_gpios_dt(struct fbtft_par *par) | |
202 | { | |
203 | int i; | |
204 | int ret; | |
205 | ||
206 | if (!par->info->device->of_node) | |
207 | return -EINVAL; | |
208 | ||
209 | ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset); | |
210 | if (ret) | |
211 | return ret; | |
212 | ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc); | |
213 | if (ret) | |
214 | return ret; | |
215 | ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd); | |
216 | if (ret) | |
217 | return ret; | |
218 | ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr); | |
219 | if (ret) | |
220 | return ret; | |
221 | ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs); | |
222 | if (ret) | |
223 | return ret; | |
224 | ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch); | |
225 | if (ret) | |
226 | return ret; | |
227 | for (i = 0; i < 16; i++) { | |
228 | ret = fbtft_request_one_gpio(par, "db-gpios", i, | |
229 | &par->gpio.db[i]); | |
230 | if (ret) | |
231 | return ret; | |
232 | ret = fbtft_request_one_gpio(par, "led-gpios", i, | |
233 | &par->gpio.led[i]); | |
234 | if (ret) | |
235 | return ret; | |
236 | ret = fbtft_request_one_gpio(par, "aux-gpios", i, | |
237 | &par->gpio.aux[i]); | |
238 | if (ret) | |
239 | return ret; | |
240 | } | |
241 | ||
242 | return 0; | |
243 | } | |
244 | #endif | |
245 | ||
246 | #ifdef CONFIG_FB_BACKLIGHT | |
ed208436 | 247 | static int fbtft_backlight_update_status(struct backlight_device *bd) |
c296d5f9 TP |
248 | { |
249 | struct fbtft_par *par = bl_get_data(bd); | |
250 | bool polarity = !!(bd->props.state & BL_CORE_DRIVER1); | |
251 | ||
252 | fbtft_par_dbg(DEBUG_BACKLIGHT, par, | |
253 | "%s: polarity=%d, power=%d, fb_blank=%d\n", | |
254 | __func__, polarity, bd->props.power, bd->props.fb_blank); | |
255 | ||
256 | if ((bd->props.power == FB_BLANK_UNBLANK) && (bd->props.fb_blank == FB_BLANK_UNBLANK)) | |
257 | gpio_set_value(par->gpio.led[0], polarity); | |
258 | else | |
259 | gpio_set_value(par->gpio.led[0], !polarity); | |
260 | ||
261 | return 0; | |
262 | } | |
263 | ||
ed208436 | 264 | static int fbtft_backlight_get_brightness(struct backlight_device *bd) |
c296d5f9 TP |
265 | { |
266 | return bd->props.brightness; | |
267 | } | |
268 | ||
269 | void fbtft_unregister_backlight(struct fbtft_par *par) | |
270 | { | |
c296d5f9 TP |
271 | if (par->info->bl_dev) { |
272 | par->info->bl_dev->props.power = FB_BLANK_POWERDOWN; | |
273 | backlight_update_status(par->info->bl_dev); | |
c296d5f9 TP |
274 | backlight_device_unregister(par->info->bl_dev); |
275 | par->info->bl_dev = NULL; | |
276 | } | |
277 | } | |
278 | ||
c18d116d MR |
279 | static const struct backlight_ops fbtft_bl_ops = { |
280 | .get_brightness = fbtft_backlight_get_brightness, | |
281 | .update_status = fbtft_backlight_update_status, | |
282 | }; | |
283 | ||
c296d5f9 TP |
284 | void fbtft_register_backlight(struct fbtft_par *par) |
285 | { | |
286 | struct backlight_device *bd; | |
287 | struct backlight_properties bl_props = { 0, }; | |
c296d5f9 | 288 | |
c296d5f9 TP |
289 | if (par->gpio.led[0] == -1) { |
290 | fbtft_par_dbg(DEBUG_BACKLIGHT, par, | |
291 | "%s(): led pin not set, exiting.\n", __func__); | |
292 | return; | |
293 | } | |
294 | ||
c296d5f9 TP |
295 | bl_props.type = BACKLIGHT_RAW; |
296 | /* Assume backlight is off, get polarity from current state of pin */ | |
297 | bl_props.power = FB_BLANK_POWERDOWN; | |
298 | if (!gpio_get_value(par->gpio.led[0])) | |
299 | bl_props.state |= BL_CORE_DRIVER1; | |
300 | ||
301 | bd = backlight_device_register(dev_driver_string(par->info->device), | |
c18d116d | 302 | par->info->device, par, &fbtft_bl_ops, &bl_props); |
c296d5f9 TP |
303 | if (IS_ERR(bd)) { |
304 | dev_err(par->info->device, | |
305 | "cannot register backlight device (%ld)\n", | |
306 | PTR_ERR(bd)); | |
307 | return; | |
308 | } | |
309 | par->info->bl_dev = bd; | |
310 | ||
311 | if (!par->fbtftops.unregister_backlight) | |
312 | par->fbtftops.unregister_backlight = fbtft_unregister_backlight; | |
313 | } | |
314 | #else | |
315 | void fbtft_register_backlight(struct fbtft_par *par) { }; | |
316 | void fbtft_unregister_backlight(struct fbtft_par *par) { }; | |
317 | #endif | |
318 | EXPORT_SYMBOL(fbtft_register_backlight); | |
319 | EXPORT_SYMBOL(fbtft_unregister_backlight); | |
320 | ||
ed208436 KA |
321 | static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, |
322 | int ye) | |
c296d5f9 | 323 | { |
a79cb390 PL |
324 | write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, |
325 | (xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF); | |
c296d5f9 | 326 | |
a79cb390 PL |
327 | write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, |
328 | (ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF); | |
c296d5f9 | 329 | |
a79cb390 | 330 | write_reg(par, MIPI_DCS_WRITE_MEMORY_START); |
c296d5f9 TP |
331 | } |
332 | ||
ed208436 | 333 | static void fbtft_reset(struct fbtft_par *par) |
c296d5f9 TP |
334 | { |
335 | if (par->gpio.reset == -1) | |
336 | return; | |
337 | fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__); | |
338 | gpio_set_value(par->gpio.reset, 0); | |
339 | udelay(20); | |
340 | gpio_set_value(par->gpio.reset, 1); | |
341 | mdelay(120); | |
342 | } | |
343 | ||
ed208436 KA |
344 | static void fbtft_update_display(struct fbtft_par *par, unsigned start_line, |
345 | unsigned end_line) | |
c296d5f9 TP |
346 | { |
347 | size_t offset, len; | |
367e8560 | 348 | ktime_t ts_start, ts_end; |
c296d5f9 TP |
349 | long fps, throughput; |
350 | bool timeit = false; | |
351 | int ret = 0; | |
352 | ||
353 | if (unlikely(par->debug & (DEBUG_TIME_FIRST_UPDATE | DEBUG_TIME_EACH_UPDATE))) { | |
6ba67a5a | 354 | if ((par->debug & DEBUG_TIME_EACH_UPDATE) || |
c296d5f9 | 355 | ((par->debug & DEBUG_TIME_FIRST_UPDATE) && !par->first_update_done)) { |
367e8560 | 356 | ts_start = ktime_get(); |
c296d5f9 TP |
357 | timeit = true; |
358 | } | |
359 | } | |
360 | ||
361 | /* Sanity checks */ | |
362 | if (start_line > end_line) { | |
363 | dev_warn(par->info->device, | |
364 | "%s: start_line=%u is larger than end_line=%u. Shouldn't happen, will do full display update\n", | |
365 | __func__, start_line, end_line); | |
366 | start_line = 0; | |
367 | end_line = par->info->var.yres - 1; | |
368 | } | |
369 | if (start_line > par->info->var.yres - 1 || end_line > par->info->var.yres - 1) { | |
370 | dev_warn(par->info->device, | |
371 | "%s: start_line=%u or end_line=%u is larger than max=%d. Shouldn't happen, will do full display update\n", | |
372 | __func__, start_line, end_line, par->info->var.yres - 1); | |
373 | start_line = 0; | |
374 | end_line = par->info->var.yres - 1; | |
375 | } | |
376 | ||
377 | fbtft_par_dbg(DEBUG_UPDATE_DISPLAY, par, "%s(start_line=%u, end_line=%u)\n", | |
378 | __func__, start_line, end_line); | |
379 | ||
380 | if (par->fbtftops.set_addr_win) | |
381 | par->fbtftops.set_addr_win(par, 0, start_line, | |
94c0a544 | 382 | par->info->var.xres - 1, end_line); |
c296d5f9 TP |
383 | |
384 | offset = start_line * par->info->fix.line_length; | |
385 | len = (end_line - start_line + 1) * par->info->fix.line_length; | |
386 | ret = par->fbtftops.write_vmem(par, offset, len); | |
387 | if (ret < 0) | |
388 | dev_err(par->info->device, | |
389 | "%s: write_vmem failed to update display buffer\n", | |
390 | __func__); | |
391 | ||
392 | if (unlikely(timeit)) { | |
367e8560 | 393 | ts_end = ktime_get(); |
e87e0de4 | 394 | if (!ktime_to_ns(par->update_time)) |
367e8560 KS |
395 | par->update_time = ts_start; |
396 | ||
367e8560 | 397 | fps = ktime_us_delta(ts_start, par->update_time); |
e87e0de4 | 398 | par->update_time = ts_start; |
c296d5f9 TP |
399 | fps = fps ? 1000000 / fps : 0; |
400 | ||
367e8560 | 401 | throughput = ktime_us_delta(ts_end, ts_start); |
c296d5f9 TP |
402 | throughput = throughput ? (len * 1000) / throughput : 0; |
403 | throughput = throughput * 1000 / 1024; | |
404 | ||
405 | dev_info(par->info->device, | |
367e8560 KS |
406 | "Display update: %ld kB/s, fps=%ld\n", |
407 | throughput, fps); | |
c296d5f9 TP |
408 | par->first_update_done = true; |
409 | } | |
410 | } | |
411 | ||
ed208436 | 412 | static void fbtft_mkdirty(struct fb_info *info, int y, int height) |
c296d5f9 TP |
413 | { |
414 | struct fbtft_par *par = info->par; | |
415 | struct fb_deferred_io *fbdefio = info->fbdefio; | |
416 | ||
417 | /* special case, needed ? */ | |
418 | if (y == -1) { | |
419 | y = 0; | |
420 | height = info->var.yres - 1; | |
421 | } | |
422 | ||
423 | /* Mark display lines/area as dirty */ | |
424 | spin_lock(&par->dirty_lock); | |
425 | if (y < par->dirty_lines_start) | |
426 | par->dirty_lines_start = y; | |
427 | if (y + height - 1 > par->dirty_lines_end) | |
428 | par->dirty_lines_end = y + height - 1; | |
429 | spin_unlock(&par->dirty_lock); | |
430 | ||
431 | /* Schedule deferred_io to update display (no-op if already on queue)*/ | |
432 | schedule_delayed_work(&info->deferred_work, fbdefio->delay); | |
433 | } | |
434 | ||
ed208436 | 435 | static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) |
c296d5f9 TP |
436 | { |
437 | struct fbtft_par *par = info->par; | |
438 | unsigned dirty_lines_start, dirty_lines_end; | |
439 | struct page *page; | |
440 | unsigned long index; | |
441 | unsigned y_low = 0, y_high = 0; | |
442 | int count = 0; | |
443 | ||
444 | spin_lock(&par->dirty_lock); | |
445 | dirty_lines_start = par->dirty_lines_start; | |
446 | dirty_lines_end = par->dirty_lines_end; | |
447 | /* set display line markers as clean */ | |
448 | par->dirty_lines_start = par->info->var.yres - 1; | |
449 | par->dirty_lines_end = 0; | |
450 | spin_unlock(&par->dirty_lock); | |
451 | ||
452 | /* Mark display lines as dirty */ | |
453 | list_for_each_entry(page, pagelist, lru) { | |
454 | count++; | |
455 | index = page->index << PAGE_SHIFT; | |
456 | y_low = index / info->fix.line_length; | |
457 | y_high = (index + PAGE_SIZE - 1) / info->fix.line_length; | |
b38c760a | 458 | dev_dbg(info->device, |
c296d5f9 TP |
459 | "page->index=%lu y_low=%d y_high=%d\n", |
460 | page->index, y_low, y_high); | |
461 | if (y_high > info->var.yres - 1) | |
462 | y_high = info->var.yres - 1; | |
463 | if (y_low < dirty_lines_start) | |
464 | dirty_lines_start = y_low; | |
465 | if (y_high > dirty_lines_end) | |
466 | dirty_lines_end = y_high; | |
467 | } | |
468 | ||
469 | par->fbtftops.update_display(info->par, | |
470 | dirty_lines_start, dirty_lines_end); | |
471 | } | |
472 | ||
ed208436 KA |
473 | static void fbtft_fb_fillrect(struct fb_info *info, |
474 | const struct fb_fillrect *rect) | |
c296d5f9 TP |
475 | { |
476 | struct fbtft_par *par = info->par; | |
477 | ||
b38c760a | 478 | dev_dbg(info->dev, |
c296d5f9 TP |
479 | "%s: dx=%d, dy=%d, width=%d, height=%d\n", |
480 | __func__, rect->dx, rect->dy, rect->width, rect->height); | |
481 | sys_fillrect(info, rect); | |
482 | ||
483 | par->fbtftops.mkdirty(info, rect->dy, rect->height); | |
484 | } | |
485 | ||
ed208436 KA |
486 | static void fbtft_fb_copyarea(struct fb_info *info, |
487 | const struct fb_copyarea *area) | |
c296d5f9 TP |
488 | { |
489 | struct fbtft_par *par = info->par; | |
490 | ||
b38c760a | 491 | dev_dbg(info->dev, |
c296d5f9 TP |
492 | "%s: dx=%d, dy=%d, width=%d, height=%d\n", |
493 | __func__, area->dx, area->dy, area->width, area->height); | |
494 | sys_copyarea(info, area); | |
495 | ||
496 | par->fbtftops.mkdirty(info, area->dy, area->height); | |
497 | } | |
498 | ||
ed208436 KA |
499 | static void fbtft_fb_imageblit(struct fb_info *info, |
500 | const struct fb_image *image) | |
c296d5f9 TP |
501 | { |
502 | struct fbtft_par *par = info->par; | |
503 | ||
b38c760a | 504 | dev_dbg(info->dev, |
c296d5f9 TP |
505 | "%s: dx=%d, dy=%d, width=%d, height=%d\n", |
506 | __func__, image->dx, image->dy, image->width, image->height); | |
507 | sys_imageblit(info, image); | |
508 | ||
509 | par->fbtftops.mkdirty(info, image->dy, image->height); | |
510 | } | |
511 | ||
ed208436 KA |
512 | static ssize_t fbtft_fb_write(struct fb_info *info, const char __user *buf, |
513 | size_t count, loff_t *ppos) | |
c296d5f9 TP |
514 | { |
515 | struct fbtft_par *par = info->par; | |
516 | ssize_t res; | |
517 | ||
b38c760a | 518 | dev_dbg(info->dev, |
c296d5f9 TP |
519 | "%s: count=%zd, ppos=%llu\n", __func__, count, *ppos); |
520 | res = fb_sys_write(info, buf, count, ppos); | |
521 | ||
e4d1bff1 | 522 | /* TODO: only mark changed area update all for now */ |
c296d5f9 TP |
523 | par->fbtftops.mkdirty(info, -1, 0); |
524 | ||
525 | return res; | |
526 | } | |
527 | ||
528 | /* from pxafb.c */ | |
ed208436 | 529 | static unsigned int chan_to_field(unsigned chan, struct fb_bitfield *bf) |
c296d5f9 TP |
530 | { |
531 | chan &= 0xffff; | |
532 | chan >>= 16 - bf->length; | |
533 | return chan << bf->offset; | |
534 | } | |
535 | ||
ed208436 KA |
536 | static int fbtft_fb_setcolreg(unsigned regno, unsigned red, unsigned green, |
537 | unsigned blue, unsigned transp, | |
538 | struct fb_info *info) | |
c296d5f9 | 539 | { |
c296d5f9 TP |
540 | unsigned val; |
541 | int ret = 1; | |
542 | ||
b38c760a | 543 | dev_dbg(info->dev, |
c296d5f9 TP |
544 | "%s(regno=%u, red=0x%X, green=0x%X, blue=0x%X, trans=0x%X)\n", |
545 | __func__, regno, red, green, blue, transp); | |
546 | ||
547 | switch (info->fix.visual) { | |
548 | case FB_VISUAL_TRUECOLOR: | |
549 | if (regno < 16) { | |
550 | u32 *pal = info->pseudo_palette; | |
551 | ||
552 | val = chan_to_field(red, &info->var.red); | |
553 | val |= chan_to_field(green, &info->var.green); | |
554 | val |= chan_to_field(blue, &info->var.blue); | |
555 | ||
556 | pal[regno] = val; | |
557 | ret = 0; | |
558 | } | |
559 | break; | |
560 | ||
561 | } | |
562 | return ret; | |
563 | } | |
564 | ||
ed208436 | 565 | static int fbtft_fb_blank(int blank, struct fb_info *info) |
c296d5f9 TP |
566 | { |
567 | struct fbtft_par *par = info->par; | |
568 | int ret = -EINVAL; | |
569 | ||
b38c760a | 570 | dev_dbg(info->dev, "%s(blank=%d)\n", |
c296d5f9 TP |
571 | __func__, blank); |
572 | ||
573 | if (!par->fbtftops.blank) | |
574 | return ret; | |
575 | ||
576 | switch (blank) { | |
577 | case FB_BLANK_POWERDOWN: | |
578 | case FB_BLANK_VSYNC_SUSPEND: | |
579 | case FB_BLANK_HSYNC_SUSPEND: | |
580 | case FB_BLANK_NORMAL: | |
581 | ret = par->fbtftops.blank(par, true); | |
582 | break; | |
583 | case FB_BLANK_UNBLANK: | |
584 | ret = par->fbtftops.blank(par, false); | |
585 | break; | |
586 | } | |
587 | return ret; | |
588 | } | |
589 | ||
ed208436 | 590 | static void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src) |
c296d5f9 TP |
591 | { |
592 | if (src->write) | |
593 | dst->write = src->write; | |
594 | if (src->read) | |
595 | dst->read = src->read; | |
596 | if (src->write_vmem) | |
597 | dst->write_vmem = src->write_vmem; | |
598 | if (src->write_register) | |
599 | dst->write_register = src->write_register; | |
600 | if (src->set_addr_win) | |
601 | dst->set_addr_win = src->set_addr_win; | |
602 | if (src->reset) | |
603 | dst->reset = src->reset; | |
604 | if (src->mkdirty) | |
605 | dst->mkdirty = src->mkdirty; | |
606 | if (src->update_display) | |
607 | dst->update_display = src->update_display; | |
608 | if (src->init_display) | |
609 | dst->init_display = src->init_display; | |
610 | if (src->blank) | |
611 | dst->blank = src->blank; | |
612 | if (src->request_gpios_match) | |
613 | dst->request_gpios_match = src->request_gpios_match; | |
614 | if (src->request_gpios) | |
615 | dst->request_gpios = src->request_gpios; | |
616 | if (src->verify_gpios) | |
617 | dst->verify_gpios = src->verify_gpios; | |
618 | if (src->register_backlight) | |
619 | dst->register_backlight = src->register_backlight; | |
620 | if (src->unregister_backlight) | |
621 | dst->unregister_backlight = src->unregister_backlight; | |
622 | if (src->set_var) | |
623 | dst->set_var = src->set_var; | |
624 | if (src->set_gamma) | |
625 | dst->set_gamma = src->set_gamma; | |
626 | } | |
627 | ||
628 | /** | |
629 | * fbtft_framebuffer_alloc - creates a new frame buffer info structure | |
630 | * | |
631 | * @display: pointer to structure describing the display | |
632 | * @dev: pointer to the device for this fb, this can be NULL | |
633 | * | |
634 | * Creates a new frame buffer info structure. | |
635 | * | |
636 | * Also creates and populates the following structures: | |
637 | * info->fbops | |
638 | * info->fbdefio | |
639 | * info->pseudo_palette | |
640 | * par->fbtftops | |
641 | * par->txbuf | |
642 | * | |
643 | * Returns the new structure, or NULL if an error occurred. | |
644 | * | |
645 | */ | |
646 | struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, | |
ad6d8812 NT |
647 | struct device *dev, |
648 | struct fbtft_platform_data *pdata) | |
c296d5f9 TP |
649 | { |
650 | struct fb_info *info; | |
651 | struct fbtft_par *par; | |
652 | struct fb_ops *fbops = NULL; | |
653 | struct fb_deferred_io *fbdefio = NULL; | |
c296d5f9 TP |
654 | u8 *vmem = NULL; |
655 | void *txbuf = NULL; | |
656 | void *buf = NULL; | |
657 | unsigned width; | |
658 | unsigned height; | |
659 | int txbuflen = display->txbuflen; | |
660 | unsigned bpp = display->bpp; | |
661 | unsigned fps = display->fps; | |
662 | int vmem_size, i; | |
663 | int *init_sequence = display->init_sequence; | |
664 | char *gamma = display->gamma; | |
665 | unsigned long *gamma_curves = NULL; | |
666 | ||
667 | /* sanity check */ | |
668 | if (display->gamma_num * display->gamma_len > FBTFT_GAMMA_MAX_VALUES_TOTAL) { | |
aed1c72e HM |
669 | dev_err(dev, "FBTFT_GAMMA_MAX_VALUES_TOTAL=%d is exceeded\n", |
670 | FBTFT_GAMMA_MAX_VALUES_TOTAL); | |
c296d5f9 TP |
671 | return NULL; |
672 | } | |
673 | ||
674 | /* defaults */ | |
675 | if (!fps) | |
676 | fps = 20; | |
677 | if (!bpp) | |
678 | bpp = 16; | |
679 | ||
680 | if (!pdata) { | |
681 | dev_err(dev, "platform data is missing\n"); | |
682 | return NULL; | |
683 | } | |
684 | ||
685 | /* override driver values? */ | |
686 | if (pdata->fps) | |
687 | fps = pdata->fps; | |
688 | if (pdata->txbuflen) | |
689 | txbuflen = pdata->txbuflen; | |
690 | if (pdata->display.init_sequence) | |
691 | init_sequence = pdata->display.init_sequence; | |
692 | if (pdata->gamma) | |
693 | gamma = pdata->gamma; | |
694 | if (pdata->display.debug) | |
695 | display->debug = pdata->display.debug; | |
696 | if (pdata->display.backlight) | |
697 | display->backlight = pdata->display.backlight; | |
698 | if (pdata->display.width) | |
699 | display->width = pdata->display.width; | |
700 | if (pdata->display.height) | |
701 | display->height = pdata->display.height; | |
702 | if (pdata->display.buswidth) | |
703 | display->buswidth = pdata->display.buswidth; | |
704 | if (pdata->display.regwidth) | |
705 | display->regwidth = pdata->display.regwidth; | |
706 | ||
707 | display->debug |= debug; | |
708 | fbtft_expand_debug_value(&display->debug); | |
709 | ||
710 | switch (pdata->rotate) { | |
711 | case 90: | |
712 | case 270: | |
713 | width = display->height; | |
714 | height = display->width; | |
715 | break; | |
716 | default: | |
717 | width = display->width; | |
718 | height = display->height; | |
719 | } | |
720 | ||
721 | vmem_size = display->width * display->height * bpp / 8; | |
722 | vmem = vzalloc(vmem_size); | |
723 | if (!vmem) | |
724 | goto alloc_fail; | |
725 | ||
726 | fbops = devm_kzalloc(dev, sizeof(struct fb_ops), GFP_KERNEL); | |
727 | if (!fbops) | |
728 | goto alloc_fail; | |
729 | ||
730 | fbdefio = devm_kzalloc(dev, sizeof(struct fb_deferred_io), GFP_KERNEL); | |
731 | if (!fbdefio) | |
732 | goto alloc_fail; | |
733 | ||
734 | buf = devm_kzalloc(dev, 128, GFP_KERNEL); | |
735 | if (!buf) | |
736 | goto alloc_fail; | |
737 | ||
738 | if (display->gamma_num && display->gamma_len) { | |
0c9ab986 AKC |
739 | gamma_curves = devm_kcalloc(dev, |
740 | display->gamma_num * | |
741 | display->gamma_len, | |
742 | sizeof(gamma_curves[0]), | |
743 | GFP_KERNEL); | |
c296d5f9 TP |
744 | if (!gamma_curves) |
745 | goto alloc_fail; | |
746 | } | |
747 | ||
748 | info = framebuffer_alloc(sizeof(struct fbtft_par), dev); | |
749 | if (!info) | |
750 | goto alloc_fail; | |
751 | ||
4b6dc179 | 752 | info->screen_buffer = vmem; |
c296d5f9 TP |
753 | info->fbops = fbops; |
754 | info->fbdefio = fbdefio; | |
755 | ||
756 | fbops->owner = dev->driver->owner; | |
757 | fbops->fb_read = fb_sys_read; | |
758 | fbops->fb_write = fbtft_fb_write; | |
759 | fbops->fb_fillrect = fbtft_fb_fillrect; | |
760 | fbops->fb_copyarea = fbtft_fb_copyarea; | |
761 | fbops->fb_imageblit = fbtft_fb_imageblit; | |
762 | fbops->fb_setcolreg = fbtft_fb_setcolreg; | |
763 | fbops->fb_blank = fbtft_fb_blank; | |
764 | ||
765 | fbdefio->delay = HZ/fps; | |
766 | fbdefio->deferred_io = fbtft_deferred_io; | |
767 | fb_deferred_io_init(info); | |
768 | ||
769 | strncpy(info->fix.id, dev->driver->name, 16); | |
770 | info->fix.type = FB_TYPE_PACKED_PIXELS; | |
771 | info->fix.visual = FB_VISUAL_TRUECOLOR; | |
772 | info->fix.xpanstep = 0; | |
773 | info->fix.ypanstep = 0; | |
774 | info->fix.ywrapstep = 0; | |
94c0a544 | 775 | info->fix.line_length = width * bpp / 8; |
c296d5f9 TP |
776 | info->fix.accel = FB_ACCEL_NONE; |
777 | info->fix.smem_len = vmem_size; | |
778 | ||
779 | info->var.rotate = pdata->rotate; | |
780 | info->var.xres = width; | |
781 | info->var.yres = height; | |
782 | info->var.xres_virtual = info->var.xres; | |
783 | info->var.yres_virtual = info->var.yres; | |
784 | info->var.bits_per_pixel = bpp; | |
785 | info->var.nonstd = 1; | |
786 | ||
787 | /* RGB565 */ | |
788 | info->var.red.offset = 11; | |
789 | info->var.red.length = 5; | |
790 | info->var.green.offset = 5; | |
791 | info->var.green.length = 6; | |
792 | info->var.blue.offset = 0; | |
793 | info->var.blue.length = 5; | |
794 | info->var.transp.offset = 0; | |
795 | info->var.transp.length = 0; | |
796 | ||
797 | info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; | |
798 | ||
799 | par = info->par; | |
800 | par->info = info; | |
ad6d8812 | 801 | par->pdata = pdata; |
c296d5f9 TP |
802 | par->debug = display->debug; |
803 | par->buf = buf; | |
804 | spin_lock_init(&par->dirty_lock); | |
805 | par->bgr = pdata->bgr; | |
806 | par->startbyte = pdata->startbyte; | |
807 | par->init_sequence = init_sequence; | |
808 | par->gamma.curves = gamma_curves; | |
809 | par->gamma.num_curves = display->gamma_num; | |
810 | par->gamma.num_values = display->gamma_len; | |
811 | mutex_init(&par->gamma.lock); | |
812 | info->pseudo_palette = par->pseudo_palette; | |
813 | ||
814 | if (par->gamma.curves && gamma) { | |
815 | if (fbtft_gamma_parse_str(par, | |
816 | par->gamma.curves, gamma, strlen(gamma))) | |
817 | goto alloc_fail; | |
818 | } | |
819 | ||
820 | /* Transmit buffer */ | |
821 | if (txbuflen == -1) | |
822 | txbuflen = vmem_size + 2; /* add in case startbyte is used */ | |
823 | ||
824 | #ifdef __LITTLE_ENDIAN | |
825 | if ((!txbuflen) && (bpp > 8)) | |
826 | txbuflen = PAGE_SIZE; /* need buffer for byteswapping */ | |
827 | #endif | |
828 | ||
829 | if (txbuflen > 0) { | |
8e1a4c7f | 830 | #ifdef CONFIG_HAS_DMA |
c296d5f9 TP |
831 | if (dma) { |
832 | dev->coherent_dma_mask = ~0; | |
833 | txbuf = dmam_alloc_coherent(dev, txbuflen, &par->txbuf.dma, GFP_DMA); | |
8e1a4c7f GU |
834 | } else |
835 | #endif | |
836 | { | |
c296d5f9 TP |
837 | txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL); |
838 | } | |
839 | if (!txbuf) | |
840 | goto alloc_fail; | |
841 | par->txbuf.buf = txbuf; | |
842 | par->txbuf.len = txbuflen; | |
843 | } | |
844 | ||
845 | /* Initialize gpios to disabled */ | |
846 | par->gpio.reset = -1; | |
847 | par->gpio.dc = -1; | |
848 | par->gpio.rd = -1; | |
849 | par->gpio.wr = -1; | |
850 | par->gpio.cs = -1; | |
851 | par->gpio.latch = -1; | |
852 | for (i = 0; i < 16; i++) { | |
853 | par->gpio.db[i] = -1; | |
854 | par->gpio.led[i] = -1; | |
855 | par->gpio.aux[i] = -1; | |
856 | } | |
857 | ||
858 | /* default fbtft operations */ | |
859 | par->fbtftops.write = fbtft_write_spi; | |
860 | par->fbtftops.read = fbtft_read_spi; | |
861 | par->fbtftops.write_vmem = fbtft_write_vmem16_bus8; | |
862 | par->fbtftops.write_register = fbtft_write_reg8_bus8; | |
863 | par->fbtftops.set_addr_win = fbtft_set_addr_win; | |
864 | par->fbtftops.reset = fbtft_reset; | |
865 | par->fbtftops.mkdirty = fbtft_mkdirty; | |
866 | par->fbtftops.update_display = fbtft_update_display; | |
867 | par->fbtftops.request_gpios = fbtft_request_gpios; | |
868 | if (display->backlight) | |
869 | par->fbtftops.register_backlight = fbtft_register_backlight; | |
870 | ||
871 | /* use driver provided functions */ | |
872 | fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops); | |
873 | ||
874 | return info; | |
875 | ||
876 | alloc_fail: | |
877 | vfree(vmem); | |
878 | ||
879 | return NULL; | |
880 | } | |
881 | EXPORT_SYMBOL(fbtft_framebuffer_alloc); | |
882 | ||
883 | /** | |
884 | * fbtft_framebuffer_release - frees up all memory used by the framebuffer | |
885 | * | |
886 | * @info: frame buffer info structure | |
887 | * | |
888 | */ | |
889 | void fbtft_framebuffer_release(struct fb_info *info) | |
890 | { | |
891 | fb_deferred_io_cleanup(info); | |
4b6dc179 | 892 | vfree(info->screen_buffer); |
c296d5f9 TP |
893 | framebuffer_release(info); |
894 | } | |
895 | EXPORT_SYMBOL(fbtft_framebuffer_release); | |
896 | ||
897 | /** | |
898 | * fbtft_register_framebuffer - registers a tft frame buffer device | |
899 | * @fb_info: frame buffer info structure | |
900 | * | |
901 | * Sets SPI driverdata if needed | |
902 | * Requests needed gpios. | |
903 | * Initializes display | |
904 | * Updates display. | |
905 | * Registers a frame buffer device @fb_info. | |
906 | * | |
907 | * Returns negative errno on error, or zero for success. | |
908 | * | |
909 | */ | |
910 | int fbtft_register_framebuffer(struct fb_info *fb_info) | |
911 | { | |
912 | int ret; | |
913 | char text1[50] = ""; | |
914 | char text2[50] = ""; | |
915 | struct fbtft_par *par = fb_info->par; | |
916 | struct spi_device *spi = par->spi; | |
917 | ||
918 | /* sanity checks */ | |
919 | if (!par->fbtftops.init_display) { | |
920 | dev_err(fb_info->device, "missing fbtftops.init_display()\n"); | |
921 | return -EINVAL; | |
922 | } | |
923 | ||
924 | if (spi) | |
925 | spi_set_drvdata(spi, fb_info); | |
926 | if (par->pdev) | |
927 | platform_set_drvdata(par->pdev, fb_info); | |
928 | ||
929 | ret = par->fbtftops.request_gpios(par); | |
930 | if (ret < 0) | |
931 | goto reg_fail; | |
932 | ||
933 | if (par->fbtftops.verify_gpios) { | |
934 | ret = par->fbtftops.verify_gpios(par); | |
935 | if (ret < 0) | |
936 | goto reg_fail; | |
937 | } | |
938 | ||
939 | ret = par->fbtftops.init_display(par); | |
940 | if (ret < 0) | |
941 | goto reg_fail; | |
942 | if (par->fbtftops.set_var) { | |
943 | ret = par->fbtftops.set_var(par); | |
944 | if (ret < 0) | |
945 | goto reg_fail; | |
946 | } | |
947 | ||
948 | /* update the entire display */ | |
949 | par->fbtftops.update_display(par, 0, par->info->var.yres - 1); | |
950 | ||
951 | if (par->fbtftops.set_gamma && par->gamma.curves) { | |
952 | ret = par->fbtftops.set_gamma(par, par->gamma.curves); | |
953 | if (ret) | |
954 | goto reg_fail; | |
955 | } | |
956 | ||
957 | if (par->fbtftops.register_backlight) | |
958 | par->fbtftops.register_backlight(par); | |
959 | ||
960 | ret = register_framebuffer(fb_info); | |
961 | if (ret < 0) | |
962 | goto reg_fail; | |
963 | ||
964 | fbtft_sysfs_init(par); | |
965 | ||
966 | if (par->txbuf.buf) | |
3fed5bac | 967 | sprintf(text1, ", %zu KiB %sbuffer memory", |
c296d5f9 TP |
968 | par->txbuf.len >> 10, par->txbuf.dma ? "DMA " : ""); |
969 | if (spi) | |
970 | sprintf(text2, ", spi%d.%d at %d MHz", spi->master->bus_num, | |
94c0a544 | 971 | spi->chip_select, spi->max_speed_hz / 1000000); |
c296d5f9 TP |
972 | dev_info(fb_info->dev, |
973 | "%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n", | |
974 | fb_info->fix.id, fb_info->var.xres, fb_info->var.yres, | |
975 | fb_info->fix.smem_len >> 10, text1, | |
94c0a544 | 976 | HZ / fb_info->fbdefio->delay, text2); |
c296d5f9 TP |
977 | |
978 | #ifdef CONFIG_FB_BACKLIGHT | |
979 | /* Turn on backlight if available */ | |
980 | if (fb_info->bl_dev) { | |
981 | fb_info->bl_dev->props.power = FB_BLANK_UNBLANK; | |
982 | fb_info->bl_dev->ops->update_status(fb_info->bl_dev); | |
983 | } | |
984 | #endif | |
985 | ||
986 | return 0; | |
987 | ||
988 | reg_fail: | |
989 | if (par->fbtftops.unregister_backlight) | |
990 | par->fbtftops.unregister_backlight(par); | |
c296d5f9 TP |
991 | |
992 | return ret; | |
993 | } | |
994 | EXPORT_SYMBOL(fbtft_register_framebuffer); | |
995 | ||
996 | /** | |
997 | * fbtft_unregister_framebuffer - releases a tft frame buffer device | |
998 | * @fb_info: frame buffer info structure | |
999 | * | |
1000 | * Frees SPI driverdata if needed | |
1001 | * Frees gpios. | |
1002 | * Unregisters frame buffer device. | |
1003 | * | |
1004 | */ | |
1005 | int fbtft_unregister_framebuffer(struct fb_info *fb_info) | |
1006 | { | |
1007 | struct fbtft_par *par = fb_info->par; | |
c296d5f9 | 1008 | |
c296d5f9 TP |
1009 | if (par->fbtftops.unregister_backlight) |
1010 | par->fbtftops.unregister_backlight(par); | |
1011 | fbtft_sysfs_exit(par); | |
11107ffe | 1012 | return unregister_framebuffer(fb_info); |
c296d5f9 TP |
1013 | } |
1014 | EXPORT_SYMBOL(fbtft_unregister_framebuffer); | |
1015 | ||
1016 | #ifdef CONFIG_OF | |
1017 | /** | |
1018 | * fbtft_init_display_dt() - Device Tree init_display() function | |
1019 | * @par: Driver data | |
1020 | * | |
1021 | * Return: 0 if successful, negative if error | |
1022 | */ | |
1023 | static int fbtft_init_display_dt(struct fbtft_par *par) | |
1024 | { | |
1025 | struct device_node *node = par->info->device->of_node; | |
1026 | struct property *prop; | |
1027 | const __be32 *p; | |
1028 | u32 val; | |
1029 | int buf[64], i, j; | |
c296d5f9 | 1030 | |
c296d5f9 TP |
1031 | if (!node) |
1032 | return -EINVAL; | |
1033 | ||
1034 | prop = of_find_property(node, "init", NULL); | |
1035 | p = of_prop_next_u32(prop, NULL, &val); | |
1036 | if (!p) | |
1037 | return -EINVAL; | |
dc4b2068 NT |
1038 | |
1039 | par->fbtftops.reset(par); | |
1040 | if (par->gpio.cs != -1) | |
1041 | gpio_set_value(par->gpio.cs, 0); /* Activate chip */ | |
1042 | ||
c296d5f9 TP |
1043 | while (p) { |
1044 | if (val & FBTFT_OF_INIT_CMD) { | |
1045 | val &= 0xFFFF; | |
1046 | i = 0; | |
1047 | while (p && !(val & 0xFFFF0000)) { | |
1048 | if (i > 63) { | |
1049 | dev_err(par->info->device, | |
1050 | "%s: Maximum register values exceeded\n", | |
1051 | __func__); | |
1052 | return -EINVAL; | |
1053 | } | |
1054 | buf[i++] = val; | |
1055 | p = of_prop_next_u32(prop, p, &val); | |
1056 | } | |
1057 | /* make debug message */ | |
c296d5f9 | 1058 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, |
11f2323a | 1059 | "init: write_register:\n"); |
e6ffd1ba SM |
1060 | for (j = 0; j < i; j++) |
1061 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, | |
1062 | "buf[%d] = %02X\n", j, buf[j]); | |
c296d5f9 TP |
1063 | |
1064 | par->fbtftops.write_register(par, i, | |
1065 | buf[0], buf[1], buf[2], buf[3], | |
1066 | buf[4], buf[5], buf[6], buf[7], | |
1067 | buf[8], buf[9], buf[10], buf[11], | |
1068 | buf[12], buf[13], buf[14], buf[15], | |
1069 | buf[16], buf[17], buf[18], buf[19], | |
1070 | buf[20], buf[21], buf[22], buf[23], | |
1071 | buf[24], buf[25], buf[26], buf[27], | |
1072 | buf[28], buf[29], buf[30], buf[31], | |
1073 | buf[32], buf[33], buf[34], buf[35], | |
1074 | buf[36], buf[37], buf[38], buf[39], | |
1075 | buf[40], buf[41], buf[42], buf[43], | |
1076 | buf[44], buf[45], buf[46], buf[47], | |
1077 | buf[48], buf[49], buf[50], buf[51], | |
1078 | buf[52], buf[53], buf[54], buf[55], | |
1079 | buf[56], buf[57], buf[58], buf[59], | |
1080 | buf[60], buf[61], buf[62], buf[63]); | |
1081 | } else if (val & FBTFT_OF_INIT_DELAY) { | |
1082 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, | |
1083 | "init: msleep(%u)\n", val & 0xFFFF); | |
1084 | msleep(val & 0xFFFF); | |
1085 | p = of_prop_next_u32(prop, p, &val); | |
1086 | } else { | |
1087 | dev_err(par->info->device, "illegal init value 0x%X\n", | |
1088 | val); | |
1089 | return -EINVAL; | |
1090 | } | |
1091 | } | |
1092 | ||
1093 | return 0; | |
1094 | } | |
1095 | #endif | |
1096 | ||
1097 | /** | |
1098 | * fbtft_init_display() - Generic init_display() function | |
1099 | * @par: Driver data | |
1100 | * | |
1101 | * Uses par->init_sequence to do the initialization | |
1102 | * | |
1103 | * Return: 0 if successful, negative if error | |
1104 | */ | |
1105 | int fbtft_init_display(struct fbtft_par *par) | |
1106 | { | |
1107 | int buf[64]; | |
1108 | char msg[128]; | |
1109 | char str[16]; | |
1110 | int i = 0; | |
1111 | int j; | |
1112 | ||
c296d5f9 TP |
1113 | /* sanity check */ |
1114 | if (!par->init_sequence) { | |
1115 | dev_err(par->info->device, | |
1116 | "error: init_sequence is not set\n"); | |
1117 | return -EINVAL; | |
1118 | } | |
1119 | ||
1120 | /* make sure stop marker exists */ | |
1121 | for (i = 0; i < FBTFT_MAX_INIT_SEQUENCE; i++) | |
1122 | if (par->init_sequence[i] == -3) | |
1123 | break; | |
1124 | if (i == FBTFT_MAX_INIT_SEQUENCE) { | |
1125 | dev_err(par->info->device, | |
1126 | "missing stop marker at end of init sequence\n"); | |
1127 | return -EINVAL; | |
1128 | } | |
1129 | ||
1130 | par->fbtftops.reset(par); | |
1131 | if (par->gpio.cs != -1) | |
1132 | gpio_set_value(par->gpio.cs, 0); /* Activate chip */ | |
1133 | ||
1134 | i = 0; | |
1135 | while (i < FBTFT_MAX_INIT_SEQUENCE) { | |
1136 | if (par->init_sequence[i] == -3) { | |
1137 | /* done */ | |
1138 | return 0; | |
1139 | } | |
1140 | if (par->init_sequence[i] >= 0) { | |
1141 | dev_err(par->info->device, | |
1142 | "missing delimiter at position %d\n", i); | |
1143 | return -EINVAL; | |
1144 | } | |
94c0a544 | 1145 | if (par->init_sequence[i + 1] < 0) { |
c296d5f9 TP |
1146 | dev_err(par->info->device, |
1147 | "missing value after delimiter %d at position %d\n", | |
1148 | par->init_sequence[i], i); | |
1149 | return -EINVAL; | |
1150 | } | |
1151 | switch (par->init_sequence[i]) { | |
1152 | case -1: | |
1153 | i++; | |
1154 | /* make debug message */ | |
1155 | strcpy(msg, ""); | |
1156 | j = i + 1; | |
1157 | while (par->init_sequence[j] >= 0) { | |
1158 | sprintf(str, "0x%02X ", par->init_sequence[j]); | |
1159 | strcat(msg, str); | |
1160 | j++; | |
1161 | } | |
1162 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, | |
1163 | "init: write(0x%02X) %s\n", | |
1164 | par->init_sequence[i], msg); | |
1165 | ||
1166 | /* Write */ | |
1167 | j = 0; | |
1168 | while (par->init_sequence[i] >= 0) { | |
1169 | if (j > 63) { | |
1170 | dev_err(par->info->device, | |
1171 | "%s: Maximum register values exceeded\n", | |
1172 | __func__); | |
1173 | return -EINVAL; | |
1174 | } | |
1175 | buf[j++] = par->init_sequence[i++]; | |
1176 | } | |
1177 | par->fbtftops.write_register(par, j, | |
1178 | buf[0], buf[1], buf[2], buf[3], | |
1179 | buf[4], buf[5], buf[6], buf[7], | |
1180 | buf[8], buf[9], buf[10], buf[11], | |
1181 | buf[12], buf[13], buf[14], buf[15], | |
1182 | buf[16], buf[17], buf[18], buf[19], | |
1183 | buf[20], buf[21], buf[22], buf[23], | |
1184 | buf[24], buf[25], buf[26], buf[27], | |
1185 | buf[28], buf[29], buf[30], buf[31], | |
1186 | buf[32], buf[33], buf[34], buf[35], | |
1187 | buf[36], buf[37], buf[38], buf[39], | |
1188 | buf[40], buf[41], buf[42], buf[43], | |
1189 | buf[44], buf[45], buf[46], buf[47], | |
1190 | buf[48], buf[49], buf[50], buf[51], | |
1191 | buf[52], buf[53], buf[54], buf[55], | |
1192 | buf[56], buf[57], buf[58], buf[59], | |
1193 | buf[60], buf[61], buf[62], buf[63]); | |
1194 | break; | |
1195 | case -2: | |
1196 | i++; | |
1197 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, | |
1198 | "init: mdelay(%d)\n", par->init_sequence[i]); | |
1199 | mdelay(par->init_sequence[i++]); | |
1200 | break; | |
1201 | default: | |
1202 | dev_err(par->info->device, | |
1203 | "unknown delimiter %d at position %d\n", | |
1204 | par->init_sequence[i], i); | |
1205 | return -EINVAL; | |
1206 | } | |
1207 | } | |
1208 | ||
1209 | dev_err(par->info->device, | |
1210 | "%s: something is wrong. Shouldn't get here.\n", __func__); | |
1211 | return -EINVAL; | |
1212 | } | |
1213 | EXPORT_SYMBOL(fbtft_init_display); | |
1214 | ||
1215 | /** | |
1216 | * fbtft_verify_gpios() - Generic verify_gpios() function | |
1217 | * @par: Driver data | |
1218 | * | |
1219 | * Uses @spi, @pdev and @buswidth to determine which GPIOs is needed | |
1220 | * | |
1221 | * Return: 0 if successful, negative if error | |
1222 | */ | |
ed208436 | 1223 | static int fbtft_verify_gpios(struct fbtft_par *par) |
c296d5f9 | 1224 | { |
ad6d8812 | 1225 | struct fbtft_platform_data *pdata = par->pdata; |
c296d5f9 TP |
1226 | int i; |
1227 | ||
1228 | fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__); | |
1229 | ||
6ba67a5a | 1230 | if (pdata->display.buswidth != 9 && par->startbyte == 0 && |
c296d5f9 TP |
1231 | par->gpio.dc < 0) { |
1232 | dev_err(par->info->device, | |
1233 | "Missing info about 'dc' gpio. Aborting.\n"); | |
1234 | return -EINVAL; | |
1235 | } | |
1236 | ||
1237 | if (!par->pdev) | |
1238 | return 0; | |
1239 | ||
1240 | if (par->gpio.wr < 0) { | |
1241 | dev_err(par->info->device, "Missing 'wr' gpio. Aborting.\n"); | |
1242 | return -EINVAL; | |
1243 | } | |
1244 | for (i = 0; i < pdata->display.buswidth; i++) { | |
1245 | if (par->gpio.db[i] < 0) { | |
1246 | dev_err(par->info->device, | |
1247 | "Missing 'db%02d' gpio. Aborting.\n", i); | |
1248 | return -EINVAL; | |
1249 | } | |
1250 | } | |
1251 | ||
1252 | return 0; | |
1253 | } | |
1254 | ||
1255 | #ifdef CONFIG_OF | |
1256 | /* returns 0 if the property is not present */ | |
1257 | static u32 fbtft_of_value(struct device_node *node, const char *propname) | |
1258 | { | |
1259 | int ret; | |
1260 | u32 val = 0; | |
1261 | ||
1262 | ret = of_property_read_u32(node, propname, &val); | |
1263 | if (ret == 0) | |
1264 | pr_info("%s: %s = %u\n", __func__, propname, val); | |
1265 | ||
1266 | return val; | |
1267 | } | |
1268 | ||
1269 | static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev) | |
1270 | { | |
1271 | struct device_node *node = dev->of_node; | |
1272 | struct fbtft_platform_data *pdata; | |
1273 | ||
1274 | if (!node) { | |
1275 | dev_err(dev, "Missing platform data or DT\n"); | |
1276 | return ERR_PTR(-EINVAL); | |
1277 | } | |
1278 | ||
1279 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | |
1280 | if (!pdata) | |
1281 | return ERR_PTR(-ENOMEM); | |
1282 | ||
1283 | pdata->display.width = fbtft_of_value(node, "width"); | |
1284 | pdata->display.height = fbtft_of_value(node, "height"); | |
1285 | pdata->display.regwidth = fbtft_of_value(node, "regwidth"); | |
1286 | pdata->display.buswidth = fbtft_of_value(node, "buswidth"); | |
1287 | pdata->display.backlight = fbtft_of_value(node, "backlight"); | |
1288 | pdata->display.bpp = fbtft_of_value(node, "bpp"); | |
1289 | pdata->display.debug = fbtft_of_value(node, "debug"); | |
1290 | pdata->rotate = fbtft_of_value(node, "rotate"); | |
1291 | pdata->bgr = of_property_read_bool(node, "bgr"); | |
1292 | pdata->fps = fbtft_of_value(node, "fps"); | |
1293 | pdata->txbuflen = fbtft_of_value(node, "txbuflen"); | |
1294 | pdata->startbyte = fbtft_of_value(node, "startbyte"); | |
1295 | of_property_read_string(node, "gamma", (const char **)&pdata->gamma); | |
1296 | ||
1297 | if (of_find_property(node, "led-gpios", NULL)) | |
1298 | pdata->display.backlight = 1; | |
1299 | if (of_find_property(node, "init", NULL)) | |
1300 | pdata->display.fbtftops.init_display = fbtft_init_display_dt; | |
1301 | pdata->display.fbtftops.request_gpios = fbtft_request_gpios_dt; | |
1302 | ||
1303 | return pdata; | |
1304 | } | |
1305 | #else | |
1306 | static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev) | |
1307 | { | |
1308 | dev_err(dev, "Missing platform data\n"); | |
1309 | return ERR_PTR(-EINVAL); | |
1310 | } | |
1311 | #endif | |
1312 | ||
1313 | /** | |
1314 | * fbtft_probe_common() - Generic device probe() helper function | |
1315 | * @display: Display properties | |
1316 | * @sdev: SPI device | |
1317 | * @pdev: Platform device | |
1318 | * | |
1319 | * Allocates, initializes and registers a framebuffer | |
1320 | * | |
1321 | * Either @sdev or @pdev should be NULL | |
1322 | * | |
1323 | * Return: 0 if successful, negative if error | |
1324 | */ | |
1325 | int fbtft_probe_common(struct fbtft_display *display, | |
1326 | struct spi_device *sdev, struct platform_device *pdev) | |
1327 | { | |
1328 | struct device *dev; | |
1329 | struct fb_info *info; | |
1330 | struct fbtft_par *par; | |
1331 | struct fbtft_platform_data *pdata; | |
1332 | int ret; | |
1333 | ||
1334 | if (sdev) | |
1335 | dev = &sdev->dev; | |
1336 | else | |
1337 | dev = &pdev->dev; | |
1338 | ||
1339 | if (unlikely(display->debug & DEBUG_DRIVER_INIT_FUNCTIONS)) | |
1340 | dev_info(dev, "%s()\n", __func__); | |
1341 | ||
1342 | pdata = dev->platform_data; | |
1343 | if (!pdata) { | |
1344 | pdata = fbtft_probe_dt(dev); | |
1345 | if (IS_ERR(pdata)) | |
1346 | return PTR_ERR(pdata); | |
c296d5f9 TP |
1347 | } |
1348 | ||
ad6d8812 | 1349 | info = fbtft_framebuffer_alloc(display, dev, pdata); |
c296d5f9 TP |
1350 | if (!info) |
1351 | return -ENOMEM; | |
1352 | ||
1353 | par = info->par; | |
1354 | par->spi = sdev; | |
1355 | par->pdev = pdev; | |
1356 | ||
1357 | if (display->buswidth == 0) { | |
1358 | dev_err(dev, "buswidth is not set\n"); | |
1359 | return -EINVAL; | |
1360 | } | |
1361 | ||
1362 | /* write register functions */ | |
1363 | if (display->regwidth == 8 && display->buswidth == 8) { | |
1364 | par->fbtftops.write_register = fbtft_write_reg8_bus8; | |
1365 | } else | |
1366 | if (display->regwidth == 8 && display->buswidth == 9 && par->spi) { | |
1367 | par->fbtftops.write_register = fbtft_write_reg8_bus9; | |
1368 | } else if (display->regwidth == 16 && display->buswidth == 8) { | |
1369 | par->fbtftops.write_register = fbtft_write_reg16_bus8; | |
1370 | } else if (display->regwidth == 16 && display->buswidth == 16) { | |
1371 | par->fbtftops.write_register = fbtft_write_reg16_bus16; | |
1372 | } else { | |
1373 | dev_warn(dev, | |
1374 | "no default functions for regwidth=%d and buswidth=%d\n", | |
1375 | display->regwidth, display->buswidth); | |
1376 | } | |
1377 | ||
1378 | /* write_vmem() functions */ | |
1379 | if (display->buswidth == 8) | |
1380 | par->fbtftops.write_vmem = fbtft_write_vmem16_bus8; | |
1381 | else if (display->buswidth == 9) | |
1382 | par->fbtftops.write_vmem = fbtft_write_vmem16_bus9; | |
1383 | else if (display->buswidth == 16) | |
1384 | par->fbtftops.write_vmem = fbtft_write_vmem16_bus16; | |
1385 | ||
1386 | /* GPIO write() functions */ | |
1387 | if (par->pdev) { | |
1388 | if (display->buswidth == 8) | |
1389 | par->fbtftops.write = fbtft_write_gpio8_wr; | |
1390 | else if (display->buswidth == 16) | |
1391 | par->fbtftops.write = fbtft_write_gpio16_wr; | |
1392 | } | |
1393 | ||
1394 | /* 9-bit SPI setup */ | |
1395 | if (par->spi && display->buswidth == 9) { | |
cabb5b2a SW |
1396 | if (par->spi->master->bits_per_word_mask & SPI_BPW_MASK(9)) { |
1397 | par->spi->bits_per_word = 9; | |
1398 | } else { | |
c296d5f9 TP |
1399 | dev_warn(&par->spi->dev, |
1400 | "9-bit SPI not available, emulating using 8-bit.\n"); | |
c296d5f9 TP |
1401 | /* allocate buffer with room for dc bits */ |
1402 | par->extra = devm_kzalloc(par->info->device, | |
1403 | par->txbuf.len + (par->txbuf.len / 8) + 8, | |
1404 | GFP_KERNEL); | |
1405 | if (!par->extra) { | |
1406 | ret = -ENOMEM; | |
1407 | goto out_release; | |
1408 | } | |
1409 | par->fbtftops.write = fbtft_write_spi_emulate_9; | |
1410 | } | |
1411 | } | |
1412 | ||
1413 | if (!par->fbtftops.verify_gpios) | |
1414 | par->fbtftops.verify_gpios = fbtft_verify_gpios; | |
1415 | ||
1416 | /* make sure we still use the driver provided functions */ | |
1417 | fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops); | |
1418 | ||
1419 | /* use init_sequence if provided */ | |
1420 | if (par->init_sequence) | |
1421 | par->fbtftops.init_display = fbtft_init_display; | |
1422 | ||
1423 | /* use platform_data provided functions above all */ | |
1424 | fbtft_merge_fbtftops(&par->fbtftops, &pdata->display.fbtftops); | |
1425 | ||
1426 | ret = fbtft_register_framebuffer(info); | |
1427 | if (ret < 0) | |
1428 | goto out_release; | |
1429 | ||
1430 | return 0; | |
1431 | ||
1432 | out_release: | |
1433 | fbtft_framebuffer_release(info); | |
1434 | ||
1435 | return ret; | |
1436 | } | |
1437 | EXPORT_SYMBOL(fbtft_probe_common); | |
1438 | ||
1439 | /** | |
1440 | * fbtft_remove_common() - Generic device remove() helper function | |
1441 | * @dev: Device | |
1442 | * @info: Framebuffer | |
1443 | * | |
1444 | * Unregisters and releases the framebuffer | |
1445 | * | |
1446 | * Return: 0 if successful, negative if error | |
1447 | */ | |
1448 | int fbtft_remove_common(struct device *dev, struct fb_info *info) | |
1449 | { | |
1450 | struct fbtft_par *par; | |
1451 | ||
1452 | if (!info) | |
1453 | return -EINVAL; | |
1454 | par = info->par; | |
1455 | if (par) | |
1456 | fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, | |
1457 | "%s()\n", __func__); | |
1458 | fbtft_unregister_framebuffer(info); | |
1459 | fbtft_framebuffer_release(info); | |
1460 | ||
1461 | return 0; | |
1462 | } | |
1463 | EXPORT_SYMBOL(fbtft_remove_common); | |
1464 | ||
1465 | MODULE_LICENSE("GPL"); |