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