Skip to content

Commit f705806

Browse files
Gyungoh YooLee Jones
authored andcommitted
backlight: Add support Skyworks SKY81452 backlight driver
Signed-off-by: Gyungoh Yoo <[email protected]> Acked-by: Jingoo Han <[email protected]> Acked-by: Bryan Wu <[email protected]> Signed-off-by: Lee Jones <[email protected]>
1 parent 2698dc2 commit f705806

File tree

4 files changed

+410
-0
lines changed

4 files changed

+410
-0
lines changed

drivers/video/backlight/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,16 @@ config BACKLIGHT_PANDORA
408408
If you have a Pandora console, say Y to enable the
409409
backlight driver.
410410

411+
config BACKLIGHT_SKY81452
412+
tristate "Backlight driver for SKY81452"
413+
depends on BACKLIGHT_CLASS_DEVICE && MFD_SKY81452
414+
help
415+
If you have a Skyworks SKY81452, say Y to enable the
416+
backlight driver.
417+
418+
To compile this driver as a module, choose M here: the module will
419+
be called sky81452-backlight
420+
411421
config BACKLIGHT_TPS65217
412422
tristate "TPS65217 Backlight"
413423
depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217

drivers/video/backlight/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o
5050
obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
5151
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
5252
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
53+
obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
5354
obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
5455
obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
5556
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
/*
2+
* sky81452-backlight.c SKY81452 backlight driver
3+
*
4+
* Copyright 2014 Skyworks Solutions Inc.
5+
* Author : Gyungoh Yoo <[email protected]>
6+
*
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.
10+
*
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.
15+
*
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/>.
18+
*/
19+
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>
26+
#include <linux/of.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>
32+
33+
/* registers */
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
39+
40+
/* bit mask */
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
52+
53+
#define SKY81452_DEFAULT_NAME "lcd-backlight"
54+
#define SKY81452_MAX_BRIGHTNESS (SKY81452_CS + 1)
55+
56+
#define CTZ(b) __builtin_ctz(b)
57+
58+
static int sky81452_bl_update_status(struct backlight_device *bd)
59+
{
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);
64+
int ret;
65+
66+
if (brightness > 0) {
67+
ret = regmap_write(regmap, SKY81452_REG0, brightness - 1);
68+
if (IS_ERR_VALUE(ret))
69+
return ret;
70+
71+
return regmap_update_bits(regmap, SKY81452_REG1, SKY81452_EN,
72+
pdata->enable << CTZ(SKY81452_EN));
73+
}
74+
75+
return regmap_update_bits(regmap, SKY81452_REG1, SKY81452_EN, 0);
76+
}
77+
78+
static const struct backlight_ops sky81452_bl_ops = {
79+
.update_status = sky81452_bl_update_status,
80+
};
81+
82+
static ssize_t sky81452_bl_store_enable(struct device *dev,
83+
struct device_attribute *attr, const char *buf, size_t count)
84+
{
85+
struct regmap *regmap = bl_get_data(to_backlight_device(dev));
86+
unsigned long value;
87+
int ret;
88+
89+
ret = kstrtoul(buf, 16, &value);
90+
if (IS_ERR_VALUE(ret))
91+
return ret;
92+
93+
ret = regmap_update_bits(regmap, SKY81452_REG1, SKY81452_EN,
94+
value << CTZ(SKY81452_EN));
95+
if (IS_ERR_VALUE(ret))
96+
return ret;
97+
98+
return count;
99+
}
100+
101+
static ssize_t sky81452_bl_show_open_short(struct device *dev,
102+
struct device_attribute *attr, char *buf)
103+
{
104+
struct regmap *regmap = bl_get_data(to_backlight_device(dev));
105+
unsigned int reg, value = 0;
106+
char tmp[3];
107+
int i, ret;
108+
109+
reg = !strcmp(attr->attr.name, "open") ? SKY81452_REG5 : SKY81452_REG4;
110+
ret = regmap_read(regmap, reg, &value);
111+
if (IS_ERR_VALUE(ret))
112+
return ret;
113+
114+
if (value & SKY81452_SHRT) {
115+
*buf = 0;
116+
for (i = 0; i < 6; i++) {
117+
if (value & 0x01) {
118+
sprintf(tmp, "%d ", i + 1);
119+
strcat(buf, tmp);
120+
}
121+
value >>= 1;
122+
}
123+
strcat(buf, "\n");
124+
} else {
125+
strcpy(buf, "none\n");
126+
}
127+
128+
return strlen(buf);
129+
}
130+
131+
static ssize_t sky81452_bl_show_fault(struct device *dev,
132+
struct device_attribute *attr, char *buf)
133+
{
134+
struct regmap *regmap = bl_get_data(to_backlight_device(dev));
135+
unsigned int value = 0;
136+
int ret;
137+
138+
ret = regmap_read(regmap, SKY81452_REG4, &value);
139+
if (IS_ERR_VALUE(ret))
140+
return ret;
141+
142+
*buf = 0;
143+
144+
if (value & SKY81452_OCP)
145+
strcat(buf, "over-current ");
146+
147+
if (value & SKY81452_OTMP)
148+
strcat(buf, "over-temperature");
149+
150+
strcat(buf, "\n");
151+
return strlen(buf);
152+
}
153+
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);
158+
159+
static struct attribute *sky81452_bl_attribute[] = {
160+
&dev_attr_enable.attr,
161+
&dev_attr_open.attr,
162+
&dev_attr_short.attr,
163+
&dev_attr_fault.attr,
164+
NULL
165+
};
166+
167+
static const struct attribute_group sky81452_bl_attr_group = {
168+
.attrs = sky81452_bl_attribute,
169+
};
170+
171+
#ifdef CONFIG_OF
172+
static struct sky81452_bl_platform_data *sky81452_bl_parse_dt(
173+
struct device *dev)
174+
{
175+
struct device_node *np = of_node_get(dev->of_node);
176+
struct sky81452_bl_platform_data *pdata;
177+
int num_entry;
178+
unsigned int sources[6];
179+
int ret;
180+
181+
if (!np) {
182+
dev_err(dev, "backlight node not found.\n");
183+
return ERR_PTR(-ENODATA);
184+
}
185+
186+
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
187+
if (!pdata) {
188+
of_node_put(np);
189+
return ERR_PTR(-ENOMEM);
190+
}
191+
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);
197+
198+
ret = of_property_count_u32_elems(np, "led-sources");
199+
if (IS_ERR_VALUE(ret)) {
200+
pdata->enable = SKY81452_EN >> CTZ(SKY81452_EN);
201+
} else {
202+
num_entry = ret;
203+
if (num_entry > 6)
204+
num_entry = 6;
205+
206+
ret = of_property_read_u32_array(np, "led-sources", sources,
207+
num_entry);
208+
if (IS_ERR_VALUE(ret)) {
209+
dev_err(dev, "led-sources node is invalid.\n");
210+
return ERR_PTR(-EINVAL);
211+
}
212+
213+
pdata->enable = 0;
214+
while (--num_entry)
215+
pdata->enable |= (1 << sources[num_entry]);
216+
}
217+
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;
223+
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;
228+
229+
of_node_put(np);
230+
return pdata;
231+
}
232+
#else
233+
static struct sky81452_bl_platform_data *sky81452_bl_parse_dt(
234+
struct device *dev)
235+
{
236+
return ERR_PTR(-EINVAL);
237+
}
238+
#endif
239+
240+
static int sky81452_bl_init_device(struct regmap *regmap,
241+
struct sky81452_bl_platform_data *pdata)
242+
{
243+
unsigned int value;
244+
245+
value = pdata->ignore_pwm ? SKY81452_IGPW : 0;
246+
value |= pdata->dpwm_mode ? SKY81452_PWMMD : 0;
247+
value |= pdata->phase_shift ? 0 : SKY81452_PHASE;
248+
249+
if (pdata->boost_current_limit == 2300)
250+
value |= SKY81452_ILIM;
251+
else if (pdata->boost_current_limit != 2750)
252+
return -EINVAL;
253+
254+
if (pdata->short_detection_threshold < 4 ||
255+
pdata->short_detection_threshold > 7)
256+
return -EINVAL;
257+
value |= (7 - pdata->short_detection_threshold) << CTZ(SKY81452_VSHRT);
258+
259+
return regmap_write(regmap, SKY81452_REG2, value);
260+
}
261+
262+
static int sky81452_bl_probe(struct platform_device *pdev)
263+
{
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;
269+
const char *name;
270+
int ret;
271+
272+
if (!pdata) {
273+
pdata = sky81452_bl_parse_dt(dev);
274+
if (IS_ERR(pdata))
275+
return PTR_ERR(pdata);
276+
}
277+
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);
283+
return ret;
284+
}
285+
}
286+
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);
290+
return ret;
291+
}
292+
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);
298+
if (IS_ERR(bd)) {
299+
dev_err(dev, "failed to register. err=%ld\n", PTR_ERR(bd));
300+
return PTR_ERR(bd);
301+
}
302+
303+
platform_set_drvdata(pdev, bd);
304+
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);
308+
return ret;
309+
}
310+
311+
return ret;
312+
}
313+
314+
static int sky81452_bl_remove(struct platform_device *pdev)
315+
{
316+
const struct sky81452_bl_platform_data *pdata =
317+
dev_get_platdata(&pdev->dev);
318+
struct backlight_device *bd = platform_get_drvdata(pdev);
319+
320+
sysfs_remove_group(&bd->dev.kobj, &sky81452_bl_attr_group);
321+
322+
bd->props.power = FB_BLANK_UNBLANK;
323+
bd->props.brightness = 0;
324+
backlight_update_status(bd);
325+
326+
if (gpio_is_valid(pdata->gpio_enable))
327+
gpio_set_value_cansleep(pdata->gpio_enable, 0);
328+
329+
return 0;
330+
}
331+
332+
#ifdef CONFIG_OF
333+
static const struct of_device_id sky81452_bl_of_match[] = {
334+
{ .compatible = "skyworks,sky81452-backlight", },
335+
{ }
336+
};
337+
MODULE_DEVICE_TABLE(of, sky81452_bl_of_match);
338+
#endif
339+
340+
static struct platform_driver sky81452_bl_driver = {
341+
.driver = {
342+
.name = "sky81452-backlight",
343+
.of_match_table = of_match_ptr(sky81452_bl_of_match),
344+
},
345+
.probe = sky81452_bl_probe,
346+
.remove = sky81452_bl_remove,
347+
};
348+
349+
module_platform_driver(sky81452_bl_driver);
350+
351+
MODULE_DESCRIPTION("Skyworks SKY81452 backlight driver");
352+
MODULE_AUTHOR("Gyungoh Yoo <[email protected]>");
353+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)