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