2011-09-29 20:50:04 +04:00
/*
* AD7314 digital temperature sensor driver for AD7314 , ADT7301 and ADT7302
*
* Copyright 2010 Analog Devices Inc .
*
* Licensed under the GPL - 2 or later .
*
* Conversion to hwmon from IIO done by Jonathan Cameron < jic23 @ cam . ac . uk >
*/
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/sysfs.h>
# include <linux/spi/spi.h>
# include <linux/module.h>
# include <linux/err.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
2015-01-23 01:44:13 +03:00
# include <linux/bitops.h>
2011-09-29 20:50:04 +04:00
/*
* AD7314 temperature masks
*/
# define AD7314_TEMP_MASK 0x7FE0
2012-04-22 08:22:00 +04:00
# define AD7314_TEMP_SHIFT 5
2011-09-29 20:50:04 +04:00
/*
* ADT7301 and ADT7302 temperature masks
*/
# define ADT7301_TEMP_MASK 0x3FFF
enum ad7314_variant {
adt7301 ,
adt7302 ,
ad7314 ,
} ;
struct ad7314_data {
struct spi_device * spi_dev ;
struct device * hwmon_dev ;
u16 rx ____cacheline_aligned ;
} ;
2012-04-20 19:39:17 +04:00
static int ad7314_spi_read ( struct ad7314_data * chip )
2011-09-29 20:50:04 +04:00
{
int ret ;
ret = spi_read ( chip - > spi_dev , ( u8 * ) & chip - > rx , sizeof ( chip - > rx ) ) ;
if ( ret < 0 ) {
dev_err ( & chip - > spi_dev - > dev , " SPI read error \n " ) ;
return ret ;
}
2012-04-20 19:39:17 +04:00
return be16_to_cpu ( chip - > rx ) ;
2011-09-29 20:50:04 +04:00
}
static ssize_t ad7314_show_temperature ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct ad7314_data * chip = dev_get_drvdata ( dev ) ;
s16 data ;
int ret ;
2012-04-20 19:39:17 +04:00
ret = ad7314_spi_read ( chip ) ;
2011-09-29 20:50:04 +04:00
if ( ret < 0 )
return ret ;
switch ( spi_get_device_id ( chip - > spi_dev ) - > driver_data ) {
case ad7314 :
2012-04-22 08:22:00 +04:00
data = ( ret & AD7314_TEMP_MASK ) > > AD7314_TEMP_SHIFT ;
2015-01-23 01:44:13 +03:00
data = sign_extend32 ( data , 9 ) ;
2011-09-29 20:50:04 +04:00
return sprintf ( buf , " %d \n " , 250 * data ) ;
case adt7301 :
case adt7302 :
/*
* Documented as a 13 bit twos complement register
* with a sign bit - which is a 14 bit 2 ' s complement
* register . 1l sb - 31.25 milli degrees centigrade
*/
2012-04-20 19:39:17 +04:00
data = ret & ADT7301_TEMP_MASK ;
2015-01-23 01:44:13 +03:00
data = sign_extend32 ( data , 13 ) ;
2011-09-29 20:50:04 +04:00
return sprintf ( buf , " %d \n " ,
DIV_ROUND_CLOSEST ( data * 3125 , 100 ) ) ;
default :
return - EINVAL ;
}
}
2012-09-12 00:43:17 +04:00
static ssize_t ad7314_show_name ( struct device * dev ,
struct device_attribute * devattr , char * buf )
{
return sprintf ( buf , " %s \n " , to_spi_device ( dev ) - > modalias ) ;
}
static DEVICE_ATTR ( name , S_IRUGO , ad7314_show_name , NULL ) ;
2011-09-29 20:50:04 +04:00
static SENSOR_DEVICE_ATTR ( temp1_input , S_IRUGO ,
ad7314_show_temperature , NULL , 0 ) ;
static struct attribute * ad7314_attributes [ ] = {
2012-09-12 00:43:17 +04:00
& dev_attr_name . attr ,
2011-09-29 20:50:04 +04:00
& sensor_dev_attr_temp1_input . dev_attr . attr ,
NULL ,
} ;
static const struct attribute_group ad7314_group = {
. attrs = ad7314_attributes ,
} ;
2012-11-19 22:22:35 +04:00
static int ad7314_probe ( struct spi_device * spi_dev )
2011-09-29 20:50:04 +04:00
{
int ret ;
struct ad7314_data * chip ;
2012-06-02 20:57:57 +04:00
chip = devm_kzalloc ( & spi_dev - > dev , sizeof ( * chip ) , GFP_KERNEL ) ;
if ( chip = = NULL )
return - ENOMEM ;
2013-04-05 05:51:29 +04:00
spi_set_drvdata ( spi_dev , chip ) ;
2011-09-29 20:50:04 +04:00
ret = sysfs_create_group ( & spi_dev - > dev . kobj , & ad7314_group ) ;
if ( ret < 0 )
2012-06-02 20:57:57 +04:00
return ret ;
2011-09-29 20:50:04 +04:00
chip - > hwmon_dev = hwmon_device_register ( & spi_dev - > dev ) ;
if ( IS_ERR ( chip - > hwmon_dev ) ) {
ret = PTR_ERR ( chip - > hwmon_dev ) ;
goto error_remove_group ;
}
2012-04-04 03:42:21 +04:00
chip - > spi_dev = spi_dev ;
2011-09-29 20:50:04 +04:00
return 0 ;
error_remove_group :
sysfs_remove_group ( & spi_dev - > dev . kobj , & ad7314_group ) ;
return ret ;
}
2012-11-19 22:25:51 +04:00
static int ad7314_remove ( struct spi_device * spi_dev )
2011-09-29 20:50:04 +04:00
{
2013-04-05 05:51:29 +04:00
struct ad7314_data * chip = spi_get_drvdata ( spi_dev ) ;
2011-09-29 20:50:04 +04:00
hwmon_device_unregister ( chip - > hwmon_dev ) ;
sysfs_remove_group ( & spi_dev - > dev . kobj , & ad7314_group ) ;
return 0 ;
}
static const struct spi_device_id ad7314_id [ ] = {
{ " adt7301 " , adt7301 } ,
{ " adt7302 " , adt7302 } ,
{ " ad7314 " , ad7314 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( spi , ad7314_id ) ;
static struct spi_driver ad7314_driver = {
. driver = {
. name = " ad7314 " ,
} ,
. probe = ad7314_probe ,
2012-11-19 22:21:20 +04:00
. remove = ad7314_remove ,
2011-09-29 20:50:04 +04:00
. id_table = ad7314_id ,
} ;
2012-01-20 11:53:47 +04:00
module_spi_driver ( ad7314_driver ) ;
2011-09-29 20:50:04 +04:00
MODULE_AUTHOR ( " Sonic Zhang <sonic.zhang@analog.com> " ) ;
2013-01-10 22:01:24 +04:00
MODULE_DESCRIPTION ( " Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver " ) ;
2011-09-29 20:50:04 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;