Skip to content

Commit 2d87f97

Browse files
pelwellpopcornmix
authored andcommitted
mfd: Add Raspberry Pi Sense HAT core driver
mfd: Add rpi_sense_core of compatible string rpisense-fb: Set pseudo_pallete to prevent crash on fbcon takeover Signed-off-by: Serge Schneider <[email protected]> rpisense-fb: Add explicit fb_deferred_io_mmap hook As of commit [1], introduced in 5.18, fbdev drivers that use deferred IO and need mmap support must include an explicit fb_mmap pointer to the fb_deferred_io_mmap. Signed-off-by: Phil Elwell <[email protected]> [1] 5905585 ("fbdev: Put mmap for deferred I/O into drivers") drivers: Remove downstream SenseHAT core and joystick drivers Parts of a SenseHAT driver have been submitted upstream using the simple-i2c-mfd framework. The joystick driver has been merged. It's been noted that there are several issues with the downstream joystick and core drivers, so remove these in favour of the upstream approach, and fix up the FB driver to match. Signed-off-by: Dave Stevenson <[email protected]>
1 parent 1edb16e commit 2d87f97

File tree

4 files changed

+344
-0
lines changed

4 files changed

+344
-0
lines changed

drivers/video/fbdev/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,6 +1833,19 @@ config FB_SM712
18331833
called sm712fb. If you want to compile it as a module, say M
18341834
here and read <file:Documentation/kbuild/modules.rst>.
18351835

1836+
config FB_RPISENSE
1837+
tristate "Raspberry Pi Sense HAT framebuffer"
1838+
depends on FB && I2C
1839+
select MFD_SIMPLE_MFD_I2C
1840+
select FB_SYS_FOPS
1841+
select FB_SYS_FILLRECT
1842+
select FB_SYS_COPYAREA
1843+
select FB_SYS_IMAGEBLIT
1844+
select FB_DEFERRED_IO
1845+
1846+
help
1847+
This is the framebuffer driver for the Raspberry Pi Sense HAT
1848+
18361849
source "drivers/video/fbdev/omap/Kconfig"
18371850
source "drivers/video/fbdev/omap2/Kconfig"
18381851
source "drivers/video/fbdev/mmp/Kconfig"

drivers/video/fbdev/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ obj-$(CONFIG_FB_VGA16) += vga16fb.o
124124
obj-$(CONFIG_FB_OF) += offb.o
125125
obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
126126
obj-$(CONFIG_FB_SIMPLE) += simplefb.o
127+
obj-$(CONFIG_FB_RPISENSE) += rpisense-fb.o
127128

128129
# the test framebuffer is last
129130
obj-$(CONFIG_FB_VIRTUAL) += vfb.o

drivers/video/fbdev/rpisense-fb.c

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
/*
2+
* Raspberry Pi Sense HAT framebuffer driver
3+
* http://raspberrypi.org
4+
*
5+
* Copyright (C) 2015 Raspberry Pi
6+
*
7+
* Author: Serge Schneider
8+
*
9+
* This program is free software; you can redistribute it and/or modify it
10+
* under the terms of the GNU General Public License as published by the
11+
* Free Software Foundation; either version 2 of the License, or (at your
12+
* option) any later version.
13+
*
14+
*/
15+
16+
#include <linux/module.h>
17+
#include <linux/kernel.h>
18+
#include <linux/errno.h>
19+
#include <linux/string.h>
20+
#include <linux/mm.h>
21+
#include <linux/slab.h>
22+
#include <linux/uaccess.h>
23+
#include <linux/delay.h>
24+
#include <linux/fb.h>
25+
#include <linux/init.h>
26+
#include <linux/vmalloc.h>
27+
#include <linux/platform_device.h>
28+
29+
#include <linux/mfd/rpisense/framebuffer.h>
30+
31+
static bool lowlight;
32+
module_param(lowlight, bool, 0);
33+
MODULE_PARM_DESC(lowlight, "Reduce LED matrix brightness to one third");
34+
35+
struct rpisense_fb_param {
36+
char __iomem *vmem;
37+
u8 *vmem_work;
38+
u32 vmemsize;
39+
u8 *gamma;
40+
};
41+
42+
static u8 gamma_default[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
43+
0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07,
44+
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x11,
45+
0x12, 0x14, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F,};
46+
47+
static u8 gamma_low[32] = {0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
48+
0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
49+
0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06,
50+
0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x0A, 0x0A,};
51+
52+
static u8 gamma_user[32];
53+
54+
static u32 pseudo_palette[16];
55+
56+
static struct rpisense_fb_param rpisense_fb_param = {
57+
.vmem = NULL,
58+
.vmemsize = 128,
59+
.gamma = gamma_default,
60+
};
61+
62+
static struct fb_deferred_io rpisense_fb_defio;
63+
64+
static struct fb_fix_screeninfo rpisense_fb_fix = {
65+
.id = "RPi-Sense FB",
66+
.type = FB_TYPE_PACKED_PIXELS,
67+
.visual = FB_VISUAL_TRUECOLOR,
68+
.xpanstep = 0,
69+
.ypanstep = 0,
70+
.ywrapstep = 0,
71+
.accel = FB_ACCEL_NONE,
72+
.line_length = 16,
73+
};
74+
75+
static struct fb_var_screeninfo rpisense_fb_var = {
76+
.xres = 8,
77+
.yres = 8,
78+
.xres_virtual = 8,
79+
.yres_virtual = 8,
80+
.bits_per_pixel = 16,
81+
.red = {11, 5, 0},
82+
.green = {5, 6, 0},
83+
.blue = {0, 5, 0},
84+
};
85+
86+
static ssize_t rpisense_fb_write(struct fb_info *info,
87+
const char __user *buf, size_t count,
88+
loff_t *ppos)
89+
{
90+
ssize_t res = fb_sys_write(info, buf, count, ppos);
91+
92+
schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
93+
return res;
94+
}
95+
96+
static void rpisense_fb_fillrect(struct fb_info *info,
97+
const struct fb_fillrect *rect)
98+
{
99+
sys_fillrect(info, rect);
100+
schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
101+
}
102+
103+
static void rpisense_fb_copyarea(struct fb_info *info,
104+
const struct fb_copyarea *area)
105+
{
106+
sys_copyarea(info, area);
107+
schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
108+
}
109+
110+
static void rpisense_fb_imageblit(struct fb_info *info,
111+
const struct fb_image *image)
112+
{
113+
sys_imageblit(info, image);
114+
schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
115+
}
116+
117+
static void rpisense_fb_deferred_io(struct fb_info *info,
118+
struct list_head *pagelist)
119+
{
120+
int i;
121+
int j;
122+
u8 *vmem_work = rpisense_fb_param.vmem_work;
123+
u16 *mem = (u16 *)rpisense_fb_param.vmem;
124+
u8 *gamma = rpisense_fb_param.gamma;
125+
struct rpisense_fb *rpisense_fb = info->par;
126+
127+
for (j = 0; j < 8; j++) {
128+
for (i = 0; i < 8; i++) {
129+
vmem_work[(j * 24) + i] =
130+
gamma[(mem[(j * 8) + i] >> 11) & 0x1F];
131+
vmem_work[(j * 24) + (i + 8)] =
132+
gamma[(mem[(j * 8) + i] >> 6) & 0x1F];
133+
vmem_work[(j * 24) + (i + 16)] =
134+
gamma[(mem[(j * 8) + i]) & 0x1F];
135+
}
136+
}
137+
regmap_bulk_write(rpisense_fb->regmap, 0, vmem_work, 192);
138+
}
139+
140+
static struct fb_deferred_io rpisense_fb_defio = {
141+
.delay = HZ/100,
142+
.deferred_io = rpisense_fb_deferred_io,
143+
};
144+
145+
static int rpisense_fb_ioctl(struct fb_info *info, unsigned int cmd,
146+
unsigned long arg)
147+
{
148+
switch (cmd) {
149+
case SENSEFB_FBIOGET_GAMMA:
150+
if (copy_to_user((void __user *) arg, rpisense_fb_param.gamma,
151+
sizeof(u8[32])))
152+
return -EFAULT;
153+
return 0;
154+
case SENSEFB_FBIOSET_GAMMA:
155+
if (copy_from_user(gamma_user, (void __user *)arg,
156+
sizeof(u8[32])))
157+
return -EFAULT;
158+
rpisense_fb_param.gamma = gamma_user;
159+
schedule_delayed_work(&info->deferred_work,
160+
rpisense_fb_defio.delay);
161+
return 0;
162+
case SENSEFB_FBIORESET_GAMMA:
163+
switch (arg) {
164+
case 0:
165+
rpisense_fb_param.gamma = gamma_default;
166+
break;
167+
case 1:
168+
rpisense_fb_param.gamma = gamma_low;
169+
break;
170+
case 2:
171+
rpisense_fb_param.gamma = gamma_user;
172+
break;
173+
default:
174+
return -EINVAL;
175+
}
176+
schedule_delayed_work(&info->deferred_work,
177+
rpisense_fb_defio.delay);
178+
break;
179+
default:
180+
return -EINVAL;
181+
}
182+
return 0;
183+
}
184+
185+
static struct fb_ops rpisense_fb_ops = {
186+
.owner = THIS_MODULE,
187+
.fb_read = fb_sys_read,
188+
.fb_write = rpisense_fb_write,
189+
.fb_fillrect = rpisense_fb_fillrect,
190+
.fb_copyarea = rpisense_fb_copyarea,
191+
.fb_imageblit = rpisense_fb_imageblit,
192+
.fb_ioctl = rpisense_fb_ioctl,
193+
.fb_mmap = fb_deferred_io_mmap,
194+
};
195+
196+
static int rpisense_fb_probe(struct platform_device *pdev)
197+
{
198+
struct fb_info *info;
199+
int ret = -ENOMEM;
200+
struct rpisense_fb *rpisense_fb;
201+
202+
info = framebuffer_alloc(sizeof(*rpisense_fb), &pdev->dev);
203+
if (!info) {
204+
dev_err(&pdev->dev, "Could not allocate framebuffer.\n");
205+
goto err_malloc;
206+
}
207+
208+
rpisense_fb = info->par;
209+
platform_set_drvdata(pdev, rpisense_fb);
210+
211+
rpisense_fb->pdev = pdev;
212+
rpisense_fb->regmap = dev_get_regmap(pdev->dev.parent, NULL);
213+
if (!rpisense_fb->regmap) {
214+
dev_err(&pdev->dev,
215+
"unable to get sensehat regmap");
216+
return -ENODEV;
217+
}
218+
219+
rpisense_fb_param.vmem = vzalloc(rpisense_fb_param.vmemsize);
220+
if (!rpisense_fb_param.vmem)
221+
return ret;
222+
223+
rpisense_fb_param.vmem_work = devm_kmalloc(&pdev->dev, 193, GFP_KERNEL);
224+
if (!rpisense_fb_param.vmem_work)
225+
goto err_malloc;
226+
227+
228+
rpisense_fb_fix.smem_start = (unsigned long)rpisense_fb_param.vmem;
229+
rpisense_fb_fix.smem_len = rpisense_fb_param.vmemsize;
230+
231+
info->fbops = &rpisense_fb_ops;
232+
info->fix = rpisense_fb_fix;
233+
info->var = rpisense_fb_var;
234+
info->fbdefio = &rpisense_fb_defio;
235+
info->flags = FBINFO_VIRTFB;
236+
info->screen_base = rpisense_fb_param.vmem;
237+
info->screen_size = rpisense_fb_param.vmemsize;
238+
info->pseudo_palette = pseudo_palette;
239+
240+
if (lowlight)
241+
rpisense_fb_param.gamma = gamma_low;
242+
243+
fb_deferred_io_init(info);
244+
245+
ret = register_framebuffer(info);
246+
if (ret < 0) {
247+
dev_err(&pdev->dev, "Could not register framebuffer.\n");
248+
goto err_fballoc;
249+
}
250+
251+
fb_info(info, "%s frame buffer device\n", info->fix.id);
252+
schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
253+
return 0;
254+
err_fballoc:
255+
framebuffer_release(info);
256+
err_malloc:
257+
vfree(rpisense_fb_param.vmem);
258+
return ret;
259+
}
260+
261+
static void rpisense_fb_remove(struct platform_device *pdev)
262+
{
263+
struct rpisense_fb *rpisense_fb = platform_get_drvdata(pdev);
264+
struct fb_info *info = rpisense_fb->info;
265+
266+
if (info) {
267+
unregister_framebuffer(info);
268+
fb_deferred_io_cleanup(info);
269+
framebuffer_release(info);
270+
vfree(rpisense_fb_param.vmem);
271+
}
272+
}
273+
274+
static const struct of_device_id rpisense_fb_id[] = {
275+
{ .compatible = "raspberrypi,rpi-sense-fb" },
276+
{ },
277+
};
278+
MODULE_DEVICE_TABLE(of, rpisense_fb_id);
279+
280+
static struct platform_driver rpisense_fb_driver = {
281+
.probe = rpisense_fb_probe,
282+
.remove = rpisense_fb_remove,
283+
.driver = {
284+
.name = "rpi-sense-fb",
285+
.owner = THIS_MODULE,
286+
.of_match_table = rpisense_fb_id,
287+
},
288+
};
289+
290+
module_platform_driver(rpisense_fb_driver);
291+
292+
MODULE_DESCRIPTION("Raspberry Pi Sense HAT framebuffer driver");
293+
MODULE_AUTHOR("Serge Schneider <[email protected]>");
294+
MODULE_LICENSE("GPL");
295+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Raspberry Pi Sense HAT framebuffer driver
3+
* http://raspberrypi.org
4+
*
5+
* Copyright (C) 2015 Raspberry Pi
6+
*
7+
* Author: Serge Schneider
8+
*
9+
* This program is free software; you can redistribute it and/or modify it
10+
* under the terms of the GNU General Public License as published by the
11+
* Free Software Foundation; either version 2 of the License, or (at your
12+
* option) any later version.
13+
*
14+
*/
15+
16+
#ifndef __LINUX_RPISENSE_FB_H_
17+
#define __LINUX_RPISENSE_FB_H_
18+
19+
#include <linux/regmap.h>
20+
21+
#define SENSEFB_FBIO_IOC_MAGIC 0xF1
22+
23+
#define SENSEFB_FBIOGET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 0)
24+
#define SENSEFB_FBIOSET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 1)
25+
#define SENSEFB_FBIORESET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 2)
26+
27+
struct rpisense;
28+
29+
struct rpisense_fb {
30+
struct fb_info *info;
31+
struct platform_device *pdev;
32+
struct regmap *regmap;
33+
};
34+
35+
#endif

0 commit comments

Comments
 (0)