2006-06-12 22:00:05 +02:00
/*
* lm70 . c
*
* The LM70 is a temperature sensor chip from National Semiconductor ( NS ) .
* Copyright ( C ) 2006 Kaiwan N Billimoria < kaiwan @ designergraphix . com >
*
* The LM70 communicates with a host processor via an SPI / Microwire Bus
* interface . The complete datasheet is available at National ' s website
* here :
* http : //www.national.com/pf/LM/LM70.html
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/device.h>
# include <linux/err.h>
# include <linux/sysfs.h>
# include <linux/hwmon.h>
# include <linux/spi/spi.h>
# include <asm/semaphore.h>
# define DRVNAME "lm70"
struct lm70 {
struct class_device * cdev ;
struct semaphore sem ;
} ;
/* sysfs hook function */
static ssize_t lm70_sense_temp ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct spi_device * spi = to_spi_device ( dev ) ;
int status , val ;
u8 rxbuf [ 2 ] ;
s16 raw = 0 ;
struct lm70 * p_lm70 = dev_get_drvdata ( & spi - > dev ) ;
if ( down_interruptible ( & p_lm70 - > sem ) )
return - ERESTARTSYS ;
/*
* spi_read ( ) requires a DMA - safe buffer ; so we use
* spi_write_then_read ( ) , transmitting 0 bytes .
*/
status = spi_write_then_read ( spi , NULL , 0 , & rxbuf [ 0 ] , 2 ) ;
if ( status < 0 ) {
printk ( KERN_WARNING
" spi_write_then_read failed with status %d \n " , status ) ;
goto out ;
}
dev_dbg ( dev , " rxbuf[1] : 0x%x rxbuf[0] : 0x%x \n " , rxbuf [ 1 ] , rxbuf [ 0 ] ) ;
raw = ( rxbuf [ 1 ] < < 8 ) + rxbuf [ 0 ] ;
dev_dbg ( dev , " raw=0x%x \n " , raw ) ;
/*
* The " raw " temperature read into rxbuf [ ] is a 16 - bit signed 2 ' s
* complement value . Only the MSB 11 bits ( 1 sign + 10 temperature
* bits ) are meaningful ; the LSB 5 bits are to be discarded .
* See the datasheet .
*
* Further , each bit represents 0.25 degrees Celsius ; so , multiply
* by 0.25 . Also multiply by 1000 to represent in millidegrees
* Celsius .
* So it ' s equivalent to multiplying by 0.25 * 1000 = 250.
*/
val = ( ( int ) raw / 32 ) * 250 ;
status = sprintf ( buf , " %+d \n " , val ) ; /* millidegrees Celsius */
out :
up ( & p_lm70 - > sem ) ;
return status ;
}
static DEVICE_ATTR ( temp1_input , S_IRUGO , lm70_sense_temp , NULL ) ;
/*----------------------------------------------------------------------*/
static int __devinit lm70_probe ( struct spi_device * spi )
{
struct lm70 * p_lm70 ;
int status ;
p_lm70 = kzalloc ( sizeof * p_lm70 , GFP_KERNEL ) ;
if ( ! p_lm70 )
return - ENOMEM ;
init_MUTEX ( & p_lm70 - > sem ) ;
/* sysfs hook */
p_lm70 - > cdev = hwmon_device_register ( & spi - > dev ) ;
if ( IS_ERR ( p_lm70 - > cdev ) ) {
dev_dbg ( & spi - > dev , " hwmon_device_register failed. \n " ) ;
status = PTR_ERR ( p_lm70 - > cdev ) ;
goto out_dev_reg_failed ;
}
dev_set_drvdata ( & spi - > dev , p_lm70 ) ;
if ( ( status = device_create_file ( & spi - > dev , & dev_attr_temp1_input ) ) ) {
dev_dbg ( & spi - > dev , " device_create_file failure. \n " ) ;
goto out_dev_create_file_failed ;
}
return 0 ;
out_dev_create_file_failed :
hwmon_device_unregister ( p_lm70 - > cdev ) ;
out_dev_reg_failed :
dev_set_drvdata ( & spi - > dev , NULL ) ;
kfree ( p_lm70 ) ;
return status ;
}
2007-02-14 21:15:04 +01:00
static int __devexit lm70_remove ( struct spi_device * spi )
2006-06-12 22:00:05 +02:00
{
struct lm70 * p_lm70 = dev_get_drvdata ( & spi - > dev ) ;
device_remove_file ( & spi - > dev , & dev_attr_temp1_input ) ;
hwmon_device_unregister ( p_lm70 - > cdev ) ;
dev_set_drvdata ( & spi - > dev , NULL ) ;
kfree ( p_lm70 ) ;
return 0 ;
}
static struct spi_driver lm70_driver = {
. driver = {
. name = " lm70 " ,
. owner = THIS_MODULE ,
} ,
. probe = lm70_probe ,
. remove = __devexit_p ( lm70_remove ) ,
} ;
static int __init init_lm70 ( void )
{
return spi_register_driver ( & lm70_driver ) ;
}
static void __exit cleanup_lm70 ( void )
{
spi_unregister_driver ( & lm70_driver ) ;
}
module_init ( init_lm70 ) ;
module_exit ( cleanup_lm70 ) ;
MODULE_AUTHOR ( " Kaiwan N Billimoria " ) ;
MODULE_DESCRIPTION ( " National Semiconductor LM70 Linux driver " ) ;
MODULE_LICENSE ( " GPL " ) ;