2006-02-08 08:42:51 +03:00
/*
* Windfarm PowerMac thermal control . MAX6690 sensor .
*
* Copyright ( C ) 2005 Paul Mackerras , IBM Corp . < paulus @ samba . org >
*
* Use and redistribute under the terms of the GNU GPL v2 .
*/
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <asm/prom.h>
# include <asm/pmac_low_i2c.h>
# include "windfarm.h"
2006-03-03 09:03:21 +03:00
# define VERSION "0.2"
2006-02-08 08:42:51 +03:00
/* This currently only exports the external temperature sensor,
since that ' s all the control loops need . */
/* Some MAX6690 register numbers */
# define MAX6690_INTERNAL_TEMP 0
# define MAX6690_EXTERNAL_TEMP 1
struct wf_6690_sensor {
2009-06-15 20:01:51 +04:00
struct i2c_client * i2c ;
2006-02-08 08:42:51 +03:00
struct wf_sensor sens ;
} ;
# define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens)
static int wf_max6690_get ( struct wf_sensor * sr , s32 * value )
{
struct wf_6690_sensor * max = wf_to_6690 ( sr ) ;
s32 data ;
2009-06-15 20:01:51 +04:00
if ( max - > i2c = = NULL )
2006-02-08 08:42:51 +03:00
return - ENODEV ;
/* chip gets initialized by firmware */
2009-06-15 20:01:51 +04:00
data = i2c_smbus_read_byte_data ( max - > i2c , MAX6690_EXTERNAL_TEMP ) ;
2006-02-08 08:42:51 +03:00
if ( data < 0 )
return data ;
* value = data < < 16 ;
return 0 ;
}
static void wf_max6690_release ( struct wf_sensor * sr )
{
struct wf_6690_sensor * max = wf_to_6690 ( sr ) ;
kfree ( max ) ;
}
static struct wf_sensor_ops wf_max6690_ops = {
. get_value = wf_max6690_get ,
. release = wf_max6690_release ,
. owner = THIS_MODULE ,
} ;
2009-06-15 20:01:51 +04:00
static int wf_max6690_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2006-02-08 08:42:51 +03:00
{
struct wf_6690_sensor * max ;
2009-06-15 20:01:51 +04:00
int rc ;
2006-02-08 08:42:51 +03:00
max = kzalloc ( sizeof ( struct wf_6690_sensor ) , GFP_KERNEL ) ;
if ( max = = NULL ) {
2009-06-15 20:01:51 +04:00
printk ( KERN_ERR " windfarm: Couldn't create MAX6690 sensor: "
" no memory \n " ) ;
return - ENOMEM ;
}
max - > i2c = client ;
max - > sens . name = client - > dev . platform_data ;
max - > sens . ops = & wf_max6690_ops ;
i2c_set_clientdata ( client , max ) ;
rc = wf_register_sensor ( & max - > sens ) ;
if ( rc ) {
kfree ( max ) ;
2006-02-08 08:42:51 +03:00
}
2009-06-15 20:01:51 +04:00
return rc ;
}
2009-10-05 00:53:46 +04:00
static struct i2c_driver wf_max6690_driver ;
2009-06-15 20:01:51 +04:00
static struct i2c_client * wf_max6690_create ( struct i2c_adapter * adapter ,
u8 addr , const char * loc )
{
struct i2c_board_info info ;
struct i2c_client * client ;
char * name ;
2008-04-29 09:39:55 +04:00
if ( ! strcmp ( loc , " BACKSIDE " ) )
name = " backside-temp " ;
else if ( ! strcmp ( loc , " NB Ambient " ) )
name = " north-bridge-temp " ;
else if ( ! strcmp ( loc , " GPU Ambient " ) )
name = " gpu-temp " ;
else
goto fail ;
2009-06-15 20:01:51 +04:00
memset ( & info , 0 , sizeof ( struct i2c_board_info ) ) ;
info . addr = addr > > 1 ;
info . platform_data = name ;
strlcpy ( info . type , " wf_max6690 " , I2C_NAME_SIZE ) ;
2006-02-08 08:42:51 +03:00
2009-06-15 20:01:51 +04:00
client = i2c_new_device ( adapter , & info ) ;
if ( client = = NULL ) {
2006-02-08 08:42:51 +03:00
printk ( KERN_ERR " windfarm: failed to attach MAX6690 sensor \n " ) ;
goto fail ;
}
2009-06-15 20:01:51 +04:00
/*
* Let i2c - core delete that device on driver removal .
* This is safe because i2c - core holds the core_lock mutex for us .
*/
2009-10-05 00:53:46 +04:00
list_add_tail ( & client - > detected , & wf_max6690_driver . clients ) ;
2009-06-15 20:01:51 +04:00
return client ;
2006-02-08 08:42:51 +03:00
fail :
2009-06-15 20:01:51 +04:00
return NULL ;
2006-02-08 08:42:51 +03:00
}
static int wf_max6690_attach ( struct i2c_adapter * adapter )
{
struct device_node * busnode , * dev = NULL ;
struct pmac_i2c_bus * bus ;
const char * loc ;
bus = pmac_i2c_adapter_to_bus ( adapter ) ;
if ( bus = = NULL )
return - ENODEV ;
busnode = pmac_i2c_get_bus_node ( bus ) ;
while ( ( dev = of_get_next_child ( busnode , dev ) ) ! = NULL ) {
2006-03-03 09:03:21 +03:00
u8 addr ;
/* We must re-match the adapter in order to properly check
* the channel on multibus setups
*/
if ( ! pmac_i2c_match_adapter ( dev , adapter ) )
continue ;
2007-05-03 11:26:52 +04:00
if ( ! of_device_is_compatible ( dev , " max6690 " ) )
2006-02-08 08:42:51 +03:00
continue ;
2006-03-03 09:03:21 +03:00
addr = pmac_i2c_get_dev_addr ( dev ) ;
2007-04-27 07:41:15 +04:00
loc = of_get_property ( dev , " hwsensor-location " , NULL ) ;
2006-03-03 09:03:21 +03:00
if ( loc = = NULL | | addr = = 0 )
2006-02-08 08:42:51 +03:00
continue ;
2006-03-03 09:03:21 +03:00
printk ( " found max6690, loc=%s addr=0x%02x \n " , loc , addr ) ;
2008-04-29 09:39:55 +04:00
wf_max6690_create ( adapter , addr , loc ) ;
2006-02-08 08:42:51 +03:00
}
return 0 ;
}
2009-06-15 20:01:51 +04:00
static int wf_max6690_remove ( struct i2c_client * client )
2006-02-08 08:42:51 +03:00
{
2009-06-15 20:01:51 +04:00
struct wf_6690_sensor * max = i2c_get_clientdata ( client ) ;
2006-02-08 08:42:51 +03:00
2009-06-15 20:01:51 +04:00
max - > i2c = NULL ;
2006-02-08 08:42:51 +03:00
wf_unregister_sensor ( & max - > sens ) ;
return 0 ;
}
2009-06-15 20:01:51 +04:00
static const struct i2c_device_id wf_max6690_id [ ] = {
{ " wf_max6690 " , 0 } ,
{ }
} ;
static struct i2c_driver wf_max6690_driver = {
. driver = {
. name = " wf_max6690 " ,
} ,
. attach_adapter = wf_max6690_attach ,
. probe = wf_max6690_probe ,
. remove = wf_max6690_remove ,
. id_table = wf_max6690_id ,
} ;
2006-02-08 08:42:51 +03:00
static int __init wf_max6690_sensor_init ( void )
{
2006-03-03 09:03:21 +03:00
/* Don't register on old machines that use therm_pm72 for now */
2010-02-02 07:34:14 +03:00
if ( of_machine_is_compatible ( " PowerMac7,2 " ) | |
of_machine_is_compatible ( " PowerMac7,3 " ) | |
of_machine_is_compatible ( " RackMac3,1 " ) )
2006-03-03 09:03:21 +03:00
return - ENODEV ;
2006-02-08 08:42:51 +03:00
return i2c_add_driver ( & wf_max6690_driver ) ;
}
static void __exit wf_max6690_sensor_exit ( void )
{
i2c_del_driver ( & wf_max6690_driver ) ;
}
module_init ( wf_max6690_sensor_init ) ;
module_exit ( wf_max6690_sensor_exit ) ;
MODULE_AUTHOR ( " Paul Mackerras <paulus@samba.org> " ) ;
MODULE_DESCRIPTION ( " MAX6690 sensor objects for PowerMac thermal control " ) ;
MODULE_LICENSE ( " GPL " ) ;