xref: /linux/drivers/video/backlight/max25014.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Backlight driver for Maxim MAX25014
4  *
5  * Copyright (C) 2025 GOcontroll B.V.
6  * Author: Maud Spierings <maudspierings@gocontroll.com>
7  */
8 
9 #include <linux/backlight.h>
10 #include <linux/gpio/consumer.h>
11 #include <linux/i2c.h>
12 #include <linux/regmap.h>
13 #include <linux/slab.h>
14 
15 #define MAX25014_ISET_DEFAULT_100 11
16 #define MAX_BRIGHTNESS            100
17 #define MIN_BRIGHTNESS            0
18 #define TON_MAX                   130720 /* @153Hz */
19 #define TON_STEP                  1307 /* @153Hz */
20 #define TON_MIN                   0
21 
22 #define MAX25014_DEV_ID           0x00
23 #define MAX25014_REV_ID           0x01
24 #define MAX25014_ISET             0x02
25 #define MAX25014_IMODE            0x03
26 #define MAX25014_TON1H            0x04
27 #define MAX25014_TON1L            0x05
28 #define MAX25014_TON2H            0x06
29 #define MAX25014_TON2L            0x07
30 #define MAX25014_TON3H            0x08
31 #define MAX25014_TON3L            0x09
32 #define MAX25014_TON4H            0x0A
33 #define MAX25014_TON4L            0x0B
34 #define MAX25014_TON_1_4_LSB      0x0C
35 #define MAX25014_SETTING          0x12
36 #define MAX25014_DISABLE          0x13
37 #define MAX25014_BSTMON           0x14
38 #define MAX25014_IOUT1            0x15
39 #define MAX25014_IOUT2            0x16
40 #define MAX25014_IOUT3            0x17
41 #define MAX25014_IOUT4            0x18
42 #define MAX25014_OPEN             0x1B
43 #define MAX25014_SHORTGND         0x1C
44 #define MAX25014_SHORTED_LED      0x1D
45 #define MAX25014_MASK             0x1E
46 #define MAX25014_DIAG             0x1F
47 
48 #define MAX25014_ISET_ENA         BIT(5)
49 #define MAX25014_ISET_PSEN        BIT(4)
50 #define MAX25014_IMODE_HDIM       BIT(2)
51 #define MAX25014_SETTING_FPWM     GENMASK(6, 4)
52 #define MAX25014_DISABLE_DIS_MASK GENMASK(3, 0)
53 #define MAX25014_DIAG_OT          BIT(0)
54 #define MAX25014_DIAG_OTW         BIT(1)
55 #define MAX25014_DIAG_HW_RST      BIT(2)
56 #define MAX25014_DIAG_BSTOV       BIT(3)
57 #define MAX25014_DIAG_BSTUV       BIT(4)
58 #define MAX25014_DIAG_IREFOOR     BIT(5)
59 
60 struct max25014 {
61 	struct i2c_client *client;
62 	struct backlight_device *bl;
63 	struct regmap *regmap;
64 	struct gpio_desc *enable;
65 	uint32_t iset;
66 	uint8_t strings_mask;
67 };
68 
69 static const struct regmap_config max25014_regmap_config = {
70 	.reg_bits = 8,
71 	.val_bits = 8,
72 	.max_register = MAX25014_DIAG,
73 };
74 
75 static int max25014_initial_power_state(struct max25014 *maxim)
76 {
77 	uint32_t val;
78 	int ret;
79 
80 	ret = regmap_read(maxim->regmap, MAX25014_ISET, &val);
81 	if (ret)
82 		return ret;
83 
84 	return val & MAX25014_ISET_ENA ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF;
85 }
86 
87 static int max25014_check_errors(struct max25014 *maxim)
88 {
89 	uint32_t val;
90 	uint8_t i;
91 	int ret;
92 
93 	ret = regmap_read(maxim->regmap, MAX25014_OPEN, &val);
94 	if (ret)
95 		return ret;
96 	if (val) {
97 		dev_err(&maxim->client->dev, "Open led strings detected on:\n");
98 		for (i = 0; i < 4; i++) {
99 			if (val & 1 << i)
100 				dev_err(&maxim->client->dev, "string %d\n", i + 1);
101 		}
102 		return -EIO;
103 	}
104 
105 	ret = regmap_read(maxim->regmap, MAX25014_SHORTGND, &val);
106 	if (ret)
107 		return ret;
108 	if (val) {
109 		dev_err(&maxim->client->dev, "Short to ground detected on:\n");
110 		for (i = 0; i < 4; i++) {
111 			if (val & 1 << i)
112 				dev_err(&maxim->client->dev, "string %d\n", i + 1);
113 		}
114 		return -EIO;
115 	}
116 
117 	ret = regmap_read(maxim->regmap, MAX25014_SHORTED_LED, &val);
118 	if (ret)
119 		return ret;
120 	if (val) {
121 		dev_err(&maxim->client->dev, "Shorted led detected on:\n");
122 		for (i = 0; i < 4; i++) {
123 			if (val & 1 << i)
124 				dev_err(&maxim->client->dev, "string %d\n", i + 1);
125 		}
126 		return -EIO;
127 	}
128 
129 	ret = regmap_read(maxim->regmap, MAX25014_DIAG, &val);
130 	if (ret)
131 		return ret;
132 	/*
133 	 * The HW_RST bit always starts at 1 after power up.
134 	 * It is reset on first read, does not indicate an error.
135 	 */
136 	if (val && val != MAX25014_DIAG_HW_RST) {
137 		if (val & MAX25014_DIAG_OT)
138 			dev_err(&maxim->client->dev,
139 				"Overtemperature shutdown\n");
140 		if (val & MAX25014_DIAG_OTW)
141 			dev_err(&maxim->client->dev,
142 				 "Chip is getting too hot (>125C)\n");
143 		if (val & MAX25014_DIAG_BSTOV)
144 			dev_err(&maxim->client->dev,
145 				"Boost converter overvoltage\n");
146 		if (val & MAX25014_DIAG_BSTUV)
147 			dev_err(&maxim->client->dev,
148 				"Boost converter undervoltage\n");
149 		if (val & MAX25014_DIAG_IREFOOR)
150 			dev_err(&maxim->client->dev, "IREF out of range\n");
151 		return -EIO;
152 	}
153 	return 0;
154 }
155 
156 /*
157  * 1. disable unused strings
158  * 2. set dim mode
159  * 3. set setting register
160  * 4. enable the backlight
161  */
162 static int max25014_configure(struct max25014 *maxim, int initial_state)
163 {
164 	uint32_t val;
165 	int ret;
166 
167 	ret = regmap_read(maxim->regmap, MAX25014_DISABLE, &val);
168 	if (ret)
169 		return ret;
170 
171 	/*
172 	 * Strings can only be disabled when MAX25014_ISET_ENA == 0, check if
173 	 * it needs to be changed at all to prevent the backlight flashing when
174 	 * it is configured correctly by the bootloader
175 	 */
176 	if (!((val & MAX25014_DISABLE_DIS_MASK) == maxim->strings_mask)) {
177 		if (initial_state == BACKLIGHT_POWER_ON) {
178 			ret = regmap_write(maxim->regmap, MAX25014_ISET, 0);
179 			if (ret)
180 				return ret;
181 		}
182 		ret = regmap_write(maxim->regmap, MAX25014_DISABLE, maxim->strings_mask);
183 		if (ret)
184 			return ret;
185 	}
186 
187 	ret = regmap_write(maxim->regmap, MAX25014_IMODE, MAX25014_IMODE_HDIM);
188 	if (ret)
189 		return ret;
190 
191 	ret = regmap_read(maxim->regmap, MAX25014_SETTING, &val);
192 	if (ret)
193 		return ret;
194 
195 	ret = regmap_write(maxim->regmap, MAX25014_SETTING,
196 			   val & ~MAX25014_SETTING_FPWM);
197 	if (ret)
198 		return ret;
199 
200 	return regmap_write(maxim->regmap, MAX25014_ISET,
201 			   maxim->iset | MAX25014_ISET_ENA |
202 			   MAX25014_ISET_PSEN);
203 }
204 
205 static int max25014_update_status(struct backlight_device *bl_dev)
206 {
207 	struct max25014 *maxim = bl_get_data(bl_dev);
208 	uint32_t reg;
209 	int ret;
210 
211 	reg  = TON_STEP * backlight_get_brightness(bl_dev);
212 
213 	/*
214 	 * 18 bit number lowest, 2 bits in first register,
215 	 * next lowest 8 in the L register, next 8 in the H register
216 	 * Seemingly setting the strength of only one string controls all of
217 	 * them, individual settings don't affect the outcome.
218 	 */
219 	ret = regmap_write(maxim->regmap, MAX25014_TON_1_4_LSB, reg & 0b00000011);
220 	if (ret != 0)
221 		return ret;
222 	ret = regmap_write(maxim->regmap, MAX25014_TON1L, (reg >> 2) & 0b11111111);
223 	if (ret != 0)
224 		return ret;
225 	return regmap_write(maxim->regmap, MAX25014_TON1H, (reg >> 10) & 0b11111111);
226 }
227 
228 static const struct backlight_ops max25014_bl_ops = {
229 	.options = BL_CORE_SUSPENDRESUME,
230 	.update_status = max25014_update_status,
231 };
232 
233 static int max25014_parse_dt(struct max25014 *maxim,
234 			     uint32_t *initial_brightness)
235 {
236 	struct device *dev = &maxim->client->dev;
237 	struct device_node *node = dev->of_node;
238 	uint32_t strings[4];
239 	int res, i;
240 
241 	res = of_property_count_u32_elems(node, "maxim,strings");
242 	if (res == 4) {
243 		of_property_read_u32_array(node, "maxim,strings", strings, 4);
244 		for (i = 0; i < 4; i++) {
245 			if (strings[i] == 0)
246 				maxim->strings_mask |= 1 << i;
247 	}
248 	} else {
249 		maxim->strings_mask = 0;
250 	}
251 
252 	*initial_brightness = 50U;
253 	of_property_read_u32(node, "default-brightness", initial_brightness);
254 
255 	maxim->iset = MAX25014_ISET_DEFAULT_100;
256 	of_property_read_u32(node, "maxim,iset", &maxim->iset);
257 
258 	if (maxim->iset > 15)
259 		return dev_err_probe(dev, -EINVAL,
260 				     "Invalid iset, should be a value from 0-15, entered was %d\n",
261 				     maxim->iset);
262 
263 	if (*initial_brightness > 100)
264 		return dev_err_probe(dev, -EINVAL,
265 				     "Invalid initial brightness, should be a value from 0-100, entered was %d\n",
266 				     *initial_brightness);
267 
268 	return 0;
269 }
270 
271 static int max25014_probe(struct i2c_client *cl)
272 {
273 	const struct i2c_device_id *id = i2c_client_get_device_id(cl);
274 	struct backlight_properties props;
275 	uint32_t initial_brightness = 50;
276 	struct backlight_device *bl;
277 	struct max25014 *maxim;
278 	int ret;
279 
280 	maxim = devm_kzalloc(&cl->dev, sizeof(struct max25014), GFP_KERNEL);
281 	if (!maxim)
282 		return -ENOMEM;
283 
284 	maxim->client = cl;
285 
286 	ret = max25014_parse_dt(maxim, &initial_brightness);
287 	if (ret)
288 		return ret;
289 
290 	ret = devm_regulator_get_enable(&maxim->client->dev, "power");
291 	if (ret)
292 		return dev_err_probe(&maxim->client->dev, ret,
293 				     "failed to get power-supply");
294 
295 	maxim->enable = devm_gpiod_get_optional(&maxim->client->dev, "enable",
296 						GPIOD_OUT_HIGH);
297 	if (IS_ERR(maxim->enable))
298 		return dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->enable),
299 				    "failed to get enable gpio\n");
300 
301 	/* Datasheet Electrical Characteristics tSTARTUP 2ms */
302 	fsleep(2000);
303 
304 	maxim->regmap = devm_regmap_init_i2c(cl, &max25014_regmap_config);
305 	if (IS_ERR(maxim->regmap))
306 		return dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->regmap),
307 			"failed to initialize the i2c regmap\n");
308 
309 	i2c_set_clientdata(cl, maxim);
310 
311 	ret = max25014_check_errors(maxim);
312 	if (ret) /* error is already reported in the above function */
313 		return ret;
314 
315 	ret = max25014_initial_power_state(maxim);
316 	if (ret < 0)
317 		return dev_err_probe(&maxim->client->dev, ret, "Could not get enabled state\n");
318 
319 	memset(&props, 0, sizeof(struct backlight_properties));
320 	props.type = BACKLIGHT_PLATFORM;
321 	props.max_brightness = MAX_BRIGHTNESS;
322 	props.brightness = initial_brightness;
323 	props.scale = BACKLIGHT_SCALE_LINEAR;
324 	props.power = ret;
325 
326 	ret = max25014_configure(maxim, ret);
327 	if (ret)
328 		return dev_err_probe(&maxim->client->dev, ret, "device config error");
329 
330 	bl = devm_backlight_device_register(&maxim->client->dev, id->name,
331 					    &maxim->client->dev, maxim,
332 					    &max25014_bl_ops, &props);
333 	if (IS_ERR(bl))
334 		return dev_err_probe(&maxim->client->dev, PTR_ERR(bl),
335 				    "failed to register backlight\n");
336 
337 	maxim->bl = bl;
338 
339 	backlight_update_status(maxim->bl);
340 
341 	return 0;
342 }
343 
344 static void max25014_remove(struct i2c_client *cl)
345 {
346 	struct max25014 *maxim = i2c_get_clientdata(cl);
347 
348 	backlight_device_set_brightness(maxim->bl, 0);
349 	gpiod_set_value_cansleep(maxim->enable, 0);
350 }
351 
352 static const struct of_device_id max25014_dt_ids[] = {
353 	{ .compatible = "maxim,max25014", },
354 	{ }
355 };
356 MODULE_DEVICE_TABLE(of, max25014_dt_ids);
357 
358 static const struct i2c_device_id max25014_ids[] = {
359 	{ "max25014" },
360 	{ }
361 };
362 MODULE_DEVICE_TABLE(i2c, max25014_ids);
363 
364 static struct i2c_driver max25014_driver = {
365 	.driver = {
366 		.name = KBUILD_MODNAME,
367 		.of_match_table = of_match_ptr(max25014_dt_ids),
368 	},
369 	.probe = max25014_probe,
370 	.remove = max25014_remove,
371 	.id_table = max25014_ids,
372 };
373 module_i2c_driver(max25014_driver);
374 
375 MODULE_DESCRIPTION("Maxim MAX25014 backlight driver");
376 MODULE_AUTHOR("Maud Spierings <maudspierings@gocontroll.com>");
377 MODULE_LICENSE("GPL");
378