Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003 * Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip
0004 * Copyright (C) 2012 Texas Instruments
0005 */
0006 #include <linux/module.h>
0007 #include <linux/slab.h>
0008 #include <linux/i2c.h>
0009 #include <linux/leds.h>
0010 #include <linux/backlight.h>
0011 #include <linux/err.h>
0012 #include <linux/delay.h>
0013 #include <linux/uaccess.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/regmap.h>
0016 #include <linux/platform_data/lm3639_bl.h>
0017 
0018 #define REG_DEV_ID  0x00
0019 #define REG_CHECKSUM    0x01
0020 #define REG_BL_CONF_1   0x02
0021 #define REG_BL_CONF_2   0x03
0022 #define REG_BL_CONF_3   0x04
0023 #define REG_BL_CONF_4   0x05
0024 #define REG_FL_CONF_1   0x06
0025 #define REG_FL_CONF_2   0x07
0026 #define REG_FL_CONF_3   0x08
0027 #define REG_IO_CTRL 0x09
0028 #define REG_ENABLE  0x0A
0029 #define REG_FLAG    0x0B
0030 #define REG_MAX     REG_FLAG
0031 
0032 struct lm3639_chip_data {
0033     struct device *dev;
0034     struct lm3639_platform_data *pdata;
0035 
0036     struct backlight_device *bled;
0037     struct led_classdev cdev_flash;
0038     struct led_classdev cdev_torch;
0039     struct regmap *regmap;
0040 
0041     unsigned int bled_mode;
0042     unsigned int bled_map;
0043     unsigned int last_flag;
0044 };
0045 
0046 /* initialize chip */
0047 static int lm3639_chip_init(struct lm3639_chip_data *pchip)
0048 {
0049     int ret;
0050     unsigned int reg_val;
0051     struct lm3639_platform_data *pdata = pchip->pdata;
0052 
0053     /* input pins config. */
0054     ret =
0055         regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x08,
0056                    pdata->pin_pwm);
0057     if (ret < 0)
0058         goto out;
0059 
0060     reg_val = (pdata->pin_pwm & 0x40) | pdata->pin_strobe | pdata->pin_tx;
0061     ret = regmap_update_bits(pchip->regmap, REG_IO_CTRL, 0x7C, reg_val);
0062     if (ret < 0)
0063         goto out;
0064 
0065     /* init brightness */
0066     ret = regmap_write(pchip->regmap, REG_BL_CONF_4, pdata->init_brt_led);
0067     if (ret < 0)
0068         goto out;
0069 
0070     ret = regmap_write(pchip->regmap, REG_BL_CONF_3, pdata->init_brt_led);
0071     if (ret < 0)
0072         goto out;
0073 
0074     /* output pins config. */
0075     if (!pdata->init_brt_led) {
0076         reg_val = pdata->fled_pins;
0077         reg_val |= pdata->bled_pins;
0078     } else {
0079         reg_val = pdata->fled_pins;
0080         reg_val |= pdata->bled_pins | 0x01;
0081     }
0082 
0083     ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x79, reg_val);
0084     if (ret < 0)
0085         goto out;
0086 
0087     return ret;
0088 out:
0089     dev_err(pchip->dev, "i2c failed to access register\n");
0090     return ret;
0091 }
0092 
0093 /* update and get brightness */
0094 static int lm3639_bled_update_status(struct backlight_device *bl)
0095 {
0096     int ret;
0097     unsigned int reg_val;
0098     struct lm3639_chip_data *pchip = bl_get_data(bl);
0099     struct lm3639_platform_data *pdata = pchip->pdata;
0100 
0101     ret = regmap_read(pchip->regmap, REG_FLAG, &reg_val);
0102     if (ret < 0)
0103         goto out;
0104 
0105     if (reg_val != 0)
0106         dev_info(pchip->dev, "last flag is 0x%x\n", reg_val);
0107 
0108     /* pwm control */
0109     if (pdata->pin_pwm) {
0110         if (pdata->pwm_set_intensity)
0111             pdata->pwm_set_intensity(bl->props.brightness,
0112                          pdata->max_brt_led);
0113         else
0114             dev_err(pchip->dev,
0115                 "No pwm control func. in plat-data\n");
0116         return bl->props.brightness;
0117     }
0118 
0119     /* i2c control and set brigtness */
0120     ret = regmap_write(pchip->regmap, REG_BL_CONF_4, bl->props.brightness);
0121     if (ret < 0)
0122         goto out;
0123     ret = regmap_write(pchip->regmap, REG_BL_CONF_3, bl->props.brightness);
0124     if (ret < 0)
0125         goto out;
0126 
0127     if (!bl->props.brightness)
0128         ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x00);
0129     else
0130         ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x01);
0131     if (ret < 0)
0132         goto out;
0133 
0134     return bl->props.brightness;
0135 out:
0136     dev_err(pchip->dev, "i2c failed to access registers\n");
0137     return bl->props.brightness;
0138 }
0139 
0140 static int lm3639_bled_get_brightness(struct backlight_device *bl)
0141 {
0142     int ret;
0143     unsigned int reg_val;
0144     struct lm3639_chip_data *pchip = bl_get_data(bl);
0145     struct lm3639_platform_data *pdata = pchip->pdata;
0146 
0147     if (pdata->pin_pwm) {
0148         if (pdata->pwm_get_intensity)
0149             bl->props.brightness = pdata->pwm_get_intensity();
0150         else
0151             dev_err(pchip->dev,
0152                 "No pwm control func. in plat-data\n");
0153         return bl->props.brightness;
0154     }
0155 
0156     ret = regmap_read(pchip->regmap, REG_BL_CONF_1, &reg_val);
0157     if (ret < 0)
0158         goto out;
0159     if (reg_val & 0x10)
0160         ret = regmap_read(pchip->regmap, REG_BL_CONF_4, &reg_val);
0161     else
0162         ret = regmap_read(pchip->regmap, REG_BL_CONF_3, &reg_val);
0163     if (ret < 0)
0164         goto out;
0165     bl->props.brightness = reg_val;
0166 
0167     return bl->props.brightness;
0168 out:
0169     dev_err(pchip->dev, "i2c failed to access register\n");
0170     return bl->props.brightness;
0171 }
0172 
0173 static const struct backlight_ops lm3639_bled_ops = {
0174     .options = BL_CORE_SUSPENDRESUME,
0175     .update_status = lm3639_bled_update_status,
0176     .get_brightness = lm3639_bled_get_brightness,
0177 };
0178 
0179 /* backlight mapping mode */
0180 static ssize_t lm3639_bled_mode_store(struct device *dev,
0181                       struct device_attribute *devAttr,
0182                       const char *buf, size_t size)
0183 {
0184     ssize_t ret;
0185     struct lm3639_chip_data *pchip = dev_get_drvdata(dev);
0186     unsigned int state;
0187 
0188     ret = kstrtouint(buf, 10, &state);
0189     if (ret)
0190         goto out_input;
0191 
0192     if (!state)
0193         ret =
0194             regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10,
0195                        0x00);
0196     else
0197         ret =
0198             regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10,
0199                        0x10);
0200 
0201     if (ret < 0)
0202         goto out;
0203 
0204     return size;
0205 
0206 out:
0207     dev_err(pchip->dev, "%s:i2c access fail to register\n", __func__);
0208     return ret;
0209 
0210 out_input:
0211     dev_err(pchip->dev, "%s:input conversion fail\n", __func__);
0212     return ret;
0213 
0214 }
0215 
0216 static DEVICE_ATTR(bled_mode, S_IWUSR, NULL, lm3639_bled_mode_store);
0217 
0218 /* torch */
0219 static void lm3639_torch_brightness_set(struct led_classdev *cdev,
0220                     enum led_brightness brightness)
0221 {
0222     int ret;
0223     unsigned int reg_val;
0224     struct lm3639_chip_data *pchip;
0225 
0226     pchip = container_of(cdev, struct lm3639_chip_data, cdev_torch);
0227 
0228     ret = regmap_read(pchip->regmap, REG_FLAG, &reg_val);
0229     if (ret < 0)
0230         goto out;
0231     if (reg_val != 0)
0232         dev_info(pchip->dev, "last flag is 0x%x\n", reg_val);
0233 
0234     /* brightness 0 means off state */
0235     if (!brightness) {
0236         ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00);
0237         if (ret < 0)
0238             goto out;
0239         return;
0240     }
0241 
0242     ret = regmap_update_bits(pchip->regmap,
0243                  REG_FL_CONF_1, 0x70, (brightness - 1) << 4);
0244     if (ret < 0)
0245         goto out;
0246     ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x02);
0247     if (ret < 0)
0248         goto out;
0249 
0250     return;
0251 out:
0252     dev_err(pchip->dev, "i2c failed to access register\n");
0253 }
0254 
0255 /* flash */
0256 static void lm3639_flash_brightness_set(struct led_classdev *cdev,
0257                     enum led_brightness brightness)
0258 {
0259     int ret;
0260     unsigned int reg_val;
0261     struct lm3639_chip_data *pchip;
0262 
0263     pchip = container_of(cdev, struct lm3639_chip_data, cdev_flash);
0264 
0265     ret = regmap_read(pchip->regmap, REG_FLAG, &reg_val);
0266     if (ret < 0)
0267         goto out;
0268     if (reg_val != 0)
0269         dev_info(pchip->dev, "last flag is 0x%x\n", reg_val);
0270 
0271     /* torch off before flash control */
0272     ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00);
0273     if (ret < 0)
0274         goto out;
0275 
0276     /* brightness 0 means off state */
0277     if (!brightness)
0278         return;
0279 
0280     ret = regmap_update_bits(pchip->regmap,
0281                  REG_FL_CONF_1, 0x0F, brightness - 1);
0282     if (ret < 0)
0283         goto out;
0284     ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x06);
0285     if (ret < 0)
0286         goto out;
0287 
0288     return;
0289 out:
0290     dev_err(pchip->dev, "i2c failed to access register\n");
0291 }
0292 
0293 static const struct regmap_config lm3639_regmap = {
0294     .reg_bits = 8,
0295     .val_bits = 8,
0296     .max_register = REG_MAX,
0297 };
0298 
0299 static int lm3639_probe(struct i2c_client *client,
0300                   const struct i2c_device_id *id)
0301 {
0302     int ret;
0303     struct lm3639_chip_data *pchip;
0304     struct lm3639_platform_data *pdata = dev_get_platdata(&client->dev);
0305     struct backlight_properties props;
0306 
0307     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
0308         dev_err(&client->dev, "i2c functionality check fail.\n");
0309         return -EOPNOTSUPP;
0310     }
0311 
0312     if (pdata == NULL) {
0313         dev_err(&client->dev, "Needs Platform Data.\n");
0314         return -ENODATA;
0315     }
0316 
0317     pchip = devm_kzalloc(&client->dev,
0318                  sizeof(struct lm3639_chip_data), GFP_KERNEL);
0319     if (!pchip)
0320         return -ENOMEM;
0321 
0322     pchip->pdata = pdata;
0323     pchip->dev = &client->dev;
0324 
0325     pchip->regmap = devm_regmap_init_i2c(client, &lm3639_regmap);
0326     if (IS_ERR(pchip->regmap)) {
0327         ret = PTR_ERR(pchip->regmap);
0328         dev_err(&client->dev, "fail : allocate register map: %d\n",
0329             ret);
0330         return ret;
0331     }
0332     i2c_set_clientdata(client, pchip);
0333 
0334     /* chip initialize */
0335     ret = lm3639_chip_init(pchip);
0336     if (ret < 0) {
0337         dev_err(&client->dev, "fail : chip init\n");
0338         goto err_out;
0339     }
0340 
0341     /* backlight */
0342     props.type = BACKLIGHT_RAW;
0343     props.brightness = pdata->init_brt_led;
0344     props.max_brightness = pdata->max_brt_led;
0345     pchip->bled =
0346         devm_backlight_device_register(pchip->dev, "lm3639_bled",
0347                        pchip->dev, pchip, &lm3639_bled_ops,
0348                        &props);
0349     if (IS_ERR(pchip->bled)) {
0350         dev_err(&client->dev, "fail : backlight register\n");
0351         ret = PTR_ERR(pchip->bled);
0352         goto err_out;
0353     }
0354 
0355     ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode);
0356     if (ret < 0) {
0357         dev_err(&client->dev, "failed : add sysfs entries\n");
0358         goto err_out;
0359     }
0360 
0361     /* flash */
0362     pchip->cdev_flash.name = "lm3639_flash";
0363     pchip->cdev_flash.max_brightness = 16;
0364     pchip->cdev_flash.brightness_set = lm3639_flash_brightness_set;
0365     ret = led_classdev_register((struct device *)
0366                     &client->dev, &pchip->cdev_flash);
0367     if (ret < 0) {
0368         dev_err(&client->dev, "fail : flash register\n");
0369         goto err_flash;
0370     }
0371 
0372     /* torch */
0373     pchip->cdev_torch.name = "lm3639_torch";
0374     pchip->cdev_torch.max_brightness = 8;
0375     pchip->cdev_torch.brightness_set = lm3639_torch_brightness_set;
0376     ret = led_classdev_register((struct device *)
0377                     &client->dev, &pchip->cdev_torch);
0378     if (ret < 0) {
0379         dev_err(&client->dev, "fail : torch register\n");
0380         goto err_torch;
0381     }
0382 
0383     return 0;
0384 
0385 err_torch:
0386     led_classdev_unregister(&pchip->cdev_flash);
0387 err_flash:
0388     device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
0389 err_out:
0390     return ret;
0391 }
0392 
0393 static int lm3639_remove(struct i2c_client *client)
0394 {
0395     struct lm3639_chip_data *pchip = i2c_get_clientdata(client);
0396 
0397     regmap_write(pchip->regmap, REG_ENABLE, 0x00);
0398 
0399     led_classdev_unregister(&pchip->cdev_torch);
0400     led_classdev_unregister(&pchip->cdev_flash);
0401     if (pchip->bled)
0402         device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
0403     return 0;
0404 }
0405 
0406 static const struct i2c_device_id lm3639_id[] = {
0407     {LM3639_NAME, 0},
0408     {}
0409 };
0410 
0411 MODULE_DEVICE_TABLE(i2c, lm3639_id);
0412 static struct i2c_driver lm3639_i2c_driver = {
0413     .driver = {
0414            .name = LM3639_NAME,
0415            },
0416     .probe = lm3639_probe,
0417     .remove = lm3639_remove,
0418     .id_table = lm3639_id,
0419 };
0420 
0421 module_i2c_driver(lm3639_i2c_driver);
0422 
0423 MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639");
0424 MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
0425 MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
0426 MODULE_LICENSE("GPL v2");