2 * lm3533-bl.c -- LM3533 Backlight driver
4 * Copyright (C) 2011-2012 Texas Instruments
6 * Author: Johan Hovold <jhovold@gmail.com>
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.
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/platform_device.h>
17 #include <linux/backlight.h>
19 #include <linux/slab.h>
21 #include <linux/mfd/lm3533.h>
24 #define LM3533_HVCTRLBANK_COUNT 2
25 #define LM3533_BL_MAX_BRIGHTNESS 255
27 #define LM3533_REG_CTRLBANK_AB_BCONF 0x1a
31 struct lm3533
*lm3533
;
32 struct lm3533_ctrlbank cb
;
33 struct backlight_device
*bd
;
38 static inline int lm3533_bl_get_ctrlbank_id(struct lm3533_bl
*bl
)
43 static int lm3533_bl_update_status(struct backlight_device
*bd
)
45 struct lm3533_bl
*bl
= bl_get_data(bd
);
46 int brightness
= bd
->props
.brightness
;
48 if (bd
->props
.power
!= FB_BLANK_UNBLANK
)
50 if (bd
->props
.fb_blank
!= FB_BLANK_UNBLANK
)
53 return lm3533_ctrlbank_set_brightness(&bl
->cb
, (u8
)brightness
);
56 static int lm3533_bl_get_brightness(struct backlight_device
*bd
)
58 struct lm3533_bl
*bl
= bl_get_data(bd
);
62 ret
= lm3533_ctrlbank_get_brightness(&bl
->cb
, &val
);
69 static const struct backlight_ops lm3533_bl_ops
= {
70 .get_brightness
= lm3533_bl_get_brightness
,
71 .update_status
= lm3533_bl_update_status
,
74 static ssize_t
show_id(struct device
*dev
,
75 struct device_attribute
*attr
, char *buf
)
77 struct lm3533_bl
*bl
= dev_get_drvdata(dev
);
79 return scnprintf(buf
, PAGE_SIZE
, "%d\n", bl
->id
);
82 static ssize_t
show_als_channel(struct device
*dev
,
83 struct device_attribute
*attr
, char *buf
)
85 struct lm3533_bl
*bl
= dev_get_drvdata(dev
);
86 unsigned channel
= lm3533_bl_get_ctrlbank_id(bl
);
88 return scnprintf(buf
, PAGE_SIZE
, "%u\n", channel
);
91 static ssize_t
show_als_en(struct device
*dev
,
92 struct device_attribute
*attr
, char *buf
)
94 struct lm3533_bl
*bl
= dev_get_drvdata(dev
);
95 int ctrlbank
= lm3533_bl_get_ctrlbank_id(bl
);
101 ret
= lm3533_read(bl
->lm3533
, LM3533_REG_CTRLBANK_AB_BCONF
, &val
);
105 mask
= 1 << (2 * ctrlbank
);
108 return scnprintf(buf
, PAGE_SIZE
, "%d\n", enable
);
111 static ssize_t
store_als_en(struct device
*dev
,
112 struct device_attribute
*attr
,
113 const char *buf
, size_t len
)
115 struct lm3533_bl
*bl
= dev_get_drvdata(dev
);
116 int ctrlbank
= lm3533_bl_get_ctrlbank_id(bl
);
122 if (kstrtoint(buf
, 0, &enable
))
125 mask
= 1 << (2 * ctrlbank
);
132 ret
= lm3533_update(bl
->lm3533
, LM3533_REG_CTRLBANK_AB_BCONF
, val
,
140 static ssize_t
show_linear(struct device
*dev
,
141 struct device_attribute
*attr
, char *buf
)
143 struct lm3533_bl
*bl
= dev_get_drvdata(dev
);
149 ret
= lm3533_read(bl
->lm3533
, LM3533_REG_CTRLBANK_AB_BCONF
, &val
);
153 mask
= 1 << (2 * lm3533_bl_get_ctrlbank_id(bl
) + 1);
160 return scnprintf(buf
, PAGE_SIZE
, "%x\n", linear
);
163 static ssize_t
store_linear(struct device
*dev
,
164 struct device_attribute
*attr
,
165 const char *buf
, size_t len
)
167 struct lm3533_bl
*bl
= dev_get_drvdata(dev
);
168 unsigned long linear
;
173 if (kstrtoul(buf
, 0, &linear
))
176 mask
= 1 << (2 * lm3533_bl_get_ctrlbank_id(bl
) + 1);
183 ret
= lm3533_update(bl
->lm3533
, LM3533_REG_CTRLBANK_AB_BCONF
, val
,
191 static ssize_t
show_pwm(struct device
*dev
,
192 struct device_attribute
*attr
,
195 struct lm3533_bl
*bl
= dev_get_drvdata(dev
);
199 ret
= lm3533_ctrlbank_get_pwm(&bl
->cb
, &val
);
203 return scnprintf(buf
, PAGE_SIZE
, "%u\n", val
);
206 static ssize_t
store_pwm(struct device
*dev
,
207 struct device_attribute
*attr
,
208 const char *buf
, size_t len
)
210 struct lm3533_bl
*bl
= dev_get_drvdata(dev
);
214 if (kstrtou8(buf
, 0, &val
))
217 ret
= lm3533_ctrlbank_set_pwm(&bl
->cb
, val
);
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
);
230 static struct attribute
*lm3533_bl_attributes
[] = {
231 &dev_attr_als_channel
.attr
,
232 &dev_attr_als_en
.attr
,
234 &dev_attr_linear
.attr
,
239 static umode_t
lm3533_bl_attr_is_visible(struct kobject
*kobj
,
240 struct attribute
*attr
, int n
)
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
;
246 if (attr
== &dev_attr_als_channel
.attr
||
247 attr
== &dev_attr_als_en
.attr
) {
248 if (!bl
->lm3533
->have_als
)
255 static struct attribute_group lm3533_bl_attribute_group
= {
256 .is_visible
= lm3533_bl_attr_is_visible
,
257 .attrs
= lm3533_bl_attributes
260 static int lm3533_bl_setup(struct lm3533_bl
*bl
,
261 struct lm3533_bl_platform_data
*pdata
)
265 ret
= lm3533_ctrlbank_set_max_current(&bl
->cb
, pdata
->max_current
);
269 return lm3533_ctrlbank_set_pwm(&bl
->cb
, pdata
->pwm
);
272 static int lm3533_bl_probe(struct platform_device
*pdev
)
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
;
281 dev_dbg(&pdev
->dev
, "%s\n", __func__
);
283 lm3533
= dev_get_drvdata(pdev
->dev
.parent
);
287 pdata
= dev_get_platdata(&pdev
->dev
);
289 dev_err(&pdev
->dev
, "no platform data\n");
293 if (pdev
->id
< 0 || pdev
->id
>= LM3533_HVCTRLBANK_COUNT
) {
294 dev_err(&pdev
->dev
, "illegal backlight id %d\n", pdev
->id
);
298 bl
= devm_kzalloc(&pdev
->dev
, sizeof(*bl
), GFP_KERNEL
);
301 "failed to allocate memory for backlight\n");
308 bl
->cb
.lm3533
= lm3533
;
309 bl
->cb
.id
= lm3533_bl_get_ctrlbank_id(bl
);
310 bl
->cb
.dev
= NULL
; /* until registered */
312 memset(&props
, 0, sizeof(props
));
313 props
.type
= BACKLIGHT_RAW
;
314 props
.max_brightness
= LM3533_BL_MAX_BRIGHTNESS
;
315 props
.brightness
= pdata
->default_brightness
;
316 bd
= devm_backlight_device_register(&pdev
->dev
, pdata
->name
,
317 pdev
->dev
.parent
, bl
, &lm3533_bl_ops
,
320 dev_err(&pdev
->dev
, "failed to register backlight device\n");
325 bl
->cb
.dev
= &bl
->bd
->dev
;
327 platform_set_drvdata(pdev
, bl
);
329 ret
= sysfs_create_group(&bd
->dev
.kobj
, &lm3533_bl_attribute_group
);
331 dev_err(&pdev
->dev
, "failed to create sysfs attributes\n");
335 backlight_update_status(bd
);
337 ret
= lm3533_bl_setup(bl
, pdata
);
339 goto err_sysfs_remove
;
341 ret
= lm3533_ctrlbank_enable(&bl
->cb
);
343 goto err_sysfs_remove
;
348 sysfs_remove_group(&bd
->dev
.kobj
, &lm3533_bl_attribute_group
);
353 static int lm3533_bl_remove(struct platform_device
*pdev
)
355 struct lm3533_bl
*bl
= platform_get_drvdata(pdev
);
356 struct backlight_device
*bd
= bl
->bd
;
358 dev_dbg(&bd
->dev
, "%s\n", __func__
);
360 bd
->props
.power
= FB_BLANK_POWERDOWN
;
361 bd
->props
.brightness
= 0;
363 lm3533_ctrlbank_disable(&bl
->cb
);
364 sysfs_remove_group(&bd
->dev
.kobj
, &lm3533_bl_attribute_group
);
369 #ifdef CONFIG_PM_SLEEP
370 static int lm3533_bl_suspend(struct device
*dev
)
372 struct lm3533_bl
*bl
= dev_get_drvdata(dev
);
374 dev_dbg(dev
, "%s\n", __func__
);
376 return lm3533_ctrlbank_disable(&bl
->cb
);
379 static int lm3533_bl_resume(struct device
*dev
)
381 struct lm3533_bl
*bl
= dev_get_drvdata(dev
);
383 dev_dbg(dev
, "%s\n", __func__
);
385 return lm3533_ctrlbank_enable(&bl
->cb
);
389 static SIMPLE_DEV_PM_OPS(lm3533_bl_pm_ops
, lm3533_bl_suspend
, lm3533_bl_resume
);
391 static void lm3533_bl_shutdown(struct platform_device
*pdev
)
393 struct lm3533_bl
*bl
= platform_get_drvdata(pdev
);
395 dev_dbg(&pdev
->dev
, "%s\n", __func__
);
397 lm3533_ctrlbank_disable(&bl
->cb
);
400 static struct platform_driver lm3533_bl_driver
= {
402 .name
= "lm3533-backlight",
403 .owner
= THIS_MODULE
,
404 .pm
= &lm3533_bl_pm_ops
,
406 .probe
= lm3533_bl_probe
,
407 .remove
= lm3533_bl_remove
,
408 .shutdown
= lm3533_bl_shutdown
,
410 module_platform_driver(lm3533_bl_driver
);
412 MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
413 MODULE_DESCRIPTION("LM3533 Backlight driver");
414 MODULE_LICENSE("GPL");
415 MODULE_ALIAS("platform:lm3533-backlight");