1 // SPDX-License-Identifier: GPL-2.0-only
3 #include <dt-bindings/leds/rt4831-backlight.h>
4 #include <linux/backlight.h>
5 #include <linux/bitops.h>
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
9 #include <linux/property.h>
10 #include <linux/regmap.h>
12 #define RT4831_REG_BLCFG 0x02
13 #define RT4831_REG_BLDIML 0x04
14 #define RT4831_REG_ENABLE 0x08
15 #define RT4831_REG_BLOPT2 0x11
17 #define RT4831_BLMAX_BRIGHTNESS 2048
19 #define RT4831_BLOVP_MASK GENMASK(7, 5)
20 #define RT4831_BLOVP_SHIFT 5
21 #define RT4831_BLPWMEN_MASK BIT(0)
22 #define RT4831_BLEN_MASK BIT(4)
23 #define RT4831_BLCH_MASK GENMASK(3, 0)
24 #define RT4831_BLDIML_MASK GENMASK(2, 0)
25 #define RT4831_BLDIMH_MASK GENMASK(10, 3)
26 #define RT4831_BLDIMH_SHIFT 3
27 #define RT4831_BLOCP_MASK GENMASK(1, 0)
29 #define RT4831_BLOCP_MINUA 900000
30 #define RT4831_BLOCP_MAXUA 1800000
31 #define RT4831_BLOCP_STEPUA 300000
35 struct regmap
*regmap
;
36 struct backlight_device
*bl
;
39 static int rt4831_bl_update_status(struct backlight_device
*bl_dev
)
41 struct rt4831_priv
*priv
= bl_get_data(bl_dev
);
42 int brightness
= backlight_get_brightness(bl_dev
);
43 unsigned int enable
= brightness
? RT4831_BLEN_MASK
: 0;
48 v
[0] = (brightness
- 1) & RT4831_BLDIML_MASK
;
49 v
[1] = ((brightness
- 1) & RT4831_BLDIMH_MASK
) >> RT4831_BLDIMH_SHIFT
;
51 ret
= regmap_raw_write(priv
->regmap
, RT4831_REG_BLDIML
, v
, sizeof(v
));
56 return regmap_update_bits(priv
->regmap
, RT4831_REG_ENABLE
, RT4831_BLEN_MASK
, enable
);
60 static int rt4831_bl_get_brightness(struct backlight_device
*bl_dev
)
62 struct rt4831_priv
*priv
= bl_get_data(bl_dev
);
67 ret
= regmap_read(priv
->regmap
, RT4831_REG_ENABLE
, &val
);
71 if (!(val
& RT4831_BLEN_MASK
))
74 ret
= regmap_raw_read(priv
->regmap
, RT4831_REG_BLDIML
, v
, sizeof(v
));
78 ret
= (v
[1] << RT4831_BLDIMH_SHIFT
) + (v
[0] & RT4831_BLDIML_MASK
) + 1;
83 static const struct backlight_ops rt4831_bl_ops
= {
84 .options
= BL_CORE_SUSPENDRESUME
,
85 .update_status
= rt4831_bl_update_status
,
86 .get_brightness
= rt4831_bl_get_brightness
,
89 static int rt4831_parse_backlight_properties(struct rt4831_priv
*priv
,
90 struct backlight_properties
*bl_props
)
92 struct device
*dev
= priv
->dev
;
94 u32 brightness
, ocp_uA
;
98 /* common properties */
99 ret
= device_property_read_u32(dev
, "max-brightness", &brightness
);
101 brightness
= RT4831_BLMAX_BRIGHTNESS
;
103 bl_props
->max_brightness
= min_t(u32
, brightness
, RT4831_BLMAX_BRIGHTNESS
);
105 ret
= device_property_read_u32(dev
, "default-brightness", &brightness
);
107 brightness
= bl_props
->max_brightness
;
109 bl_props
->brightness
= min_t(u32
, brightness
, bl_props
->max_brightness
);
111 /* vendor properties */
112 if (device_property_read_bool(dev
, "richtek,pwm-enable"))
113 val
= RT4831_BLPWMEN_MASK
;
115 ret
= regmap_update_bits(priv
->regmap
, RT4831_REG_BLCFG
, RT4831_BLPWMEN_MASK
, val
);
119 ret
= device_property_read_u8(dev
, "richtek,bled-ovp-sel", &propval
);
121 propval
= RT4831_BLOVPLVL_21V
;
123 propval
= min_t(u8
, propval
, RT4831_BLOVPLVL_29V
);
124 ret
= regmap_update_bits(priv
->regmap
, RT4831_REG_BLCFG
, RT4831_BLOVP_MASK
,
125 propval
<< RT4831_BLOVP_SHIFT
);
130 * This OCP level is used to protect and limit the inductor current.
131 * If inductor peak current reach the level, low-side MOSFET will be
132 * turned off. Meanwhile, the output channel current may be limited.
133 * To match the configured channel current, the inductor chosen must
134 * be higher than the OCP level.
136 * Not like the OVP level, the default 21V can be used in the most
137 * application. But if the chosen OCP level is smaller than needed,
138 * it will also affect the backlight channel output current to be
139 * smaller than the register setting.
141 ret
= device_property_read_u32(dev
, "richtek,bled-ocp-microamp",
144 ocp_uA
= clamp_val(ocp_uA
, RT4831_BLOCP_MINUA
,
146 val
= DIV_ROUND_UP(ocp_uA
- RT4831_BLOCP_MINUA
,
147 RT4831_BLOCP_STEPUA
);
148 ret
= regmap_update_bits(priv
->regmap
, RT4831_REG_BLOPT2
,
149 RT4831_BLOCP_MASK
, val
);
154 ret
= device_property_read_u8(dev
, "richtek,channel-use", &propval
);
156 dev_err(dev
, "richtek,channel-use DT property missing\n");
160 if (!(propval
& RT4831_BLCH_MASK
)) {
161 dev_err(dev
, "No channel specified\n");
165 return regmap_update_bits(priv
->regmap
, RT4831_REG_ENABLE
, RT4831_BLCH_MASK
, propval
);
168 static int rt4831_bl_probe(struct platform_device
*pdev
)
170 struct rt4831_priv
*priv
;
171 struct backlight_properties bl_props
= { .type
= BACKLIGHT_RAW
,
172 .scale
= BACKLIGHT_SCALE_LINEAR
};
175 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
179 priv
->dev
= &pdev
->dev
;
181 priv
->regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
183 dev_err(&pdev
->dev
, "Failed to init regmap\n");
187 ret
= rt4831_parse_backlight_properties(priv
, &bl_props
);
189 dev_err(&pdev
->dev
, "Failed to parse backlight properties\n");
193 priv
->bl
= devm_backlight_device_register(&pdev
->dev
, pdev
->name
, &pdev
->dev
, priv
,
194 &rt4831_bl_ops
, &bl_props
);
195 if (IS_ERR(priv
->bl
)) {
196 dev_err(&pdev
->dev
, "Failed to register backlight\n");
197 return PTR_ERR(priv
->bl
);
200 backlight_update_status(priv
->bl
);
201 platform_set_drvdata(pdev
, priv
);
206 static void rt4831_bl_remove(struct platform_device
*pdev
)
208 struct rt4831_priv
*priv
= platform_get_drvdata(pdev
);
209 struct backlight_device
*bl_dev
= priv
->bl
;
211 bl_dev
->props
.brightness
= 0;
212 backlight_update_status(priv
->bl
);
215 static const struct of_device_id __maybe_unused rt4831_bl_of_match
[] = {
216 { .compatible
= "richtek,rt4831-backlight", },
219 MODULE_DEVICE_TABLE(of
, rt4831_bl_of_match
);
221 static struct platform_driver rt4831_bl_driver
= {
223 .name
= "rt4831-backlight",
224 .of_match_table
= rt4831_bl_of_match
,
226 .probe
= rt4831_bl_probe
,
227 .remove
= rt4831_bl_remove
,
229 module_platform_driver(rt4831_bl_driver
);
231 MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
232 MODULE_DESCRIPTION("Richtek RT4831 Backlight Driver");
233 MODULE_LICENSE("GPL v2");