11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Backlight Lowlevel Control Abstraction 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003,2004 Hewlett-Packard Company 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/backlight.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/notifier.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ctype.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fb.h> 165a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie#ifdef CONFIG_PMAC_BACKLIGHT 19321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie#include <asm/backlight.h> 20321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie#endif 213d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons 22c338bfb5ecf6c36b2112479691d69db4c2b5a78aBart Van Asschestatic const char *const backlight_types[] = { 23bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett [BACKLIGHT_RAW] = "raw", 24bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett [BACKLIGHT_PLATFORM] = "platform", 25bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett [BACKLIGHT_FIRMWARE] = "firmware", 26bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett}; 27bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett 283d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ 293d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) 303d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons/* This callback gets called when something important happens inside a 313d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons * framebuffer driver. We're looking if that important event is blanking, 323d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons * and if it is, we're switching backlight power as well ... 333d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons */ 343d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmonsstatic int fb_notifier_callback(struct notifier_block *self, 353d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons unsigned long event, void *data) 363d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons{ 373d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons struct backlight_device *bd; 383d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons struct fb_event *evdata = data; 393d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons 403d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons /* If we aren't interested in this event, skip it immediately ... */ 41994efacdf9a087b52f71e620b58dfa526b0cf928Richard Purdie if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK) 423d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons return 0; 433d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons 443d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons bd = container_of(self, struct backlight_device, fb_notif); 45599a52d12629394236d785615808845823875868Richard Purdie mutex_lock(&bd->ops_lock); 46599a52d12629394236d785615808845823875868Richard Purdie if (bd->ops) 47599a52d12629394236d785615808845823875868Richard Purdie if (!bd->ops->check_fb || 4857e148b6a975980944f4466ccb669b1d02dfc6a1Bruno Prémont bd->ops->check_fb(bd, evdata->info)) { 49599a52d12629394236d785615808845823875868Richard Purdie bd->props.fb_blank = *(int *)evdata->data; 50c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie if (bd->props.fb_blank == FB_BLANK_UNBLANK) 51c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie bd->props.state &= ~BL_CORE_FBBLANK; 52c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie else 53c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie bd->props.state |= BL_CORE_FBBLANK; 5428ee086d5b36aab2931f6740e409bb0fb6c65e5fRichard Purdie backlight_update_status(bd); 553d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons } 56599a52d12629394236d785615808845823875868Richard Purdie mutex_unlock(&bd->ops_lock); 573d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons return 0; 583d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons} 593d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons 603d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmonsstatic int backlight_register_fb(struct backlight_device *bd) 613d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons{ 623d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons memset(&bd->fb_notif, 0, sizeof(bd->fb_notif)); 633d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons bd->fb_notif.notifier_call = fb_notifier_callback; 643d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons 653d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons return fb_register_client(&bd->fb_notif); 663d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons} 673d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons 683d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmonsstatic void backlight_unregister_fb(struct backlight_device *bd) 693d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons{ 703d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons fb_unregister_client(&bd->fb_notif); 713d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons} 723d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons#else 733d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmonsstatic inline int backlight_register_fb(struct backlight_device *bd) 743d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons{ 753d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons return 0; 763d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons} 773d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons 783d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmonsstatic inline void backlight_unregister_fb(struct backlight_device *bd) 793d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons{ 803d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons} 813d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons#endif /* CONFIG_FB */ 823d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons 83325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrettstatic void backlight_generate_event(struct backlight_device *bd, 84325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett enum backlight_update_reason reason) 85325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett{ 86325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett char *envp[2]; 87325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett 88325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett switch (reason) { 89325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett case BACKLIGHT_UPDATE_SYSFS: 90325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett envp[0] = "SOURCE=sysfs"; 91325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett break; 92325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett case BACKLIGHT_UPDATE_HOTKEY: 93325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett envp[0] = "SOURCE=hotkey"; 94325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett break; 95325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett default: 96325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett envp[0] = "SOURCE=unknown"; 97325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett break; 98325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett } 99325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett envp[1] = NULL; 100325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett kobject_uevent_env(&bd->dev.kobj, KOBJ_CHANGE, envp); 10189dfc28ccbff6521a4df9dc3699a94bbde11a6edHenrique de Moraes Holschuh sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness"); 102325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett} 103325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett 104655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdiestatic ssize_t backlight_show_power(struct device *dev, 10566655760bf38861299e3c8196f5303f886b0eef9Jingoo Han struct device_attribute *attr, char *buf) 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 107655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct backlight_device *bd = to_backlight_device(dev); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 109599a52d12629394236d785615808845823875868Richard Purdie return sprintf(buf, "%d\n", bd->props.power); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 112655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdiestatic ssize_t backlight_store_power(struct device *dev, 113655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct device_attribute *attr, const char *buf, size_t count) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1159a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek int rc; 116655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct backlight_device *bd = to_backlight_device(dev); 1179a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek unsigned long power; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11966655760bf38861299e3c8196f5303f886b0eef9Jingoo Han rc = kstrtoul(buf, 0, &power); 1209a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek if (rc) 1219a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek return rc; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1239a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek rc = -ENXIO; 124599a52d12629394236d785615808845823875868Richard Purdie mutex_lock(&bd->ops_lock); 125599a52d12629394236d785615808845823875868Richard Purdie if (bd->ops) { 1269a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek pr_debug("backlight: set power to %lu\n", power); 127515524537999c1f107a0a7c7f74c034979c2c86dHelge Deller if (bd->props.power != power) { 128515524537999c1f107a0a7c7f74c034979c2c86dHelge Deller bd->props.power = power; 129515524537999c1f107a0a7c7f74c034979c2c86dHelge Deller backlight_update_status(bd); 130515524537999c1f107a0a7c7f74c034979c2c86dHelge Deller } 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = count; 1326ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie } 133599a52d12629394236d785615808845823875868Richard Purdie mutex_unlock(&bd->ops_lock); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 138655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdiestatic ssize_t backlight_show_brightness(struct device *dev, 139655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct device_attribute *attr, char *buf) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 141655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct backlight_device *bd = to_backlight_device(dev); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 143599a52d12629394236d785615808845823875868Richard Purdie return sprintf(buf, "%d\n", bd->props.brightness); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 146655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdiestatic ssize_t backlight_store_brightness(struct device *dev, 147655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct device_attribute *attr, const char *buf, size_t count) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1499a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek int rc; 150655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct backlight_device *bd = to_backlight_device(dev); 1519a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek unsigned long brightness; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15366655760bf38861299e3c8196f5303f886b0eef9Jingoo Han rc = kstrtoul(buf, 0, &brightness); 1549a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek if (rc) 1559a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek return rc; 1569a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek 1579a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek rc = -ENXIO; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 159599a52d12629394236d785615808845823875868Richard Purdie mutex_lock(&bd->ops_lock); 160599a52d12629394236d785615808845823875868Richard Purdie if (bd->ops) { 161599a52d12629394236d785615808845823875868Richard Purdie if (brightness > bd->props.max_brightness) 1626ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie rc = -EINVAL; 1636ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie else { 1649a2c61a921a8aeabacaccad0d2fdf75e1c1475fbPavel Machek pr_debug("backlight: set brightness to %lu\n", 1656ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie brightness); 1669be1df98bca44dbe3769cd22f4ab8122b76c5313Zhang Rui bd->props.brightness = brightness; 1679be1df98bca44dbe3769cd22f4ab8122b76c5313Zhang Rui backlight_update_status(bd); 1686ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie rc = count; 1696ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie } 1706ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie } 171599a52d12629394236d785615808845823875868Richard Purdie mutex_unlock(&bd->ops_lock); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 173325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS); 174325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 178bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrettstatic ssize_t backlight_show_type(struct device *dev, 179bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett struct device_attribute *attr, char *buf) 180bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett{ 181bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett struct backlight_device *bd = to_backlight_device(dev); 182bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett 183bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett return sprintf(buf, "%s\n", backlight_types[bd->props.type]); 184bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett} 185bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett 186655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdiestatic ssize_t backlight_show_max_brightness(struct device *dev, 187655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct device_attribute *attr, char *buf) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 189655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct backlight_device *bd = to_backlight_device(dev); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191599a52d12629394236d785615808845823875868Richard Purdie return sprintf(buf, "%d\n", bd->props.max_brightness); 1926ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie} 1936ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie 194655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdiestatic ssize_t backlight_show_actual_brightness(struct device *dev, 195655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct device_attribute *attr, char *buf) 1966ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie{ 1976ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie int rc = -ENXIO; 198655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie struct backlight_device *bd = to_backlight_device(dev); 1996ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie 200599a52d12629394236d785615808845823875868Richard Purdie mutex_lock(&bd->ops_lock); 201599a52d12629394236d785615808845823875868Richard Purdie if (bd->ops && bd->ops->get_brightness) 202599a52d12629394236d785615808845823875868Richard Purdie rc = sprintf(buf, "%d\n", bd->ops->get_brightness(bd)); 203599a52d12629394236d785615808845823875868Richard Purdie mutex_unlock(&bd->ops_lock); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2080ad90efde278866a4ba7510e6e1fbd9626da1689Adrian Bunkstatic struct class *backlight_class; 209655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie 210c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdiestatic int backlight_suspend(struct device *dev, pm_message_t state) 211c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie{ 212c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie struct backlight_device *bd = to_backlight_device(dev); 213c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie 214d1d73578e053b981c3611e5a211534290d24a5ebUwe Kleine-König mutex_lock(&bd->ops_lock); 215d1d73578e053b981c3611e5a211534290d24a5ebUwe Kleine-König if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) { 216c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie bd->props.state |= BL_CORE_SUSPENDED; 217c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie backlight_update_status(bd); 218c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie } 219d1d73578e053b981c3611e5a211534290d24a5ebUwe Kleine-König mutex_unlock(&bd->ops_lock); 220c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie 221c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie return 0; 222c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie} 223c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie 224c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdiestatic int backlight_resume(struct device *dev) 225c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie{ 226c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie struct backlight_device *bd = to_backlight_device(dev); 227c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie 228d1d73578e053b981c3611e5a211534290d24a5ebUwe Kleine-König mutex_lock(&bd->ops_lock); 229d1d73578e053b981c3611e5a211534290d24a5ebUwe Kleine-König if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) { 230c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie bd->props.state &= ~BL_CORE_SUSPENDED; 231c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie backlight_update_status(bd); 232c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie } 233d1d73578e053b981c3611e5a211534290d24a5ebUwe Kleine-König mutex_unlock(&bd->ops_lock); 234c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie 235c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie return 0; 236c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie} 237c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie 238655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdiestatic void bl_device_release(struct device *dev) 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct backlight_device *bd = to_backlight_device(dev); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(bd); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 244655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdiestatic struct device_attribute bl_device_attributes[] = { 245655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie __ATTR(bl_power, 0644, backlight_show_power, backlight_store_power), 246655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie __ATTR(brightness, 0644, backlight_show_brightness, 2476ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie backlight_store_brightness), 248655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie __ATTR(actual_brightness, 0444, backlight_show_actual_brightness, 2496ca017658b1f902c9bba2cc1017e301581f7728dRichard Purdie NULL), 250655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL), 251bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett __ATTR(type, 0444, backlight_show_type, NULL), 252655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie __ATTR_NULL, 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 256325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett * backlight_force_update - tell the backlight subsystem that hardware state 257325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett * has changed 258325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett * @bd: the backlight device to update 259325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett * 260325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett * Updates the internal state of the backlight in response to a hardware event, 261325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett * and generate a uevent to notify userspace 262325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett */ 263325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrettvoid backlight_force_update(struct backlight_device *bd, 264325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett enum backlight_update_reason reason) 265325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett{ 266325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett mutex_lock(&bd->ops_lock); 267325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett if (bd->ops && bd->ops->get_brightness) 268325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett bd->props.brightness = bd->ops->get_brightness(bd); 269325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett mutex_unlock(&bd->ops_lock); 270325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett backlight_generate_event(bd, reason); 271325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett} 272325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew GarrettEXPORT_SYMBOL(backlight_force_update); 273325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett 274325253a6b2de4bdfa9ef0e28b5df8a4a4fe2b677Matthew Garrett/** 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * backlight_device_register - create and register a new object of 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * backlight_device class. 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @name: the name of the new object(must be the same as the name of the 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * respective framebuffer device). 279f6ec2d96796d0accda6c325890206f3629130729Sebastian Siewior * @parent: a pointer to the parent device 280655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie * @devdata: an optional pointer to be stored for private driver use. The 281655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie * methods may retrieve it by using bl_get_data(bd). 282599a52d12629394236d785615808845823875868Richard Purdie * @ops: the backlight operations structure. 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 284655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie * Creates and registers new backlight device. Returns either an 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ERR_PTR() or a pointer to the newly allocated device. 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 287519ab5f2be65b72cf12ae99c89752bbe79b44df6Yu Lumingstruct backlight_device *backlight_device_register(const char *name, 288a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett struct device *parent, void *devdata, const struct backlight_ops *ops, 289a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett const struct backlight_properties *props) 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct backlight_device *new_bd; 292655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie int rc; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 294655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie pr_debug("backlight_device_register: name=%s\n", name); 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 296599a52d12629394236d785615808845823875868Richard Purdie new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL); 29790968e8ebc4611896ff7f2ef0c0bf8455e845cd1Dmitry Torokhov if (!new_bd) 29810ad1b7363090c0eec2b4054a5a3b82d2cc09ee5Jean Delvare return ERR_PTR(-ENOMEM); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30028ee086d5b36aab2931f6740e409bb0fb6c65e5fRichard Purdie mutex_init(&new_bd->update_lock); 301599a52d12629394236d785615808845823875868Richard Purdie mutex_init(&new_bd->ops_lock); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 303655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie new_bd->dev.class = backlight_class; 304655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie new_bd->dev.parent = parent; 305655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie new_bd->dev.release = bl_device_release; 30664dba9a9a33ec9ba00b0a504562d9f692ae89884Kay Sievers dev_set_name(&new_bd->dev, name); 307655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie dev_set_drvdata(&new_bd->dev, devdata); 308655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie 309a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett /* Set default properties */ 310bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett if (props) { 311a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett memcpy(&new_bd->props, props, 312a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett sizeof(struct backlight_properties)); 313bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett if (props->type <= 0 || props->type >= BACKLIGHT_TYPE_MAX) { 314bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett WARN(1, "%s: invalid backlight type", name); 315bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett new_bd->props.type = BACKLIGHT_RAW; 316bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett } 317bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett } else { 318bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett new_bd->props.type = BACKLIGHT_RAW; 319bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett } 320a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett 321655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie rc = device_register(&new_bd->dev); 32290968e8ebc4611896ff7f2ef0c0bf8455e845cd1Dmitry Torokhov if (rc) { 3232fd5a15489dd2e58009ffd4ecbadb36a40f67d2bDmitry Torokhov kfree(new_bd); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(rc); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3273d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons rc = backlight_register_fb(new_bd); 3282fd5a15489dd2e58009ffd4ecbadb36a40f67d2bDmitry Torokhov if (rc) { 329655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie device_unregister(&new_bd->dev); 3302fd5a15489dd2e58009ffd4ecbadb36a40f67d2bDmitry Torokhov return ERR_PTR(rc); 3312fd5a15489dd2e58009ffd4ecbadb36a40f67d2bDmitry Torokhov } 3322fd5a15489dd2e58009ffd4ecbadb36a40f67d2bDmitry Torokhov 333655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie new_bd->ops = ops; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 335321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie#ifdef CONFIG_PMAC_BACKLIGHT 336321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie mutex_lock(&pmac_backlight_mutex); 337321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie if (!pmac_backlight) 338321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie pmac_backlight = new_bd; 339321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie mutex_unlock(&pmac_backlight_mutex); 340321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie#endif 341321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return new_bd; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(backlight_device_register); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * backlight_device_unregister - unregisters a backlight device object. 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bd: the backlight device object to be unregistered and freed. 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unregisters a previously registered via backlight_device_register object. 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid backlight_device_unregister(struct backlight_device *bd) 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bd) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 357321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie#ifdef CONFIG_PMAC_BACKLIGHT 358321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie mutex_lock(&pmac_backlight_mutex); 359321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie if (pmac_backlight == bd) 360321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie pmac_backlight = NULL; 361321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie mutex_unlock(&pmac_backlight_mutex); 362321709c5994f952b78d567fd7083dbebbdc381b7Richard Purdie#endif 363599a52d12629394236d785615808845823875868Richard Purdie mutex_lock(&bd->ops_lock); 364599a52d12629394236d785615808845823875868Richard Purdie bd->ops = NULL; 365599a52d12629394236d785615808845823875868Richard Purdie mutex_unlock(&bd->ops_lock); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3673d5eeaddad9338f39d25ee0c6c2ab1eda1ed2ef6James Simmons backlight_unregister_fb(bd); 368655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie device_unregister(&bd->dev); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(backlight_device_unregister); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit backlight_class_exit(void) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 374655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie class_destroy(backlight_class); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init backlight_class_init(void) 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 379655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie backlight_class = class_create(THIS_MODULE, "backlight"); 380655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie if (IS_ERR(backlight_class)) { 381655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n", 382655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie PTR_ERR(backlight_class)); 383655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie return PTR_ERR(backlight_class); 384655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie } 385655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie 386655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie backlight_class->dev_attrs = bl_device_attributes; 387c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie backlight_class->suspend = backlight_suspend; 388c835ee7f4154992e6cf0674d7ee136f5d36247a4Richard Purdie backlight_class->resume = backlight_resume; 389655bfd7aebb12481ab9275284d9500bee5ba3e70Richard Purdie return 0; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if this is compiled into the kernel, we need to ensure that the 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * class is registered before users of the class try to register lcd's 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldspostcore_initcall(backlight_class_init); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(backlight_class_exit); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>"); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Backlight Lowlevel Control Abstraction"); 402