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