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 {
struct i2c_client i2c ;
struct wf_sensor sens ;
} ;
# define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens)
# define i2c_to_6690(x) container_of((x), struct wf_6690_sensor, i2c)
static int wf_max6690_attach ( struct i2c_adapter * adapter ) ;
static int wf_max6690_detach ( struct i2c_client * client ) ;
static struct i2c_driver wf_max6690_driver = {
. driver = {
. name = " wf_max6690 " ,
} ,
. attach_adapter = wf_max6690_attach ,
. detach_client = wf_max6690_detach ,
} ;
static int wf_max6690_get ( struct wf_sensor * sr , s32 * value )
{
struct wf_6690_sensor * max = wf_to_6690 ( sr ) ;
s32 data ;
if ( max - > i2c . adapter = = NULL )
return - ENODEV ;
/* chip gets initialized by firmware */
data = i2c_smbus_read_byte_data ( & max - > i2c , MAX6690_EXTERNAL_TEMP ) ;
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 ) ;
if ( max - > i2c . adapter ) {
i2c_detach_client ( & max - > i2c ) ;
max - > i2c . adapter = NULL ;
}
kfree ( max ) ;
}
static struct wf_sensor_ops wf_max6690_ops = {
. get_value = wf_max6690_get ,
. release = wf_max6690_release ,
. owner = THIS_MODULE ,
} ;
static void wf_max6690_create ( struct i2c_adapter * adapter , u8 addr )
{
struct wf_6690_sensor * max ;
2006-03-03 09:03:21 +03:00
char * name = " backside-temp " ;
2006-02-08 08:42:51 +03:00
max = kzalloc ( sizeof ( struct wf_6690_sensor ) , GFP_KERNEL ) ;
if ( max = = NULL ) {
printk ( KERN_ERR " windfarm: Couldn't create MAX6690 sensor %s: "
" no memory \n " , name ) ;
return ;
}
max - > sens . ops = & wf_max6690_ops ;
max - > sens . name = name ;
max - > i2c . addr = addr > > 1 ;
max - > i2c . adapter = adapter ;
max - > i2c . driver = & wf_max6690_driver ;
strncpy ( max - > i2c . name , name , I2C_NAME_SIZE - 1 ) ;
if ( i2c_attach_client ( & max - > i2c ) ) {
printk ( KERN_ERR " windfarm: failed to attach MAX6690 sensor \n " ) ;
goto fail ;
}
if ( wf_register_sensor ( & max - > sens ) ) {
i2c_detach_client ( & max - > i2c ) ;
goto fail ;
}
return ;
fail :
kfree ( max ) ;
}
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 ) ;
2006-02-08 08:42:51 +03:00
if ( strcmp ( loc , " BACKSIDE " ) )
continue ;
2006-03-03 09:03:21 +03:00
wf_max6690_create ( adapter , addr ) ;
2006-02-08 08:42:51 +03:00
}
return 0 ;
}
static int wf_max6690_detach ( struct i2c_client * client )
{
struct wf_6690_sensor * max = i2c_to_6690 ( client ) ;
max - > i2c . adapter = NULL ;
wf_unregister_sensor ( & max - > sens ) ;
return 0 ;
}
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 */
if ( machine_is_compatible ( " PowerMac7,2 " ) | |
machine_is_compatible ( " PowerMac7,3 " ) | |
machine_is_compatible ( " RackMac3,1 " ) )
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 " ) ;