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