summaryrefslogtreecommitdiff
path: root/target/linux/brcm2708/patches-4.9/0085-rpi_display-add-backlight-driver-and-overlay.patch
blob: 67c0e3f5cd8fe17540409eb0919c5aff99212bb0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
From ae5ae9278768c3d096910705bfa9af85da20a8cf Mon Sep 17 00:00:00 2001
From: P33M <P33M@github.com>
Date: Wed, 21 Oct 2015 14:55:21 +0100
Subject: [PATCH] rpi_display: add backlight driver and overlay

Add a mailbox-driven backlight controller for the Raspberry Pi DSI
touchscreen display. Requires updated GPU firmware to recognise the
mailbox request.

Signed-off-by: Gordon Hollingworth <gordon@raspberrypi.org>
---
 drivers/video/backlight/Kconfig         |   6 ++
 drivers/video/backlight/Makefile        |   1 +
 drivers/video/backlight/rpi_backlight.c | 119 ++++++++++++++++++++++++++++++++
 3 files changed, 126 insertions(+)
 create mode 100644 drivers/video/backlight/rpi_backlight.c

--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -265,6 +265,12 @@ config BACKLIGHT_PWM
 	  If you have a LCD backlight adjustable by PWM, say Y to enable
 	  this driver.
 
+config BACKLIGHT_RPI
+	tristate "Raspberry Pi display firmware driven backlight"
+	help
+	  If you have the Raspberry Pi DSI touchscreen display, say Y to
+	  enable the mailbox-controlled backlight driver.
+
 config BACKLIGHT_DA903X
 	tristate "Backlight Driver for DA9030/DA9034 using WLED"
 	depends on PMIC_DA903X
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA)		+= pand
 obj-$(CONFIG_BACKLIGHT_PCF50633)	+= pcf50633-backlight.o
 obj-$(CONFIG_BACKLIGHT_PM8941_WLED)	+= pm8941-wled.o
 obj-$(CONFIG_BACKLIGHT_PWM)		+= pwm_bl.o
+obj-$(CONFIG_BACKLIGHT_RPI)			+= rpi_backlight.o
 obj-$(CONFIG_BACKLIGHT_SAHARA)		+= kb3886_bl.o
 obj-$(CONFIG_BACKLIGHT_SKY81452)	+= sky81452-backlight.o
 obj-$(CONFIG_BACKLIGHT_TOSA)		+= tosa_bl.o
--- /dev/null
+++ b/drivers/video/backlight/rpi_backlight.c
@@ -0,0 +1,119 @@
+/*
+ * rpi_bl.c - Backlight controller through VPU
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+struct rpi_backlight {
+	struct device *dev;
+	struct device *fbdev;
+	struct rpi_firmware *fw;
+};
+
+static int rpi_backlight_update_status(struct backlight_device *bl)
+{
+	struct rpi_backlight *gbl = bl_get_data(bl);
+	int brightness = bl->props.brightness;
+	int ret;
+
+	if (bl->props.power != FB_BLANK_UNBLANK ||
+	    bl->props.fb_blank != FB_BLANK_UNBLANK ||
+	    bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
+		brightness = 0;
+
+	ret = rpi_firmware_property(gbl->fw,
+			RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT,
+			&brightness, sizeof(brightness));
+	if (ret) {
+		dev_err(gbl->dev, "Failed to set brightness\n");
+		return ret;
+	}
+
+	if (brightness < 0) {
+		dev_err(gbl->dev, "Backlight change failed\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static const struct backlight_ops rpi_backlight_ops = {
+	.options	= BL_CORE_SUSPENDRESUME,
+	.update_status	= rpi_backlight_update_status,
+};
+
+static int rpi_backlight_probe(struct platform_device *pdev)
+{
+	struct backlight_properties props;
+	struct backlight_device *bl;
+	struct rpi_backlight *gbl;
+	struct device_node *fw_node;
+
+	gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
+	if (gbl == NULL)
+		return -ENOMEM;
+
+	gbl->dev = &pdev->dev;
+
+	fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
+	if (!fw_node) {
+		dev_err(&pdev->dev, "Missing firmware node\n");
+		return -ENOENT;
+	}
+
+	gbl->fw = rpi_firmware_get(fw_node);
+	if (!gbl->fw)
+		return -EPROBE_DEFER;
+
+	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_RAW;
+	props.max_brightness = 255;
+	bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev),
+					&pdev->dev, gbl, &rpi_backlight_ops,
+					&props);
+	if (IS_ERR(bl)) {
+		dev_err(&pdev->dev, "failed to register backlight\n");
+		return PTR_ERR(bl);
+	}
+
+	bl->props.brightness = 255;
+	backlight_update_status(bl);
+
+	platform_set_drvdata(pdev, bl);
+	return 0;
+}
+
+static const struct of_device_id rpi_backlight_of_match[] = {
+	{ .compatible = "raspberrypi,rpi-backlight" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rpi_backlight_of_match);
+
+static struct platform_driver rpi_backlight_driver = {
+	.driver		= {
+		.name		= "rpi-backlight",
+		.of_match_table = of_match_ptr(rpi_backlight_of_match),
+	},
+	.probe		= rpi_backlight_probe,
+};
+
+module_platform_driver(rpi_backlight_driver);
+
+MODULE_AUTHOR("Gordon Hollingworth <gordon@raspberrypi.org>");
+MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver");
+MODULE_LICENSE("GPL");