backlight.c 20.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
Linus Torvalds's avatar
Linus Torvalds committed
2 3 4 5 6 7 8
/*
 * Backlight Lowlevel Control Abstraction
 *
 * Copyright (C) 2003,2004 Hewlett-Packard Company
 *
 */

9 10
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

Linus Torvalds's avatar
Linus Torvalds committed
11 12 13 14 15 16 17 18
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/backlight.h>
#include <linux/notifier.h>
#include <linux/ctype.h>
#include <linux/err.h>
#include <linux/fb.h>
19
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
20

21 22 23
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
/**
 * DOC: overview
 *
 * The backlight core supports implementing backlight drivers.
 *
 * A backlight driver registers a driver using
 * devm_backlight_device_register(). The properties of the backlight
 * driver such as type and max_brightness must be specified.
 * When the core detect changes in for example brightness or power state
 * the update_status() operation is called. The backlight driver shall
 * implement this operation and use it to adjust backlight.
 *
 * Several sysfs attributes are provided by the backlight core::
 *
 * - brightness         R/W, set the requested brightness level
 * - actual_brightness  RO, the brightness level used by the HW
 * - max_brightness     RO, the maximum  brightness level supported
 *
 * See Documentation/ABI/stable/sysfs-class-backlight for the full list.
 *
 * The backlight can be adjusted using the sysfs interface, and
 * the backlight driver may also support adjusting backlight using
 * a hot-key or some other platform or firmware specific way.
 *
 * The driver must implement the get_brightness() operation if
 * the HW do not support all the levels that can be specified in
 * brightness, thus providing user-space access to the actual level
 * via the actual_brightness attribute.
 *
 * When the backlight changes this is reported to user-space using
 * an uevent connected to the actual_brightness attribute.
 * When brightness is set by platform specific means, for example
 * a hot-key to adjust backlight, the driver must notify the backlight
 * core that brightness has changed using backlight_force_update().
 *
 * The backlight driver core receives notifications from fbdev and
 * if the event is FB_EVENT_BLANK and if the value of blank, from the
 * FBIOBLANK ioctrl, results in a change in the backlight state the
 * update_status() operation is called.
 */

66 67
static struct list_head backlight_dev_list;
static struct mutex backlight_dev_list_mutex;
68
static struct blocking_notifier_head backlight_notifier;
69

70
static const char *const backlight_types[] = {
71 72 73 74 75
	[BACKLIGHT_RAW] = "raw",
	[BACKLIGHT_PLATFORM] = "platform",
	[BACKLIGHT_FIRMWARE] = "firmware",
};

76 77 78 79 80 81
static const char *const backlight_scale_types[] = {
	[BACKLIGHT_SCALE_UNKNOWN]	= "unknown",
	[BACKLIGHT_SCALE_LINEAR]	= "linear",
	[BACKLIGHT_SCALE_NON_LINEAR]	= "non-linear",
};

82 83
#if defined(CONFIG_FB_CORE) || (defined(CONFIG_FB_CORE_MODULE) && \
				defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
84 85 86 87 88 89 90 91 92 93 94
/*
 * fb_notifier_callback
 *
 * This callback gets called when something important happens inside a
 * framebuffer driver. The backlight core only cares about FB_BLANK_UNBLANK
 * which is reported to the driver using backlight_update_status()
 * as a state change.
 *
 * There may be several fbdev's connected to the backlight device,
 * in which case they are kept track of. A state change is only reported
 * if there is a change in backlight for the specified fbdev.
95 96 97 98 99 100
 */
static int fb_notifier_callback(struct notifier_block *self,
				unsigned long event, void *data)
{
	struct backlight_device *bd;
	struct fb_event *evdata = data;
101 102 103
	struct fb_info *info = evdata->info;
	struct backlight_device *fb_bd = fb_bl_device(info);
	int node = info->node;
104
	int fb_blank = 0;
105 106

	/* If we aren't interested in this event, skip it immediately ... */
107
	if (event != FB_EVENT_BLANK)
108 109 110
		return 0;

	bd = container_of(self, struct backlight_device, fb_notif);
111
	mutex_lock(&bd->ops_lock);
112 113 114

	if (!bd->ops)
		goto out;
115
	if (bd->ops->controls_device && !bd->ops->controls_device(bd, info->device))
116 117
		goto out;
	if (fb_bd && fb_bd != bd)
118 119 120 121 122 123 124 125 126 127 128 129 130 131
		goto out;

	fb_blank = *(int *)evdata->data;
	if (fb_blank == FB_BLANK_UNBLANK && !bd->fb_bl_on[node]) {
		bd->fb_bl_on[node] = true;
		if (!bd->use_count++) {
			bd->props.state &= ~BL_CORE_FBBLANK;
			backlight_update_status(bd);
		}
	} else if (fb_blank != FB_BLANK_UNBLANK && bd->fb_bl_on[node]) {
		bd->fb_bl_on[node] = false;
		if (!(--bd->use_count)) {
			bd->props.state |= BL_CORE_FBBLANK;
			backlight_update_status(bd);
132
		}
133 134
	}
out:
135
	mutex_unlock(&bd->ops_lock);
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
	return 0;
}

static int backlight_register_fb(struct backlight_device *bd)
{
	memset(&bd->fb_notif, 0, sizeof(bd->fb_notif));
	bd->fb_notif.notifier_call = fb_notifier_callback;

	return fb_register_client(&bd->fb_notif);
}

static void backlight_unregister_fb(struct backlight_device *bd)
{
	fb_unregister_client(&bd->fb_notif);
}
#else
static inline int backlight_register_fb(struct backlight_device *bd)
{
	return 0;
}

static inline void backlight_unregister_fb(struct backlight_device *bd)
{
}
160
#endif /* CONFIG_FB_CORE */
161

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
static void backlight_generate_event(struct backlight_device *bd,
				     enum backlight_update_reason reason)
{
	char *envp[2];

	switch (reason) {
	case BACKLIGHT_UPDATE_SYSFS:
		envp[0] = "SOURCE=sysfs";
		break;
	case BACKLIGHT_UPDATE_HOTKEY:
		envp[0] = "SOURCE=hotkey";
		break;
	default:
		envp[0] = "SOURCE=unknown";
		break;
	}
	envp[1] = NULL;
	kobject_uevent_env(&bd->dev.kobj, KOBJ_CHANGE, envp);
180
	sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness");
181 182
}

183 184
static ssize_t bl_power_show(struct device *dev, struct device_attribute *attr,
		char *buf)
Linus Torvalds's avatar
Linus Torvalds committed
185
{
186
	struct backlight_device *bd = to_backlight_device(dev);
Linus Torvalds's avatar
Linus Torvalds committed
187

188
	return sprintf(buf, "%d\n", bd->props.power);
Linus Torvalds's avatar
Linus Torvalds committed
189 190
}

191 192
static ssize_t bl_power_store(struct device *dev, struct device_attribute *attr,
		const char *buf, size_t count)
Linus Torvalds's avatar
Linus Torvalds committed
193
{
194
	int rc;
195
	struct backlight_device *bd = to_backlight_device(dev);
196
	unsigned long power, old_power;
Linus Torvalds's avatar
Linus Torvalds committed
197

Jingoo Han's avatar
Jingoo Han committed
198
	rc = kstrtoul(buf, 0, &power);
199 200
	if (rc)
		return rc;
Linus Torvalds's avatar
Linus Torvalds committed
201

202
	rc = -ENXIO;
203 204
	mutex_lock(&bd->ops_lock);
	if (bd->ops) {
205
		pr_debug("set power to %lu\n", power);
206
		if (bd->props.power != power) {
207
			old_power = bd->props.power;
208
			bd->props.power = power;
209 210 211 212 213 214 215
			rc = backlight_update_status(bd);
			if (rc)
				bd->props.power = old_power;
			else
				rc = count;
		} else {
			rc = count;
216
		}
217
	}
218
	mutex_unlock(&bd->ops_lock);
Linus Torvalds's avatar
Linus Torvalds committed
219 220 221

	return rc;
}
222
static DEVICE_ATTR_RW(bl_power);
Linus Torvalds's avatar
Linus Torvalds committed
223

224
static ssize_t brightness_show(struct device *dev,
225
		struct device_attribute *attr, char *buf)
Linus Torvalds's avatar
Linus Torvalds committed
226
{
227
	struct backlight_device *bd = to_backlight_device(dev);
Linus Torvalds's avatar
Linus Torvalds committed
228

229
	return sprintf(buf, "%d\n", bd->props.brightness);
Linus Torvalds's avatar
Linus Torvalds committed
230 231
}

232 233
int backlight_device_set_brightness(struct backlight_device *bd,
				    unsigned long brightness)
Linus Torvalds's avatar
Linus Torvalds committed
234
{
235
	int rc = -ENXIO;
Linus Torvalds's avatar
Linus Torvalds committed
236

237 238 239
	mutex_lock(&bd->ops_lock);
	if (bd->ops) {
		if (brightness > bd->props.max_brightness)
240 241
			rc = -EINVAL;
		else {
242
			pr_debug("set brightness to %lu\n", brightness);
243
			bd->props.brightness = brightness;
244
			rc = backlight_update_status(bd);
245 246
		}
	}
247
	mutex_unlock(&bd->ops_lock);
Linus Torvalds's avatar
Linus Torvalds committed
248

249 250
	backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS);

Linus Torvalds's avatar
Linus Torvalds committed
251 252
	return rc;
}
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
EXPORT_SYMBOL(backlight_device_set_brightness);

static ssize_t brightness_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int rc;
	struct backlight_device *bd = to_backlight_device(dev);
	unsigned long brightness;

	rc = kstrtoul(buf, 0, &brightness);
	if (rc)
		return rc;

	rc = backlight_device_set_brightness(bd, brightness);

	return rc ? rc : count;
}
270
static DEVICE_ATTR_RW(brightness);
Linus Torvalds's avatar
Linus Torvalds committed
271

272 273
static ssize_t type_show(struct device *dev, struct device_attribute *attr,
		char *buf)
274 275 276 277 278
{
	struct backlight_device *bd = to_backlight_device(dev);

	return sprintf(buf, "%s\n", backlight_types[bd->props.type]);
}
279
static DEVICE_ATTR_RO(type);
280

281
static ssize_t max_brightness_show(struct device *dev,
282
		struct device_attribute *attr, char *buf)
Linus Torvalds's avatar
Linus Torvalds committed
283
{
284
	struct backlight_device *bd = to_backlight_device(dev);
Linus Torvalds's avatar
Linus Torvalds committed
285

286
	return sprintf(buf, "%d\n", bd->props.max_brightness);
287
}
288
static DEVICE_ATTR_RO(max_brightness);
289

290
static ssize_t actual_brightness_show(struct device *dev,
291
		struct device_attribute *attr, char *buf)
292 293
{
	int rc = -ENXIO;
294
	struct backlight_device *bd = to_backlight_device(dev);
295

296
	mutex_lock(&bd->ops_lock);
297 298 299 300 301
	if (bd->ops && bd->ops->get_brightness) {
		rc = bd->ops->get_brightness(bd);
		if (rc >= 0)
			rc = sprintf(buf, "%d\n", rc);
	} else {
302
		rc = sprintf(buf, "%d\n", bd->props.brightness);
303
	}
304
	mutex_unlock(&bd->ops_lock);
Linus Torvalds's avatar
Linus Torvalds committed
305 306 307

	return rc;
}
308
static DEVICE_ATTR_RO(actual_brightness);
Linus Torvalds's avatar
Linus Torvalds committed
309

310 311 312 313 314 315 316 317 318 319 320 321
static ssize_t scale_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct backlight_device *bd = to_backlight_device(dev);

	if (WARN_ON(bd->props.scale > BACKLIGHT_SCALE_NON_LINEAR))
		return sprintf(buf, "unknown\n");

	return sprintf(buf, "%s\n", backlight_scale_types[bd->props.scale]);
}
static DEVICE_ATTR_RO(scale);

322 323
#ifdef CONFIG_PM_SLEEP
static int backlight_suspend(struct device *dev)
324 325 326
{
	struct backlight_device *bd = to_backlight_device(dev);

327 328
	mutex_lock(&bd->ops_lock);
	if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
329 330 331
		bd->props.state |= BL_CORE_SUSPENDED;
		backlight_update_status(bd);
	}
332
	mutex_unlock(&bd->ops_lock);
333 334 335 336 337 338 339 340

	return 0;
}

static int backlight_resume(struct device *dev)
{
	struct backlight_device *bd = to_backlight_device(dev);

341 342
	mutex_lock(&bd->ops_lock);
	if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
343 344 345
		bd->props.state &= ~BL_CORE_SUSPENDED;
		backlight_update_status(bd);
	}
346
	mutex_unlock(&bd->ops_lock);
347 348 349

	return 0;
}
350 351 352 353
#endif

static SIMPLE_DEV_PM_OPS(backlight_class_dev_pm_ops, backlight_suspend,
			 backlight_resume);
354

355
static void bl_device_release(struct device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
356 357 358 359 360
{
	struct backlight_device *bd = to_backlight_device(dev);
	kfree(bd);
}

361 362 363 364 365
static struct attribute *bl_device_attrs[] = {
	&dev_attr_bl_power.attr,
	&dev_attr_brightness.attr,
	&dev_attr_actual_brightness.attr,
	&dev_attr_max_brightness.attr,
366
	&dev_attr_scale.attr,
367 368
	&dev_attr_type.attr,
	NULL,
Linus Torvalds's avatar
Linus Torvalds committed
369
};
370
ATTRIBUTE_GROUPS(bl_device);
Linus Torvalds's avatar
Linus Torvalds committed
371

372 373 374 375 376 377
static const struct class backlight_class = {
	.name = "backlight",
	.dev_groups = bl_device_groups,
	.pm = &backlight_class_dev_pm_ops,
};

378 379 380 381
/**
 * backlight_force_update - tell the backlight subsystem that hardware state
 *   has changed
 * @bd: the backlight device to update
382
 * @reason: reason for update
383 384
 *
 * Updates the internal state of the backlight in response to a hardware event,
385 386 387 388
 * and generates an uevent to notify userspace. A backlight driver shall call
 * backlight_force_update() when the backlight is changed using, for example,
 * a hot-key. The updated brightness is read using get_brightness() and the
 * brightness value is reported using an uevent.
389 390 391 392
 */
void backlight_force_update(struct backlight_device *bd,
			    enum backlight_update_reason reason)
{
393 394
	int brightness;

395
	mutex_lock(&bd->ops_lock);
396 397 398 399 400 401 402 403 404
	if (bd->ops && bd->ops->get_brightness) {
		brightness = bd->ops->get_brightness(bd);
		if (brightness >= 0)
			bd->props.brightness = brightness;
		else
			dev_err(&bd->dev,
				"Could not update brightness from device: %pe\n",
				ERR_PTR(brightness));
	}
405 406 407 408 409
	mutex_unlock(&bd->ops_lock);
	backlight_generate_event(bd, reason);
}
EXPORT_SYMBOL(backlight_force_update);

410
/* deprecated - use devm_backlight_device_register() */
411
struct backlight_device *backlight_device_register(const char *name,
412 413
	struct device *parent, void *devdata, const struct backlight_ops *ops,
	const struct backlight_properties *props)
Linus Torvalds's avatar
Linus Torvalds committed
414 415
{
	struct backlight_device *new_bd;
416
	int rc;
Linus Torvalds's avatar
Linus Torvalds committed
417

418
	pr_debug("backlight_device_register: name=%s\n", name);
Linus Torvalds's avatar
Linus Torvalds committed
419

420
	new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
421
	if (!new_bd)
422
		return ERR_PTR(-ENOMEM);
Linus Torvalds's avatar
Linus Torvalds committed
423

424
	mutex_init(&new_bd->update_lock);
425
	mutex_init(&new_bd->ops_lock);
Linus Torvalds's avatar
Linus Torvalds committed
426

427
	new_bd->dev.class = &backlight_class;
428 429
	new_bd->dev.parent = parent;
	new_bd->dev.release = bl_device_release;
430
	dev_set_name(&new_bd->dev, "%s", name);
431 432
	dev_set_drvdata(&new_bd->dev, devdata);

433
	/* Set default properties */
434
	if (props) {
435 436
		memcpy(&new_bd->props, props,
		       sizeof(struct backlight_properties));
437 438 439 440 441 442 443
		if (props->type <= 0 || props->type >= BACKLIGHT_TYPE_MAX) {
			WARN(1, "%s: invalid backlight type", name);
			new_bd->props.type = BACKLIGHT_RAW;
		}
	} else {
		new_bd->props.type = BACKLIGHT_RAW;
	}
444

445
	rc = device_register(&new_bd->dev);
446
	if (rc) {
447
		put_device(&new_bd->dev);
Linus Torvalds's avatar
Linus Torvalds committed
448 449 450
		return ERR_PTR(rc);
	}

451
	rc = backlight_register_fb(new_bd);
452
	if (rc) {
453
		device_unregister(&new_bd->dev);
454 455 456
		return ERR_PTR(rc);
	}

457
	new_bd->ops = ops;
Linus Torvalds's avatar
Linus Torvalds committed
458

459 460 461 462 463 464 465
#ifdef CONFIG_PMAC_BACKLIGHT
	mutex_lock(&pmac_backlight_mutex);
	if (!pmac_backlight)
		pmac_backlight = new_bd;
	mutex_unlock(&pmac_backlight_mutex);
#endif

466 467 468 469
	mutex_lock(&backlight_dev_list_mutex);
	list_add(&new_bd->entry, &backlight_dev_list);
	mutex_unlock(&backlight_dev_list_mutex);

470 471 472
	blocking_notifier_call_chain(&backlight_notifier,
				     BACKLIGHT_REGISTERED, new_bd);

Linus Torvalds's avatar
Linus Torvalds committed
473 474 475 476
	return new_bd;
}
EXPORT_SYMBOL(backlight_device_register);

477 478 479 480 481 482 483 484 485
/** backlight_device_get_by_type - find first backlight device of a type
 * @type: the type of backlight device
 *
 * Look up the first backlight device of the specified type
 *
 * RETURNS:
 *
 * Pointer to backlight device if any was found. Otherwise NULL.
 */
486
struct backlight_device *backlight_device_get_by_type(enum backlight_type type)
487 488 489 490 491 492 493 494 495 496 497 498 499
{
	bool found = false;
	struct backlight_device *bd;

	mutex_lock(&backlight_dev_list_mutex);
	list_for_each_entry(bd, &backlight_dev_list, entry) {
		if (bd->props.type == type) {
			found = true;
			break;
		}
	}
	mutex_unlock(&backlight_dev_list_mutex);

500 501 502 503
	return found ? bd : NULL;
}
EXPORT_SYMBOL(backlight_device_get_by_type);

504 505 506 507 508 509
/**
 * backlight_device_get_by_name - Get backlight device by name
 * @name: Device name
 *
 * This function looks up a backlight device by its name. It obtains a reference
 * on the backlight device and it is the caller's responsibility to drop the
510
 * reference by calling put_device().
511 512 513 514 515 516 517 518
 *
 * Returns:
 * A pointer to the backlight device if found, otherwise NULL.
 */
struct backlight_device *backlight_device_get_by_name(const char *name)
{
	struct device *dev;

519
	dev = class_find_device_by_name(&backlight_class, name);
520 521 522 523 524

	return dev ? to_backlight_device(dev) : NULL;
}
EXPORT_SYMBOL(backlight_device_get_by_name);

525
/* deprecated - use devm_backlight_device_unregister() */
Linus Torvalds's avatar
Linus Torvalds committed
526 527 528 529 530
void backlight_device_unregister(struct backlight_device *bd)
{
	if (!bd)
		return;

531 532 533 534
	mutex_lock(&backlight_dev_list_mutex);
	list_del(&bd->entry);
	mutex_unlock(&backlight_dev_list_mutex);

535 536 537 538 539 540
#ifdef CONFIG_PMAC_BACKLIGHT
	mutex_lock(&pmac_backlight_mutex);
	if (pmac_backlight == bd)
		pmac_backlight = NULL;
	mutex_unlock(&pmac_backlight_mutex);
#endif
541 542 543 544

	blocking_notifier_call_chain(&backlight_notifier,
				     BACKLIGHT_UNREGISTERED, bd);

545 546 547
	mutex_lock(&bd->ops_lock);
	bd->ops = NULL;
	mutex_unlock(&bd->ops_lock);
Linus Torvalds's avatar
Linus Torvalds committed
548

549
	backlight_unregister_fb(bd);
550
	device_unregister(&bd->dev);
Linus Torvalds's avatar
Linus Torvalds committed
551 552 553
}
EXPORT_SYMBOL(backlight_device_unregister);

554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
static void devm_backlight_device_release(struct device *dev, void *res)
{
	struct backlight_device *backlight = *(struct backlight_device **)res;

	backlight_device_unregister(backlight);
}

static int devm_backlight_device_match(struct device *dev, void *res,
					void *data)
{
	struct backlight_device **r = res;

	return *r == data;
}

569 570 571 572 573 574
/**
 * backlight_register_notifier - get notified of backlight (un)registration
 * @nb: notifier block with the notifier to call on backlight (un)registration
 *
 * Register a notifier to get notified when backlight devices get registered
 * or unregistered.
575 576 577 578
 *
 * RETURNS:
 *
 * 0 on success, otherwise a negative error code
579 580 581 582 583 584 585 586 587 588 589 590 591
 */
int backlight_register_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&backlight_notifier, nb);
}
EXPORT_SYMBOL(backlight_register_notifier);

/**
 * backlight_unregister_notifier - unregister a backlight notifier
 * @nb: notifier block to unregister
 *
 * Register a notifier to get notified when backlight devices get registered
 * or unregistered.
592 593 594 595
 *
 * RETURNS:
 *
 * 0 on success, otherwise a negative error code
596 597 598 599 600 601 602
 */
int backlight_unregister_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_unregister(&backlight_notifier, nb);
}
EXPORT_SYMBOL(backlight_unregister_notifier);

603
/**
604
 * devm_backlight_device_register - register a new backlight device
605 606
 * @dev: the device to register
 * @name: the name of the device
607
 * @parent: a pointer to the parent device (often the same as @dev)
608 609 610 611
 * @devdata: an optional pointer to be stored for private driver use
 * @ops: the backlight operations structure
 * @props: the backlight properties
 *
612 613 614 615 616
 * Creates and registers new backlight device. When a backlight device
 * is registered the configuration must be specified in the @props
 * parameter. See description of &backlight_properties.
 *
 * RETURNS:
617
 *
618
 * struct backlight on success, or an ERR_PTR on error
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
 */
struct backlight_device *devm_backlight_device_register(struct device *dev,
	const char *name, struct device *parent, void *devdata,
	const struct backlight_ops *ops,
	const struct backlight_properties *props)
{
	struct backlight_device **ptr, *backlight;

	ptr = devres_alloc(devm_backlight_device_release, sizeof(*ptr),
			GFP_KERNEL);
	if (!ptr)
		return ERR_PTR(-ENOMEM);

	backlight = backlight_device_register(name, parent, devdata, ops,
						props);
	if (!IS_ERR(backlight)) {
		*ptr = backlight;
		devres_add(dev, ptr);
	} else {
		devres_free(ptr);
	}

	return backlight;
}
EXPORT_SYMBOL(devm_backlight_device_register);

/**
646
 * devm_backlight_device_unregister - unregister backlight device
647 648 649
 * @dev: the device to unregister
 * @bd: the backlight device to unregister
 *
650
 * Deallocates a backlight allocated with devm_backlight_device_register().
651
 * Normally this function will not need to be called and the resource management
652
 * code will ensure that the resources are freed.
653 654 655 656 657 658 659 660 661 662 663 664
 */
void devm_backlight_device_unregister(struct device *dev,
				struct backlight_device *bd)
{
	int rc;

	rc = devres_release(dev, devm_backlight_device_release,
				devm_backlight_device_match, bd);
	WARN_ON(rc);
}
EXPORT_SYMBOL(devm_backlight_device_unregister);

665
#ifdef CONFIG_OF
666
static int of_parent_match(struct device *dev, const void *data)
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
{
	return dev->parent && dev->parent->of_node == data;
}

/**
 * of_find_backlight_by_node() - find backlight device by device-tree node
 * @node: device-tree node of the backlight device
 *
 * Returns a pointer to the backlight device corresponding to the given DT
 * node or NULL if no such backlight device exists or if the device hasn't
 * been probed yet.
 *
 * This function obtains a reference on the backlight device and it is the
 * caller's responsibility to drop the reference by calling put_device() on
 * the backlight device's .dev field.
 */
struct backlight_device *of_find_backlight_by_node(struct device_node *node)
{
	struct device *dev;

687
	dev = class_find_device(&backlight_class, NULL, node, of_parent_match);
688 689 690 691 692 693

	return dev ? to_backlight_device(dev) : NULL;
}
EXPORT_SYMBOL(of_find_backlight_by_node);
#endif

694
static struct backlight_device *of_find_backlight(struct device *dev)
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
{
	struct backlight_device *bd = NULL;
	struct device_node *np;

	if (!dev)
		return NULL;

	if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
		np = of_parse_phandle(dev->of_node, "backlight", 0);
		if (np) {
			bd = of_find_backlight_by_node(np);
			of_node_put(np);
			if (!bd)
				return ERR_PTR(-EPROBE_DEFER);
		}
	}

	return bd;
}

715 716
static void devm_backlight_release(void *data)
{
717 718
	struct backlight_device *bd = data;

719
	put_device(&bd->dev);
720 721 722
}

/**
723 724
 * devm_of_find_backlight - find backlight for a device
 * @dev: the device
725
 *
726 727 728
 * This function looks for a property named 'backlight' on the DT node
 * connected to @dev and looks up the backlight device. The lookup is
 * device managed so the reference to the backlight device is automatically
729
 * dropped on driver detach.
730 731 732 733 734 735
 *
 * RETURNS:
 *
 * A pointer to the backlight device if found.
 * Error pointer -EPROBE_DEFER if the DT property is set, but no backlight
 * device is found. NULL if there's no backlight property.
736 737 738 739 740 741 742 743 744
 */
struct backlight_device *devm_of_find_backlight(struct device *dev)
{
	struct backlight_device *bd;
	int ret;

	bd = of_find_backlight(dev);
	if (IS_ERR_OR_NULL(bd))
		return bd;
745 746
	ret = devm_add_action_or_reset(dev, devm_backlight_release, bd);
	if (ret)
747
		return ERR_PTR(ret);
748

749 750 751 752
	return bd;
}
EXPORT_SYMBOL(devm_of_find_backlight);

Linus Torvalds's avatar
Linus Torvalds committed
753 754
static void __exit backlight_class_exit(void)
{
755
	class_unregister(&backlight_class);
Linus Torvalds's avatar
Linus Torvalds committed
756 757 758 759
}

static int __init backlight_class_init(void)
{
760 761 762 763 764 765
	int ret;

	ret = class_register(&backlight_class);
	if (ret) {
		pr_warn("Unable to create backlight class; errno = %d\n", ret);
		return ret;
766 767
	}

768 769
	INIT_LIST_HEAD(&backlight_dev_list);
	mutex_init(&backlight_dev_list_mutex);
770 771
	BLOCKING_INIT_NOTIFIER_HEAD(&backlight_notifier);

772
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
773 774 775 776 777 778 779 780 781 782 783 784
}

/*
 * if this is compiled into the kernel, we need to ensure that the
 * class is registered before users of the class try to register lcd's
 */
postcore_initcall(backlight_class_init);
module_exit(backlight_class_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>");
MODULE_DESCRIPTION("Backlight Lowlevel Control Abstraction");