2005-11-07 08:08:17 +03:00
/*
* Windfarm PowerMac thermal control . LM75 sensor
*
* ( c ) Copyright 2005 Benjamin Herrenschmidt , IBM Corp .
* < benh @ kernel . crashing . org >
*
* Released under the term of the GNU GPL v2 .
*/
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/wait.h>
# include <linux/i2c.h>
# include <asm/prom.h>
# include <asm/machdep.h>
# include <asm/io.h>
# include <asm/sections.h>
2006-01-07 03:35:26 +03:00
# include <asm/pmac_low_i2c.h>
2005-11-07 08:08:17 +03:00
# include "windfarm.h"
2012-04-19 02:16:44 +04:00
# define VERSION "1.0"
2005-11-07 08:08:17 +03:00
# undef DEBUG
# ifdef DEBUG
# define DBG(args...) printk(args)
# else
# define DBG(args...) do { } while(0)
# endif
struct wf_lm75_sensor {
int ds1775 : 1 ;
int inited : 1 ;
2012-04-19 02:16:44 +04:00
struct i2c_client * i2c ;
struct wf_sensor sens ;
2005-11-07 08:08:17 +03:00
} ;
# define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
static int wf_lm75_get ( struct wf_sensor * sr , s32 * value )
{
struct wf_lm75_sensor * lm = wf_to_lm75 ( sr ) ;
s32 data ;
2009-06-15 20:01:51 +04:00
if ( lm - > i2c = = NULL )
2005-11-07 08:08:17 +03:00
return - ENODEV ;
/* Init chip if necessary */
if ( ! lm - > inited ) {
2009-06-15 20:01:51 +04:00
u8 cfg_new , cfg = ( u8 ) i2c_smbus_read_byte_data ( lm - > i2c , 1 ) ;
2005-11-07 08:08:17 +03:00
DBG ( " wf_lm75: Initializing %s, cfg was: %02x \n " ,
sr - > name , cfg ) ;
/* clear shutdown bit, keep other settings as left by
* the firmware for now
*/
cfg_new = cfg & ~ 0x01 ;
2009-06-15 20:01:51 +04:00
i2c_smbus_write_byte_data ( lm - > i2c , 1 , cfg_new ) ;
2005-11-07 08:08:17 +03:00
lm - > inited = 1 ;
/* If we just powered it up, let's wait 200 ms */
msleep ( 200 ) ;
}
/* Read temperature register */
2009-06-15 20:01:51 +04:00
data = ( s32 ) le16_to_cpu ( i2c_smbus_read_word_data ( lm - > i2c , 0 ) ) ;
2005-11-07 08:08:17 +03:00
data < < = 8 ;
* value = data ;
return 0 ;
}
static void wf_lm75_release ( struct wf_sensor * sr )
{
struct wf_lm75_sensor * lm = wf_to_lm75 ( sr ) ;
kfree ( lm ) ;
}
static struct wf_sensor_ops wf_lm75_ops = {
. get_value = wf_lm75_get ,
. release = wf_lm75_release ,
. owner = THIS_MODULE ,
} ;
2009-06-15 20:01:51 +04:00
static int wf_lm75_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2012-04-19 02:16:44 +04:00
{
2005-11-07 08:08:17 +03:00
struct wf_lm75_sensor * lm ;
2012-04-19 02:16:44 +04:00
int rc , ds1775 = id - > driver_data ;
const char * name , * loc ;
2009-06-15 20:01:51 +04:00
DBG ( " wf_lm75: creating %s device at address 0x%02x \n " ,
2012-04-19 02:16:44 +04:00
ds1775 ? " ds1775 " : " lm75 " , client - > addr ) ;
loc = of_get_property ( client - > dev . of_node , " hwsensor-location " , NULL ) ;
if ( ! loc ) {
dev_warn ( & client - > dev , " Missing hwsensor-location property! \n " ) ;
return - ENXIO ;
}
2005-11-07 08:08:17 +03:00
/* Usual rant about sensor names not beeing very consistent in
* the device - tree , oh well . . .
* Add more entries below as you deal with more setups
*/
if ( ! strcmp ( loc , " Hard drive " ) | | ! strcmp ( loc , " DRIVE BAY " ) )
2009-06-15 20:01:51 +04:00
name = " hd-temp " ;
2008-04-29 09:39:55 +04:00
else if ( ! strcmp ( loc , " Incoming Air Temp " ) )
2009-06-15 20:01:51 +04:00
name = " incoming-air-temp " ;
2008-04-29 09:39:55 +04:00
else if ( ! strcmp ( loc , " ODD Temp " ) )
2009-06-15 20:01:51 +04:00
name = " optical-drive-temp " ;
2008-04-29 09:39:55 +04:00
else if ( ! strcmp ( loc , " HD Temp " ) )
2009-06-15 20:01:51 +04:00
name = " hard-drive-temp " ;
2012-04-19 02:16:54 +04:00
else if ( ! strcmp ( loc , " PCI SLOTS " ) )
name = " slots-temp " ;
else if ( ! strcmp ( loc , " CPU A INLET " ) )
name = " cpu-inlet-temp-0 " ;
else if ( ! strcmp ( loc , " CPU B INLET " ) )
name = " cpu-inlet-temp-1 " ;
2005-11-07 08:08:17 +03:00
else
2012-04-19 02:16:44 +04:00
return - ENXIO ;
2005-11-07 08:08:17 +03:00
2012-04-19 02:16:44 +04:00
lm = kzalloc ( sizeof ( struct wf_lm75_sensor ) , GFP_KERNEL ) ;
if ( lm = = NULL )
2006-01-07 03:35:26 +03:00
return - ENODEV ;
2005-11-07 08:08:17 +03:00
2012-04-19 02:16:44 +04:00
lm - > inited = 0 ;
lm - > ds1775 = ds1775 ;
lm - > i2c = client ;
2013-11-12 23:07:14 +04:00
lm - > sens . name = name ;
2012-04-19 02:16:44 +04:00
lm - > sens . ops = & wf_lm75_ops ;
i2c_set_clientdata ( client , lm ) ;
2006-03-03 09:03:21 +03:00
2012-04-19 02:16:44 +04:00
rc = wf_register_sensor ( & lm - > sens ) ;
if ( rc )
kfree ( lm ) ;
return rc ;
2005-11-07 08:08:17 +03:00
}
2009-06-15 20:01:51 +04:00
static int wf_lm75_remove ( struct i2c_client * client )
2005-11-07 08:08:17 +03:00
{
2009-06-15 20:01:51 +04:00
struct wf_lm75_sensor * lm = i2c_get_clientdata ( client ) ;
2005-11-07 08:08:17 +03:00
DBG ( " wf_lm75: i2c detatch called for %s \n " , lm - > sens . name ) ;
/* Mark client detached */
2009-06-15 20:01:51 +04:00
lm - > i2c = NULL ;
2005-11-07 08:08:17 +03:00
/* release sensor */
wf_unregister_sensor ( & lm - > sens ) ;
return 0 ;
}
2009-06-15 20:01:51 +04:00
static const struct i2c_device_id wf_lm75_id [ ] = {
2012-04-19 02:16:44 +04:00
{ " MAC,lm75 " , 0 } ,
{ " MAC,ds1775 " , 1 } ,
2009-06-15 20:01:51 +04:00
{ }
} ;
2012-04-19 02:16:44 +04:00
MODULE_DEVICE_TABLE ( i2c , wf_lm75_id ) ;
2009-06-15 20:01:51 +04:00
static struct i2c_driver wf_lm75_driver = {
. driver = {
. name = " wf_lm75 " ,
} ,
. probe = wf_lm75_probe ,
. remove = wf_lm75_remove ,
. id_table = wf_lm75_id ,
} ;
2012-10-08 07:00:04 +04:00
module_i2c_driver ( wf_lm75_driver ) ;
2005-11-07 08:08:17 +03:00
MODULE_AUTHOR ( " Benjamin Herrenschmidt <benh@kernel.crashing.org> " ) ;
MODULE_DESCRIPTION ( " LM75 sensor objects for PowerMacs thermal control " ) ;
MODULE_LICENSE ( " GPL " ) ;