1 // SPDX-License-Identifier: GPL-2.0-only
3 * gpio_backlight.c - Simple GPIO-controlled backlight
6 #include <linux/backlight.h>
9 #include <linux/gpio.h> /* Only for legacy support */
10 #include <linux/gpio/consumer.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
15 #include <linux/of_gpio.h>
16 #include <linux/platform_data/gpio_backlight.h>
17 #include <linux/platform_device.h>
18 #include <linux/property.h>
19 #include <linux/slab.h>
21 struct gpio_backlight
{
25 struct gpio_desc
*gpiod
;
29 static int gpio_backlight_update_status(struct backlight_device
*bl
)
31 struct gpio_backlight
*gbl
= bl_get_data(bl
);
32 int brightness
= bl
->props
.brightness
;
34 if (bl
->props
.power
!= FB_BLANK_UNBLANK
||
35 bl
->props
.fb_blank
!= FB_BLANK_UNBLANK
||
36 bl
->props
.state
& (BL_CORE_SUSPENDED
| BL_CORE_FBBLANK
))
39 gpiod_set_value_cansleep(gbl
->gpiod
, brightness
);
44 static int gpio_backlight_check_fb(struct backlight_device
*bl
,
47 struct gpio_backlight
*gbl
= bl_get_data(bl
);
49 return gbl
->fbdev
== NULL
|| gbl
->fbdev
== info
->dev
;
52 static const struct backlight_ops gpio_backlight_ops
= {
53 .options
= BL_CORE_SUSPENDRESUME
,
54 .update_status
= gpio_backlight_update_status
,
55 .check_fb
= gpio_backlight_check_fb
,
58 static int gpio_backlight_probe_dt(struct platform_device
*pdev
,
59 struct gpio_backlight
*gbl
)
61 struct device
*dev
= &pdev
->dev
;
64 gbl
->def_value
= device_property_read_bool(dev
, "default-on");
66 gbl
->gpiod
= devm_gpiod_get(dev
, NULL
, GPIOD_ASIS
);
67 if (IS_ERR(gbl
->gpiod
)) {
68 ret
= PTR_ERR(gbl
->gpiod
);
70 if (ret
!= -EPROBE_DEFER
) {
72 "Error: The gpios parameter is missing or invalid.\n");
80 static int gpio_backlight_initial_power_state(struct gpio_backlight
*gbl
)
82 struct device_node
*node
= gbl
->dev
->of_node
;
84 /* Not booted with device tree or no phandle link to the node */
85 if (!node
|| !node
->phandle
)
86 return gbl
->def_value
? FB_BLANK_UNBLANK
: FB_BLANK_POWERDOWN
;
88 /* if the enable GPIO is disabled, do not enable the backlight */
89 if (gpiod_get_value_cansleep(gbl
->gpiod
) == 0)
90 return FB_BLANK_POWERDOWN
;
92 return FB_BLANK_UNBLANK
;
96 static int gpio_backlight_probe(struct platform_device
*pdev
)
98 struct gpio_backlight_platform_data
*pdata
=
99 dev_get_platdata(&pdev
->dev
);
100 struct backlight_properties props
;
101 struct backlight_device
*bl
;
102 struct gpio_backlight
*gbl
;
105 gbl
= devm_kzalloc(&pdev
->dev
, sizeof(*gbl
), GFP_KERNEL
);
109 gbl
->dev
= &pdev
->dev
;
111 if (pdev
->dev
.fwnode
) {
112 ret
= gpio_backlight_probe_dt(pdev
, gbl
);
117 * Legacy platform data GPIO retrieveal. Do not expand
118 * the use of this code path, currently only used by one
121 unsigned long flags
= GPIOF_DIR_OUT
;
123 gbl
->fbdev
= pdata
->fbdev
;
124 gbl
->def_value
= pdata
->def_value
;
125 flags
|= gbl
->def_value
? GPIOF_INIT_HIGH
: GPIOF_INIT_LOW
;
127 ret
= devm_gpio_request_one(gbl
->dev
, pdata
->gpio
, flags
,
128 pdata
? pdata
->name
: "backlight");
130 dev_err(&pdev
->dev
, "unable to request GPIO\n");
133 gbl
->gpiod
= gpio_to_desc(pdata
->gpio
);
138 "failed to find platform data or device tree node.\n");
142 memset(&props
, 0, sizeof(props
));
143 props
.type
= BACKLIGHT_RAW
;
144 props
.max_brightness
= 1;
145 bl
= devm_backlight_device_register(&pdev
->dev
, dev_name(&pdev
->dev
),
146 &pdev
->dev
, gbl
, &gpio_backlight_ops
,
149 dev_err(&pdev
->dev
, "failed to register backlight\n");
153 bl
->props
.power
= gpio_backlight_initial_power_state(gbl
);
154 bl
->props
.brightness
= 1;
156 backlight_update_status(bl
);
158 platform_set_drvdata(pdev
, bl
);
162 static struct of_device_id gpio_backlight_of_match
[] = {
163 { .compatible
= "gpio-backlight" },
167 MODULE_DEVICE_TABLE(of
, gpio_backlight_of_match
);
169 static struct platform_driver gpio_backlight_driver
= {
171 .name
= "gpio-backlight",
172 .of_match_table
= gpio_backlight_of_match
,
174 .probe
= gpio_backlight_probe
,
177 module_platform_driver(gpio_backlight_driver
);
179 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
180 MODULE_DESCRIPTION("GPIO-based Backlight Driver");
181 MODULE_LICENSE("GPL");
182 MODULE_ALIAS("platform:gpio-backlight");