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 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 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 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 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 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