1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Driver for MPS MP3309C White LED driver with I2C interface
4 *
5 * This driver support both analog (by I2C commands) and PWM dimming control
6 * modes.
7 *
8 * Copyright (C) 2023 ASEM Srl
9 * Author: Flavio Suligoi <f.suligoi@asem.it>
10 *
11 * Based on pwm_bl.c
12 */
13
14 #include <linux/backlight.h>
15 #include <linux/delay.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/i2c.h>
18 #include <linux/property.h>
19 #include <linux/pwm.h>
20 #include <linux/regmap.h>
21
22 #define REG_I2C_0 0x00
23 #define REG_I2C_1 0x01
24
25 #define REG_I2C_0_EN 0x80
26 #define REG_I2C_0_D0 0x40
27 #define REG_I2C_0_D1 0x20
28 #define REG_I2C_0_D2 0x10
29 #define REG_I2C_0_D3 0x08
30 #define REG_I2C_0_D4 0x04
31 #define REG_I2C_0_RSRV1 0x02
32 #define REG_I2C_0_RSRV2 0x01
33
34 #define REG_I2C_1_RSRV1 0x80
35 #define REG_I2C_1_DIMS 0x40
36 #define REG_I2C_1_SYNC 0x20
37 #define REG_I2C_1_OVP0 0x10
38 #define REG_I2C_1_OVP1 0x08
39 #define REG_I2C_1_VOS 0x04
40 #define REG_I2C_1_LEDO 0x02
41 #define REG_I2C_1_OTP 0x01
42
43 #define ANALOG_I2C_NUM_LEVELS 32 /* 0..31 */
44 #define ANALOG_I2C_REG_MASK 0x7c
45
46 #define MP3309C_PWM_DEFAULT_NUM_LEVELS 256 /* 0..255 */
47
48 enum mp3309c_status_value {
49 FIRST_POWER_ON,
50 BACKLIGHT_OFF,
51 BACKLIGHT_ON,
52 };
53
54 enum mp3309c_dimming_mode_value {
55 DIMMING_PWM,
56 DIMMING_ANALOG_I2C,
57 };
58
59 struct mp3309c_platform_data {
60 unsigned int max_brightness;
61 unsigned int default_brightness;
62 unsigned int *levels;
63 u8 dimming_mode;
64 u8 over_voltage_protection;
65 bool sync_mode;
66 u8 status;
67 };
68
69 struct mp3309c_chip {
70 struct device *dev;
71 struct mp3309c_platform_data *pdata;
72 struct backlight_device *bl;
73 struct gpio_desc *enable_gpio;
74 struct regmap *regmap;
75 struct pwm_device *pwmd;
76 };
77
78 static const struct regmap_config mp3309c_regmap = {
79 .name = "mp3309c_regmap",
80 .reg_bits = 8,
81 .reg_stride = 1,
82 .val_bits = 8,
83 .max_register = REG_I2C_1,
84 };
85
mp3309c_enable_device(struct mp3309c_chip * chip)86 static int mp3309c_enable_device(struct mp3309c_chip *chip)
87 {
88 u8 reg_val;
89 int ret;
90
91 /* I2C register #0 - Device enable */
92 ret = regmap_update_bits(chip->regmap, REG_I2C_0, REG_I2C_0_EN,
93 REG_I2C_0_EN);
94 if (ret)
95 return ret;
96
97 /*
98 * I2C register #1 - Set working mode:
99 * - enable/disable synchronous mode
100 * - set overvoltage protection (OVP)
101 */
102 reg_val = 0x00;
103 if (chip->pdata->sync_mode)
104 reg_val |= REG_I2C_1_SYNC;
105 reg_val |= chip->pdata->over_voltage_protection;
106 ret = regmap_write(chip->regmap, REG_I2C_1, reg_val);
107 if (ret)
108 return ret;
109
110 return 0;
111 }
112
mp3309c_bl_update_status(struct backlight_device * bl)113 static int mp3309c_bl_update_status(struct backlight_device *bl)
114 {
115 struct mp3309c_chip *chip = bl_get_data(bl);
116 int brightness = backlight_get_brightness(bl);
117 struct pwm_state pwmstate;
118 unsigned int analog_val, bits_val;
119 int i, ret;
120
121 if (chip->pdata->dimming_mode == DIMMING_PWM) {
122 /*
123 * PWM control mode
124 */
125 pwm_get_state(chip->pwmd, &pwmstate);
126 pwm_set_relative_duty_cycle(&pwmstate,
127 chip->pdata->levels[brightness],
128 chip->pdata->levels[chip->pdata->max_brightness]);
129 pwmstate.enabled = true;
130 ret = pwm_apply_might_sleep(chip->pwmd, &pwmstate);
131 if (ret)
132 return ret;
133
134 switch (chip->pdata->status) {
135 case FIRST_POWER_ON:
136 case BACKLIGHT_OFF:
137 /*
138 * After 20ms of low pwm signal level, the chip turns
139 * off automatically. In this case, before enabling the
140 * chip again, we must wait about 10ms for pwm signal to
141 * stabilize.
142 */
143 if (brightness > 0) {
144 msleep(10);
145 mp3309c_enable_device(chip);
146 chip->pdata->status = BACKLIGHT_ON;
147 } else {
148 chip->pdata->status = BACKLIGHT_OFF;
149 }
150 break;
151 case BACKLIGHT_ON:
152 if (brightness == 0)
153 chip->pdata->status = BACKLIGHT_OFF;
154 break;
155 }
156 } else {
157 /*
158 * Analog (by I2C command) control mode
159 *
160 * The first time, before setting brightness, we must enable the
161 * device
162 */
163 if (chip->pdata->status == FIRST_POWER_ON)
164 mp3309c_enable_device(chip);
165
166 /*
167 * Dimming mode I2C command (fixed dimming range 0..31)
168 *
169 * The 5 bits of the dimming analog value D4..D0 is allocated
170 * in the I2C register #0, in the following way:
171 *
172 * +--+--+--+--+--+--+--+--+
173 * |EN|D0|D1|D2|D3|D4|XX|XX|
174 * +--+--+--+--+--+--+--+--+
175 */
176 analog_val = brightness;
177 bits_val = 0;
178 for (i = 0; i <= 5; i++)
179 bits_val += ((analog_val >> i) & 0x01) << (6 - i);
180 ret = regmap_update_bits(chip->regmap, REG_I2C_0,
181 ANALOG_I2C_REG_MASK, bits_val);
182 if (ret)
183 return ret;
184
185 if (brightness > 0)
186 chip->pdata->status = BACKLIGHT_ON;
187 else
188 chip->pdata->status = BACKLIGHT_OFF;
189 }
190
191 return 0;
192 }
193
194 static const struct backlight_ops mp3309c_bl_ops = {
195 .update_status = mp3309c_bl_update_status,
196 };
197
mp3309c_parse_fwnode(struct mp3309c_chip * chip,struct mp3309c_platform_data * pdata)198 static int mp3309c_parse_fwnode(struct mp3309c_chip *chip,
199 struct mp3309c_platform_data *pdata)
200 {
201 int ret, i;
202 unsigned int tmp_value;
203 struct device *dev = chip->dev;
204 int num_levels;
205
206 if (!dev_fwnode(dev))
207 return dev_err_probe(dev, -ENODEV, "failed to get firmware node\n");
208
209 /*
210 * Dimming mode: the MP3309C provides two dimming control mode:
211 *
212 * - PWM mode
213 * - Analog by I2C control mode (default)
214 *
215 * I2C control mode is assumed as default but, if the pwms property is
216 * found in the backlight node, the mode switches to PWM mode.
217 */
218 pdata->dimming_mode = DIMMING_ANALOG_I2C;
219 if (device_property_present(dev, "pwms")) {
220 chip->pwmd = devm_pwm_get(dev, NULL);
221 if (IS_ERR(chip->pwmd))
222 return dev_err_probe(dev, PTR_ERR(chip->pwmd), "error getting pwm data\n");
223 pdata->dimming_mode = DIMMING_PWM;
224 }
225
226 /*
227 * In I2C control mode the dimming levels (0..31) are fixed by the
228 * hardware, while in PWM control mode they can be chosen by the user,
229 * to allow nonlinear mappings.
230 */
231 if (pdata->dimming_mode == DIMMING_ANALOG_I2C) {
232 /*
233 * Analog (by I2C commands) control mode: fixed 0..31 brightness
234 * levels
235 */
236 num_levels = ANALOG_I2C_NUM_LEVELS;
237
238 /* Enable GPIO used in I2C dimming mode only */
239 chip->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
240 if (IS_ERR(chip->enable_gpio))
241 return dev_err_probe(dev, PTR_ERR(chip->enable_gpio),
242 "error getting enable gpio\n");
243 } else {
244 /*
245 * PWM control mode: check for brightness level in DT
246 */
247 if (device_property_present(dev, "brightness-levels")) {
248 /* Read brightness levels from DT */
249 num_levels = device_property_count_u32(dev, "brightness-levels");
250 if (num_levels < 2)
251 return -EINVAL;
252 } else {
253 /* Use default brightness levels */
254 num_levels = MP3309C_PWM_DEFAULT_NUM_LEVELS;
255 }
256 }
257
258 /* Fill brightness levels array */
259 pdata->levels = devm_kcalloc(dev, num_levels, sizeof(*pdata->levels), GFP_KERNEL);
260 if (!pdata->levels)
261 return -ENOMEM;
262 if (device_property_present(dev, "brightness-levels")) {
263 ret = device_property_read_u32_array(dev, "brightness-levels",
264 pdata->levels, num_levels);
265 if (ret < 0)
266 return ret;
267 } else {
268 for (i = 0; i < num_levels; i++)
269 pdata->levels[i] = i;
270 }
271
272 pdata->max_brightness = num_levels - 1;
273
274 ret = device_property_read_u32(dev, "default-brightness", &pdata->default_brightness);
275 if (ret)
276 pdata->default_brightness = pdata->max_brightness;
277 if (pdata->default_brightness > pdata->max_brightness) {
278 dev_err_probe(dev, -ERANGE, "default brightness exceeds max brightness\n");
279 pdata->default_brightness = pdata->max_brightness;
280 }
281
282 /*
283 * Over-voltage protection (OVP)
284 *
285 * This (optional) property values are:
286 *
287 * - 13.5V
288 * - 24V
289 * - 35.5V (hardware default setting)
290 *
291 * If missing, the default value for OVP is 35.5V
292 */
293 pdata->over_voltage_protection = REG_I2C_1_OVP1;
294 ret = device_property_read_u32(dev, "mps,overvoltage-protection-microvolt", &tmp_value);
295 if (!ret) {
296 switch (tmp_value) {
297 case 13500000:
298 pdata->over_voltage_protection = 0x00;
299 break;
300 case 24000000:
301 pdata->over_voltage_protection = REG_I2C_1_OVP0;
302 break;
303 case 35500000:
304 pdata->over_voltage_protection = REG_I2C_1_OVP1;
305 break;
306 default:
307 return -EINVAL;
308 }
309 }
310
311 /* Synchronous (default) and non-synchronous mode */
312 pdata->sync_mode = !device_property_read_bool(dev, "mps,no-sync-mode");
313
314 return 0;
315 }
316
mp3309c_probe(struct i2c_client * client)317 static int mp3309c_probe(struct i2c_client *client)
318 {
319 struct device *dev = &client->dev;
320 struct mp3309c_platform_data *pdata = dev_get_platdata(dev);
321 struct mp3309c_chip *chip;
322 struct backlight_properties props;
323 struct pwm_state pwmstate;
324 int ret;
325
326 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
327 return dev_err_probe(dev, -EOPNOTSUPP, "failed to check i2c functionality\n");
328
329 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
330 if (!chip)
331 return -ENOMEM;
332
333 chip->dev = dev;
334
335 chip->regmap = devm_regmap_init_i2c(client, &mp3309c_regmap);
336 if (IS_ERR(chip->regmap))
337 return dev_err_probe(dev, PTR_ERR(chip->regmap),
338 "failed to allocate register map\n");
339
340 i2c_set_clientdata(client, chip);
341
342 if (!pdata) {
343 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
344 if (!pdata)
345 return -ENOMEM;
346
347 ret = mp3309c_parse_fwnode(chip, pdata);
348 if (ret)
349 return ret;
350 }
351 chip->pdata = pdata;
352
353 /* Backlight properties */
354 props = (typeof(props)){
355 .brightness = pdata->default_brightness,
356 .max_brightness = pdata->max_brightness,
357 .scale = BACKLIGHT_SCALE_LINEAR,
358 .type = BACKLIGHT_RAW,
359 .power = BACKLIGHT_POWER_ON,
360 };
361 chip->bl = devm_backlight_device_register(dev, "mp3309c", dev, chip,
362 &mp3309c_bl_ops, &props);
363 if (IS_ERR(chip->bl))
364 return dev_err_probe(dev, PTR_ERR(chip->bl),
365 "error registering backlight device\n");
366
367 /* In PWM dimming mode, enable pwm device */
368 if (chip->pdata->dimming_mode == DIMMING_PWM) {
369 pwm_init_state(chip->pwmd, &pwmstate);
370 pwm_set_relative_duty_cycle(&pwmstate,
371 chip->pdata->default_brightness,
372 chip->pdata->max_brightness);
373 pwmstate.enabled = true;
374 ret = pwm_apply_might_sleep(chip->pwmd, &pwmstate);
375 if (ret)
376 return dev_err_probe(dev, ret, "error setting pwm device\n");
377 }
378
379 chip->pdata->status = FIRST_POWER_ON;
380 backlight_update_status(chip->bl);
381
382 return 0;
383 }
384
mp3309c_remove(struct i2c_client * client)385 static void mp3309c_remove(struct i2c_client *client)
386 {
387 struct mp3309c_chip *chip = i2c_get_clientdata(client);
388 struct backlight_device *bl = chip->bl;
389
390 bl->props.power = BACKLIGHT_POWER_OFF;
391 bl->props.brightness = 0;
392 backlight_update_status(chip->bl);
393 }
394
395 static const struct of_device_id mp3309c_match_table[] = {
396 { .compatible = "mps,mp3309c", },
397 { },
398 };
399 MODULE_DEVICE_TABLE(of, mp3309c_match_table);
400
401 static const struct i2c_device_id mp3309c_id[] = {
402 { .name = "mp3309c" },
403 { }
404 };
405 MODULE_DEVICE_TABLE(i2c, mp3309c_id);
406
407 static struct i2c_driver mp3309c_i2c_driver = {
408 .driver = {
409 .name = KBUILD_MODNAME,
410 .of_match_table = mp3309c_match_table,
411 },
412 .probe = mp3309c_probe,
413 .remove = mp3309c_remove,
414 .id_table = mp3309c_id,
415 };
416
417 module_i2c_driver(mp3309c_i2c_driver);
418
419 MODULE_DESCRIPTION("Backlight Driver for MPS MP3309C");
420 MODULE_AUTHOR("Flavio Suligoi <f.suligoi@asem.it>");
421 MODULE_LICENSE("GPL");
422