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/system.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"
2006-03-03 09:03:21 +03:00
# define VERSION "0.2"
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 ;
struct i2c_client i2c ;
struct wf_sensor sens ;
} ;
# define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
# define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c)
static int wf_lm75_attach ( struct i2c_adapter * adapter ) ;
static int wf_lm75_detach ( struct i2c_client * client ) ;
static struct i2c_driver wf_lm75_driver = {
2005-11-26 22:40:34 +03:00
. driver = {
. name = " wf_lm75 " ,
} ,
2005-11-07 08:08:17 +03:00
. attach_adapter = wf_lm75_attach ,
. detach_client = wf_lm75_detach ,
} ;
static int wf_lm75_get ( struct wf_sensor * sr , s32 * value )
{
struct wf_lm75_sensor * lm = wf_to_lm75 ( sr ) ;
s32 data ;
if ( lm - > i2c . adapter = = NULL )
return - ENODEV ;
/* Init chip if necessary */
if ( ! lm - > inited ) {
u8 cfg_new , cfg = ( u8 ) i2c_smbus_read_byte_data ( & lm - > i2c , 1 ) ;
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 ;
i2c_smbus_write_byte_data ( & lm - > i2c , 1 , cfg_new ) ;
lm - > inited = 1 ;
/* If we just powered it up, let's wait 200 ms */
msleep ( 200 ) ;
}
/* Read temperature register */
data = ( s32 ) le16_to_cpu ( i2c_smbus_read_word_data ( & lm - > i2c , 0 ) ) ;
data < < = 8 ;
* value = data ;
return 0 ;
}
static void wf_lm75_release ( struct wf_sensor * sr )
{
struct wf_lm75_sensor * lm = wf_to_lm75 ( sr ) ;
/* check if client is registered and detach from i2c */
if ( lm - > i2c . adapter ) {
i2c_detach_client ( & lm - > i2c ) ;
lm - > i2c . adapter = NULL ;
}
kfree ( lm ) ;
}
static struct wf_sensor_ops wf_lm75_ops = {
. get_value = wf_lm75_get ,
. release = wf_lm75_release ,
. owner = THIS_MODULE ,
} ;
static struct wf_lm75_sensor * wf_lm75_create ( struct i2c_adapter * adapter ,
u8 addr , int ds1775 ,
const char * loc )
{
struct wf_lm75_sensor * lm ;
2006-03-03 09:03:21 +03:00
int rc ;
2005-11-07 08:08:17 +03:00
DBG ( " wf_lm75: creating %s device at address 0x%02x \n " ,
ds1775 ? " ds1775 " : " lm75 " , addr ) ;
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 12:49:03 +04:00
lm = kzalloc ( sizeof ( struct wf_lm75_sensor ) , GFP_KERNEL ) ;
2005-11-07 08:08:17 +03:00
if ( lm = = NULL )
return NULL ;
/* 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 " ) )
lm - > sens . name = " hd-temp " ;
else
goto fail ;
lm - > inited = 0 ;
lm - > sens . ops = & wf_lm75_ops ;
lm - > ds1775 = ds1775 ;
lm - > i2c . addr = ( addr > > 1 ) & 0x7f ;
lm - > i2c . adapter = adapter ;
lm - > i2c . driver = & wf_lm75_driver ;
strncpy ( lm - > i2c . name , lm - > sens . name , I2C_NAME_SIZE - 1 ) ;
2006-03-03 09:03:21 +03:00
rc = i2c_attach_client ( & lm - > i2c ) ;
if ( rc ) {
printk ( KERN_ERR " windfarm: failed to attach %s %s to i2c, "
" err %d \n " , ds1775 ? " ds1775 " : " lm75 " ,
lm - > i2c . name , rc ) ;
2005-11-07 08:08:17 +03:00
goto fail ;
}
if ( wf_register_sensor ( & lm - > sens ) ) {
i2c_detach_client ( & lm - > i2c ) ;
goto fail ;
}
return lm ;
fail :
kfree ( lm ) ;
return NULL ;
}
static int wf_lm75_attach ( struct i2c_adapter * adapter )
{
2006-01-07 03:35:26 +03:00
struct device_node * busnode , * dev ;
struct pmac_i2c_bus * bus ;
2005-11-07 08:08:17 +03:00
DBG ( " wf_lm75: adapter %s detected \n " , adapter - > name ) ;
2006-01-07 03:35:26 +03:00
bus = pmac_i2c_adapter_to_bus ( adapter ) ;
if ( bus = = NULL )
return - ENODEV ;
busnode = pmac_i2c_get_bus_node ( bus ) ;
2005-11-07 08:08:17 +03:00
DBG ( " wf_lm75: bus found, looking for device... \n " ) ;
/* Now look for lm75(s) in there */
for ( dev = NULL ;
2006-01-07 03:35:26 +03:00
( dev = of_get_next_child ( busnode , dev ) ) ! = NULL ; ) {
2005-11-07 08:08:17 +03:00
const char * loc =
2007-04-27 07:41:15 +04:00
of_get_property ( dev , " hwsensor-location " , 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 ;
addr = pmac_i2c_get_dev_addr ( dev ) ;
if ( loc = = NULL | | addr = = 0 )
2005-11-07 08:08:17 +03:00
continue ;
/* real lm75 */
2007-05-03 11:26:52 +04:00
if ( of_device_is_compatible ( dev , " lm75 " ) )
2006-03-03 09:03:21 +03:00
wf_lm75_create ( adapter , addr , 0 , loc ) ;
2005-11-07 08:08:17 +03:00
/* ds1775 (compatible, better resolution */
2007-05-03 11:26:52 +04:00
else if ( of_device_is_compatible ( dev , " ds1775 " ) )
2006-03-03 09:03:21 +03:00
wf_lm75_create ( adapter , addr , 1 , loc ) ;
2005-11-07 08:08:17 +03:00
}
return 0 ;
}
static int wf_lm75_detach ( struct i2c_client * client )
{
struct wf_lm75_sensor * lm = i2c_to_lm75 ( client ) ;
DBG ( " wf_lm75: i2c detatch called for %s \n " , lm - > sens . name ) ;
/* Mark client detached */
lm - > i2c . adapter = NULL ;
/* release sensor */
wf_unregister_sensor ( & lm - > sens ) ;
return 0 ;
}
static int __init wf_lm75_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-01-06 11:11:29 +03:00
return i2c_add_driver ( & wf_lm75_driver ) ;
2005-11-07 08:08:17 +03:00
}
static void __exit wf_lm75_sensor_exit ( void )
{
i2c_del_driver ( & wf_lm75_driver ) ;
}
module_init ( wf_lm75_sensor_init ) ;
module_exit ( wf_lm75_sensor_exit ) ;
MODULE_AUTHOR ( " Benjamin Herrenschmidt <benh@kernel.crashing.org> " ) ;
MODULE_DESCRIPTION ( " LM75 sensor objects for PowerMacs thermal control " ) ;
MODULE_LICENSE ( " GPL " ) ;