0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/i2c.h>
0013 #include <linux/leds.h>
0014 #include <linux/slab.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/input.h>
0017 #include <linux/led-lm3530.h>
0018 #include <linux/types.h>
0019 #include <linux/regulator/consumer.h>
0020 #include <linux/module.h>
0021
0022 #define LM3530_LED_DEV "lcd-backlight"
0023 #define LM3530_NAME "lm3530-led"
0024
0025 #define LM3530_GEN_CONFIG 0x10
0026 #define LM3530_ALS_CONFIG 0x20
0027 #define LM3530_BRT_RAMP_RATE 0x30
0028 #define LM3530_ALS_IMP_SELECT 0x41
0029 #define LM3530_BRT_CTRL_REG 0xA0
0030 #define LM3530_ALS_ZB0_REG 0x60
0031 #define LM3530_ALS_ZB1_REG 0x61
0032 #define LM3530_ALS_ZB2_REG 0x62
0033 #define LM3530_ALS_ZB3_REG 0x63
0034 #define LM3530_ALS_Z0T_REG 0x70
0035 #define LM3530_ALS_Z1T_REG 0x71
0036 #define LM3530_ALS_Z2T_REG 0x72
0037 #define LM3530_ALS_Z3T_REG 0x73
0038 #define LM3530_ALS_Z4T_REG 0x74
0039 #define LM3530_REG_MAX 14
0040
0041
0042 #define LM3530_EN_I2C_SHIFT (0)
0043 #define LM3530_RAMP_LAW_SHIFT (1)
0044 #define LM3530_MAX_CURR_SHIFT (2)
0045 #define LM3530_EN_PWM_SHIFT (5)
0046 #define LM3530_PWM_POL_SHIFT (6)
0047 #define LM3530_EN_PWM_SIMPLE_SHIFT (7)
0048
0049 #define LM3530_ENABLE_I2C (1 << LM3530_EN_I2C_SHIFT)
0050 #define LM3530_ENABLE_PWM (1 << LM3530_EN_PWM_SHIFT)
0051 #define LM3530_POL_LOW (1 << LM3530_PWM_POL_SHIFT)
0052 #define LM3530_ENABLE_PWM_SIMPLE (1 << LM3530_EN_PWM_SIMPLE_SHIFT)
0053
0054
0055 #define LM3530_ALS_AVG_TIME_SHIFT (0)
0056 #define LM3530_EN_ALS_SHIFT (3)
0057 #define LM3530_ALS_SEL_SHIFT (5)
0058
0059 #define LM3530_ENABLE_ALS (3 << LM3530_EN_ALS_SHIFT)
0060
0061
0062 #define LM3530_BRT_RAMP_FALL_SHIFT (0)
0063 #define LM3530_BRT_RAMP_RISE_SHIFT (3)
0064
0065
0066 #define LM3530_ALS1_IMP_SHIFT (0)
0067 #define LM3530_ALS2_IMP_SHIFT (4)
0068
0069
0070 #define LM3530_ALS_ZB_MAX (4)
0071 #define LM3530_ALS_WINDOW_mV (1000)
0072 #define LM3530_ALS_OFFSET_mV (4)
0073
0074
0075 #define LM3530_DEF_ZT_0 (0x7F)
0076 #define LM3530_DEF_ZT_1 (0x66)
0077 #define LM3530_DEF_ZT_2 (0x4C)
0078 #define LM3530_DEF_ZT_3 (0x33)
0079 #define LM3530_DEF_ZT_4 (0x19)
0080
0081
0082 #define MAX_BRIGHTNESS (127)
0083
0084 struct lm3530_mode_map {
0085 const char *mode;
0086 enum lm3530_mode mode_val;
0087 };
0088
0089 static struct lm3530_mode_map mode_map[] = {
0090 { "man", LM3530_BL_MODE_MANUAL },
0091 { "als", LM3530_BL_MODE_ALS },
0092 { "pwm", LM3530_BL_MODE_PWM },
0093 };
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 struct lm3530_data {
0106 struct led_classdev led_dev;
0107 struct i2c_client *client;
0108 struct lm3530_platform_data *pdata;
0109 enum lm3530_mode mode;
0110 struct regulator *regulator;
0111 enum led_brightness brightness;
0112 bool enable;
0113 };
0114
0115
0116
0117
0118
0119
0120
0121 struct lm3530_als_data {
0122 u8 config;
0123 u8 imp_sel;
0124 u8 zones[LM3530_ALS_ZB_MAX];
0125 };
0126
0127 static const u8 lm3530_reg[LM3530_REG_MAX] = {
0128 LM3530_GEN_CONFIG,
0129 LM3530_ALS_CONFIG,
0130 LM3530_BRT_RAMP_RATE,
0131 LM3530_ALS_IMP_SELECT,
0132 LM3530_BRT_CTRL_REG,
0133 LM3530_ALS_ZB0_REG,
0134 LM3530_ALS_ZB1_REG,
0135 LM3530_ALS_ZB2_REG,
0136 LM3530_ALS_ZB3_REG,
0137 LM3530_ALS_Z0T_REG,
0138 LM3530_ALS_Z1T_REG,
0139 LM3530_ALS_Z2T_REG,
0140 LM3530_ALS_Z3T_REG,
0141 LM3530_ALS_Z4T_REG,
0142 };
0143
0144 static int lm3530_get_mode_from_str(const char *str)
0145 {
0146 int i;
0147
0148 for (i = 0; i < ARRAY_SIZE(mode_map); i++)
0149 if (sysfs_streq(str, mode_map[i].mode))
0150 return mode_map[i].mode_val;
0151
0152 return -EINVAL;
0153 }
0154
0155 static void lm3530_als_configure(struct lm3530_platform_data *pdata,
0156 struct lm3530_als_data *als)
0157 {
0158 int i;
0159 u32 als_vmin, als_vmax, als_vstep;
0160
0161 if (pdata->als_vmax == 0) {
0162 pdata->als_vmin = 0;
0163 pdata->als_vmax = LM3530_ALS_WINDOW_mV;
0164 }
0165
0166 als_vmin = pdata->als_vmin;
0167 als_vmax = pdata->als_vmax;
0168
0169 if ((als_vmax - als_vmin) > LM3530_ALS_WINDOW_mV)
0170 pdata->als_vmax = als_vmax = als_vmin + LM3530_ALS_WINDOW_mV;
0171
0172
0173 als_vstep = (als_vmax - als_vmin) / (LM3530_ALS_ZB_MAX + 1);
0174
0175 for (i = 0; i < LM3530_ALS_ZB_MAX; i++)
0176 als->zones[i] = (((als_vmin + LM3530_ALS_OFFSET_mV) +
0177 als_vstep + (i * als_vstep)) * LED_FULL) / 1000;
0178
0179 als->config =
0180 (pdata->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) |
0181 (LM3530_ENABLE_ALS) |
0182 (pdata->als_input_mode << LM3530_ALS_SEL_SHIFT);
0183
0184 als->imp_sel =
0185 (pdata->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) |
0186 (pdata->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
0187 }
0188
0189 static int lm3530_led_enable(struct lm3530_data *drvdata)
0190 {
0191 int ret;
0192
0193 if (drvdata->enable)
0194 return 0;
0195
0196 ret = regulator_enable(drvdata->regulator);
0197 if (ret) {
0198 dev_err(drvdata->led_dev.dev, "Failed to enable vin:%d\n", ret);
0199 return ret;
0200 }
0201
0202 drvdata->enable = true;
0203 return 0;
0204 }
0205
0206 static void lm3530_led_disable(struct lm3530_data *drvdata)
0207 {
0208 int ret;
0209
0210 if (!drvdata->enable)
0211 return;
0212
0213 ret = regulator_disable(drvdata->regulator);
0214 if (ret) {
0215 dev_err(drvdata->led_dev.dev, "Failed to disable vin:%d\n",
0216 ret);
0217 return;
0218 }
0219
0220 drvdata->enable = false;
0221 }
0222
0223 static int lm3530_init_registers(struct lm3530_data *drvdata)
0224 {
0225 int ret = 0;
0226 int i;
0227 u8 gen_config;
0228 u8 brt_ramp;
0229 u8 brightness;
0230 u8 reg_val[LM3530_REG_MAX];
0231 struct lm3530_platform_data *pdata = drvdata->pdata;
0232 struct i2c_client *client = drvdata->client;
0233 struct lm3530_pwm_data *pwm = &pdata->pwm_data;
0234 struct lm3530_als_data als;
0235
0236 memset(&als, 0, sizeof(struct lm3530_als_data));
0237
0238 gen_config = (pdata->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) |
0239 ((pdata->max_current & 7) << LM3530_MAX_CURR_SHIFT);
0240
0241 switch (drvdata->mode) {
0242 case LM3530_BL_MODE_MANUAL:
0243 gen_config |= LM3530_ENABLE_I2C;
0244 break;
0245 case LM3530_BL_MODE_ALS:
0246 gen_config |= LM3530_ENABLE_I2C;
0247 lm3530_als_configure(pdata, &als);
0248 break;
0249 case LM3530_BL_MODE_PWM:
0250 gen_config |= LM3530_ENABLE_PWM | LM3530_ENABLE_PWM_SIMPLE |
0251 (pdata->pwm_pol_hi << LM3530_PWM_POL_SHIFT);
0252 break;
0253 }
0254
0255 brt_ramp = (pdata->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
0256 (pdata->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
0257
0258 if (drvdata->brightness)
0259 brightness = drvdata->brightness;
0260 else
0261 brightness = drvdata->brightness = pdata->brt_val;
0262
0263 if (brightness > drvdata->led_dev.max_brightness)
0264 brightness = drvdata->led_dev.max_brightness;
0265
0266 reg_val[0] = gen_config;
0267 reg_val[1] = als.config;
0268 reg_val[2] = brt_ramp;
0269 reg_val[3] = als.imp_sel;
0270 reg_val[4] = brightness;
0271 reg_val[5] = als.zones[0];
0272 reg_val[6] = als.zones[1];
0273 reg_val[7] = als.zones[2];
0274 reg_val[8] = als.zones[3];
0275 reg_val[9] = LM3530_DEF_ZT_0;
0276 reg_val[10] = LM3530_DEF_ZT_1;
0277 reg_val[11] = LM3530_DEF_ZT_2;
0278 reg_val[12] = LM3530_DEF_ZT_3;
0279 reg_val[13] = LM3530_DEF_ZT_4;
0280
0281 ret = lm3530_led_enable(drvdata);
0282 if (ret)
0283 return ret;
0284
0285 for (i = 0; i < LM3530_REG_MAX; i++) {
0286
0287 if (lm3530_reg[i] == LM3530_BRT_CTRL_REG &&
0288 drvdata->mode == LM3530_BL_MODE_PWM) {
0289 if (pwm->pwm_set_intensity)
0290 pwm->pwm_set_intensity(reg_val[i],
0291 drvdata->led_dev.max_brightness);
0292 continue;
0293 }
0294
0295 ret = i2c_smbus_write_byte_data(client,
0296 lm3530_reg[i], reg_val[i]);
0297 if (ret)
0298 break;
0299 }
0300
0301 return ret;
0302 }
0303
0304 static void lm3530_brightness_set(struct led_classdev *led_cdev,
0305 enum led_brightness brt_val)
0306 {
0307 int err;
0308 struct lm3530_data *drvdata =
0309 container_of(led_cdev, struct lm3530_data, led_dev);
0310 struct lm3530_platform_data *pdata = drvdata->pdata;
0311 struct lm3530_pwm_data *pwm = &pdata->pwm_data;
0312 u8 max_brightness = led_cdev->max_brightness;
0313
0314 switch (drvdata->mode) {
0315 case LM3530_BL_MODE_MANUAL:
0316
0317 if (!drvdata->enable) {
0318 err = lm3530_init_registers(drvdata);
0319 if (err) {
0320 dev_err(&drvdata->client->dev,
0321 "Register Init failed: %d\n", err);
0322 break;
0323 }
0324 }
0325
0326
0327 err = i2c_smbus_write_byte_data(drvdata->client,
0328 LM3530_BRT_CTRL_REG, brt_val);
0329 if (err)
0330 dev_err(&drvdata->client->dev,
0331 "Unable to set brightness: %d\n", err);
0332 else
0333 drvdata->brightness = brt_val;
0334
0335 if (brt_val == 0)
0336 lm3530_led_disable(drvdata);
0337 break;
0338 case LM3530_BL_MODE_ALS:
0339 break;
0340 case LM3530_BL_MODE_PWM:
0341 if (pwm->pwm_set_intensity)
0342 pwm->pwm_set_intensity(brt_val, max_brightness);
0343 break;
0344 default:
0345 break;
0346 }
0347 }
0348
0349 static ssize_t mode_show(struct device *dev,
0350 struct device_attribute *attr, char *buf)
0351 {
0352 struct led_classdev *led_cdev = dev_get_drvdata(dev);
0353 struct lm3530_data *drvdata;
0354 int i, len = 0;
0355
0356 drvdata = container_of(led_cdev, struct lm3530_data, led_dev);
0357 for (i = 0; i < ARRAY_SIZE(mode_map); i++)
0358 if (drvdata->mode == mode_map[i].mode_val)
0359 len += sprintf(buf + len, "[%s] ", mode_map[i].mode);
0360 else
0361 len += sprintf(buf + len, "%s ", mode_map[i].mode);
0362
0363 len += sprintf(buf + len, "\n");
0364
0365 return len;
0366 }
0367
0368 static ssize_t mode_store(struct device *dev, struct device_attribute
0369 *attr, const char *buf, size_t size)
0370 {
0371 struct led_classdev *led_cdev = dev_get_drvdata(dev);
0372 struct lm3530_data *drvdata;
0373 struct lm3530_pwm_data *pwm;
0374 u8 max_brightness;
0375 int mode, err;
0376
0377 drvdata = container_of(led_cdev, struct lm3530_data, led_dev);
0378 pwm = &drvdata->pdata->pwm_data;
0379 max_brightness = led_cdev->max_brightness;
0380 mode = lm3530_get_mode_from_str(buf);
0381 if (mode < 0) {
0382 dev_err(dev, "Invalid mode\n");
0383 return mode;
0384 }
0385
0386 drvdata->mode = mode;
0387
0388
0389 if (mode != LM3530_BL_MODE_PWM && pwm->pwm_set_intensity)
0390 pwm->pwm_set_intensity(0, max_brightness);
0391
0392 err = lm3530_init_registers(drvdata);
0393 if (err) {
0394 dev_err(dev, "Setting %s Mode failed :%d\n", buf, err);
0395 return err;
0396 }
0397
0398 return sizeof(drvdata->mode);
0399 }
0400 static DEVICE_ATTR_RW(mode);
0401
0402 static struct attribute *lm3530_attrs[] = {
0403 &dev_attr_mode.attr,
0404 NULL
0405 };
0406 ATTRIBUTE_GROUPS(lm3530);
0407
0408 static int lm3530_probe(struct i2c_client *client,
0409 const struct i2c_device_id *id)
0410 {
0411 struct lm3530_platform_data *pdata = dev_get_platdata(&client->dev);
0412 struct lm3530_data *drvdata;
0413 int err = 0;
0414
0415 if (pdata == NULL) {
0416 dev_err(&client->dev, "platform data required\n");
0417 return -ENODEV;
0418 }
0419
0420
0421 if (pdata->mode > LM3530_BL_MODE_PWM) {
0422 dev_err(&client->dev, "Illegal Mode request\n");
0423 return -EINVAL;
0424 }
0425
0426 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
0427 dev_err(&client->dev, "I2C_FUNC_I2C not supported\n");
0428 return -EIO;
0429 }
0430
0431 drvdata = devm_kzalloc(&client->dev, sizeof(struct lm3530_data),
0432 GFP_KERNEL);
0433 if (drvdata == NULL)
0434 return -ENOMEM;
0435
0436 drvdata->mode = pdata->mode;
0437 drvdata->client = client;
0438 drvdata->pdata = pdata;
0439 drvdata->brightness = LED_OFF;
0440 drvdata->enable = false;
0441 drvdata->led_dev.name = LM3530_LED_DEV;
0442 drvdata->led_dev.brightness_set = lm3530_brightness_set;
0443 drvdata->led_dev.max_brightness = MAX_BRIGHTNESS;
0444 drvdata->led_dev.groups = lm3530_groups;
0445
0446 i2c_set_clientdata(client, drvdata);
0447
0448 drvdata->regulator = devm_regulator_get(&client->dev, "vin");
0449 if (IS_ERR(drvdata->regulator)) {
0450 dev_err(&client->dev, "regulator get failed\n");
0451 err = PTR_ERR(drvdata->regulator);
0452 drvdata->regulator = NULL;
0453 return err;
0454 }
0455
0456 if (drvdata->pdata->brt_val) {
0457 err = lm3530_init_registers(drvdata);
0458 if (err < 0) {
0459 dev_err(&client->dev,
0460 "Register Init failed: %d\n", err);
0461 return err;
0462 }
0463 }
0464 err = led_classdev_register(&client->dev, &drvdata->led_dev);
0465 if (err < 0) {
0466 dev_err(&client->dev, "Register led class failed: %d\n", err);
0467 return err;
0468 }
0469
0470 return 0;
0471 }
0472
0473 static int lm3530_remove(struct i2c_client *client)
0474 {
0475 struct lm3530_data *drvdata = i2c_get_clientdata(client);
0476
0477 lm3530_led_disable(drvdata);
0478 led_classdev_unregister(&drvdata->led_dev);
0479 return 0;
0480 }
0481
0482 static const struct i2c_device_id lm3530_id[] = {
0483 {LM3530_NAME, 0},
0484 {}
0485 };
0486 MODULE_DEVICE_TABLE(i2c, lm3530_id);
0487
0488 static struct i2c_driver lm3530_i2c_driver = {
0489 .probe = lm3530_probe,
0490 .remove = lm3530_remove,
0491 .id_table = lm3530_id,
0492 .driver = {
0493 .name = LM3530_NAME,
0494 },
0495 };
0496
0497 module_i2c_driver(lm3530_i2c_driver);
0498
0499 MODULE_DESCRIPTION("Back Light driver for LM3530");
0500 MODULE_LICENSE("GPL v2");
0501 MODULE_AUTHOR("Shreshtha Kumar SAHU <shreshthakumar.sahu@stericsson.com>");