1 // SPDX-License-Identifier: GPL-2.0-only
2 /***************************************************************************
3 * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> *
5 * Based on Logitech G13 driver (v0.4) *
6 * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> *
8 ***************************************************************************/
10 #include <linux/hid.h>
11 #include <linux/vmalloc.h>
14 #include <linux/module.h>
16 #include "hid-picolcd.h"
20 * The PicoLCD use a Topway LCD module of 256x64 pixel
21 * This display area is tiled over 4 controllers with 8 tiles
22 * each. Each tile has 8x64 pixel, each data byte representing
23 * a 1-bit wide vertical line of the tile.
25 * The display can be updated at a tile granularity.
27 * Chip 1 Chip 2 Chip 3 Chip 4
28 * +----------------+----------------+----------------+----------------+
29 * | Tile 1 | Tile 1 | Tile 1 | Tile 1 |
30 * +----------------+----------------+----------------+----------------+
31 * | Tile 2 | Tile 2 | Tile 2 | Tile 2 |
32 * +----------------+----------------+----------------+----------------+
34 * +----------------+----------------+----------------+----------------+
35 * | Tile 8 | Tile 8 | Tile 8 | Tile 8 |
36 * +----------------+----------------+----------------+----------------+
38 #define PICOLCDFB_NAME "picolcdfb"
39 #define PICOLCDFB_WIDTH (256)
40 #define PICOLCDFB_HEIGHT (64)
41 #define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)
43 #define PICOLCDFB_UPDATE_RATE_LIMIT 10
44 #define PICOLCDFB_UPDATE_RATE_DEFAULT 2
46 /* Framebuffer visual structures */
47 static const struct fb_fix_screeninfo picolcdfb_fix
= {
49 .type
= FB_TYPE_PACKED_PIXELS
,
50 .visual
= FB_VISUAL_MONO01
,
54 .line_length
= PICOLCDFB_WIDTH
/ 8,
55 .accel
= FB_ACCEL_NONE
,
58 static const struct fb_var_screeninfo picolcdfb_var
= {
59 .xres
= PICOLCDFB_WIDTH
,
60 .yres
= PICOLCDFB_HEIGHT
,
61 .xres_virtual
= PICOLCDFB_WIDTH
,
62 .yres_virtual
= PICOLCDFB_HEIGHT
,
89 /* Send a given tile to PicoLCD */
90 static int picolcd_fb_send_tile(struct picolcd_data
*data
, u8
*vbitmap
,
93 struct hid_report
*report1
, *report2
;
98 report1
= picolcd_out_report(REPORT_LCD_CMD_DATA
, data
->hdev
);
99 if (!report1
|| report1
->maxfield
!= 1)
101 report2
= picolcd_out_report(REPORT_LCD_DATA
, data
->hdev
);
102 if (!report2
|| report2
->maxfield
!= 1)
105 spin_lock_irqsave(&data
->lock
, flags
);
106 if ((data
->status
& PICOLCD_FAILED
)) {
107 spin_unlock_irqrestore(&data
->lock
, flags
);
110 hid_set_field(report1
->field
[0], 0, chip
<< 2);
111 hid_set_field(report1
->field
[0], 1, 0x02);
112 hid_set_field(report1
->field
[0], 2, 0x00);
113 hid_set_field(report1
->field
[0], 3, 0x00);
114 hid_set_field(report1
->field
[0], 4, 0xb8 | tile
);
115 hid_set_field(report1
->field
[0], 5, 0x00);
116 hid_set_field(report1
->field
[0], 6, 0x00);
117 hid_set_field(report1
->field
[0], 7, 0x40);
118 hid_set_field(report1
->field
[0], 8, 0x00);
119 hid_set_field(report1
->field
[0], 9, 0x00);
120 hid_set_field(report1
->field
[0], 10, 32);
122 hid_set_field(report2
->field
[0], 0, (chip
<< 2) | 0x01);
123 hid_set_field(report2
->field
[0], 1, 0x00);
124 hid_set_field(report2
->field
[0], 2, 0x00);
125 hid_set_field(report2
->field
[0], 3, 32);
127 tdata
= vbitmap
+ (tile
* 4 + chip
) * 64;
128 for (i
= 0; i
< 64; i
++)
130 hid_set_field(report1
->field
[0], 11 + i
, tdata
[i
]);
132 hid_set_field(report2
->field
[0], 4 + i
- 32, tdata
[i
]);
134 hid_hw_request(data
->hdev
, report1
, HID_REQ_SET_REPORT
);
135 hid_hw_request(data
->hdev
, report2
, HID_REQ_SET_REPORT
);
136 spin_unlock_irqrestore(&data
->lock
, flags
);
140 /* Translate a single tile*/
141 static int picolcd_fb_update_tile(u8
*vbitmap
, const u8
*bitmap
, int bpp
,
144 int i
, b
, changed
= 0;
146 u8
*vdata
= vbitmap
+ (tile
* 4 + chip
) * 64;
149 for (b
= 7; b
>= 0; b
--) {
150 const u8
*bdata
= bitmap
+ tile
* 256 + chip
* 8 + b
* 32;
151 for (i
= 0; i
< 64; i
++) {
153 tdata
[i
] |= (bdata
[i
/8] >> (i
% 8)) & 0x01;
156 } else if (bpp
== 8) {
157 for (b
= 7; b
>= 0; b
--) {
158 const u8
*bdata
= bitmap
+ (tile
* 256 + chip
* 8 + b
* 32) * 8;
159 for (i
= 0; i
< 64; i
++) {
161 tdata
[i
] |= (bdata
[i
] & 0x80) ? 0x01 : 0x00;
165 /* Oops, we should never get here! */
170 for (i
= 0; i
< 64; i
++)
171 if (tdata
[i
] != vdata
[i
]) {
178 void picolcd_fb_refresh(struct picolcd_data
*data
)
181 schedule_delayed_work(&data
->fb_info
->deferred_work
, 0);
184 /* Reconfigure LCD display */
185 int picolcd_fb_reset(struct picolcd_data
*data
, int clear
)
187 struct hid_report
*report
= picolcd_out_report(REPORT_LCD_CMD
, data
->hdev
);
188 struct picolcd_fb_data
*fbdata
= data
->fb_info
->par
;
191 static const u8 mapcmd
[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };
193 if (!report
|| report
->maxfield
!= 1)
196 spin_lock_irqsave(&data
->lock
, flags
);
197 for (i
= 0; i
< 4; i
++) {
198 for (j
= 0; j
< report
->field
[0]->maxusage
; j
++)
200 hid_set_field(report
->field
[0], j
, i
<< 2);
201 else if (j
< sizeof(mapcmd
))
202 hid_set_field(report
->field
[0], j
, mapcmd
[j
]);
204 hid_set_field(report
->field
[0], j
, 0);
205 hid_hw_request(data
->hdev
, report
, HID_REQ_SET_REPORT
);
207 spin_unlock_irqrestore(&data
->lock
, flags
);
210 memset(fbdata
->vbitmap
, 0, PICOLCDFB_SIZE
);
211 memset(fbdata
->bitmap
, 0, PICOLCDFB_SIZE
*fbdata
->bpp
);
215 /* schedule first output of framebuffer */
217 schedule_delayed_work(&data
->fb_info
->deferred_work
, 0);
224 /* Update fb_vbitmap from the screen_base and send changed tiles to device */
225 static void picolcd_fb_update(struct fb_info
*info
)
229 struct picolcd_fb_data
*fbdata
= info
->par
;
230 struct picolcd_data
*data
;
232 mutex_lock(&info
->lock
);
234 spin_lock_irqsave(&fbdata
->lock
, flags
);
235 if (!fbdata
->ready
&& fbdata
->picolcd
)
236 picolcd_fb_reset(fbdata
->picolcd
, 0);
237 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
240 * Translate the framebuffer into the format needed by the PicoLCD.
241 * See display layout above.
242 * Do this one tile after the other and push those tiles that changed.
244 * Wait for our IO to complete as otherwise we might flood the queue!
247 for (chip
= 0; chip
< 4; chip
++)
248 for (tile
= 0; tile
< 8; tile
++) {
249 if (!fbdata
->force
&& !picolcd_fb_update_tile(
250 fbdata
->vbitmap
, fbdata
->bitmap
,
251 fbdata
->bpp
, chip
, tile
))
254 if (n
>= HID_OUTPUT_FIFO_SIZE
/ 2) {
255 spin_lock_irqsave(&fbdata
->lock
, flags
);
256 data
= fbdata
->picolcd
;
257 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
258 mutex_unlock(&info
->lock
);
261 hid_hw_wait(data
->hdev
);
262 mutex_lock(&info
->lock
);
265 spin_lock_irqsave(&fbdata
->lock
, flags
);
266 data
= fbdata
->picolcd
;
267 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
268 if (!data
|| picolcd_fb_send_tile(data
,
269 fbdata
->vbitmap
, chip
, tile
))
272 fbdata
->force
= false;
274 spin_lock_irqsave(&fbdata
->lock
, flags
);
275 data
= fbdata
->picolcd
;
276 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
277 mutex_unlock(&info
->lock
);
279 hid_hw_wait(data
->hdev
);
283 mutex_unlock(&info
->lock
);
286 /* Stub to call the system default and update the image on the picoLCD */
287 static void picolcd_fb_fillrect(struct fb_info
*info
,
288 const struct fb_fillrect
*rect
)
292 sys_fillrect(info
, rect
);
294 schedule_delayed_work(&info
->deferred_work
, 0);
297 /* Stub to call the system default and update the image on the picoLCD */
298 static void picolcd_fb_copyarea(struct fb_info
*info
,
299 const struct fb_copyarea
*area
)
303 sys_copyarea(info
, area
);
305 schedule_delayed_work(&info
->deferred_work
, 0);
308 /* Stub to call the system default and update the image on the picoLCD */
309 static void picolcd_fb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
313 sys_imageblit(info
, image
);
315 schedule_delayed_work(&info
->deferred_work
, 0);
319 * this is the slow path from userspace. they can seek and write to
320 * the fb. it's inefficient to do anything less than a full screen draw
322 static ssize_t
picolcd_fb_write(struct fb_info
*info
, const char __user
*buf
,
323 size_t count
, loff_t
*ppos
)
328 ret
= fb_sys_write(info
, buf
, count
, ppos
);
330 schedule_delayed_work(&info
->deferred_work
, 0);
334 static int picolcd_fb_blank(int blank
, struct fb_info
*info
)
336 /* We let fb notification do this for us via lcd/backlight device */
340 static void picolcd_fb_destroy(struct fb_info
*info
)
342 struct picolcd_fb_data
*fbdata
= info
->par
;
344 /* make sure no work is deferred */
345 fb_deferred_io_cleanup(info
);
347 /* No thridparty should ever unregister our framebuffer! */
348 WARN_ON(fbdata
->picolcd
!= NULL
);
350 vfree((u8
*)info
->fix
.smem_start
);
351 framebuffer_release(info
);
354 static int picolcd_fb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
356 __u32 bpp
= var
->bits_per_pixel
;
357 __u32 activate
= var
->activate
;
359 /* only allow 1/8 bit depth (8-bit is grayscale) */
360 *var
= picolcdfb_var
;
361 var
->activate
= activate
;
363 var
->bits_per_pixel
= 8;
365 var
->green
.length
= 8;
366 var
->blue
.length
= 8;
368 var
->bits_per_pixel
= 1;
370 var
->green
.length
= 1;
371 var
->blue
.length
= 1;
376 static int picolcd_set_par(struct fb_info
*info
)
378 struct picolcd_fb_data
*fbdata
= info
->par
;
380 if (info
->var
.bits_per_pixel
== fbdata
->bpp
)
382 /* switch between 1/8 bit depths */
383 if (info
->var
.bits_per_pixel
!= 1 && info
->var
.bits_per_pixel
!= 8)
386 o_fb
= fbdata
->bitmap
;
387 tmp_fb
= kmalloc_array(PICOLCDFB_SIZE
, info
->var
.bits_per_pixel
,
392 /* translate FB content to new bits-per-pixel */
393 if (info
->var
.bits_per_pixel
== 1) {
395 for (i
= 0; i
< PICOLCDFB_SIZE
; i
++) {
397 for (b
= 0; b
< 8; b
++) {
399 p
|= o_fb
[i
*8+b
] ? 0x01 : 0x00;
403 memcpy(o_fb
, tmp_fb
, PICOLCDFB_SIZE
);
404 info
->fix
.visual
= FB_VISUAL_MONO01
;
405 info
->fix
.line_length
= PICOLCDFB_WIDTH
/ 8;
408 memcpy(tmp_fb
, o_fb
, PICOLCDFB_SIZE
);
409 for (i
= 0; i
< PICOLCDFB_SIZE
* 8; i
++)
410 o_fb
[i
] = tmp_fb
[i
/8] & (0x01 << (7 - i
% 8)) ? 0xff : 0x00;
411 info
->fix
.visual
= FB_VISUAL_DIRECTCOLOR
;
412 info
->fix
.line_length
= PICOLCDFB_WIDTH
;
416 fbdata
->bpp
= info
->var
.bits_per_pixel
;
420 static const struct fb_ops picolcdfb_ops
= {
421 .owner
= THIS_MODULE
,
422 .fb_destroy
= picolcd_fb_destroy
,
423 .fb_read
= fb_sys_read
,
424 .fb_write
= picolcd_fb_write
,
425 .fb_blank
= picolcd_fb_blank
,
426 .fb_fillrect
= picolcd_fb_fillrect
,
427 .fb_copyarea
= picolcd_fb_copyarea
,
428 .fb_imageblit
= picolcd_fb_imageblit
,
429 .fb_check_var
= picolcd_fb_check_var
,
430 .fb_set_par
= picolcd_set_par
,
434 /* Callback from deferred IO workqueue */
435 static void picolcd_fb_deferred_io(struct fb_info
*info
, struct list_head
*pagelist
)
437 picolcd_fb_update(info
);
440 static const struct fb_deferred_io picolcd_fb_defio
= {
441 .delay
= HZ
/ PICOLCDFB_UPDATE_RATE_DEFAULT
,
442 .deferred_io
= picolcd_fb_deferred_io
,
447 * The "fb_update_rate" sysfs attribute
449 static ssize_t
picolcd_fb_update_rate_show(struct device
*dev
,
450 struct device_attribute
*attr
, char *buf
)
452 struct picolcd_data
*data
= dev_get_drvdata(dev
);
453 struct picolcd_fb_data
*fbdata
= data
->fb_info
->par
;
454 unsigned i
, fb_update_rate
= fbdata
->update_rate
;
457 for (i
= 1; i
<= PICOLCDFB_UPDATE_RATE_LIMIT
; i
++)
458 if (ret
>= PAGE_SIZE
)
460 else if (i
== fb_update_rate
)
461 ret
+= snprintf(buf
+ret
, PAGE_SIZE
-ret
, "[%u] ", i
);
463 ret
+= snprintf(buf
+ret
, PAGE_SIZE
-ret
, "%u ", i
);
465 buf
[min(ret
, (size_t)PAGE_SIZE
)-1] = '\n';
469 static ssize_t
picolcd_fb_update_rate_store(struct device
*dev
,
470 struct device_attribute
*attr
, const char *buf
, size_t count
)
472 struct picolcd_data
*data
= dev_get_drvdata(dev
);
473 struct picolcd_fb_data
*fbdata
= data
->fb_info
->par
;
477 if (count
< 1 || count
> 10)
480 i
= sscanf(buf
, "%u", &u
);
484 if (u
> PICOLCDFB_UPDATE_RATE_LIMIT
)
487 u
= PICOLCDFB_UPDATE_RATE_DEFAULT
;
489 fbdata
->update_rate
= u
;
490 data
->fb_info
->fbdefio
->delay
= HZ
/ fbdata
->update_rate
;
494 static DEVICE_ATTR(fb_update_rate
, 0664, picolcd_fb_update_rate_show
,
495 picolcd_fb_update_rate_store
);
497 /* initialize Framebuffer device */
498 int picolcd_init_framebuffer(struct picolcd_data
*data
)
500 struct device
*dev
= &data
->hdev
->dev
;
501 struct fb_info
*info
= NULL
;
502 struct picolcd_fb_data
*fbdata
= NULL
;
503 int i
, error
= -ENOMEM
;
506 /* The extra memory is:
507 * - 256*u32 for pseudo_palette
508 * - struct fb_deferred_io
510 info
= framebuffer_alloc(256 * sizeof(u32
) +
511 sizeof(struct fb_deferred_io
) +
512 sizeof(struct picolcd_fb_data
) +
513 PICOLCDFB_SIZE
, dev
);
517 info
->fbdefio
= info
->par
;
518 *info
->fbdefio
= picolcd_fb_defio
;
519 info
->par
+= sizeof(struct fb_deferred_io
);
521 info
->par
+= 256 * sizeof(u32
);
522 for (i
= 0; i
< 256; i
++)
523 palette
[i
] = i
> 0 && i
< 16 ? 0xff : 0;
524 info
->pseudo_palette
= palette
;
525 info
->fbops
= &picolcdfb_ops
;
526 info
->var
= picolcdfb_var
;
527 info
->fix
= picolcdfb_fix
;
528 info
->fix
.smem_len
= PICOLCDFB_SIZE
*8;
529 info
->flags
= FBINFO_FLAG_DEFAULT
;
532 spin_lock_init(&fbdata
->lock
);
533 fbdata
->picolcd
= data
;
534 fbdata
->update_rate
= PICOLCDFB_UPDATE_RATE_DEFAULT
;
535 fbdata
->bpp
= picolcdfb_var
.bits_per_pixel
;
537 fbdata
->vbitmap
= info
->par
+ sizeof(struct picolcd_fb_data
);
538 fbdata
->bitmap
= vmalloc(PICOLCDFB_SIZE
*8);
539 if (fbdata
->bitmap
== NULL
) {
540 dev_err(dev
, "can't get a free page for framebuffer\n");
543 info
->screen_base
= (char __force __iomem
*)fbdata
->bitmap
;
544 info
->fix
.smem_start
= (unsigned long)fbdata
->bitmap
;
545 memset(fbdata
->vbitmap
, 0xff, PICOLCDFB_SIZE
);
546 data
->fb_info
= info
;
548 error
= picolcd_fb_reset(data
, 1);
550 dev_err(dev
, "failed to configure display\n");
554 error
= device_create_file(dev
, &dev_attr_fb_update_rate
);
556 dev_err(dev
, "failed to create sysfs attributes\n");
560 fb_deferred_io_init(info
);
561 error
= register_framebuffer(info
);
563 dev_err(dev
, "failed to register framebuffer\n");
569 device_remove_file(dev
, &dev_attr_fb_update_rate
);
570 fb_deferred_io_cleanup(info
);
572 data
->fb_info
= NULL
;
576 vfree(fbdata
->bitmap
);
577 framebuffer_release(info
);
581 void picolcd_exit_framebuffer(struct picolcd_data
*data
)
583 struct fb_info
*info
= data
->fb_info
;
584 struct picolcd_fb_data
*fbdata
;
590 device_remove_file(&data
->hdev
->dev
, &dev_attr_fb_update_rate
);
593 /* disconnect framebuffer from HID dev */
594 spin_lock_irqsave(&fbdata
->lock
, flags
);
595 fbdata
->picolcd
= NULL
;
596 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
598 /* make sure there is no running update - thus that fbdata->picolcd
599 * once obtained under lock is guaranteed not to get free() under
600 * the feet of the deferred work */
601 flush_delayed_work(&info
->deferred_work
);
603 data
->fb_info
= NULL
;
604 unregister_framebuffer(info
);