File Index
Files and directories
Sign in
FILE

lm3533_bl.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/backlight/lm3533_bl.c C
  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
 25struct lm3533_bl {
 26	struct lm3533 *lm3533;
 27	struct lm3533_ctrlbank cb;
 28	struct backlight_device *bd;
 29	int id;
 30};
 31
 32
 33static inline int lm3533_bl_get_ctrlbank_id(struct lm3533_bl *bl)
 34{
 35	return bl->id;
 36}
 37
 38static 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
 45static 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
 58static const struct backlight_ops lm3533_bl_ops = {
 59	.get_brightness	= lm3533_bl_get_brightness,
 60	.update_status	= lm3533_bl_update_status,
 61};
 62
 63static 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
 71static 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
 80static 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
100static 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
129static 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
152static 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
180static 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
195static 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
213static LM3533_ATTR_RO(als_channel);
214static LM3533_ATTR_RW(als_en);
215static LM3533_ATTR_RO(id);
216static LM3533_ATTR_RW(linear);
217static LM3533_ATTR_RW(pwm);
218
219static 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
228static 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
244static struct attribute_group lm3533_bl_attribute_group = {
245	.is_visible	= lm3533_bl_attr_is_visible,
246	.attrs		= lm3533_bl_attributes
247};
248
249static 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
261static 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
333err_sysfs_remove:
334	sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
335
336	return ret;
337}
338
339static 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
354static 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
363static 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
373static SIMPLE_DEV_PM_OPS(lm3533_bl_pm_ops, lm3533_bl_suspend, lm3533_bl_resume);
374
375static 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
384static 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		= lm3533_bl_remove,
391	.shutdown	= lm3533_bl_shutdown,
392};
393module_platform_driver(lm3533_bl_driver);
394
395MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
396MODULE_DESCRIPTION("LM3533 Backlight driver");
397MODULE_LICENSE("GPL");
398MODULE_ALIAS("platform:lm3533-backlight");
~/ Read-only file preview.