brcm2708: update 4.1 patches
[openwrt.git] / target / linux / brcm2708 / patches-4.1 / 0122-Merge-pull-request-1043-from-XECDesign-sense-4.0.patch
1 From aa6bc84a28af9acd24d457944700b7880c86a343 Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <pelwell@users.noreply.github.com>
3 Date: Tue, 14 Jul 2015 14:32:47 +0100
4 Subject: [PATCH 122/203] Merge pull request #1043 from XECDesign/sense-4.0
5
6 mfd: Add Raspberry Pi Sense HAT core driver
7 ---
8  arch/arm/boot/dts/overlays/Makefile              |   1 +
9  arch/arm/boot/dts/overlays/README                |   6 +
10  arch/arm/boot/dts/overlays/rpi-sense-overlay.dts |  47 +++++
11  arch/arm/configs/bcm2709_defconfig               |   2 +
12  arch/arm/configs/bcmrpi_defconfig                |   2 +
13  drivers/input/joystick/Kconfig                   |   8 +
14  drivers/input/joystick/Makefile                  |   1 +
15  drivers/input/joystick/rpisense-js.c             | 153 +++++++++++++++
16  drivers/mfd/Kconfig                              |   8 +
17  drivers/mfd/Makefile                             |   2 +
18  drivers/mfd/rpisense-core.c                      | 157 +++++++++++++++
19  drivers/video/fbdev/Kconfig                      |  13 ++
20  drivers/video/fbdev/Makefile                     |   1 +
21  drivers/video/fbdev/rpisense-fb.c                | 235 +++++++++++++++++++++++
22  include/linux/mfd/rpisense/core.h                |  47 +++++
23  include/linux/mfd/rpisense/framebuffer.h         |  28 +++
24  include/linux/mfd/rpisense/joystick.h            |  35 ++++
25  17 files changed, 746 insertions(+)
26  create mode 100644 arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
27  create mode 100644 drivers/input/joystick/rpisense-js.c
28  create mode 100644 drivers/mfd/rpisense-core.c
29  create mode 100644 drivers/video/fbdev/rpisense-fb.c
30  create mode 100644 include/linux/mfd/rpisense/core.h
31  create mode 100644 include/linux/mfd/rpisense/framebuffer.h
32  create mode 100644 include/linux/mfd/rpisense/joystick.h
33
34 --- a/arch/arm/boot/dts/overlays/Makefile
35 +++ b/arch/arm/boot/dts/overlays/Makefile
36 @@ -39,6 +39,7 @@ dtb-$(RPI_DT_OVERLAYS) += rpi-dac-overla
37  dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb
38  dtb-$(RPI_DT_OVERLAYS) += rpi-ft5406-overlay.dtb
39  dtb-$(RPI_DT_OVERLAYS) += rpi-proto-overlay.dtb
40 +dtb-$(RPI_DT_OVERLAYS) += rpi-sense-overlay.dtb
41  dtb-$(RPI_DT_OVERLAYS) += sdhost-overlay.dtb
42  dtb-$(RPI_DT_OVERLAYS) += spi-bcm2708-overlay.dtb
43  dtb-$(RPI_DT_OVERLAYS) += spi-bcm2835-overlay.dtb
44 --- a/arch/arm/boot/dts/overlays/README
45 +++ b/arch/arm/boot/dts/overlays/README
46 @@ -442,6 +442,12 @@ Load:   dtoverlay=rpi-proto
47  Params: <None>
48  
49  
50 +Name:   rpi-sense
51 +Info:   Raspberry Pi Sense HAT
52 +Load:   dtoverlay=rpi-sense
53 +Params: <None>
54 +
55 +
56  Name:   sdhost
57  Info:   Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock
58  Load:   dtoverlay=sdhost,<param>=<val>
59 --- /dev/null
60 +++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
61 @@ -0,0 +1,47 @@
62 +// rpi-sense HAT
63 +/dts-v1/;
64 +/plugin/;
65 +
66 +/ {
67 +       compatible = "brcm,bcm2708", "brcm,bcm2709";
68 +
69 +       fragment@0 {
70 +               target = <&i2c1>;
71 +               __overlay__ {
72 +                       #address-cells = <1>;
73 +                       #size-cells = <0>;
74 +                       status = "okay";
75 +
76 +                       rpi-sense@46 {
77 +                               compatible = "rpi,rpi-sense";
78 +                               reg = <0x46>;
79 +                               keys-int-gpios = <&gpio 23 1>;
80 +                               status = "okay";
81 +                       };
82 +
83 +                       lsm9ds1-magn@1c {
84 +                               compatible = "st,lsm9ds1-magn";
85 +                               reg = <0x1c>;
86 +                               status = "okay";
87 +                       };
88 +
89 +                       lsm9ds1-accel6a {
90 +                               compatible = "st,lsm9ds1-accel";
91 +                               reg = <0x6a>;
92 +                               status = "okay";
93 +                       };
94 +
95 +                       lps25h-press@5c {
96 +                               compatible = "st,lps25h-press";
97 +                               reg = <0x5c>;
98 +                               status = "okay";
99 +                       };
100 +
101 +                       hts221-humid@5f {
102 +                               compatible = "st,hts221-humid";
103 +                               reg = <0x5f>;
104 +                               status = "okay";
105 +                       };
106 +               };
107 +       };
108 +};
109 --- a/arch/arm/configs/bcm2709_defconfig
110 +++ b/arch/arm/configs/bcm2709_defconfig
111 @@ -533,6 +533,7 @@ CONFIG_JOYSTICK_IFORCE=m
112  CONFIG_JOYSTICK_IFORCE_USB=y
113  CONFIG_JOYSTICK_XPAD=m
114  CONFIG_JOYSTICK_XPAD_FF=y
115 +CONFIG_JOYSTICK_RPISENSE=m
116  CONFIG_INPUT_TOUCHSCREEN=y
117  CONFIG_TOUCHSCREEN_ADS7846=m
118  CONFIG_TOUCHSCREEN_EGALAX=m
119 @@ -789,6 +790,7 @@ CONFIG_VIDEO_MT9V011=m
120  CONFIG_FB=y
121  CONFIG_FB_BCM2708=y
122  CONFIG_FB_SSD1307=m
123 +CONFIG_FB_RPISENSE=m
124  # CONFIG_BACKLIGHT_GENERIC is not set
125  CONFIG_BACKLIGHT_GPIO=m
126  CONFIG_FRAMEBUFFER_CONSOLE=y
127 --- a/arch/arm/configs/bcmrpi_defconfig
128 +++ b/arch/arm/configs/bcmrpi_defconfig
129 @@ -526,6 +526,7 @@ CONFIG_JOYSTICK_IFORCE=m
130  CONFIG_JOYSTICK_IFORCE_USB=y
131  CONFIG_JOYSTICK_XPAD=m
132  CONFIG_JOYSTICK_XPAD_FF=y
133 +CONFIG_JOYSTICK_RPISENSE=m
134  CONFIG_INPUT_TOUCHSCREEN=y
135  CONFIG_TOUCHSCREEN_ADS7846=m
136  CONFIG_TOUCHSCREEN_EGALAX=m
137 @@ -782,6 +783,7 @@ CONFIG_VIDEO_MT9V011=m
138  CONFIG_FB=y
139  CONFIG_FB_BCM2708=y
140  CONFIG_FB_SSD1307=m
141 +CONFIG_FB_RPISENSE=m
142  # CONFIG_BACKLIGHT_GENERIC is not set
143  CONFIG_BACKLIGHT_GPIO=m
144  CONFIG_FRAMEBUFFER_CONSOLE=y
145 --- a/drivers/input/joystick/Kconfig
146 +++ b/drivers/input/joystick/Kconfig
147 @@ -329,4 +329,12 @@ config JOYSTICK_MAPLE
148           To compile this as a module choose M here: the module will be called
149           maplecontrol.
150  
151 +config JOYSTICK_RPISENSE
152 +       tristate "Raspberry Pi Sense HAT joystick"
153 +       depends on GPIOLIB && INPUT
154 +       select MFD_RPISENSE_CORE
155 +
156 +       help
157 +         This is the joystick driver for the Raspberry Pi Sense HAT
158 +
159  endif
160 --- a/drivers/input/joystick/Makefile
161 +++ b/drivers/input/joystick/Makefile
162 @@ -32,4 +32,5 @@ obj-$(CONFIG_JOYSTICK_WARRIOR)                += warri
163  obj-$(CONFIG_JOYSTICK_XPAD)            += xpad.o
164  obj-$(CONFIG_JOYSTICK_ZHENHUA)         += zhenhua.o
165  obj-$(CONFIG_JOYSTICK_WALKERA0701)     += walkera0701.o
166 +obj-$(CONFIG_JOYSTICK_RPISENSE)                += rpisense-js.o
167  
168 --- /dev/null
169 +++ b/drivers/input/joystick/rpisense-js.c
170 @@ -0,0 +1,153 @@
171 +/*
172 + * Raspberry Pi Sense HAT joystick driver
173 + * http://raspberrypi.org
174 + *
175 + * Copyright (C) 2015 Raspberry Pi
176 + *
177 + * Author: Serge Schneider
178 + *
179 + *  This program is free software; you can redistribute  it and/or modify it
180 + *  under  the terms of  the GNU General  Public License as published by the
181 + *  Free Software Foundation;  either version 2 of the  License, or (at your
182 + *  option) any later version.
183 + *
184 + */
185 +
186 +#include <linux/module.h>
187 +
188 +#include <linux/mfd/rpisense/joystick.h>
189 +#include <linux/mfd/rpisense/core.h>
190 +
191 +struct rpisense *rpisense;
192 +unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,};
193 +
194 +static void keys_work_fn(struct work_struct *work)
195 +{
196 +       int i;
197 +       static s32 prev_keys;
198 +       struct rpisense_js *rpisense_js = &rpisense->joystick;
199 +       s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS);
200 +       s32 changes = keys ^ prev_keys;
201 +
202 +       prev_keys = keys;
203 +       for (i = 0; i < 5; i++) {
204 +               if (changes & 1) {
205 +                       input_report_key(rpisense_js->keys_dev,
206 +                                        keymap[i], keys & 1);
207 +               }
208 +               changes >>= 1;
209 +               keys >>= 1;
210 +       }
211 +       input_sync(rpisense_js->keys_dev);
212 +}
213 +
214 +static irqreturn_t keys_irq_handler(int irq, void *pdev)
215 +{
216 +       struct rpisense_js *rpisense_js = &rpisense->joystick;
217 +
218 +       schedule_work(&rpisense_js->keys_work_s);
219 +       return IRQ_HANDLED;
220 +}
221 +
222 +static int rpisense_js_probe(struct platform_device *pdev)
223 +{
224 +       int ret;
225 +       int i;
226 +       struct rpisense_js *rpisense_js;
227 +
228 +       rpisense = rpisense_get_dev();
229 +       rpisense_js = &rpisense->joystick;
230 +
231 +       INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn);
232 +
233 +       rpisense_js->keys_dev = input_allocate_device();
234 +       if (!rpisense_js->keys_dev) {
235 +               dev_err(&pdev->dev, "Could not allocate input device.\n");
236 +               return -ENOMEM;
237 +       }
238 +
239 +       rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY);
240 +       for (i = 0; i < ARRAY_SIZE(keymap); i++) {
241 +               set_bit(keymap[i],
242 +                       rpisense_js->keys_dev->keybit);
243 +       }
244 +
245 +       rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick";
246 +       rpisense_js->keys_dev->phys = "rpi-sense-joy/input0";
247 +       rpisense_js->keys_dev->id.bustype = BUS_I2C;
248 +       rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
249 +       rpisense_js->keys_dev->keycode = keymap;
250 +       rpisense_js->keys_dev->keycodesize = sizeof(unsigned char);
251 +       rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap);
252 +
253 +       ret = input_register_device(rpisense_js->keys_dev);
254 +       if (ret) {
255 +               dev_err(&pdev->dev, "Could not register input device.\n");
256 +               goto err_keys_alloc;
257 +       }
258 +
259 +       ret = gpiod_direction_input(rpisense_js->keys_desc);
260 +       if (ret) {
261 +               dev_err(&pdev->dev, "Could not set keys-int direction.\n");
262 +               goto err_keys_reg;
263 +       }
264 +
265 +       rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc);
266 +       if (rpisense_js->keys_irq < 0) {
267 +               dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n");
268 +               ret = rpisense_js->keys_irq;
269 +               goto err_keys_reg;
270 +       }
271 +
272 +       ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq,
273 +                              keys_irq_handler, IRQF_TRIGGER_RISING,
274 +                              "keys", &pdev->dev);
275 +       if (ret) {
276 +               dev_err(&pdev->dev, "IRQ request failed.\n");
277 +               goto err_keys_reg;
278 +       }
279 +       return 0;
280 +err_keys_reg:
281 +       input_unregister_device(rpisense_js->keys_dev);
282 +err_keys_alloc:
283 +       input_free_device(rpisense_js->keys_dev);
284 +       return ret;
285 +}
286 +
287 +static int rpisense_js_remove(struct platform_device *pdev)
288 +{
289 +       struct rpisense_js *rpisense_js = &rpisense->joystick;
290 +
291 +       input_unregister_device(rpisense_js->keys_dev);
292 +       input_free_device(rpisense_js->keys_dev);
293 +       return 0;
294 +}
295 +
296 +#ifdef CONFIG_OF
297 +static const struct of_device_id rpisense_js_id[] = {
298 +       { .compatible = "rpi,rpi-sense-js" },
299 +       { },
300 +};
301 +MODULE_DEVICE_TABLE(of, rpisense_js_id);
302 +#endif
303 +
304 +static struct platform_device_id rpisense_js_device_id[] = {
305 +       { .name = "rpi-sense-js" },
306 +       { },
307 +};
308 +MODULE_DEVICE_TABLE(platform, rpisense_js_device_id);
309 +
310 +static struct platform_driver rpisense_js_driver = {
311 +       .probe = rpisense_js_probe,
312 +       .remove = rpisense_js_remove,
313 +       .driver = {
314 +               .name = "rpi-sense-js",
315 +               .owner = THIS_MODULE,
316 +       },
317 +};
318 +
319 +module_platform_driver(rpisense_js_driver);
320 +
321 +MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver");
322 +MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
323 +MODULE_LICENSE("GPL");
324 --- a/drivers/mfd/Kconfig
325 +++ b/drivers/mfd/Kconfig
326 @@ -10,6 +10,14 @@ config MFD_CORE
327         select IRQ_DOMAIN
328         default n
329  
330 +config MFD_RPISENSE_CORE
331 +       tristate "Raspberry Pi Sense HAT core functions"
332 +       depends on I2C
333 +       select MFD_CORE
334 +       help
335 +         This is the core driver for the Raspberry Pi Sense HAT. This provides
336 +         the necessary functions to communicate with the hardware.
337 +
338  config MFD_CS5535
339         tristate "AMD CS5535 and CS5536 southbridge core functions"
340         select MFD_CORE
341 --- a/drivers/mfd/Makefile
342 +++ b/drivers/mfd/Makefile
343 @@ -185,3 +185,5 @@ obj-$(CONFIG_MFD_SKY81452)  += sky81452.o
344  intel-soc-pmic-objs            := intel_soc_pmic_core.o intel_soc_pmic_crc.o
345  obj-$(CONFIG_INTEL_SOC_PMIC)   += intel-soc-pmic.o
346  obj-$(CONFIG_MFD_MT6397)       += mt6397-core.o
347 +
348 +obj-$(CONFIG_MFD_RPISENSE_CORE)        += rpisense-core.o
349 --- /dev/null
350 +++ b/drivers/mfd/rpisense-core.c
351 @@ -0,0 +1,157 @@
352 +/*
353 + * Raspberry Pi Sense HAT core driver
354 + * http://raspberrypi.org
355 + *
356 + * Copyright (C) 2015 Raspberry Pi
357 + *
358 + * Author: Serge Schneider
359 + *
360 + *  This program is free software; you can redistribute  it and/or modify it
361 + *  under  the terms of  the GNU General  Public License as published by the
362 + *  Free Software Foundation;  either version 2 of the  License, or (at your
363 + *  option) any later version.
364 + *
365 + *  This driver is based on wm8350 implementation.
366 + */
367 +
368 +#include <linux/module.h>
369 +#include <linux/moduleparam.h>
370 +#include <linux/err.h>
371 +#include <linux/init.h>
372 +#include <linux/i2c.h>
373 +#include <linux/platform_device.h>
374 +#include <linux/mfd/rpisense/core.h>
375 +#include <linux/slab.h>
376 +
377 +struct rpisense *rpisense;
378 +
379 +static void rpisense_client_dev_register(struct rpisense *rpisense,
380 +                                        const char *name,
381 +                                        struct platform_device **pdev)
382 +{
383 +       int ret;
384 +
385 +       *pdev = platform_device_alloc(name, -1);
386 +       if (*pdev == NULL) {
387 +               dev_err(rpisense->dev, "Failed to allocate %s\n", name);
388 +               return;
389 +       }
390 +
391 +       (*pdev)->dev.parent = rpisense->dev;
392 +       platform_set_drvdata(*pdev, rpisense);
393 +       ret = platform_device_add(*pdev);
394 +       if (ret != 0) {
395 +               dev_err(rpisense->dev, "Failed to register %s: %d\n",
396 +                       name, ret);
397 +               platform_device_put(*pdev);
398 +               *pdev = NULL;
399 +       }
400 +}
401 +
402 +static int rpisense_probe(struct i2c_client *i2c,
403 +                              const struct i2c_device_id *id)
404 +{
405 +       int ret;
406 +       struct rpisense_js *rpisense_js;
407 +
408 +       rpisense = devm_kzalloc(&i2c->dev, sizeof(struct rpisense), GFP_KERNEL);
409 +       if (rpisense == NULL)
410 +               return -ENOMEM;
411 +
412 +       i2c_set_clientdata(i2c, rpisense);
413 +       rpisense->dev = &i2c->dev;
414 +       rpisense->i2c_client = i2c;
415 +
416 +       ret = rpisense_reg_read(rpisense, RPISENSE_WAI);
417 +       if (ret > 0) {
418 +               if (ret != 's')
419 +                       return -EINVAL;
420 +       } else {
421 +               return ret;
422 +       }
423 +       ret = rpisense_reg_read(rpisense, RPISENSE_VER);
424 +       if (ret < 0)
425 +               return ret;
426 +
427 +       dev_info(rpisense->dev,
428 +                "Raspberry Pi Sense HAT firmware version %i\n", ret);
429 +
430 +       rpisense_js = &rpisense->joystick;
431 +       rpisense_js->keys_desc = devm_gpiod_get(&i2c->dev,
432 +                                               "keys-int", GPIOD_IN);
433 +       if (IS_ERR(rpisense_js->keys_desc)) {
434 +               dev_warn(&i2c->dev, "Failed to get keys-int descriptor.\n");
435 +               rpisense_js->keys_desc = gpio_to_desc(23);
436 +               if (rpisense_js->keys_desc == NULL) {
437 +                       dev_err(&i2c->dev, "GPIO23 fallback failed.\n");
438 +                       return PTR_ERR(rpisense_js->keys_desc);
439 +               }
440 +       }
441 +       rpisense_client_dev_register(rpisense, "rpi-sense-js",
442 +                                    &(rpisense->joystick.pdev));
443 +       rpisense_client_dev_register(rpisense, "rpi-sense-fb",
444 +                                    &(rpisense->framebuffer.pdev));
445 +
446 +       return 0;
447 +}
448 +
449 +static int rpisense_remove(struct i2c_client *i2c)
450 +{
451 +       struct rpisense *rpisense = i2c_get_clientdata(i2c);
452 +
453 +       platform_device_unregister(rpisense->joystick.pdev);
454 +       return 0;
455 +}
456 +
457 +struct rpisense *rpisense_get_dev(void)
458 +{
459 +       return rpisense;
460 +}
461 +EXPORT_SYMBOL_GPL(rpisense_get_dev);
462 +
463 +s32 rpisense_reg_read(struct rpisense *rpisense, int reg)
464 +{
465 +       int ret = i2c_smbus_read_byte_data(rpisense->i2c_client, reg);
466 +
467 +       if (ret < 0)
468 +               dev_err(rpisense->dev, "Read from reg %d failed\n", reg);
469 +       /* Due to the BCM270x I2C clock stretching bug, some values
470 +        * may have MSB set. Clear it to avoid incorrect values.
471 +        * */
472 +       return ret & 0x7F;
473 +}
474 +EXPORT_SYMBOL_GPL(rpisense_reg_read);
475 +
476 +int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count)
477 +{
478 +       int ret = i2c_master_send(rpisense->i2c_client, buf, count);
479 +
480 +       if (ret < 0)
481 +               dev_err(rpisense->dev, "Block write failed\n");
482 +       return ret;
483 +}
484 +EXPORT_SYMBOL_GPL(rpisense_block_write);
485 +
486 +static const struct i2c_device_id rpisense_i2c_id[] = {
487 +       { "rpi-sense", 0 },
488 +       { }
489 +};
490 +MODULE_DEVICE_TABLE(i2c, rpisense_i2c_id);
491 +
492 +
493 +static struct i2c_driver rpisense_driver = {
494 +       .driver = {
495 +                  .name = "rpi-sense",
496 +                  .owner = THIS_MODULE,
497 +       },
498 +       .probe = rpisense_probe,
499 +       .remove = rpisense_remove,
500 +       .id_table = rpisense_i2c_id,
501 +};
502 +
503 +module_i2c_driver(rpisense_driver);
504 +
505 +MODULE_DESCRIPTION("Raspberry Pi Sense HAT core driver");
506 +MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
507 +MODULE_LICENSE("GPL");
508 +
509 --- a/drivers/video/fbdev/Kconfig
510 +++ b/drivers/video/fbdev/Kconfig
511 @@ -2495,3 +2495,16 @@ config FB_SSD1307
512         help
513           This driver implements support for the Solomon SSD1307
514           OLED controller over I2C.
515 +
516 +config FB_RPISENSE
517 +       tristate "Raspberry Pi Sense HAT framebuffer"
518 +       depends on FB
519 +       select MFD_RPISENSE_CORE
520 +       select FB_SYS_FOPS
521 +       select FB_SYS_FILLRECT
522 +       select FB_SYS_COPYAREA
523 +       select FB_SYS_IMAGEBLIT
524 +       select FB_DEFERRED_IO
525 +
526 +       help
527 +         This is the framebuffer driver for the Raspberry Pi Sense HAT
528 --- a/drivers/video/fbdev/Makefile
529 +++ b/drivers/video/fbdev/Makefile
530 @@ -150,6 +150,7 @@ obj-$(CONFIG_FB_DA8XX)                += da8xx-fb.o
531  obj-$(CONFIG_FB_MXS)             += mxsfb.o
532  obj-$(CONFIG_FB_SSD1307)         += ssd1307fb.o
533  obj-$(CONFIG_FB_SIMPLE)           += simplefb.o
534 +obj-$(CONFIG_FB_RPISENSE)        += rpisense-fb.o
535  
536  # the test framebuffer is last
537  obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
538 --- /dev/null
539 +++ b/drivers/video/fbdev/rpisense-fb.c
540 @@ -0,0 +1,235 @@
541 +/*
542 + * Raspberry Pi Sense HAT framebuffer driver
543 + * http://raspberrypi.org
544 + *
545 + * Copyright (C) 2015 Raspberry Pi
546 + *
547 + * Author: Serge Schneider
548 + *
549 + *  This program is free software; you can redistribute  it and/or modify it
550 + *  under  the terms of  the GNU General  Public License as published by the
551 + *  Free Software Foundation;  either version 2 of the  License, or (at your
552 + *  option) any later version.
553 + *
554 + */
555 +
556 +#include <linux/module.h>
557 +#include <linux/kernel.h>
558 +#include <linux/errno.h>
559 +#include <linux/string.h>
560 +#include <linux/mm.h>
561 +#include <linux/slab.h>
562 +#include <linux/delay.h>
563 +#include <linux/fb.h>
564 +#include <linux/init.h>
565 +
566 +#include <linux/mfd/rpisense/framebuffer.h>
567 +#include <linux/mfd/rpisense/core.h>
568 +
569 +struct rpisense *rpisense;
570 +
571 +struct rpisense_fb_param {
572 +       char __iomem *vmem;
573 +       u8 *vmem_work;
574 +       u32 vmemsize;
575 +       u8 gamma[32];
576 +};
577 +
578 +static struct rpisense_fb_param rpisense_fb_param = {
579 +       .vmem = NULL,
580 +       .vmemsize = 128,
581 +       .gamma = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
582 +                 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07,
583 +                 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x11,
584 +                 0x12, 0x14, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F,},
585 +};
586 +
587 +static struct fb_deferred_io rpisense_fb_defio;
588 +
589 +static struct fb_fix_screeninfo rpisense_fb_fix = {
590 +       .id =           "RPi-Sense FB",
591 +       .type =         FB_TYPE_PACKED_PIXELS,
592 +       .visual =       FB_VISUAL_TRUECOLOR,
593 +       .xpanstep =     0,
594 +       .ypanstep =     0,
595 +       .ywrapstep =    0,
596 +       .accel =        FB_ACCEL_NONE,
597 +       .line_length =  16,
598 +};
599 +
600 +static struct fb_var_screeninfo rpisense_fb_var = {
601 +       .xres           = 8,
602 +       .yres           = 8,
603 +       .xres_virtual   = 8,
604 +       .yres_virtual   = 8,
605 +       .bits_per_pixel = 16,
606 +       .red            = {11, 5, 0},
607 +       .green          = {5, 6, 0},
608 +       .blue           = {0, 5, 0},
609 +};
610 +
611 +static ssize_t rpisense_fb_write(struct fb_info *info,
612 +                                const char __user *buf, size_t count,
613 +                                loff_t *ppos)
614 +{
615 +       ssize_t res = fb_sys_write(info, buf, count, ppos);
616 +
617 +       schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
618 +       return res;
619 +}
620 +
621 +static void rpisense_fb_fillrect(struct fb_info *info,
622 +                                const struct fb_fillrect *rect)
623 +{
624 +       sys_fillrect(info, rect);
625 +       schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
626 +}
627 +
628 +static void rpisense_fb_copyarea(struct fb_info *info,
629 +                                const struct fb_copyarea *area)
630 +{
631 +       sys_copyarea(info, area);
632 +       schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
633 +}
634 +
635 +static void rpisense_fb_imageblit(struct fb_info *info,
636 +                                 const struct fb_image *image)
637 +{
638 +       sys_imageblit(info, image);
639 +       schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
640 +}
641 +
642 +static void rpisense_fb_deferred_io(struct fb_info *info,
643 +                               struct list_head *pagelist)
644 +{
645 +       int i;
646 +       int j;
647 +       u8 *vmem_work = rpisense_fb_param.vmem_work;
648 +       u16 *mem = (u16 *)rpisense_fb_param.vmem;
649 +       u8 *gamma = rpisense_fb_param.gamma;
650 +
651 +       vmem_work[0] = 0;
652 +       for (j = 0; j < 8; j++) {
653 +               for (i = 0; i < 8; i++) {
654 +                       vmem_work[(j * 24) + i + 1] =
655 +                               gamma[(mem[(j * 8) + i] >> 11) & 0x1F];
656 +                       vmem_work[(j * 24) + (i + 8) + 1] =
657 +                               gamma[(mem[(j * 8) + i] >> 6) & 0x1F];
658 +                       vmem_work[(j * 24) + (i + 16) + 1] =
659 +                               gamma[(mem[(j * 8) + i]) & 0x1F];
660 +               }
661 +       }
662 +       rpisense_block_write(rpisense, vmem_work, 193);
663 +}
664 +
665 +static struct fb_deferred_io rpisense_fb_defio = {
666 +       .delay          = HZ/100,
667 +       .deferred_io    = rpisense_fb_deferred_io,
668 +};
669 +
670 +static struct fb_ops rpisense_fb_ops = {
671 +       .owner          = THIS_MODULE,
672 +       .fb_read        = fb_sys_read,
673 +       .fb_write       = rpisense_fb_write,
674 +       .fb_fillrect    = rpisense_fb_fillrect,
675 +       .fb_copyarea    = rpisense_fb_copyarea,
676 +       .fb_imageblit   = rpisense_fb_imageblit,
677 +};
678 +
679 +static int rpisense_fb_probe(struct platform_device *pdev)
680 +{
681 +       struct fb_info *info;
682 +       int ret = -ENOMEM;
683 +       struct rpisense_fb *rpisense_fb;
684 +
685 +       rpisense = rpisense_get_dev();
686 +       rpisense_fb = &rpisense->framebuffer;
687 +
688 +       rpisense_fb_param.vmem = vzalloc(rpisense_fb_param.vmemsize);
689 +       if (!rpisense_fb_param.vmem)
690 +               return ret;
691 +
692 +       rpisense_fb_param.vmem_work = devm_kmalloc(&pdev->dev, 193, GFP_KERNEL);
693 +       if (!rpisense_fb_param.vmem_work)
694 +               goto err_malloc;
695 +
696 +       info = framebuffer_alloc(0, &pdev->dev);
697 +       if (!info) {
698 +               dev_err(&pdev->dev, "Could not allocate framebuffer.\n");
699 +               goto err_malloc;
700 +       }
701 +       rpisense_fb->info = info;
702 +
703 +       rpisense_fb_fix.smem_start = (unsigned long)rpisense_fb_param.vmem;
704 +       rpisense_fb_fix.smem_len = rpisense_fb_param.vmemsize;
705 +
706 +       info->fbops = &rpisense_fb_ops;
707 +       info->fix = rpisense_fb_fix;
708 +       info->var = rpisense_fb_var;
709 +       info->fbdefio = &rpisense_fb_defio;
710 +       info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
711 +       info->screen_base = rpisense_fb_param.vmem;
712 +       info->screen_size = rpisense_fb_param.vmemsize;
713 +
714 +       fb_deferred_io_init(info);
715 +
716 +       ret = register_framebuffer(info);
717 +       if (ret < 0) {
718 +               dev_err(&pdev->dev, "Could not register framebuffer.\n");
719 +               goto err_fballoc;
720 +       }
721 +
722 +       fb_info(info, "%s frame buffer device\n", info->fix.id);
723 +       schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
724 +       return 0;
725 +err_fballoc:
726 +       framebuffer_release(info);
727 +err_malloc:
728 +       vfree(rpisense_fb_param.vmem);
729 +       return ret;
730 +}
731 +
732 +static int rpisense_fb_remove(struct platform_device *pdev)
733 +{
734 +       struct rpisense_fb *rpisense_fb = &rpisense->framebuffer;
735 +       struct fb_info *info = rpisense_fb->info;
736 +
737 +       if (info) {
738 +               unregister_framebuffer(info);
739 +               fb_deferred_io_cleanup(info);
740 +               framebuffer_release(info);
741 +               vfree(rpisense_fb_param.vmem);
742 +       }
743 +
744 +       return 0;
745 +}
746 +
747 +#ifdef CONFIG_OF
748 +static const struct of_device_id rpisense_fb_id[] = {
749 +       { .compatible = "rpi,rpi-sense-fb" },
750 +       { },
751 +};
752 +MODULE_DEVICE_TABLE(of, rpisense_fb_id);
753 +#endif
754 +
755 +static struct platform_device_id rpisense_fb_device_id[] = {
756 +       { .name = "rpi-sense-fb" },
757 +       { },
758 +};
759 +MODULE_DEVICE_TABLE(platform, rpisense_fb_device_id);
760 +
761 +static struct platform_driver rpisense_fb_driver = {
762 +       .probe = rpisense_fb_probe,
763 +       .remove = rpisense_fb_remove,
764 +       .driver = {
765 +               .name = "rpi-sense-fb",
766 +               .owner = THIS_MODULE,
767 +       },
768 +};
769 +
770 +module_platform_driver(rpisense_fb_driver);
771 +
772 +MODULE_DESCRIPTION("Raspberry Pi Sense HAT framebuffer driver");
773 +MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
774 +MODULE_LICENSE("GPL");
775 +
776 --- /dev/null
777 +++ b/include/linux/mfd/rpisense/core.h
778 @@ -0,0 +1,47 @@
779 +/*
780 + * Raspberry Pi Sense HAT core driver
781 + * http://raspberrypi.org
782 + *
783 + * Copyright (C) 2015 Raspberry Pi
784 + *
785 + * Author: Serge Schneider
786 + *
787 + *  This program is free software; you can redistribute  it and/or modify it
788 + *  under  the terms of  the GNU General  Public License as published by the
789 + *  Free Software Foundation;  either version 2 of the  License, or (at your
790 + *  option) any later version.
791 + *
792 + */
793 +
794 +#ifndef __LINUX_MFD_RPISENSE_CORE_H_
795 +#define __LINUX_MFD_RPISENSE_CORE_H_
796 +
797 +#include <linux/mfd/rpisense/joystick.h>
798 +#include <linux/mfd/rpisense/framebuffer.h>
799 +
800 +/*
801 + * Register values.
802 + */
803 +#define RPISENSE_FB                    0x00
804 +#define RPISENSE_WAI                   0xF0
805 +#define RPISENSE_VER                   0xF1
806 +#define RPISENSE_KEYS                  0xF2
807 +#define RPISENSE_EE_WP                 0xF3
808 +
809 +#define RPISENSE_ID                    's'
810 +
811 +struct rpisense {
812 +       struct device *dev;
813 +       struct i2c_client *i2c_client;
814 +
815 +       /* Client devices */
816 +       struct rpisense_js joystick;
817 +       struct rpisense_fb framebuffer;
818 +};
819 +
820 +struct rpisense *rpisense_get_dev(void);
821 +s32 rpisense_reg_read(struct rpisense *rpisense, int reg);
822 +int rpisense_reg_write(struct rpisense *rpisense, int reg, u16 val);
823 +int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count);
824 +
825 +#endif
826 --- /dev/null
827 +++ b/include/linux/mfd/rpisense/framebuffer.h
828 @@ -0,0 +1,28 @@
829 +/*
830 + * Raspberry Pi Sense HAT framebuffer driver
831 + * http://raspberrypi.org
832 + *
833 + * Copyright (C) 2015 Raspberry Pi
834 + *
835 + * Author: Serge Schneider
836 + *
837 + *  This program is free software; you can redistribute  it and/or modify it
838 + *  under  the terms of  the GNU General  Public License as published by the
839 + *  Free Software Foundation;  either version 2 of the  License, or (at your
840 + *  option) any later version.
841 + *
842 + */
843 +
844 +#ifndef __LINUX_RPISENSE_FB_H_
845 +#define __LINUX_RPISENSE_FB_H_
846 +
847 +#include <linux/platform_device.h>
848 +
849 +struct rpisense;
850 +
851 +struct rpisense_fb {
852 +       struct platform_device *pdev;
853 +       struct fb_info *info;
854 +};
855 +
856 +#endif
857 --- /dev/null
858 +++ b/include/linux/mfd/rpisense/joystick.h
859 @@ -0,0 +1,35 @@
860 +/*
861 + * Raspberry Pi Sense HAT joystick driver
862 + * http://raspberrypi.org
863 + *
864 + * Copyright (C) 2015 Raspberry Pi
865 + *
866 + * Author: Serge Schneider
867 + *
868 + *  This program is free software; you can redistribute  it and/or modify it
869 + *  under  the terms of  the GNU General  Public License as published by the
870 + *  Free Software Foundation;  either version 2 of the  License, or (at your
871 + *  option) any later version.
872 + *
873 + */
874 +
875 +#ifndef __LINUX_RPISENSE_JOYSTICK_H_
876 +#define __LINUX_RPISENSE_JOYSTICK_H_
877 +
878 +#include <linux/input.h>
879 +#include <linux/interrupt.h>
880 +#include <linux/gpio/consumer.h>
881 +#include <linux/platform_device.h>
882 +
883 +struct rpisense;
884 +
885 +struct rpisense_js {
886 +       struct platform_device *pdev;
887 +       struct input_dev *keys_dev;
888 +       struct gpio_desc *keys_desc;
889 +       struct work_struct keys_work_s;
890 +       int keys_irq;
891 +};
892 +
893 +
894 +#endif