1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * lm3533-bl.c -- LM3533 Backlight driver 4 * 5 * Copyright (C) 2011-2012 Texas Instruments 6 * 7 * Author: Johan Hovold <jhovold@gmail.com> 8 */ 9 10 #include <linux/module.h> 11 #include <linux/init.h> 12 #include <linux/platform_device.h> 13 #include <linux/backlight.h> 14 #include <linux/fb.h> 15 #include <linux/slab.h> 16 17 #include <linux/mfd/lm3533.h> 18 19 20 #define LM3533_HVCTRLBANK_COUNT 2 21 #define LM3533_BL_MAX_BRIGHTNESS 255 22 23 #define LM3533_REG_CTRLBANK_AB_BCONF 0x1a 24 25 26 struct lm3533_bl { 27 struct lm3533 *lm3533; 28 struct lm3533_ctrlbank cb; 29 struct backlight_device *bd; 30 int id; 31 }; 32 33 34 static inline int lm3533_bl_get_ctrlbank_id(struct lm3533_bl *bl) 35 { 36 return bl->id; 37 } 38 39 static int lm3533_bl_update_status(struct backlight_device *bd) 40 { 41 struct lm3533_bl *bl = bl_get_data(bd); 42 int brightness = bd->props.brightness; 43 44 if (bd->props.power != FB_BLANK_UNBLANK) 45 brightness = 0; 46 if (bd->props.fb_blank != FB_BLANK_UNBLANK) 47 brightness = 0; 48 49 return lm3533_ctrlbank_set_brightness(&bl->cb, (u8)brightness); 50 } 51 52 static int lm3533_bl_get_brightness(struct backlight_device *bd) 53 { 54 struct lm3533_bl *bl = bl_get_data(bd); 55 u8 val; 56 int ret; 57 58 ret = lm3533_ctrlbank_get_brightness(&bl->cb, &val); 59 if (ret) 60 return ret; 61 62 return val; 63 } 64 65 static const struct backlight_ops lm3533_bl_ops = { 66 .get_brightness = lm3533_bl_get_brightness, 67 .update_status = lm3533_bl_update_status, 68 }; 69 70 static ssize_t show_id(struct device *dev, 71 struct device_attribute *attr, char *buf) 72 { 73 struct lm3533_bl *bl = dev_get_drvdata(dev); 74 75 return scnprintf(buf, PAGE_SIZE, "%d\n", bl->id); 76 } 77 78 static ssize_t show_als_channel(struct device *dev, 79 struct device_attribute *attr, char *buf) 80 { 81 struct lm3533_bl *bl = dev_get_drvdata(dev); 82 unsigned channel = lm3533_bl_get_ctrlbank_id(bl); 83 84 return scnprintf(buf, PAGE_SIZE, "%u\n", channel); 85 } 86 87 static ssize_t show_als_en(struct device *dev, 88 struct device_attribute *attr, char *buf) 89 { 90 struct lm3533_bl *bl = dev_get_drvdata(dev); 91 int ctrlbank = lm3533_bl_get_ctrlbank_id(bl); 92 u8 val; 93 u8 mask; 94 bool enable; 95 int ret; 96 97 ret = lm3533_read(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, &val); 98 if (ret) 99 return ret; 100 101 mask = 1 << (2 * ctrlbank); 102 enable = val & mask; 103 104 return scnprintf(buf, PAGE_SIZE, "%d\n", enable); 105 } 106 107 static ssize_t store_als_en(struct device *dev, 108 struct device_attribute *attr, 109 const char *buf, size_t len) 110 { 111 struct lm3533_bl *bl = dev_get_drvdata(dev); 112 int ctrlbank = lm3533_bl_get_ctrlbank_id(bl); 113 int enable; 114 u8 val; 115 u8 mask; 116 int ret; 117 118 if (kstrtoint(buf, 0, &enable)) 119 return -EINVAL; 120 121 mask = 1 << (2 * ctrlbank); 122 123 if (enable) 124 val = mask; 125 else 126 val = 0; 127 128 ret = lm3533_update(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, val, 129 mask); 130 if (ret) 131 return ret; 132 133 return len; 134 } 135 136 static ssize_t show_linear(struct device *dev, 137 struct device_attribute *attr, char *buf) 138 { 139 struct lm3533_bl *bl = dev_get_drvdata(dev); 140 u8 val; 141 u8 mask; 142 int linear; 143 int ret; 144 145 ret = lm3533_read(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, &val); 146 if (ret) 147 return ret; 148 149 mask = 1 << (2 * lm3533_bl_get_ctrlbank_id(bl) + 1); 150 151 if (val & mask) 152 linear = 1; 153 else 154 linear = 0; 155 156 return scnprintf(buf, PAGE_SIZE, "%x\n", linear); 157 } 158 159 static ssize_t store_linear(struct device *dev, 160 struct device_attribute *attr, 161 const char *buf, size_t len) 162 { 163 struct lm3533_bl *bl = dev_get_drvdata(dev); 164 unsigned long linear; 165 u8 mask; 166 u8 val; 167 int ret; 168 169 if (kstrtoul(buf, 0, &linear)) 170 return -EINVAL; 171 172 mask = 1 << (2 * lm3533_bl_get_ctrlbank_id(bl) + 1); 173 174 if (linear) 175 val = mask; 176 else 177 val = 0; 178 179 ret = lm3533_update(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, val, 180 mask); 181 if (ret) 182 return ret; 183 184 return len; 185 } 186 187 static ssize_t show_pwm(struct device *dev, 188 struct device_attribute *attr, 189 char *buf) 190 { 191 struct lm3533_bl *bl = dev_get_drvdata(dev); 192 u8 val; 193 int ret; 194 195 ret = lm3533_ctrlbank_get_pwm(&bl->cb, &val); 196 if (ret) 197 return ret; 198 199 return scnprintf(buf, PAGE_SIZE, "%u\n", val); 200 } 201 202 static ssize_t store_pwm(struct device *dev, 203 struct device_attribute *attr, 204 const char *buf, size_t len) 205 { 206 struct lm3533_bl *bl = dev_get_drvdata(dev); 207 u8 val; 208 int ret; 209 210 if (kstrtou8(buf, 0, &val)) 211 return -EINVAL; 212 213 ret = lm3533_ctrlbank_set_pwm(&bl->cb, val); 214 if (ret) 215 return ret; 216 217 return len; 218 } 219 220 static LM3533_ATTR_RO(als_channel); 221 static LM3533_ATTR_RW(als_en); 222 static LM3533_ATTR_RO(id); 223 static LM3533_ATTR_RW(linear); 224 static LM3533_ATTR_RW(pwm); 225 226 static struct attribute *lm3533_bl_attributes[] = { 227 &dev_attr_als_channel.attr, 228 &dev_attr_als_en.attr, 229 &dev_attr_id.attr, 230 &dev_attr_linear.attr, 231 &dev_attr_pwm.attr, 232 NULL, 233 }; 234 235 static umode_t lm3533_bl_attr_is_visible(struct kobject *kobj, 236 struct attribute *attr, int n) 237 { 238 struct device *dev = container_of(kobj, struct device, kobj); 239 struct lm3533_bl *bl = dev_get_drvdata(dev); 240 umode_t mode = attr->mode; 241 242 if (attr == &dev_attr_als_channel.attr || 243 attr == &dev_attr_als_en.attr) { 244 if (!bl->lm3533->have_als) 245 mode = 0; 246 } 247 248 return mode; 249 }; 250 251 static struct attribute_group lm3533_bl_attribute_group = { 252 .is_visible = lm3533_bl_attr_is_visible, 253 .attrs = lm3533_bl_attributes 254 }; 255 256 static int lm3533_bl_setup(struct lm3533_bl *bl, 257 struct lm3533_bl_platform_data *pdata) 258 { 259 int ret; 260 261 ret = lm3533_ctrlbank_set_max_current(&bl->cb, pdata->max_current); 262 if (ret) 263 return ret; 264 265 return lm3533_ctrlbank_set_pwm(&bl->cb, pdata->pwm); 266 } 267 268 static int lm3533_bl_probe(struct platform_device *pdev) 269 { 270 struct lm3533 *lm3533; 271 struct lm3533_bl_platform_data *pdata; 272 struct lm3533_bl *bl; 273 struct backlight_device *bd; 274 struct backlight_properties props; 275 int ret; 276 277 dev_dbg(&pdev->dev, "%s\n", __func__); 278 279 lm3533 = dev_get_drvdata(pdev->dev.parent); 280 if (!lm3533) 281 return -EINVAL; 282 283 pdata = dev_get_platdata(&pdev->dev); 284 if (!pdata) { 285 dev_err(&pdev->dev, "no platform data\n"); 286 return -EINVAL; 287 } 288 289 if (pdev->id < 0 || pdev->id >= LM3533_HVCTRLBANK_COUNT) { 290 dev_err(&pdev->dev, "illegal backlight id %d\n", pdev->id); 291 return -EINVAL; 292 } 293 294 bl = devm_kzalloc(&pdev->dev, sizeof(*bl), GFP_KERNEL); 295 if (!bl) 296 return -ENOMEM; 297 298 bl->lm3533 = lm3533; 299 bl->id = pdev->id; 300 301 bl->cb.lm3533 = lm3533; 302 bl->cb.id = lm3533_bl_get_ctrlbank_id(bl); 303 bl->cb.dev = NULL; /* until registered */ 304 305 memset(&props, 0, sizeof(props)); 306 props.type = BACKLIGHT_RAW; 307 props.max_brightness = LM3533_BL_MAX_BRIGHTNESS; 308 props.brightness = pdata->default_brightness; 309 bd = devm_backlight_device_register(&pdev->dev, pdata->name, 310 pdev->dev.parent, bl, &lm3533_bl_ops, 311 &props); 312 if (IS_ERR(bd)) { 313 dev_err(&pdev->dev, "failed to register backlight device\n"); 314 return PTR_ERR(bd); 315 } 316 317 bl->bd = bd; 318 bl->cb.dev = &bl->bd->dev; 319 320 platform_set_drvdata(pdev, bl); 321 322 ret = sysfs_create_group(&bd->dev.kobj, &lm3533_bl_attribute_group); 323 if (ret < 0) { 324 dev_err(&pdev->dev, "failed to create sysfs attributes\n"); 325 return ret; 326 } 327 328 backlight_update_status(bd); 329 330 ret = lm3533_bl_setup(bl, pdata); 331 if (ret) 332 goto err_sysfs_remove; 333 334 ret = lm3533_ctrlbank_enable(&bl->cb); 335 if (ret) 336 goto err_sysfs_remove; 337 338 return 0; 339 340 err_sysfs_remove: 341 sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group); 342 343 return ret; 344 } 345 346 static int lm3533_bl_remove(struct platform_device *pdev) 347 { 348 struct lm3533_bl *bl = platform_get_drvdata(pdev); 349 struct backlight_device *bd = bl->bd; 350 351 dev_dbg(&bd->dev, "%s\n", __func__); 352 353 bd->props.power = FB_BLANK_POWERDOWN; 354 bd->props.brightness = 0; 355 356 lm3533_ctrlbank_disable(&bl->cb); 357 sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group); 358 359 return 0; 360 } 361 362 #ifdef CONFIG_PM_SLEEP 363 static int lm3533_bl_suspend(struct device *dev) 364 { 365 struct lm3533_bl *bl = dev_get_drvdata(dev); 366 367 dev_dbg(dev, "%s\n", __func__); 368 369 return lm3533_ctrlbank_disable(&bl->cb); 370 } 371 372 static int lm3533_bl_resume(struct device *dev) 373 { 374 struct lm3533_bl *bl = dev_get_drvdata(dev); 375 376 dev_dbg(dev, "%s\n", __func__); 377 378 return lm3533_ctrlbank_enable(&bl->cb); 379 } 380 #endif 381 382 static SIMPLE_DEV_PM_OPS(lm3533_bl_pm_ops, lm3533_bl_suspend, lm3533_bl_resume); 383 384 static void lm3533_bl_shutdown(struct platform_device *pdev) 385 { 386 struct lm3533_bl *bl = platform_get_drvdata(pdev); 387 388 dev_dbg(&pdev->dev, "%s\n", __func__); 389 390 lm3533_ctrlbank_disable(&bl->cb); 391 } 392 393 static struct platform_driver lm3533_bl_driver = { 394 .driver = { 395 .name = "lm3533-backlight", 396 .pm = &lm3533_bl_pm_ops, 397 }, 398 .probe = lm3533_bl_probe, 399 .remove = lm3533_bl_remove, 400 .shutdown = lm3533_bl_shutdown, 401 }; 402 module_platform_driver(lm3533_bl_driver); 403 404 MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>"); 405 MODULE_DESCRIPTION("LM3533 Backlight driver"); 406 MODULE_LICENSE("GPL"); 407 MODULE_ALIAS("platform:lm3533-backlight"); 408