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