Skip to content

Commit 4bfa4a5

Browse files
committed
Merge tag 'backlight-next-6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight
Pull backlight updates from Lee Jones: "New Support & Features: - Add a new driver for the Congatec Board Controller (CGBC) backlight, providing brightness control via the board controller's PWM interface Improvements & Fixes: - Resolve build failures in the Awinic AW99706 driver by switching to the correct GPIO consumer header - Extend the Qualcomm WLED driver to support the specific over-voltage protection (OVP) values required for the PMI8994 and PMI8950 variants Device Tree Bindings Updates: - Document the device-specific over-voltage protection (OVP) millivolt ranges and default values for Qualcomm PMI8994 and PMI8950 WLED controllers" * tag 'backlight-next-6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight: backlight: qcom-wled: Change PM8950 WLED configurations dt-bindings: backlight: qcom-wled: Document ovp values for PMI8950 backlight: qcom-wled: Support ovp values for PMI8994 dt-bindings: backlight: qcom-wled: Document ovp values for PMI8994 backlight: aw99706: Fix build errors caused by wrong gpio header backlight: Add Congatec Board Controller (CGBC) backlight support
2 parents 4668c48 + 83333aa commit 4bfa4a5

6 files changed

Lines changed: 255 additions & 5 deletions

File tree

Documentation/devicetree/bindings/leds/backlight/qcom-wled.yaml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ properties:
9898
description: |
9999
Over-voltage protection limit. This property is for WLED4 only.
100100
$ref: /schemas/types.yaml#/definitions/uint32
101-
enum: [ 18100, 19600, 29600, 31100 ]
102-
default: 29600
101+
minimum: 17800
102+
maximum: 31100
103103

104104
qcom,num-strings:
105105
description: |
@@ -239,6 +239,26 @@ allOf:
239239
minimum: 0
240240
maximum: 4095
241241

242+
- if:
243+
properties:
244+
compatible:
245+
contains:
246+
enum:
247+
- qcom,pmi8950-wled
248+
- qcom,pmi8994-wled
249+
250+
then:
251+
properties:
252+
qcom,ovp-millivolt:
253+
enum: [ 17800, 19400, 29500, 31000 ]
254+
default: 29500
255+
256+
else:
257+
properties:
258+
qcom,ovp-millivolt:
259+
enum: [ 18100, 19600, 29600, 31100 ]
260+
default: 29600
261+
242262
required:
243263
- compatible
244264
- reg

drivers/video/backlight/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,17 @@ config BACKLIGHT_PWM
258258
If you have a LCD backlight adjustable by PWM, say Y to enable
259259
this driver.
260260

261+
config BACKLIGHT_CGBC
262+
tristate "Congatec Board Controller (CGBC) backlight support"
263+
depends on MFD_CGBC && X86
264+
help
265+
Say Y here to enable support for LCD backlight control on Congatec
266+
x86-based boards via the CGBC (Congatec Board Controller).
267+
268+
This driver provides backlight brightness control through the Linux
269+
backlight subsystem. It communicates with the board controller to
270+
adjust LCD backlight using PWM signals.
271+
261272
config BACKLIGHT_DA903X
262273
tristate "Backlight Driver for DA9030/DA9034 using WLED"
263274
depends on PMIC_DA903X

drivers/video/backlight/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ obj-$(CONFIG_BACKLIGHT_APPLE_DWI) += apple_dwi_bl.o
2727
obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o
2828
obj-$(CONFIG_BACKLIGHT_AW99706) += aw99706.o
2929
obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o
30+
obj-$(CONFIG_BACKLIGHT_CGBC) += cgbc_bl.o
3031
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
3132
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
3233
obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o

drivers/video/backlight/aw99706.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include <linux/backlight.h>
1313
#include <linux/bitfield.h>
1414
#include <linux/delay.h>
15-
#include <linux/gpio.h>
15+
#include <linux/gpio/consumer.h>
1616
#include <linux/i2c.h>
1717
#include <linux/kernel.h>
1818
#include <linux/module.h>

drivers/video/backlight/cgbc_bl.c

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Congatec Board Controller (CGBC) Backlight Driver
4+
*
5+
* This driver provides backlight control for LCD displays connected to
6+
* Congatec boards via the CGBC (Congatec Board Controller). It integrates
7+
* with the Linux backlight subsystem and communicates with hardware through
8+
* the cgbc-core module.
9+
*
10+
* Copyright (C) 2025 Novatron Oy
11+
*
12+
* Author: Petri Karhula <petri.karhula@novatron.fi>
13+
*/
14+
15+
#include <linux/backlight.h>
16+
#include <linux/bitfield.h>
17+
#include <linux/bits.h>
18+
#include <linux/mfd/cgbc.h>
19+
#include <linux/module.h>
20+
#include <linux/platform_device.h>
21+
22+
#define BLT_PWM_DUTY_MASK GENMASK(6, 0)
23+
24+
/* CGBC command for PWM brightness control*/
25+
#define CGBC_CMD_BLT0_PWM 0x75
26+
27+
#define CGBC_BL_MAX_BRIGHTNESS 100
28+
29+
/**
30+
* CGBC backlight driver data
31+
* @dev: Pointer to the platform device
32+
* @cgbc: Pointer to the parent CGBC device data
33+
* @current_brightness: Current brightness level (0-100)
34+
*/
35+
struct cgbc_bl_data {
36+
struct device *dev;
37+
struct cgbc_device_data *cgbc;
38+
unsigned int current_brightness;
39+
};
40+
41+
static int cgbc_bl_read_brightness(struct cgbc_bl_data *bl_data)
42+
{
43+
u8 cmd_buf[4] = { CGBC_CMD_BLT0_PWM };
44+
u8 reply_buf[3];
45+
int ret;
46+
47+
ret = cgbc_command(bl_data->cgbc, cmd_buf, sizeof(cmd_buf),
48+
reply_buf, sizeof(reply_buf), NULL);
49+
if (ret < 0)
50+
return ret;
51+
52+
/*
53+
* Get only PWM duty factor percentage,
54+
* ignore polarity inversion bit (bit 7)
55+
*/
56+
bl_data->current_brightness = FIELD_GET(BLT_PWM_DUTY_MASK, reply_buf[0]);
57+
58+
return 0;
59+
}
60+
61+
static int cgbc_bl_update_status(struct backlight_device *bl)
62+
{
63+
struct cgbc_bl_data *bl_data = bl_get_data(bl);
64+
u8 cmd_buf[4] = { CGBC_CMD_BLT0_PWM };
65+
u8 reply_buf[3];
66+
u8 brightness;
67+
int ret;
68+
69+
brightness = backlight_get_brightness(bl);
70+
71+
if (brightness != bl_data->current_brightness) {
72+
/* Read the current values */
73+
ret = cgbc_command(bl_data->cgbc, cmd_buf, sizeof(cmd_buf), reply_buf,
74+
sizeof(reply_buf), NULL);
75+
if (ret < 0) {
76+
dev_err(bl_data->dev, "Failed to read PWM settings: %d\n", ret);
77+
return ret;
78+
}
79+
80+
/*
81+
* Prepare command buffer for writing new settings. Only 2nd byte is changed
82+
* to set new brightness (PWM duty cycle %). Other values (polarity, frequency)
83+
* are preserved from the read values.
84+
*/
85+
cmd_buf[1] = (reply_buf[0] & ~BLT_PWM_DUTY_MASK) |
86+
FIELD_PREP(BLT_PWM_DUTY_MASK, brightness);
87+
cmd_buf[2] = reply_buf[1];
88+
cmd_buf[3] = reply_buf[2];
89+
90+
ret = cgbc_command(bl_data->cgbc, cmd_buf, sizeof(cmd_buf), reply_buf,
91+
sizeof(reply_buf), NULL);
92+
if (ret < 0) {
93+
dev_err(bl_data->dev, "Failed to set brightness: %d\n", ret);
94+
return ret;
95+
}
96+
97+
bl_data->current_brightness = reply_buf[0] & BLT_PWM_DUTY_MASK;
98+
99+
/* Verify the setting was applied correctly */
100+
if (bl_data->current_brightness != brightness) {
101+
dev_err(bl_data->dev,
102+
"Brightness setting verification failed (got %u, expected %u)\n",
103+
bl_data->current_brightness, (unsigned int)brightness);
104+
return -EIO;
105+
}
106+
}
107+
108+
return 0;
109+
}
110+
111+
static int cgbc_bl_get_brightness(struct backlight_device *bl)
112+
{
113+
struct cgbc_bl_data *bl_data = bl_get_data(bl);
114+
int ret;
115+
116+
ret = cgbc_bl_read_brightness(bl_data);
117+
if (ret < 0) {
118+
dev_err(bl_data->dev, "Failed to read brightness: %d\n", ret);
119+
return ret;
120+
}
121+
122+
return bl_data->current_brightness;
123+
}
124+
125+
static const struct backlight_ops cgbc_bl_ops = {
126+
.options = BL_CORE_SUSPENDRESUME,
127+
.update_status = cgbc_bl_update_status,
128+
.get_brightness = cgbc_bl_get_brightness,
129+
};
130+
131+
static int cgbc_bl_probe(struct platform_device *pdev)
132+
{
133+
struct cgbc_device_data *cgbc = dev_get_drvdata(pdev->dev.parent);
134+
struct backlight_properties props = { };
135+
struct backlight_device *bl_dev;
136+
struct cgbc_bl_data *bl_data;
137+
int ret;
138+
139+
bl_data = devm_kzalloc(&pdev->dev, sizeof(*bl_data), GFP_KERNEL);
140+
if (!bl_data)
141+
return -ENOMEM;
142+
143+
bl_data->dev = &pdev->dev;
144+
bl_data->cgbc = cgbc;
145+
146+
ret = cgbc_bl_read_brightness(bl_data);
147+
if (ret < 0)
148+
return dev_err_probe(&pdev->dev, ret,
149+
"Failed to read initial brightness\n");
150+
151+
props.type = BACKLIGHT_PLATFORM;
152+
props.max_brightness = CGBC_BL_MAX_BRIGHTNESS;
153+
props.brightness = bl_data->current_brightness;
154+
props.scale = BACKLIGHT_SCALE_LINEAR;
155+
156+
bl_dev = devm_backlight_device_register(&pdev->dev, "cgbc-backlight",
157+
&pdev->dev, bl_data,
158+
&cgbc_bl_ops, &props);
159+
if (IS_ERR(bl_dev))
160+
return dev_err_probe(&pdev->dev, PTR_ERR(bl_dev),
161+
"Failed to register backlight device\n");
162+
163+
platform_set_drvdata(pdev, bl_data);
164+
165+
return 0;
166+
}
167+
168+
static struct platform_driver cgbc_bl_driver = {
169+
.driver = {
170+
.name = "cgbc-backlight",
171+
},
172+
.probe = cgbc_bl_probe,
173+
};
174+
175+
module_platform_driver(cgbc_bl_driver);
176+
177+
MODULE_AUTHOR("Petri Karhula <petri.karhula@novatron.fi>");
178+
MODULE_DESCRIPTION("Congatec Board Controller (CGBC) Backlight Driver");
179+
MODULE_LICENSE("GPL");
180+
MODULE_ALIAS("platform:cgbc-backlight");

drivers/video/backlight/qcom-wled.c

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,15 @@ static const struct wled_var_cfg wled4_ovp_cfg = {
12441244
.size = ARRAY_SIZE(wled4_ovp_values),
12451245
};
12461246

1247+
static const u32 pmi8994_wled_ovp_values[] = {
1248+
31000, 29500, 19400, 17800,
1249+
};
1250+
1251+
static const struct wled_var_cfg pmi8994_wled_ovp_cfg = {
1252+
.values = pmi8994_wled_ovp_values,
1253+
.size = ARRAY_SIZE(pmi8994_wled_ovp_values),
1254+
};
1255+
12471256
static inline u32 wled5_ovp_values_fn(u32 idx)
12481257
{
12491258
/*
@@ -1357,6 +1366,29 @@ static int wled_configure(struct wled *wled)
13571366
},
13581367
};
13591368

1369+
const struct wled_u32_opts pmi8994_wled_opts[] = {
1370+
{
1371+
.name = "qcom,current-boost-limit",
1372+
.val_ptr = &cfg->boost_i_limit,
1373+
.cfg = &wled4_boost_i_limit_cfg,
1374+
},
1375+
{
1376+
.name = "qcom,current-limit-microamp",
1377+
.val_ptr = &cfg->string_i_limit,
1378+
.cfg = &wled4_string_i_limit_cfg,
1379+
},
1380+
{
1381+
.name = "qcom,ovp-millivolt",
1382+
.val_ptr = &cfg->ovp,
1383+
.cfg = &pmi8994_wled_ovp_cfg,
1384+
},
1385+
{
1386+
.name = "qcom,switching-freq",
1387+
.val_ptr = &cfg->switch_freq,
1388+
.cfg = &wled3_switch_freq_cfg,
1389+
},
1390+
};
1391+
13601392
const struct wled_u32_opts wled5_opts[] = {
13611393
{
13621394
.name = "qcom,current-boost-limit",
@@ -1423,8 +1455,14 @@ static int wled_configure(struct wled *wled)
14231455
break;
14241456

14251457
case 4:
1426-
u32_opts = wled4_opts;
1427-
size = ARRAY_SIZE(wled4_opts);
1458+
if (of_device_is_compatible(dev->of_node, "qcom,pmi8950-wled") ||
1459+
of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) {
1460+
u32_opts = pmi8994_wled_opts;
1461+
size = ARRAY_SIZE(pmi8994_wled_opts);
1462+
} else {
1463+
u32_opts = wled4_opts;
1464+
size = ARRAY_SIZE(wled4_opts);
1465+
}
14281466
*cfg = wled4_config_defaults;
14291467
wled->wled_set_brightness = wled4_set_brightness;
14301468
wled->wled_sync_toggle = wled3_sync_toggle;

0 commit comments

Comments
 (0)