1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
4 * PCF50633 backlight device driver
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/slab.h>
10 #include <linux/platform_device.h>
12 #include <linux/backlight.h>
15 #include <linux/mfd/pcf50633/core.h>
16 #include <linux/mfd/pcf50633/backlight.h>
20 struct backlight_device
*bl
;
22 unsigned int brightness
;
23 unsigned int brightness_limit
;
27 * pcf50633_bl_set_brightness_limit
29 * Update the brightness limit for the pc50633 backlight. The actual brightness
30 * will not go above the limit. This is useful to limit power drain for example
33 * @dev: Pointer to a pcf50633 device
34 * @limit: The brightness limit. Valid values are 0-63
36 int pcf50633_bl_set_brightness_limit(struct pcf50633
*pcf
, unsigned int limit
)
38 struct pcf50633_bl
*pcf_bl
= platform_get_drvdata(pcf
->bl_pdev
);
43 pcf_bl
->brightness_limit
= limit
& 0x3f;
44 backlight_update_status(pcf_bl
->bl
);
49 static int pcf50633_bl_update_status(struct backlight_device
*bl
)
51 struct pcf50633_bl
*pcf_bl
= bl_get_data(bl
);
52 unsigned int new_brightness
;
55 if (bl
->props
.state
& (BL_CORE_SUSPENDED
| BL_CORE_FBBLANK
) ||
56 bl
->props
.power
!= FB_BLANK_UNBLANK
)
58 else if (bl
->props
.brightness
< pcf_bl
->brightness_limit
)
59 new_brightness
= bl
->props
.brightness
;
61 new_brightness
= pcf_bl
->brightness_limit
;
64 if (pcf_bl
->brightness
== new_brightness
)
68 pcf50633_reg_write(pcf_bl
->pcf
, PCF50633_REG_LEDOUT
,
70 if (!pcf_bl
->brightness
)
71 pcf50633_reg_write(pcf_bl
->pcf
, PCF50633_REG_LEDENA
, 1);
73 pcf50633_reg_write(pcf_bl
->pcf
, PCF50633_REG_LEDENA
, 0);
76 pcf_bl
->brightness
= new_brightness
;
81 static int pcf50633_bl_get_brightness(struct backlight_device
*bl
)
83 struct pcf50633_bl
*pcf_bl
= bl_get_data(bl
);
85 return pcf_bl
->brightness
;
88 static const struct backlight_ops pcf50633_bl_ops
= {
89 .get_brightness
= pcf50633_bl_get_brightness
,
90 .update_status
= pcf50633_bl_update_status
,
91 .options
= BL_CORE_SUSPENDRESUME
,
94 static int pcf50633_bl_probe(struct platform_device
*pdev
)
96 struct pcf50633_bl
*pcf_bl
;
97 struct device
*parent
= pdev
->dev
.parent
;
98 struct pcf50633_platform_data
*pcf50633_data
= dev_get_platdata(parent
);
99 struct pcf50633_bl_platform_data
*pdata
= pcf50633_data
->backlight_data
;
100 struct backlight_properties bl_props
;
102 pcf_bl
= devm_kzalloc(&pdev
->dev
, sizeof(*pcf_bl
), GFP_KERNEL
);
106 memset(&bl_props
, 0, sizeof(bl_props
));
107 bl_props
.type
= BACKLIGHT_RAW
;
108 bl_props
.max_brightness
= 0x3f;
109 bl_props
.power
= FB_BLANK_UNBLANK
;
112 bl_props
.brightness
= pdata
->default_brightness
;
113 pcf_bl
->brightness_limit
= pdata
->default_brightness_limit
;
115 bl_props
.brightness
= 0x3f;
116 pcf_bl
->brightness_limit
= 0x3f;
119 pcf_bl
->pcf
= dev_to_pcf50633(pdev
->dev
.parent
);
121 pcf_bl
->bl
= devm_backlight_device_register(&pdev
->dev
, pdev
->name
,
123 &pcf50633_bl_ops
, &bl_props
);
125 if (IS_ERR(pcf_bl
->bl
))
126 return PTR_ERR(pcf_bl
->bl
);
128 platform_set_drvdata(pdev
, pcf_bl
);
130 pcf50633_reg_write(pcf_bl
->pcf
, PCF50633_REG_LEDDIM
, pdata
->ramp_time
);
133 * Should be different from bl_props.brightness, so we do not exit
134 * update_status early the first time it's called
136 pcf_bl
->brightness
= pcf_bl
->bl
->props
.brightness
+ 1;
138 backlight_update_status(pcf_bl
->bl
);
143 static struct platform_driver pcf50633_bl_driver
= {
144 .probe
= pcf50633_bl_probe
,
146 .name
= "pcf50633-backlight",
150 module_platform_driver(pcf50633_bl_driver
);
152 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
153 MODULE_DESCRIPTION("PCF50633 backlight driver");
154 MODULE_LICENSE("GPL");
155 MODULE_ALIAS("platform:pcf50633-backlight");