cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

backlight.c (21184B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Backlight Lowlevel Control Abstraction
      4 *
      5 * Copyright (C) 2003,2004 Hewlett-Packard Company
      6 *
      7 */
      8
      9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     10
     11#include <linux/module.h>
     12#include <linux/init.h>
     13#include <linux/device.h>
     14#include <linux/backlight.h>
     15#include <linux/notifier.h>
     16#include <linux/ctype.h>
     17#include <linux/err.h>
     18#include <linux/fb.h>
     19#include <linux/slab.h>
     20
     21#ifdef CONFIG_PMAC_BACKLIGHT
     22#include <asm/backlight.h>
     23#endif
     24
     25/**
     26 * DOC: overview
     27 *
     28 * The backlight core supports implementing backlight drivers.
     29 *
     30 * A backlight driver registers a driver using
     31 * devm_backlight_device_register(). The properties of the backlight
     32 * driver such as type and max_brightness must be specified.
     33 * When the core detect changes in for example brightness or power state
     34 * the update_status() operation is called. The backlight driver shall
     35 * implement this operation and use it to adjust backlight.
     36 *
     37 * Several sysfs attributes are provided by the backlight core::
     38 *
     39 * - brightness         R/W, set the requested brightness level
     40 * - actual_brightness  RO, the brightness level used by the HW
     41 * - max_brightness     RO, the maximum  brightness level supported
     42 *
     43 * See Documentation/ABI/stable/sysfs-class-backlight for the full list.
     44 *
     45 * The backlight can be adjusted using the sysfs interface, and
     46 * the backlight driver may also support adjusting backlight using
     47 * a hot-key or some other platform or firmware specific way.
     48 *
     49 * The driver must implement the get_brightness() operation if
     50 * the HW do not support all the levels that can be specified in
     51 * brightness, thus providing user-space access to the actual level
     52 * via the actual_brightness attribute.
     53 *
     54 * When the backlight changes this is reported to user-space using
     55 * an uevent connected to the actual_brightness attribute.
     56 * When brightness is set by platform specific means, for example
     57 * a hot-key to adjust backlight, the driver must notify the backlight
     58 * core that brightness has changed using backlight_force_update().
     59 *
     60 * The backlight driver core receives notifications from fbdev and
     61 * if the event is FB_EVENT_BLANK and if the value of blank, from the
     62 * FBIOBLANK ioctrl, results in a change in the backlight state the
     63 * update_status() operation is called.
     64 */
     65
     66static struct list_head backlight_dev_list;
     67static struct mutex backlight_dev_list_mutex;
     68static struct blocking_notifier_head backlight_notifier;
     69
     70static const char *const backlight_types[] = {
     71	[BACKLIGHT_RAW] = "raw",
     72	[BACKLIGHT_PLATFORM] = "platform",
     73	[BACKLIGHT_FIRMWARE] = "firmware",
     74};
     75
     76static const char *const backlight_scale_types[] = {
     77	[BACKLIGHT_SCALE_UNKNOWN]	= "unknown",
     78	[BACKLIGHT_SCALE_LINEAR]	= "linear",
     79	[BACKLIGHT_SCALE_NON_LINEAR]	= "non-linear",
     80};
     81
     82#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
     83			   defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
     84/*
     85 * fb_notifier_callback
     86 *
     87 * This callback gets called when something important happens inside a
     88 * framebuffer driver. The backlight core only cares about FB_BLANK_UNBLANK
     89 * which is reported to the driver using backlight_update_status()
     90 * as a state change.
     91 *
     92 * There may be several fbdev's connected to the backlight device,
     93 * in which case they are kept track of. A state change is only reported
     94 * if there is a change in backlight for the specified fbdev.
     95 */
     96static int fb_notifier_callback(struct notifier_block *self,
     97				unsigned long event, void *data)
     98{
     99	struct backlight_device *bd;
    100	struct fb_event *evdata = data;
    101	int node = evdata->info->node;
    102	int fb_blank = 0;
    103
    104	/* If we aren't interested in this event, skip it immediately ... */
    105	if (event != FB_EVENT_BLANK)
    106		return 0;
    107
    108	bd = container_of(self, struct backlight_device, fb_notif);
    109	mutex_lock(&bd->ops_lock);
    110
    111	if (!bd->ops)
    112		goto out;
    113	if (bd->ops->check_fb && !bd->ops->check_fb(bd, evdata->info))
    114		goto out;
    115
    116	fb_blank = *(int *)evdata->data;
    117	if (fb_blank == FB_BLANK_UNBLANK && !bd->fb_bl_on[node]) {
    118		bd->fb_bl_on[node] = true;
    119		if (!bd->use_count++) {
    120			bd->props.state &= ~BL_CORE_FBBLANK;
    121			bd->props.fb_blank = FB_BLANK_UNBLANK;
    122			backlight_update_status(bd);
    123		}
    124	} else if (fb_blank != FB_BLANK_UNBLANK && bd->fb_bl_on[node]) {
    125		bd->fb_bl_on[node] = false;
    126		if (!(--bd->use_count)) {
    127			bd->props.state |= BL_CORE_FBBLANK;
    128			bd->props.fb_blank = fb_blank;
    129			backlight_update_status(bd);
    130		}
    131	}
    132out:
    133	mutex_unlock(&bd->ops_lock);
    134	return 0;
    135}
    136
    137static int backlight_register_fb(struct backlight_device *bd)
    138{
    139	memset(&bd->fb_notif, 0, sizeof(bd->fb_notif));
    140	bd->fb_notif.notifier_call = fb_notifier_callback;
    141
    142	return fb_register_client(&bd->fb_notif);
    143}
    144
    145static void backlight_unregister_fb(struct backlight_device *bd)
    146{
    147	fb_unregister_client(&bd->fb_notif);
    148}
    149#else
    150static inline int backlight_register_fb(struct backlight_device *bd)
    151{
    152	return 0;
    153}
    154
    155static inline void backlight_unregister_fb(struct backlight_device *bd)
    156{
    157}
    158#endif /* CONFIG_FB */
    159
    160static void backlight_generate_event(struct backlight_device *bd,
    161				     enum backlight_update_reason reason)
    162{
    163	char *envp[2];
    164
    165	switch (reason) {
    166	case BACKLIGHT_UPDATE_SYSFS:
    167		envp[0] = "SOURCE=sysfs";
    168		break;
    169	case BACKLIGHT_UPDATE_HOTKEY:
    170		envp[0] = "SOURCE=hotkey";
    171		break;
    172	default:
    173		envp[0] = "SOURCE=unknown";
    174		break;
    175	}
    176	envp[1] = NULL;
    177	kobject_uevent_env(&bd->dev.kobj, KOBJ_CHANGE, envp);
    178	sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness");
    179}
    180
    181static ssize_t bl_power_show(struct device *dev, struct device_attribute *attr,
    182		char *buf)
    183{
    184	struct backlight_device *bd = to_backlight_device(dev);
    185
    186	return sprintf(buf, "%d\n", bd->props.power);
    187}
    188
    189static ssize_t bl_power_store(struct device *dev, struct device_attribute *attr,
    190		const char *buf, size_t count)
    191{
    192	int rc;
    193	struct backlight_device *bd = to_backlight_device(dev);
    194	unsigned long power, old_power;
    195
    196	rc = kstrtoul(buf, 0, &power);
    197	if (rc)
    198		return rc;
    199
    200	rc = -ENXIO;
    201	mutex_lock(&bd->ops_lock);
    202	if (bd->ops) {
    203		pr_debug("set power to %lu\n", power);
    204		if (bd->props.power != power) {
    205			old_power = bd->props.power;
    206			bd->props.power = power;
    207			rc = backlight_update_status(bd);
    208			if (rc)
    209				bd->props.power = old_power;
    210			else
    211				rc = count;
    212		} else {
    213			rc = count;
    214		}
    215	}
    216	mutex_unlock(&bd->ops_lock);
    217
    218	return rc;
    219}
    220static DEVICE_ATTR_RW(bl_power);
    221
    222static ssize_t brightness_show(struct device *dev,
    223		struct device_attribute *attr, char *buf)
    224{
    225	struct backlight_device *bd = to_backlight_device(dev);
    226
    227	return sprintf(buf, "%d\n", bd->props.brightness);
    228}
    229
    230int backlight_device_set_brightness(struct backlight_device *bd,
    231				    unsigned long brightness)
    232{
    233	int rc = -ENXIO;
    234
    235	mutex_lock(&bd->ops_lock);
    236	if (bd->ops) {
    237		if (brightness > bd->props.max_brightness)
    238			rc = -EINVAL;
    239		else {
    240			pr_debug("set brightness to %lu\n", brightness);
    241			bd->props.brightness = brightness;
    242			rc = backlight_update_status(bd);
    243		}
    244	}
    245	mutex_unlock(&bd->ops_lock);
    246
    247	backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS);
    248
    249	return rc;
    250}
    251EXPORT_SYMBOL(backlight_device_set_brightness);
    252
    253static ssize_t brightness_store(struct device *dev,
    254		struct device_attribute *attr, const char *buf, size_t count)
    255{
    256	int rc;
    257	struct backlight_device *bd = to_backlight_device(dev);
    258	unsigned long brightness;
    259
    260	rc = kstrtoul(buf, 0, &brightness);
    261	if (rc)
    262		return rc;
    263
    264	rc = backlight_device_set_brightness(bd, brightness);
    265
    266	return rc ? rc : count;
    267}
    268static DEVICE_ATTR_RW(brightness);
    269
    270static ssize_t type_show(struct device *dev, struct device_attribute *attr,
    271		char *buf)
    272{
    273	struct backlight_device *bd = to_backlight_device(dev);
    274
    275	return sprintf(buf, "%s\n", backlight_types[bd->props.type]);
    276}
    277static DEVICE_ATTR_RO(type);
    278
    279static ssize_t max_brightness_show(struct device *dev,
    280		struct device_attribute *attr, char *buf)
    281{
    282	struct backlight_device *bd = to_backlight_device(dev);
    283
    284	return sprintf(buf, "%d\n", bd->props.max_brightness);
    285}
    286static DEVICE_ATTR_RO(max_brightness);
    287
    288static ssize_t actual_brightness_show(struct device *dev,
    289		struct device_attribute *attr, char *buf)
    290{
    291	int rc = -ENXIO;
    292	struct backlight_device *bd = to_backlight_device(dev);
    293
    294	mutex_lock(&bd->ops_lock);
    295	if (bd->ops && bd->ops->get_brightness) {
    296		rc = bd->ops->get_brightness(bd);
    297		if (rc >= 0)
    298			rc = sprintf(buf, "%d\n", rc);
    299	} else {
    300		rc = sprintf(buf, "%d\n", bd->props.brightness);
    301	}
    302	mutex_unlock(&bd->ops_lock);
    303
    304	return rc;
    305}
    306static DEVICE_ATTR_RO(actual_brightness);
    307
    308static ssize_t scale_show(struct device *dev,
    309		struct device_attribute *attr, char *buf)
    310{
    311	struct backlight_device *bd = to_backlight_device(dev);
    312
    313	if (WARN_ON(bd->props.scale > BACKLIGHT_SCALE_NON_LINEAR))
    314		return sprintf(buf, "unknown\n");
    315
    316	return sprintf(buf, "%s\n", backlight_scale_types[bd->props.scale]);
    317}
    318static DEVICE_ATTR_RO(scale);
    319
    320static struct class *backlight_class;
    321
    322#ifdef CONFIG_PM_SLEEP
    323static int backlight_suspend(struct device *dev)
    324{
    325	struct backlight_device *bd = to_backlight_device(dev);
    326
    327	mutex_lock(&bd->ops_lock);
    328	if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
    329		bd->props.state |= BL_CORE_SUSPENDED;
    330		backlight_update_status(bd);
    331	}
    332	mutex_unlock(&bd->ops_lock);
    333
    334	return 0;
    335}
    336
    337static int backlight_resume(struct device *dev)
    338{
    339	struct backlight_device *bd = to_backlight_device(dev);
    340
    341	mutex_lock(&bd->ops_lock);
    342	if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
    343		bd->props.state &= ~BL_CORE_SUSPENDED;
    344		backlight_update_status(bd);
    345	}
    346	mutex_unlock(&bd->ops_lock);
    347
    348	return 0;
    349}
    350#endif
    351
    352static SIMPLE_DEV_PM_OPS(backlight_class_dev_pm_ops, backlight_suspend,
    353			 backlight_resume);
    354
    355static void bl_device_release(struct device *dev)
    356{
    357	struct backlight_device *bd = to_backlight_device(dev);
    358	kfree(bd);
    359}
    360
    361static struct attribute *bl_device_attrs[] = {
    362	&dev_attr_bl_power.attr,
    363	&dev_attr_brightness.attr,
    364	&dev_attr_actual_brightness.attr,
    365	&dev_attr_max_brightness.attr,
    366	&dev_attr_scale.attr,
    367	&dev_attr_type.attr,
    368	NULL,
    369};
    370ATTRIBUTE_GROUPS(bl_device);
    371
    372/**
    373 * backlight_force_update - tell the backlight subsystem that hardware state
    374 *   has changed
    375 * @bd: the backlight device to update
    376 * @reason: reason for update
    377 *
    378 * Updates the internal state of the backlight in response to a hardware event,
    379 * and generates an uevent to notify userspace. A backlight driver shall call
    380 * backlight_force_update() when the backlight is changed using, for example,
    381 * a hot-key. The updated brightness is read using get_brightness() and the
    382 * brightness value is reported using an uevent.
    383 */
    384void backlight_force_update(struct backlight_device *bd,
    385			    enum backlight_update_reason reason)
    386{
    387	int brightness;
    388
    389	mutex_lock(&bd->ops_lock);
    390	if (bd->ops && bd->ops->get_brightness) {
    391		brightness = bd->ops->get_brightness(bd);
    392		if (brightness >= 0)
    393			bd->props.brightness = brightness;
    394		else
    395			dev_err(&bd->dev,
    396				"Could not update brightness from device: %pe\n",
    397				ERR_PTR(brightness));
    398	}
    399	mutex_unlock(&bd->ops_lock);
    400	backlight_generate_event(bd, reason);
    401}
    402EXPORT_SYMBOL(backlight_force_update);
    403
    404/* deprecated - use devm_backlight_device_register() */
    405struct backlight_device *backlight_device_register(const char *name,
    406	struct device *parent, void *devdata, const struct backlight_ops *ops,
    407	const struct backlight_properties *props)
    408{
    409	struct backlight_device *new_bd;
    410	int rc;
    411
    412	pr_debug("backlight_device_register: name=%s\n", name);
    413
    414	new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
    415	if (!new_bd)
    416		return ERR_PTR(-ENOMEM);
    417
    418	mutex_init(&new_bd->update_lock);
    419	mutex_init(&new_bd->ops_lock);
    420
    421	new_bd->dev.class = backlight_class;
    422	new_bd->dev.parent = parent;
    423	new_bd->dev.release = bl_device_release;
    424	dev_set_name(&new_bd->dev, "%s", name);
    425	dev_set_drvdata(&new_bd->dev, devdata);
    426
    427	/* Set default properties */
    428	if (props) {
    429		memcpy(&new_bd->props, props,
    430		       sizeof(struct backlight_properties));
    431		if (props->type <= 0 || props->type >= BACKLIGHT_TYPE_MAX) {
    432			WARN(1, "%s: invalid backlight type", name);
    433			new_bd->props.type = BACKLIGHT_RAW;
    434		}
    435	} else {
    436		new_bd->props.type = BACKLIGHT_RAW;
    437	}
    438
    439	rc = device_register(&new_bd->dev);
    440	if (rc) {
    441		put_device(&new_bd->dev);
    442		return ERR_PTR(rc);
    443	}
    444
    445	rc = backlight_register_fb(new_bd);
    446	if (rc) {
    447		device_unregister(&new_bd->dev);
    448		return ERR_PTR(rc);
    449	}
    450
    451	new_bd->ops = ops;
    452
    453#ifdef CONFIG_PMAC_BACKLIGHT
    454	mutex_lock(&pmac_backlight_mutex);
    455	if (!pmac_backlight)
    456		pmac_backlight = new_bd;
    457	mutex_unlock(&pmac_backlight_mutex);
    458#endif
    459
    460	mutex_lock(&backlight_dev_list_mutex);
    461	list_add(&new_bd->entry, &backlight_dev_list);
    462	mutex_unlock(&backlight_dev_list_mutex);
    463
    464	blocking_notifier_call_chain(&backlight_notifier,
    465				     BACKLIGHT_REGISTERED, new_bd);
    466
    467	return new_bd;
    468}
    469EXPORT_SYMBOL(backlight_device_register);
    470
    471/** backlight_device_get_by_type - find first backlight device of a type
    472 * @type: the type of backlight device
    473 *
    474 * Look up the first backlight device of the specified type
    475 *
    476 * RETURNS:
    477 *
    478 * Pointer to backlight device if any was found. Otherwise NULL.
    479 */
    480struct backlight_device *backlight_device_get_by_type(enum backlight_type type)
    481{
    482	bool found = false;
    483	struct backlight_device *bd;
    484
    485	mutex_lock(&backlight_dev_list_mutex);
    486	list_for_each_entry(bd, &backlight_dev_list, entry) {
    487		if (bd->props.type == type) {
    488			found = true;
    489			break;
    490		}
    491	}
    492	mutex_unlock(&backlight_dev_list_mutex);
    493
    494	return found ? bd : NULL;
    495}
    496EXPORT_SYMBOL(backlight_device_get_by_type);
    497
    498/**
    499 * backlight_device_get_by_name - Get backlight device by name
    500 * @name: Device name
    501 *
    502 * This function looks up a backlight device by its name. It obtains a reference
    503 * on the backlight device and it is the caller's responsibility to drop the
    504 * reference by calling backlight_put().
    505 *
    506 * Returns:
    507 * A pointer to the backlight device if found, otherwise NULL.
    508 */
    509struct backlight_device *backlight_device_get_by_name(const char *name)
    510{
    511	struct device *dev;
    512
    513	dev = class_find_device_by_name(backlight_class, name);
    514
    515	return dev ? to_backlight_device(dev) : NULL;
    516}
    517EXPORT_SYMBOL(backlight_device_get_by_name);
    518
    519/* deprecated - use devm_backlight_device_unregister() */
    520void backlight_device_unregister(struct backlight_device *bd)
    521{
    522	if (!bd)
    523		return;
    524
    525	mutex_lock(&backlight_dev_list_mutex);
    526	list_del(&bd->entry);
    527	mutex_unlock(&backlight_dev_list_mutex);
    528
    529#ifdef CONFIG_PMAC_BACKLIGHT
    530	mutex_lock(&pmac_backlight_mutex);
    531	if (pmac_backlight == bd)
    532		pmac_backlight = NULL;
    533	mutex_unlock(&pmac_backlight_mutex);
    534#endif
    535
    536	blocking_notifier_call_chain(&backlight_notifier,
    537				     BACKLIGHT_UNREGISTERED, bd);
    538
    539	mutex_lock(&bd->ops_lock);
    540	bd->ops = NULL;
    541	mutex_unlock(&bd->ops_lock);
    542
    543	backlight_unregister_fb(bd);
    544	device_unregister(&bd->dev);
    545}
    546EXPORT_SYMBOL(backlight_device_unregister);
    547
    548static void devm_backlight_device_release(struct device *dev, void *res)
    549{
    550	struct backlight_device *backlight = *(struct backlight_device **)res;
    551
    552	backlight_device_unregister(backlight);
    553}
    554
    555static int devm_backlight_device_match(struct device *dev, void *res,
    556					void *data)
    557{
    558	struct backlight_device **r = res;
    559
    560	return *r == data;
    561}
    562
    563/**
    564 * backlight_register_notifier - get notified of backlight (un)registration
    565 * @nb: notifier block with the notifier to call on backlight (un)registration
    566 *
    567 * Register a notifier to get notified when backlight devices get registered
    568 * or unregistered.
    569 *
    570 * RETURNS:
    571 *
    572 * 0 on success, otherwise a negative error code
    573 */
    574int backlight_register_notifier(struct notifier_block *nb)
    575{
    576	return blocking_notifier_chain_register(&backlight_notifier, nb);
    577}
    578EXPORT_SYMBOL(backlight_register_notifier);
    579
    580/**
    581 * backlight_unregister_notifier - unregister a backlight notifier
    582 * @nb: notifier block to unregister
    583 *
    584 * Register a notifier to get notified when backlight devices get registered
    585 * or unregistered.
    586 *
    587 * RETURNS:
    588 *
    589 * 0 on success, otherwise a negative error code
    590 */
    591int backlight_unregister_notifier(struct notifier_block *nb)
    592{
    593	return blocking_notifier_chain_unregister(&backlight_notifier, nb);
    594}
    595EXPORT_SYMBOL(backlight_unregister_notifier);
    596
    597/**
    598 * devm_backlight_device_register - register a new backlight device
    599 * @dev: the device to register
    600 * @name: the name of the device
    601 * @parent: a pointer to the parent device (often the same as @dev)
    602 * @devdata: an optional pointer to be stored for private driver use
    603 * @ops: the backlight operations structure
    604 * @props: the backlight properties
    605 *
    606 * Creates and registers new backlight device. When a backlight device
    607 * is registered the configuration must be specified in the @props
    608 * parameter. See description of &backlight_properties.
    609 *
    610 * RETURNS:
    611 *
    612 * struct backlight on success, or an ERR_PTR on error
    613 */
    614struct backlight_device *devm_backlight_device_register(struct device *dev,
    615	const char *name, struct device *parent, void *devdata,
    616	const struct backlight_ops *ops,
    617	const struct backlight_properties *props)
    618{
    619	struct backlight_device **ptr, *backlight;
    620
    621	ptr = devres_alloc(devm_backlight_device_release, sizeof(*ptr),
    622			GFP_KERNEL);
    623	if (!ptr)
    624		return ERR_PTR(-ENOMEM);
    625
    626	backlight = backlight_device_register(name, parent, devdata, ops,
    627						props);
    628	if (!IS_ERR(backlight)) {
    629		*ptr = backlight;
    630		devres_add(dev, ptr);
    631	} else {
    632		devres_free(ptr);
    633	}
    634
    635	return backlight;
    636}
    637EXPORT_SYMBOL(devm_backlight_device_register);
    638
    639/**
    640 * devm_backlight_device_unregister - unregister backlight device
    641 * @dev: the device to unregister
    642 * @bd: the backlight device to unregister
    643 *
    644 * Deallocates a backlight allocated with devm_backlight_device_register().
    645 * Normally this function will not need to be called and the resource management
    646 * code will ensure that the resources are freed.
    647 */
    648void devm_backlight_device_unregister(struct device *dev,
    649				struct backlight_device *bd)
    650{
    651	int rc;
    652
    653	rc = devres_release(dev, devm_backlight_device_release,
    654				devm_backlight_device_match, bd);
    655	WARN_ON(rc);
    656}
    657EXPORT_SYMBOL(devm_backlight_device_unregister);
    658
    659#ifdef CONFIG_OF
    660static int of_parent_match(struct device *dev, const void *data)
    661{
    662	return dev->parent && dev->parent->of_node == data;
    663}
    664
    665/**
    666 * of_find_backlight_by_node() - find backlight device by device-tree node
    667 * @node: device-tree node of the backlight device
    668 *
    669 * Returns a pointer to the backlight device corresponding to the given DT
    670 * node or NULL if no such backlight device exists or if the device hasn't
    671 * been probed yet.
    672 *
    673 * This function obtains a reference on the backlight device and it is the
    674 * caller's responsibility to drop the reference by calling put_device() on
    675 * the backlight device's .dev field.
    676 */
    677struct backlight_device *of_find_backlight_by_node(struct device_node *node)
    678{
    679	struct device *dev;
    680
    681	dev = class_find_device(backlight_class, NULL, node, of_parent_match);
    682
    683	return dev ? to_backlight_device(dev) : NULL;
    684}
    685EXPORT_SYMBOL(of_find_backlight_by_node);
    686#endif
    687
    688static struct backlight_device *of_find_backlight(struct device *dev)
    689{
    690	struct backlight_device *bd = NULL;
    691	struct device_node *np;
    692
    693	if (!dev)
    694		return NULL;
    695
    696	if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
    697		np = of_parse_phandle(dev->of_node, "backlight", 0);
    698		if (np) {
    699			bd = of_find_backlight_by_node(np);
    700			of_node_put(np);
    701			if (!bd)
    702				return ERR_PTR(-EPROBE_DEFER);
    703		}
    704	}
    705
    706	return bd;
    707}
    708
    709static void devm_backlight_release(void *data)
    710{
    711	struct backlight_device *bd = data;
    712
    713	put_device(&bd->dev);
    714}
    715
    716/**
    717 * devm_of_find_backlight - find backlight for a device
    718 * @dev: the device
    719 *
    720 * This function looks for a property named 'backlight' on the DT node
    721 * connected to @dev and looks up the backlight device. The lookup is
    722 * device managed so the reference to the backlight device is automatically
    723 * dropped on driver detach.
    724 *
    725 * RETURNS:
    726 *
    727 * A pointer to the backlight device if found.
    728 * Error pointer -EPROBE_DEFER if the DT property is set, but no backlight
    729 * device is found. NULL if there's no backlight property.
    730 */
    731struct backlight_device *devm_of_find_backlight(struct device *dev)
    732{
    733	struct backlight_device *bd;
    734	int ret;
    735
    736	bd = of_find_backlight(dev);
    737	if (IS_ERR_OR_NULL(bd))
    738		return bd;
    739	ret = devm_add_action_or_reset(dev, devm_backlight_release, bd);
    740	if (ret)
    741		return ERR_PTR(ret);
    742
    743	return bd;
    744}
    745EXPORT_SYMBOL(devm_of_find_backlight);
    746
    747static void __exit backlight_class_exit(void)
    748{
    749	class_destroy(backlight_class);
    750}
    751
    752static int __init backlight_class_init(void)
    753{
    754	backlight_class = class_create(THIS_MODULE, "backlight");
    755	if (IS_ERR(backlight_class)) {
    756		pr_warn("Unable to create backlight class; errno = %ld\n",
    757			PTR_ERR(backlight_class));
    758		return PTR_ERR(backlight_class);
    759	}
    760
    761	backlight_class->dev_groups = bl_device_groups;
    762	backlight_class->pm = &backlight_class_dev_pm_ops;
    763	INIT_LIST_HEAD(&backlight_dev_list);
    764	mutex_init(&backlight_dev_list_mutex);
    765	BLOCKING_INIT_NOTIFIER_HEAD(&backlight_notifier);
    766
    767	return 0;
    768}
    769
    770/*
    771 * if this is compiled into the kernel, we need to ensure that the
    772 * class is registered before users of the class try to register lcd's
    773 */
    774postcore_initcall(backlight_class_init);
    775module_exit(backlight_class_exit);
    776
    777MODULE_LICENSE("GPL");
    778MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>");
    779MODULE_DESCRIPTION("Backlight Lowlevel Control Abstraction");