2005-04-17 02:20:36 +04:00
/*
* Backlight Lowlevel Control Abstraction
*
* Copyright ( C ) 2003 , 2004 Hewlett - Packard Company
*
*/
# 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>
2007-02-10 18:04:08 +03:00
# ifdef CONFIG_PMAC_BACKLIGHT
# include <asm/backlight.h>
# endif
2006-12-08 13:40:47 +03:00
# if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
defined ( CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE ) )
/* This callback gets called when something important happens inside a
* framebuffer driver . We ' re looking if that important event is blanking ,
* and if it is , we ' re switching backlight power as well . . .
*/
static int fb_notifier_callback ( struct notifier_block * self ,
unsigned long event , void * data )
{
struct backlight_device * bd ;
struct fb_event * evdata = data ;
/* If we aren't interested in this event, skip it immediately ... */
2007-02-09 12:46:45 +03:00
if ( event ! = FB_EVENT_BLANK & & event ! = FB_EVENT_CONBLANK )
2006-12-08 13:40:47 +03:00
return 0 ;
bd = container_of ( self , struct backlight_device , fb_notif ) ;
2007-02-11 02:07:48 +03:00
mutex_lock ( & bd - > ops_lock ) ;
if ( bd - > ops )
if ( ! bd - > ops - > check_fb | |
bd - > ops - > check_fb ( evdata - > info ) ) {
bd - > props . fb_blank = * ( int * ) evdata - > data ;
2009-01-07 00:00:19 +03:00
if ( bd - > props . fb_blank = = FB_BLANK_UNBLANK )
bd - > props . state & = ~ BL_CORE_FBBLANK ;
else
bd - > props . state | = BL_CORE_FBBLANK ;
2007-02-09 01:25:09 +03:00
backlight_update_status ( bd ) ;
2006-12-08 13:40:47 +03:00
}
2007-02-11 02:07:48 +03:00
mutex_unlock ( & bd - > ops_lock ) ;
2006-12-08 13:40:47 +03:00
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 )
{
}
# endif /* CONFIG_FB */
2007-07-09 15:17:24 +04:00
static ssize_t backlight_show_power ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-07-09 15:17:24 +04:00
struct backlight_device * bd = to_backlight_device ( dev ) ;
2005-04-17 02:20:36 +04:00
2007-02-11 02:07:48 +03:00
return sprintf ( buf , " %d \n " , bd - > props . power ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-09 15:17:24 +04:00
static ssize_t backlight_store_power ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2008-12-03 11:43:48 +03:00
int rc ;
2007-07-09 15:17:24 +04:00
struct backlight_device * bd = to_backlight_device ( dev ) ;
2008-12-03 11:43:48 +03:00
unsigned long power ;
2005-04-17 02:20:36 +04:00
2008-12-03 11:43:48 +03:00
rc = strict_strtoul ( buf , 0 , & power ) ;
if ( rc )
return rc ;
2005-04-17 02:20:36 +04:00
2008-12-03 11:43:48 +03:00
rc = - ENXIO ;
2007-02-11 02:07:48 +03:00
mutex_lock ( & bd - > ops_lock ) ;
if ( bd - > ops ) {
2008-12-03 11:43:48 +03:00
pr_debug ( " backlight: set power to %lu \n " , power ) ;
2008-01-14 02:01:13 +03:00
if ( bd - > props . power ! = power ) {
bd - > props . power = power ;
backlight_update_status ( bd ) ;
}
2005-04-17 02:20:36 +04:00
rc = count ;
2006-03-31 14:31:49 +04:00
}
2007-02-11 02:07:48 +03:00
mutex_unlock ( & bd - > ops_lock ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
2007-07-09 15:17:24 +04:00
static ssize_t backlight_show_brightness ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-07-09 15:17:24 +04:00
struct backlight_device * bd = to_backlight_device ( dev ) ;
2005-04-17 02:20:36 +04:00
2007-02-11 02:07:48 +03:00
return sprintf ( buf , " %d \n " , bd - > props . brightness ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-09 15:17:24 +04:00
static ssize_t backlight_store_brightness ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2008-12-03 11:43:48 +03:00
int rc ;
2007-07-09 15:17:24 +04:00
struct backlight_device * bd = to_backlight_device ( dev ) ;
2008-12-03 11:43:48 +03:00
unsigned long brightness ;
2005-04-17 02:20:36 +04:00
2008-12-03 11:43:48 +03:00
rc = strict_strtoul ( buf , 0 , & brightness ) ;
if ( rc )
return rc ;
rc = - ENXIO ;
2005-04-17 02:20:36 +04:00
2007-02-11 02:07:48 +03:00
mutex_lock ( & bd - > ops_lock ) ;
if ( bd - > ops ) {
if ( brightness > bd - > props . max_brightness )
2006-03-31 14:31:49 +04:00
rc = - EINVAL ;
else {
2008-12-03 11:43:48 +03:00
pr_debug ( " backlight: set brightness to %lu \n " ,
2006-03-31 14:31:49 +04:00
brightness ) ;
2009-01-08 17:11:30 +03:00
bd - > props . brightness = brightness ;
backlight_update_status ( bd ) ;
2006-03-31 14:31:49 +04:00
rc = count ;
}
}
2007-02-11 02:07:48 +03:00
mutex_unlock ( & bd - > ops_lock ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
2007-07-09 15:17:24 +04:00
static ssize_t backlight_show_max_brightness ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-07-09 15:17:24 +04:00
struct backlight_device * bd = to_backlight_device ( dev ) ;
2005-04-17 02:20:36 +04:00
2007-02-11 02:07:48 +03:00
return sprintf ( buf , " %d \n " , bd - > props . max_brightness ) ;
2006-03-31 14:31:49 +04:00
}
2007-07-09 15:17:24 +04:00
static ssize_t backlight_show_actual_brightness ( struct device * dev ,
struct device_attribute * attr , char * buf )
2006-03-31 14:31:49 +04:00
{
int rc = - ENXIO ;
2007-07-09 15:17:24 +04:00
struct backlight_device * bd = to_backlight_device ( dev ) ;
2006-03-31 14:31:49 +04:00
2007-02-11 02:07:48 +03:00
mutex_lock ( & bd - > ops_lock ) ;
if ( bd - > ops & & bd - > ops - > get_brightness )
rc = sprintf ( buf , " %d \n " , bd - > ops - > get_brightness ( bd ) ) ;
mutex_unlock ( & bd - > ops_lock ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
2007-08-11 13:27:19 +04:00
static struct class * backlight_class ;
2007-07-09 15:17:24 +04:00
2009-01-07 00:00:19 +03:00
static int backlight_suspend ( struct device * dev , pm_message_t state )
{
struct backlight_device * bd = to_backlight_device ( dev ) ;
if ( bd - > ops - > options & BL_CORE_SUSPENDRESUME ) {
mutex_lock ( & bd - > ops_lock ) ;
bd - > props . state | = BL_CORE_SUSPENDED ;
backlight_update_status ( bd ) ;
mutex_unlock ( & bd - > ops_lock ) ;
}
return 0 ;
}
static int backlight_resume ( struct device * dev )
{
struct backlight_device * bd = to_backlight_device ( dev ) ;
if ( bd - > ops - > options & BL_CORE_SUSPENDRESUME ) {
mutex_lock ( & bd - > ops_lock ) ;
bd - > props . state & = ~ BL_CORE_SUSPENDED ;
backlight_update_status ( bd ) ;
mutex_unlock ( & bd - > ops_lock ) ;
}
return 0 ;
}
2007-07-09 15:17:24 +04:00
static void bl_device_release ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
struct backlight_device * bd = to_backlight_device ( dev ) ;
kfree ( bd ) ;
}
2007-07-09 15:17:24 +04:00
static struct device_attribute bl_device_attributes [ ] = {
__ATTR ( bl_power , 0644 , backlight_show_power , backlight_store_power ) ,
__ATTR ( brightness , 0644 , backlight_show_brightness ,
2006-03-31 14:31:49 +04:00
backlight_store_brightness ) ,
2007-07-09 15:17:24 +04:00
__ATTR ( actual_brightness , 0444 , backlight_show_actual_brightness ,
2006-03-31 14:31:49 +04:00
NULL ) ,
2007-07-09 15:17:24 +04:00
__ATTR ( max_brightness , 0444 , backlight_show_max_brightness , NULL ) ,
__ATTR_NULL ,
2005-04-17 02:20:36 +04:00
} ;
/**
* backlight_device_register - create and register a new object of
* backlight_device class .
* @ name : the name of the new object ( must be the same as the name of the
* respective framebuffer device ) .
2008-07-17 02:05:49 +04:00
* @ parent : a pointer to the parent device
2007-07-09 15:17:24 +04:00
* @ devdata : an optional pointer to be stored for private driver use . The
* methods may retrieve it by using bl_get_data ( bd ) .
2007-02-11 02:07:48 +03:00
* @ ops : the backlight operations structure .
2005-04-17 02:20:36 +04:00
*
2007-07-09 15:17:24 +04:00
* Creates and registers new backlight device . Returns either an
2005-04-17 02:20:36 +04:00
* ERR_PTR ( ) or a pointer to the newly allocated device .
*/
2006-12-19 23:56:15 +03:00
struct backlight_device * backlight_device_register ( const char * name ,
2007-07-09 15:17:24 +04:00
struct device * parent , void * devdata , struct backlight_ops * ops )
2005-04-17 02:20:36 +04:00
{
struct backlight_device * new_bd ;
2007-07-09 15:17:24 +04:00
int rc ;
2005-04-17 02:20:36 +04:00
2007-07-09 15:17:24 +04:00
pr_debug ( " backlight_device_register: name=%s \n " , name ) ;
2005-04-17 02:20:36 +04:00
2007-02-11 02:07:48 +03:00
new_bd = kzalloc ( sizeof ( struct backlight_device ) , GFP_KERNEL ) ;
2007-02-08 03:12:28 +03:00
if ( ! new_bd )
2006-03-10 04:33:36 +03:00
return ERR_PTR ( - ENOMEM ) ;
2005-04-17 02:20:36 +04:00
2007-02-09 01:25:09 +03:00
mutex_init ( & new_bd - > update_lock ) ;
2007-02-11 02:07:48 +03:00
mutex_init ( & new_bd - > ops_lock ) ;
2005-04-17 02:20:36 +04:00
2007-07-09 15:17:24 +04:00
new_bd - > dev . class = backlight_class ;
new_bd - > dev . parent = parent ;
new_bd - > dev . release = bl_device_release ;
2009-01-06 21:44:35 +03:00
dev_set_name ( & new_bd - > dev , name ) ;
2007-07-09 15:17:24 +04:00
dev_set_drvdata ( & new_bd - > dev , devdata ) ;
rc = device_register ( & new_bd - > dev ) ;
2007-02-08 03:12:28 +03:00
if ( rc ) {
2007-02-08 01:25:50 +03:00
kfree ( new_bd ) ;
2005-04-17 02:20:36 +04:00
return ERR_PTR ( rc ) ;
}
2006-12-08 13:40:47 +03:00
rc = backlight_register_fb ( new_bd ) ;
2007-02-08 01:25:50 +03:00
if ( rc ) {
2007-07-09 15:17:24 +04:00
device_unregister ( & new_bd - > dev ) ;
2007-02-08 01:25:50 +03:00
return ERR_PTR ( rc ) ;
}
2007-07-09 15:17:24 +04:00
new_bd - > ops = ops ;
2005-04-17 02:20:36 +04:00
2007-02-10 18:04:08 +03:00
# ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock ( & pmac_backlight_mutex ) ;
if ( ! pmac_backlight )
pmac_backlight = new_bd ;
mutex_unlock ( & pmac_backlight_mutex ) ;
# endif
2005-04-17 02:20:36 +04:00
return new_bd ;
}
EXPORT_SYMBOL ( backlight_device_register ) ;
/**
* backlight_device_unregister - unregisters a backlight device object .
* @ bd : the backlight device object to be unregistered and freed .
*
* Unregisters a previously registered via backlight_device_register object .
*/
void backlight_device_unregister ( struct backlight_device * bd )
{
if ( ! bd )
return ;
2007-02-10 18:04:08 +03:00
# ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock ( & pmac_backlight_mutex ) ;
if ( pmac_backlight = = bd )
pmac_backlight = NULL ;
mutex_unlock ( & pmac_backlight_mutex ) ;
# endif
2007-02-11 02:07:48 +03:00
mutex_lock ( & bd - > ops_lock ) ;
bd - > ops = NULL ;
mutex_unlock ( & bd - > ops_lock ) ;
2005-04-17 02:20:36 +04:00
2006-12-08 13:40:47 +03:00
backlight_unregister_fb ( bd ) ;
2007-07-09 15:17:24 +04:00
device_unregister ( & bd - > dev ) ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( backlight_device_unregister ) ;
static void __exit backlight_class_exit ( void )
{
2007-07-09 15:17:24 +04:00
class_destroy ( backlight_class ) ;
2005-04-17 02:20:36 +04:00
}
static int __init backlight_class_init ( void )
{
2007-07-09 15:17:24 +04:00
backlight_class = class_create ( THIS_MODULE , " backlight " ) ;
if ( IS_ERR ( backlight_class ) ) {
printk ( KERN_WARNING " Unable to create backlight class; errno = %ld \n " ,
PTR_ERR ( backlight_class ) ) ;
return PTR_ERR ( backlight_class ) ;
}
backlight_class - > dev_attrs = bl_device_attributes ;
2009-01-07 00:00:19 +03:00
backlight_class - > suspend = backlight_suspend ;
backlight_class - > resume = backlight_resume ;
2007-07-09 15:17:24 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
* 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 " ) ;