2005-04-16 15:20:36 -07:00
/*
* acpi_fan . c - ACPI Fan Driver ( $ Revision : 29 $ )
*
* Copyright ( C ) 2001 , 2002 Andy Grover < andrew . grover @ intel . com >
* Copyright ( C ) 2001 , 2002 Paul Diefenbaugh < paul . s . diefenbaugh @ intel . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or ( at
* your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA .
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/types.h>
# include <asm/uaccess.h>
2008-01-17 15:51:24 +08:00
# include <linux/thermal.h>
2005-04-16 15:20:36 -07:00
# include <acpi/acpi_bus.h>
# include <acpi/acpi_drivers.h>
2009-07-28 16:45:54 -04:00
# define PREFIX "ACPI: "
2005-04-16 15:20:36 -07:00
# define ACPI_FAN_CLASS "fan"
# define ACPI_FAN_FILE_STATE "state"
# define _COMPONENT ACPI_FAN_COMPONENT
2007-02-12 22:42:12 -05:00
ACPI_MODULE_NAME ( " fan " ) ;
2005-04-16 15:20:36 -07:00
2007-02-12 22:42:12 -05:00
MODULE_AUTHOR ( " Paul Diefenbaugh " ) ;
2007-02-12 23:50:02 -05:00
MODULE_DESCRIPTION ( " ACPI Fan Driver " ) ;
2005-04-16 15:20:36 -07:00
MODULE_LICENSE ( " GPL " ) ;
2005-08-05 00:44:28 -04:00
static int acpi_fan_add ( struct acpi_device * device ) ;
2013-01-24 00:24:48 +01:00
static int acpi_fan_remove ( struct acpi_device * device ) ;
2005-04-16 15:20:36 -07:00
2007-07-23 14:44:41 +02:00
static const struct acpi_device_id fan_device_ids [ ] = {
{ " PNP0C0B " , 0 } ,
{ " " , 0 } ,
} ;
MODULE_DEVICE_TABLE ( acpi , fan_device_ids ) ;
2012-08-09 23:00:02 +02:00
# ifdef CONFIG_PM_SLEEP
2012-06-27 23:26:07 +02:00
static int acpi_fan_suspend ( struct device * dev ) ;
static int acpi_fan_resume ( struct device * dev ) ;
2012-08-09 23:00:02 +02:00
# endif
2012-06-27 23:26:07 +02:00
static SIMPLE_DEV_PM_OPS ( acpi_fan_pm , acpi_fan_suspend , acpi_fan_resume ) ;
2005-04-16 15:20:36 -07:00
static struct acpi_driver acpi_fan_driver = {
2007-02-12 23:33:40 -05:00
. name = " fan " ,
2005-08-05 00:44:28 -04:00
. class = ACPI_FAN_CLASS ,
2007-07-23 14:44:41 +02:00
. ids = fan_device_ids ,
2005-08-05 00:44:28 -04:00
. ops = {
. add = acpi_fan_add ,
. remove = acpi_fan_remove ,
} ,
2012-06-27 23:26:07 +02:00
. drv . pm = & acpi_fan_pm ,
2005-04-16 15:20:36 -07:00
} ;
2008-01-17 15:51:24 +08:00
/* thermal cooling device callbacks */
2008-11-27 17:48:13 +00:00
static int fan_get_max_state ( struct thermal_cooling_device * cdev , unsigned long
* state )
2008-01-17 15:51:24 +08:00
{
/* ACPI fan device only support two states: ON/OFF */
2008-11-27 17:48:13 +00:00
* state = 1 ;
return 0 ;
2008-01-17 15:51:24 +08:00
}
2008-11-27 17:48:13 +00:00
static int fan_get_cur_state ( struct thermal_cooling_device * cdev , unsigned long
* state )
2008-01-17 15:51:24 +08:00
{
struct acpi_device * device = cdev - > devdata ;
int result ;
2013-07-01 19:51:00 +05:30
int acpi_state = ACPI_STATE_D0 ;
2008-01-17 15:51:24 +08:00
if ( ! device )
return - EINVAL ;
2010-11-25 00:11:24 +01:00
result = acpi_bus_update_power ( device - > handle , & acpi_state ) ;
2008-01-17 15:51:24 +08:00
if ( result )
return result ;
2013-07-30 14:36:20 +02:00
* state = ( acpi_state = = ACPI_STATE_D3_COLD ? 0 :
2008-11-27 17:48:13 +00:00
( acpi_state = = ACPI_STATE_D0 ? 1 : - 1 ) ) ;
return 0 ;
2008-01-17 15:51:24 +08:00
}
static int
2008-11-27 17:48:13 +00:00
fan_set_cur_state ( struct thermal_cooling_device * cdev , unsigned long state )
2008-01-17 15:51:24 +08:00
{
struct acpi_device * device = cdev - > devdata ;
int result ;
if ( ! device | | ( state ! = 0 & & state ! = 1 ) )
return - EINVAL ;
result = acpi_bus_set_power ( device - > handle ,
2013-07-30 14:36:20 +02:00
state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD ) ;
2008-01-17 15:51:24 +08:00
return result ;
}
2011-06-25 21:07:52 +04:00
static const struct thermal_cooling_device_ops fan_cooling_ops = {
2008-01-17 15:51:24 +08:00
. get_max_state = fan_get_max_state ,
. get_cur_state = fan_get_cur_state ,
. set_cur_state = fan_set_cur_state ,
} ;
2005-04-16 15:20:36 -07:00
/* --------------------------------------------------------------------------
Driver Interface
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-05 00:44:28 -04:00
static int acpi_fan_add ( struct acpi_device * device )
2005-04-16 15:20:36 -07:00
{
2005-08-05 00:44:28 -04:00
int result = 0 ;
2008-01-17 15:51:24 +08:00
struct thermal_cooling_device * cdev ;
2005-04-16 15:20:36 -07:00
if ( ! device )
2006-06-27 00:41:40 -04:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2005-08-05 00:37:45 -04:00
strcpy ( acpi_device_name ( device ) , " Fan " ) ;
2005-04-16 15:20:36 -07:00
strcpy ( acpi_device_class ( device ) , ACPI_FAN_CLASS ) ;
2010-11-25 00:11:24 +01:00
result = acpi_bus_update_power ( device - > handle , NULL ) ;
2005-04-16 15:20:36 -07:00
if ( result ) {
2010-11-25 00:11:24 +01:00
printk ( KERN_ERR PREFIX " Setting initial power state \n " ) ;
2005-04-16 15:20:36 -07:00
goto end ;
}
2008-01-17 15:51:24 +08:00
cdev = thermal_cooling_device_register ( " Fan " , device ,
& fan_cooling_ops ) ;
2008-02-15 01:01:52 -05:00
if ( IS_ERR ( cdev ) ) {
result = PTR_ERR ( cdev ) ;
goto end ;
}
2008-04-11 10:09:24 +08:00
2009-12-14 13:38:30 -08:00
dev_dbg ( & device - > dev , " registered as cooling_device%d \n " , cdev - > id ) ;
2008-04-11 10:09:24 +08:00
2008-09-22 14:37:34 -07:00
device - > driver_data = cdev ;
2008-04-11 10:09:24 +08:00
result = sysfs_create_link ( & device - > dev . kobj ,
& cdev - > device . kobj ,
" thermal_cooling " ) ;
if ( result )
2008-05-02 06:02:41 +02:00
dev_err ( & device - > dev , " Failed to create sysfs link "
" 'thermal_cooling' \n " ) ;
2008-04-11 10:09:24 +08:00
result = sysfs_create_link ( & cdev - > device . kobj ,
& device - > dev . kobj ,
" device " ) ;
if ( result )
2008-05-02 06:02:41 +02:00
dev_err ( & device - > dev , " Failed to create sysfs link "
" 'device' \n " ) ;
2008-01-17 15:51:24 +08:00
2005-04-16 15:20:36 -07:00
printk ( KERN_INFO PREFIX " %s [%s] (%s) \n " ,
2005-08-05 00:44:28 -04:00
acpi_device_name ( device ) , acpi_device_bid ( device ) ,
! device - > power . state ? " on " : " off " ) ;
2005-04-16 15:20:36 -07:00
2005-08-05 00:44:28 -04:00
end :
2006-06-27 00:41:40 -04:00
return result ;
2005-04-16 15:20:36 -07:00
}
2013-01-24 00:24:48 +01:00
static int acpi_fan_remove ( struct acpi_device * device )
2005-04-16 15:20:36 -07:00
{
2013-03-25 10:50:05 +00:00
struct thermal_cooling_device * cdev ;
if ( ! device )
return - EINVAL ;
2008-01-17 15:51:24 +08:00
2013-03-25 10:50:05 +00:00
cdev = acpi_driver_data ( device ) ;
if ( ! cdev )
2006-06-27 00:41:40 -04:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2008-01-17 15:51:24 +08:00
sysfs_remove_link ( & device - > dev . kobj , " thermal_cooling " ) ;
sysfs_remove_link ( & cdev - > device . kobj , " device " ) ;
thermal_cooling_device_unregister ( cdev ) ;
2005-04-16 15:20:36 -07:00
2006-06-27 00:41:40 -04:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2012-08-09 23:00:02 +02:00
# ifdef CONFIG_PM_SLEEP
2012-06-27 23:26:07 +02:00
static int acpi_fan_suspend ( struct device * dev )
2008-01-23 22:41:20 -05:00
{
2012-06-27 23:26:07 +02:00
if ( ! dev )
2008-01-23 22:41:20 -05:00
return - EINVAL ;
2012-06-27 23:26:07 +02:00
acpi_bus_set_power ( to_acpi_device ( dev ) - > handle , ACPI_STATE_D0 ) ;
2008-01-23 22:41:20 -05:00
return AE_OK ;
}
2012-06-27 23:26:07 +02:00
static int acpi_fan_resume ( struct device * dev )
2008-01-23 22:41:20 -05:00
{
2010-11-25 00:11:24 +01:00
int result ;
2008-01-23 22:41:20 -05:00
2012-06-27 23:26:07 +02:00
if ( ! dev )
2008-01-23 22:41:20 -05:00
return - EINVAL ;
2012-06-27 23:26:07 +02:00
result = acpi_bus_update_power ( to_acpi_device ( dev ) - > handle , NULL ) ;
2010-11-25 00:11:24 +01:00
if ( result )
printk ( KERN_ERR PREFIX " Error updating fan power state \n " ) ;
2008-01-23 22:41:20 -05:00
return result ;
}
2012-08-09 23:00:02 +02:00
# endif
2008-01-23 22:41:20 -05:00
2012-09-07 10:31:40 +03:00
module_acpi_driver ( acpi_fan_driver ) ;