2 * sky81452-backlight.c SKY81452 backlight driver
4 * Copyright 2014 Skyworks Solutions Inc.
5 * Author : Gyungoh Yoo <jack.yoo@skyworksinc.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <linux/backlight.h>
21 #include <linux/err.h>
22 #include <linux/gpio.h>
23 #include <linux/init.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
27 #include <linux/of_gpio.h>
28 #include <linux/platform_device.h>
29 #include <linux/regmap.h>
30 #include <linux/platform_data/sky81452-backlight.h>
31 #include <linux/slab.h>
34 #define SKY81452_REG0 0x00
35 #define SKY81452_REG1 0x01
36 #define SKY81452_REG2 0x02
37 #define SKY81452_REG4 0x04
38 #define SKY81452_REG5 0x05
41 #define SKY81452_CS 0xFF
42 #define SKY81452_EN 0x3F
43 #define SKY81452_IGPW 0x20
44 #define SKY81452_PWMMD 0x10
45 #define SKY81452_PHASE 0x08
46 #define SKY81452_ILIM 0x04
47 #define SKY81452_VSHRT 0x03
48 #define SKY81452_OCP 0x80
49 #define SKY81452_OTMP 0x40
50 #define SKY81452_SHRT 0x3F
51 #define SKY81452_OPN 0x3F
53 #define SKY81452_DEFAULT_NAME "lcd-backlight"
54 #define SKY81452_MAX_BRIGHTNESS (SKY81452_CS + 1)
56 #define CTZ(b) __builtin_ctz(b)
58 static int sky81452_bl_update_status(struct backlight_device
*bd
)
60 const struct sky81452_bl_platform_data
*pdata
=
61 dev_get_platdata(bd
->dev
.parent
);
62 const unsigned int brightness
= (unsigned int)bd
->props
.brightness
;
63 struct regmap
*regmap
= bl_get_data(bd
);
67 ret
= regmap_write(regmap
, SKY81452_REG0
, brightness
- 1);
68 if (IS_ERR_VALUE(ret
))
71 return regmap_update_bits(regmap
, SKY81452_REG1
, SKY81452_EN
,
72 pdata
->enable
<< CTZ(SKY81452_EN
));
75 return regmap_update_bits(regmap
, SKY81452_REG1
, SKY81452_EN
, 0);
78 static const struct backlight_ops sky81452_bl_ops
= {
79 .update_status
= sky81452_bl_update_status
,
82 static ssize_t
sky81452_bl_store_enable(struct device
*dev
,
83 struct device_attribute
*attr
, const char *buf
, size_t count
)
85 struct regmap
*regmap
= bl_get_data(to_backlight_device(dev
));
89 ret
= kstrtoul(buf
, 16, &value
);
90 if (IS_ERR_VALUE(ret
))
93 ret
= regmap_update_bits(regmap
, SKY81452_REG1
, SKY81452_EN
,
94 value
<< CTZ(SKY81452_EN
));
95 if (IS_ERR_VALUE(ret
))
101 static ssize_t
sky81452_bl_show_open_short(struct device
*dev
,
102 struct device_attribute
*attr
, char *buf
)
104 struct regmap
*regmap
= bl_get_data(to_backlight_device(dev
));
105 unsigned int reg
, value
= 0;
109 reg
= !strcmp(attr
->attr
.name
, "open") ? SKY81452_REG5
: SKY81452_REG4
;
110 ret
= regmap_read(regmap
, reg
, &value
);
111 if (IS_ERR_VALUE(ret
))
114 if (value
& SKY81452_SHRT
) {
116 for (i
= 0; i
< 6; i
++) {
118 sprintf(tmp
, "%d ", i
+ 1);
125 strcpy(buf
, "none\n");
131 static ssize_t
sky81452_bl_show_fault(struct device
*dev
,
132 struct device_attribute
*attr
, char *buf
)
134 struct regmap
*regmap
= bl_get_data(to_backlight_device(dev
));
135 unsigned int value
= 0;
138 ret
= regmap_read(regmap
, SKY81452_REG4
, &value
);
139 if (IS_ERR_VALUE(ret
))
144 if (value
& SKY81452_OCP
)
145 strcat(buf
, "over-current ");
147 if (value
& SKY81452_OTMP
)
148 strcat(buf
, "over-temperature");
154 static DEVICE_ATTR(enable
, S_IWGRP
| S_IWUSR
, NULL
, sky81452_bl_store_enable
);
155 static DEVICE_ATTR(open
, S_IRUGO
, sky81452_bl_show_open_short
, NULL
);
156 static DEVICE_ATTR(short, S_IRUGO
, sky81452_bl_show_open_short
, NULL
);
157 static DEVICE_ATTR(fault
, S_IRUGO
, sky81452_bl_show_fault
, NULL
);
159 static struct attribute
*sky81452_bl_attribute
[] = {
160 &dev_attr_enable
.attr
,
162 &dev_attr_short
.attr
,
163 &dev_attr_fault
.attr
,
167 static const struct attribute_group sky81452_bl_attr_group
= {
168 .attrs
= sky81452_bl_attribute
,
172 static struct sky81452_bl_platform_data
*sky81452_bl_parse_dt(
175 struct device_node
*np
= of_node_get(dev
->of_node
);
176 struct sky81452_bl_platform_data
*pdata
;
178 unsigned int sources
[6];
182 dev_err(dev
, "backlight node not found.\n");
183 return ERR_PTR(-ENODATA
);
186 pdata
= devm_kzalloc(dev
, sizeof(*pdata
), GFP_KERNEL
);
189 return ERR_PTR(-ENOMEM
);
192 of_property_read_string(np
, "name", &pdata
->name
);
193 pdata
->ignore_pwm
= of_property_read_bool(np
, "skyworks,ignore-pwm");
194 pdata
->dpwm_mode
= of_property_read_bool(np
, "skyworks,dpwm-mode");
195 pdata
->phase_shift
= of_property_read_bool(np
, "skyworks,phase-shift");
196 pdata
->gpio_enable
= of_get_gpio(np
, 0);
198 ret
= of_property_count_u32_elems(np
, "led-sources");
199 if (IS_ERR_VALUE(ret
)) {
200 pdata
->enable
= SKY81452_EN
>> CTZ(SKY81452_EN
);
206 ret
= of_property_read_u32_array(np
, "led-sources", sources
,
208 if (IS_ERR_VALUE(ret
)) {
209 dev_err(dev
, "led-sources node is invalid.\n");
210 return ERR_PTR(-EINVAL
);
215 pdata
->enable
|= (1 << sources
[num_entry
]);
218 ret
= of_property_read_u32(np
,
219 "skyworks,short-detection-threshold-volt",
220 &pdata
->short_detection_threshold
);
221 if (IS_ERR_VALUE(ret
))
222 pdata
->short_detection_threshold
= 7;
224 ret
= of_property_read_u32(np
, "skyworks,current-limit-mA",
225 &pdata
->boost_current_limit
);
226 if (IS_ERR_VALUE(ret
))
227 pdata
->boost_current_limit
= 2750;
233 static struct sky81452_bl_platform_data
*sky81452_bl_parse_dt(
236 return ERR_PTR(-EINVAL
);
240 static int sky81452_bl_init_device(struct regmap
*regmap
,
241 struct sky81452_bl_platform_data
*pdata
)
245 value
= pdata
->ignore_pwm
? SKY81452_IGPW
: 0;
246 value
|= pdata
->dpwm_mode
? SKY81452_PWMMD
: 0;
247 value
|= pdata
->phase_shift
? 0 : SKY81452_PHASE
;
249 if (pdata
->boost_current_limit
== 2300)
250 value
|= SKY81452_ILIM
;
251 else if (pdata
->boost_current_limit
!= 2750)
254 if (pdata
->short_detection_threshold
< 4 ||
255 pdata
->short_detection_threshold
> 7)
257 value
|= (7 - pdata
->short_detection_threshold
) << CTZ(SKY81452_VSHRT
);
259 return regmap_write(regmap
, SKY81452_REG2
, value
);
262 static int sky81452_bl_probe(struct platform_device
*pdev
)
264 struct device
*dev
= &pdev
->dev
;
265 struct regmap
*regmap
= dev_get_drvdata(dev
->parent
);
266 struct sky81452_bl_platform_data
*pdata
= dev_get_platdata(dev
);
267 struct backlight_device
*bd
;
268 struct backlight_properties props
;
273 pdata
= sky81452_bl_parse_dt(dev
);
275 return PTR_ERR(pdata
);
278 if (gpio_is_valid(pdata
->gpio_enable
)) {
279 ret
= devm_gpio_request_one(dev
, pdata
->gpio_enable
,
280 GPIOF_OUT_INIT_HIGH
, "sky81452-en");
281 if (IS_ERR_VALUE(ret
)) {
282 dev_err(dev
, "failed to request GPIO. err=%d\n", ret
);
287 ret
= sky81452_bl_init_device(regmap
, pdata
);
288 if (IS_ERR_VALUE(ret
)) {
289 dev_err(dev
, "failed to initialize. err=%d\n", ret
);
293 memset(&props
, 0, sizeof(props
));
294 props
.max_brightness
= SKY81452_MAX_BRIGHTNESS
,
295 name
= pdata
->name
? pdata
->name
: SKY81452_DEFAULT_NAME
;
296 bd
= devm_backlight_device_register(dev
, name
, dev
, regmap
,
297 &sky81452_bl_ops
, &props
);
299 dev_err(dev
, "failed to register. err=%ld\n", PTR_ERR(bd
));
303 platform_set_drvdata(pdev
, bd
);
305 ret
= sysfs_create_group(&bd
->dev
.kobj
, &sky81452_bl_attr_group
);
306 if (IS_ERR_VALUE(ret
)) {
307 dev_err(dev
, "failed to create attribute. err=%d\n", ret
);
314 static int sky81452_bl_remove(struct platform_device
*pdev
)
316 const struct sky81452_bl_platform_data
*pdata
=
317 dev_get_platdata(&pdev
->dev
);
318 struct backlight_device
*bd
= platform_get_drvdata(pdev
);
320 sysfs_remove_group(&bd
->dev
.kobj
, &sky81452_bl_attr_group
);
322 bd
->props
.power
= FB_BLANK_UNBLANK
;
323 bd
->props
.brightness
= 0;
324 backlight_update_status(bd
);
326 if (gpio_is_valid(pdata
->gpio_enable
))
327 gpio_set_value_cansleep(pdata
->gpio_enable
, 0);
333 static const struct of_device_id sky81452_bl_of_match
[] = {
334 { .compatible
= "skyworks,sky81452-backlight", },
337 MODULE_DEVICE_TABLE(of
, sky81452_bl_of_match
);
340 static struct platform_driver sky81452_bl_driver
= {
342 .name
= "sky81452-backlight",
343 .of_match_table
= of_match_ptr(sky81452_bl_of_match
),
345 .probe
= sky81452_bl_probe
,
346 .remove
= sky81452_bl_remove
,
349 module_platform_driver(sky81452_bl_driver
);
351 MODULE_DESCRIPTION("Skyworks SKY81452 backlight driver");
352 MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@skyworksinc.com>");
353 MODULE_LICENSE("GPL v2");