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