Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * lm3533-bl.c -- LM3533 Backlight driver
0004  *
0005  * Copyright (C) 2011-2012 Texas Instruments
0006  *
0007  * Author: Johan Hovold <jhovold@gmail.com>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/init.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/backlight.h>
0014 #include <linux/fb.h>
0015 #include <linux/slab.h>
0016 
0017 #include <linux/mfd/lm3533.h>
0018 
0019 
0020 #define LM3533_HVCTRLBANK_COUNT     2
0021 #define LM3533_BL_MAX_BRIGHTNESS    255
0022 
0023 #define LM3533_REG_CTRLBANK_AB_BCONF    0x1a
0024 
0025 
0026 struct lm3533_bl {
0027     struct lm3533 *lm3533;
0028     struct lm3533_ctrlbank cb;
0029     struct backlight_device *bd;
0030     int id;
0031 };
0032 
0033 
0034 static inline int lm3533_bl_get_ctrlbank_id(struct lm3533_bl *bl)
0035 {
0036     return bl->id;
0037 }
0038 
0039 static int lm3533_bl_update_status(struct backlight_device *bd)
0040 {
0041     struct lm3533_bl *bl = bl_get_data(bd);
0042 
0043     return lm3533_ctrlbank_set_brightness(&bl->cb, backlight_get_brightness(bd));
0044 }
0045 
0046 static int lm3533_bl_get_brightness(struct backlight_device *bd)
0047 {
0048     struct lm3533_bl *bl = bl_get_data(bd);
0049     u8 val;
0050     int ret;
0051 
0052     ret = lm3533_ctrlbank_get_brightness(&bl->cb, &val);
0053     if (ret)
0054         return ret;
0055 
0056     return val;
0057 }
0058 
0059 static const struct backlight_ops lm3533_bl_ops = {
0060     .get_brightness = lm3533_bl_get_brightness,
0061     .update_status  = lm3533_bl_update_status,
0062 };
0063 
0064 static ssize_t show_id(struct device *dev,
0065                 struct device_attribute *attr, char *buf)
0066 {
0067     struct lm3533_bl *bl = dev_get_drvdata(dev);
0068 
0069     return scnprintf(buf, PAGE_SIZE, "%d\n", bl->id);
0070 }
0071 
0072 static ssize_t show_als_channel(struct device *dev,
0073                 struct device_attribute *attr, char *buf)
0074 {
0075     struct lm3533_bl *bl = dev_get_drvdata(dev);
0076     unsigned channel = lm3533_bl_get_ctrlbank_id(bl);
0077 
0078     return scnprintf(buf, PAGE_SIZE, "%u\n", channel);
0079 }
0080 
0081 static ssize_t show_als_en(struct device *dev,
0082                 struct device_attribute *attr, char *buf)
0083 {
0084     struct lm3533_bl *bl = dev_get_drvdata(dev);
0085     int ctrlbank = lm3533_bl_get_ctrlbank_id(bl);
0086     u8 val;
0087     u8 mask;
0088     bool enable;
0089     int ret;
0090 
0091     ret = lm3533_read(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, &val);
0092     if (ret)
0093         return ret;
0094 
0095     mask = 1 << (2 * ctrlbank);
0096     enable = val & mask;
0097 
0098     return scnprintf(buf, PAGE_SIZE, "%d\n", enable);
0099 }
0100 
0101 static ssize_t store_als_en(struct device *dev,
0102                     struct device_attribute *attr,
0103                     const char *buf, size_t len)
0104 {
0105     struct lm3533_bl *bl = dev_get_drvdata(dev);
0106     int ctrlbank = lm3533_bl_get_ctrlbank_id(bl);
0107     int enable;
0108     u8 val;
0109     u8 mask;
0110     int ret;
0111 
0112     if (kstrtoint(buf, 0, &enable))
0113         return -EINVAL;
0114 
0115     mask = 1 << (2 * ctrlbank);
0116 
0117     if (enable)
0118         val = mask;
0119     else
0120         val = 0;
0121 
0122     ret = lm3533_update(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, val,
0123                                     mask);
0124     if (ret)
0125         return ret;
0126 
0127     return len;
0128 }
0129 
0130 static ssize_t show_linear(struct device *dev,
0131                 struct device_attribute *attr, char *buf)
0132 {
0133     struct lm3533_bl *bl = dev_get_drvdata(dev);
0134     u8 val;
0135     u8 mask;
0136     int linear;
0137     int ret;
0138 
0139     ret = lm3533_read(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, &val);
0140     if (ret)
0141         return ret;
0142 
0143     mask = 1 << (2 * lm3533_bl_get_ctrlbank_id(bl) + 1);
0144 
0145     if (val & mask)
0146         linear = 1;
0147     else
0148         linear = 0;
0149 
0150     return scnprintf(buf, PAGE_SIZE, "%x\n", linear);
0151 }
0152 
0153 static ssize_t store_linear(struct device *dev,
0154                     struct device_attribute *attr,
0155                     const char *buf, size_t len)
0156 {
0157     struct lm3533_bl *bl = dev_get_drvdata(dev);
0158     unsigned long linear;
0159     u8 mask;
0160     u8 val;
0161     int ret;
0162 
0163     if (kstrtoul(buf, 0, &linear))
0164         return -EINVAL;
0165 
0166     mask = 1 << (2 * lm3533_bl_get_ctrlbank_id(bl) + 1);
0167 
0168     if (linear)
0169         val = mask;
0170     else
0171         val = 0;
0172 
0173     ret = lm3533_update(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, val,
0174                                     mask);
0175     if (ret)
0176         return ret;
0177 
0178     return len;
0179 }
0180 
0181 static ssize_t show_pwm(struct device *dev,
0182                     struct device_attribute *attr,
0183                     char *buf)
0184 {
0185     struct lm3533_bl *bl = dev_get_drvdata(dev);
0186     u8 val;
0187     int ret;
0188 
0189     ret = lm3533_ctrlbank_get_pwm(&bl->cb, &val);
0190     if (ret)
0191         return ret;
0192 
0193     return scnprintf(buf, PAGE_SIZE, "%u\n", val);
0194 }
0195 
0196 static ssize_t store_pwm(struct device *dev,
0197                     struct device_attribute *attr,
0198                     const char *buf, size_t len)
0199 {
0200     struct lm3533_bl *bl = dev_get_drvdata(dev);
0201     u8 val;
0202     int ret;
0203 
0204     if (kstrtou8(buf, 0, &val))
0205         return -EINVAL;
0206 
0207     ret = lm3533_ctrlbank_set_pwm(&bl->cb, val);
0208     if (ret)
0209         return ret;
0210 
0211     return len;
0212 }
0213 
0214 static LM3533_ATTR_RO(als_channel);
0215 static LM3533_ATTR_RW(als_en);
0216 static LM3533_ATTR_RO(id);
0217 static LM3533_ATTR_RW(linear);
0218 static LM3533_ATTR_RW(pwm);
0219 
0220 static struct attribute *lm3533_bl_attributes[] = {
0221     &dev_attr_als_channel.attr,
0222     &dev_attr_als_en.attr,
0223     &dev_attr_id.attr,
0224     &dev_attr_linear.attr,
0225     &dev_attr_pwm.attr,
0226     NULL,
0227 };
0228 
0229 static umode_t lm3533_bl_attr_is_visible(struct kobject *kobj,
0230                          struct attribute *attr, int n)
0231 {
0232     struct device *dev = kobj_to_dev(kobj);
0233     struct lm3533_bl *bl = dev_get_drvdata(dev);
0234     umode_t mode = attr->mode;
0235 
0236     if (attr == &dev_attr_als_channel.attr ||
0237                     attr == &dev_attr_als_en.attr) {
0238         if (!bl->lm3533->have_als)
0239             mode = 0;
0240     }
0241 
0242     return mode;
0243 };
0244 
0245 static struct attribute_group lm3533_bl_attribute_group = {
0246     .is_visible = lm3533_bl_attr_is_visible,
0247     .attrs      = lm3533_bl_attributes
0248 };
0249 
0250 static int lm3533_bl_setup(struct lm3533_bl *bl,
0251                     struct lm3533_bl_platform_data *pdata)
0252 {
0253     int ret;
0254 
0255     ret = lm3533_ctrlbank_set_max_current(&bl->cb, pdata->max_current);
0256     if (ret)
0257         return ret;
0258 
0259     return lm3533_ctrlbank_set_pwm(&bl->cb, pdata->pwm);
0260 }
0261 
0262 static int lm3533_bl_probe(struct platform_device *pdev)
0263 {
0264     struct lm3533 *lm3533;
0265     struct lm3533_bl_platform_data *pdata;
0266     struct lm3533_bl *bl;
0267     struct backlight_device *bd;
0268     struct backlight_properties props;
0269     int ret;
0270 
0271     dev_dbg(&pdev->dev, "%s\n", __func__);
0272 
0273     lm3533 = dev_get_drvdata(pdev->dev.parent);
0274     if (!lm3533)
0275         return -EINVAL;
0276 
0277     pdata = dev_get_platdata(&pdev->dev);
0278     if (!pdata) {
0279         dev_err(&pdev->dev, "no platform data\n");
0280         return -EINVAL;
0281     }
0282 
0283     if (pdev->id < 0 || pdev->id >= LM3533_HVCTRLBANK_COUNT) {
0284         dev_err(&pdev->dev, "illegal backlight id %d\n", pdev->id);
0285         return -EINVAL;
0286     }
0287 
0288     bl = devm_kzalloc(&pdev->dev, sizeof(*bl), GFP_KERNEL);
0289     if (!bl)
0290         return -ENOMEM;
0291 
0292     bl->lm3533 = lm3533;
0293     bl->id = pdev->id;
0294 
0295     bl->cb.lm3533 = lm3533;
0296     bl->cb.id = lm3533_bl_get_ctrlbank_id(bl);
0297     bl->cb.dev = NULL;          /* until registered */
0298 
0299     memset(&props, 0, sizeof(props));
0300     props.type = BACKLIGHT_RAW;
0301     props.max_brightness = LM3533_BL_MAX_BRIGHTNESS;
0302     props.brightness = pdata->default_brightness;
0303     bd = devm_backlight_device_register(&pdev->dev, pdata->name,
0304                     pdev->dev.parent, bl, &lm3533_bl_ops,
0305                     &props);
0306     if (IS_ERR(bd)) {
0307         dev_err(&pdev->dev, "failed to register backlight device\n");
0308         return PTR_ERR(bd);
0309     }
0310 
0311     bl->bd = bd;
0312     bl->cb.dev = &bl->bd->dev;
0313 
0314     platform_set_drvdata(pdev, bl);
0315 
0316     ret = sysfs_create_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
0317     if (ret < 0) {
0318         dev_err(&pdev->dev, "failed to create sysfs attributes\n");
0319         return ret;
0320     }
0321 
0322     backlight_update_status(bd);
0323 
0324     ret = lm3533_bl_setup(bl, pdata);
0325     if (ret)
0326         goto err_sysfs_remove;
0327 
0328     ret = lm3533_ctrlbank_enable(&bl->cb);
0329     if (ret)
0330         goto err_sysfs_remove;
0331 
0332     return 0;
0333 
0334 err_sysfs_remove:
0335     sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
0336 
0337     return ret;
0338 }
0339 
0340 static int lm3533_bl_remove(struct platform_device *pdev)
0341 {
0342     struct lm3533_bl *bl = platform_get_drvdata(pdev);
0343     struct backlight_device *bd = bl->bd;
0344 
0345     dev_dbg(&bd->dev, "%s\n", __func__);
0346 
0347     bd->props.power = FB_BLANK_POWERDOWN;
0348     bd->props.brightness = 0;
0349 
0350     lm3533_ctrlbank_disable(&bl->cb);
0351     sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
0352 
0353     return 0;
0354 }
0355 
0356 #ifdef CONFIG_PM_SLEEP
0357 static int lm3533_bl_suspend(struct device *dev)
0358 {
0359     struct lm3533_bl *bl = dev_get_drvdata(dev);
0360 
0361     dev_dbg(dev, "%s\n", __func__);
0362 
0363     return lm3533_ctrlbank_disable(&bl->cb);
0364 }
0365 
0366 static int lm3533_bl_resume(struct device *dev)
0367 {
0368     struct lm3533_bl *bl = dev_get_drvdata(dev);
0369 
0370     dev_dbg(dev, "%s\n", __func__);
0371 
0372     return lm3533_ctrlbank_enable(&bl->cb);
0373 }
0374 #endif
0375 
0376 static SIMPLE_DEV_PM_OPS(lm3533_bl_pm_ops, lm3533_bl_suspend, lm3533_bl_resume);
0377 
0378 static void lm3533_bl_shutdown(struct platform_device *pdev)
0379 {
0380     struct lm3533_bl *bl = platform_get_drvdata(pdev);
0381 
0382     dev_dbg(&pdev->dev, "%s\n", __func__);
0383 
0384     lm3533_ctrlbank_disable(&bl->cb);
0385 }
0386 
0387 static struct platform_driver lm3533_bl_driver = {
0388     .driver = {
0389         .name   = "lm3533-backlight",
0390         .pm = &lm3533_bl_pm_ops,
0391     },
0392     .probe      = lm3533_bl_probe,
0393     .remove     = lm3533_bl_remove,
0394     .shutdown   = lm3533_bl_shutdown,
0395 };
0396 module_platform_driver(lm3533_bl_driver);
0397 
0398 MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
0399 MODULE_DESCRIPTION("LM3533 Backlight driver");
0400 MODULE_LICENSE("GPL");
0401 MODULE_ALIAS("platform:lm3533-backlight");