2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2015-05-14 17:21:16 +03:00
/*
* m62332 . c - Support for Mitsubishi m62332 DAC
*
* Copyright ( c ) 2014 Dmitry Eremin - Solenikov
*
* Based on max517 driver :
* Copyright ( C ) 2010 , 2011 Roland Stigge < stigge @ antcom . de >
*/
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/err.h>
# include <linux/iio/iio.h>
# include <linux/iio/driver.h>
# include <linux/regulator/consumer.h>
# define M62332_CHANNELS 2
struct m62332_data {
struct i2c_client * client ;
struct regulator * vcc ;
struct mutex mutex ;
u8 raw [ M62332_CHANNELS ] ;
# ifdef CONFIG_PM_SLEEP
u8 save [ M62332_CHANNELS ] ;
# endif
} ;
2015-08-29 00:59:57 +03:00
static int m62332_set_value ( struct iio_dev * indio_dev , u8 val , int channel )
2015-05-14 17:21:16 +03:00
{
struct m62332_data * data = iio_priv ( indio_dev ) ;
struct i2c_client * client = data - > client ;
u8 outbuf [ 2 ] ;
int res ;
if ( val = = data - > raw [ channel ] )
return 0 ;
outbuf [ 0 ] = channel ;
outbuf [ 1 ] = val ;
mutex_lock ( & data - > mutex ) ;
if ( val ) {
res = regulator_enable ( data - > vcc ) ;
if ( res )
goto out ;
}
2015-08-29 00:59:55 +03:00
res = i2c_master_send ( client , outbuf , ARRAY_SIZE ( outbuf ) ) ;
if ( res > = 0 & & res ! = ARRAY_SIZE ( outbuf ) )
2015-05-14 17:21:16 +03:00
res = - EIO ;
if ( res < 0 )
goto out ;
data - > raw [ channel ] = val ;
if ( ! val )
regulator_disable ( data - > vcc ) ;
mutex_unlock ( & data - > mutex ) ;
return 0 ;
out :
mutex_unlock ( & data - > mutex ) ;
return res ;
}
static int m62332_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
2015-08-29 00:59:57 +03:00
long mask )
2015-05-14 17:21:16 +03:00
{
struct m62332_data * data = iio_priv ( indio_dev ) ;
2015-08-29 00:59:58 +03:00
int ret ;
2015-05-14 17:21:16 +03:00
2015-08-29 00:59:57 +03:00
switch ( mask ) {
2015-05-14 17:21:16 +03:00
case IIO_CHAN_INFO_SCALE :
/* Corresponds to Vref / 2^(bits) */
2015-08-29 00:59:58 +03:00
ret = regulator_get_voltage ( data - > vcc ) ;
if ( ret < 0 )
return ret ;
* val = ret / 1000 ; /* mV */
2015-05-14 17:21:16 +03:00
* val2 = 8 ;
2015-08-29 00:59:57 +03:00
2015-05-14 17:21:16 +03:00
return IIO_VAL_FRACTIONAL_LOG2 ;
case IIO_CHAN_INFO_RAW :
* val = data - > raw [ chan - > channel ] ;
2015-08-29 00:59:57 +03:00
2015-05-14 17:21:16 +03:00
return IIO_VAL_INT ;
case IIO_CHAN_INFO_OFFSET :
* val = 1 ;
2015-08-29 00:59:57 +03:00
2015-05-14 17:21:16 +03:00
return IIO_VAL_INT ;
default :
break ;
}
2015-08-29 00:59:57 +03:00
2015-05-14 17:21:16 +03:00
return - EINVAL ;
}
static int m62332_write_raw ( struct iio_dev * indio_dev ,
2015-08-29 00:59:57 +03:00
struct iio_chan_spec const * chan , int val , int val2 ,
long mask )
2015-05-14 17:21:16 +03:00
{
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
if ( val < 0 | | val > 255 )
return - EINVAL ;
2015-08-29 00:59:56 +03:00
return m62332_set_value ( indio_dev , val , chan - > channel ) ;
2015-05-14 17:21:16 +03:00
default :
break ;
}
2015-08-29 00:59:56 +03:00
return - EINVAL ;
2015-05-14 17:21:16 +03:00
}
# ifdef CONFIG_PM_SLEEP
static int m62332_suspend ( struct device * dev )
{
struct i2c_client * client = to_i2c_client ( dev ) ;
struct iio_dev * indio_dev = i2c_get_clientdata ( client ) ;
struct m62332_data * data = iio_priv ( indio_dev ) ;
int ret ;
data - > save [ 0 ] = data - > raw [ 0 ] ;
data - > save [ 1 ] = data - > raw [ 1 ] ;
ret = m62332_set_value ( indio_dev , 0 , 0 ) ;
if ( ret < 0 )
return ret ;
return m62332_set_value ( indio_dev , 0 , 1 ) ;
}
static int m62332_resume ( struct device * dev )
{
struct i2c_client * client = to_i2c_client ( dev ) ;
struct iio_dev * indio_dev = i2c_get_clientdata ( client ) ;
struct m62332_data * data = iio_priv ( indio_dev ) ;
int ret ;
ret = m62332_set_value ( indio_dev , data - > save [ 0 ] , 0 ) ;
if ( ret < 0 )
return ret ;
return m62332_set_value ( indio_dev , data - > save [ 1 ] , 1 ) ;
}
static SIMPLE_DEV_PM_OPS ( m62332_pm_ops , m62332_suspend , m62332_resume ) ;
# define M62332_PM_OPS (&m62332_pm_ops)
# else
# define M62332_PM_OPS NULL
# endif
static const struct iio_info m62332_info = {
. read_raw = m62332_read_raw ,
. write_raw = m62332_write_raw ,
} ;
2015-08-29 00:59:53 +03:00
# define M62332_CHANNEL(chan) { \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. output = 1 , \
. channel = ( chan ) , \
. datasheet_name = " CH " # chan , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_OFFSET ) , \
2015-05-14 17:21:16 +03:00
}
static const struct iio_chan_spec m62332_channels [ M62332_CHANNELS ] = {
M62332_CHANNEL ( 0 ) ,
M62332_CHANNEL ( 1 )
} ;
static int m62332_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct m62332_data * data ;
struct iio_dev * indio_dev ;
int ret ;
indio_dev = devm_iio_device_alloc ( & client - > dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2015-08-29 00:59:57 +03:00
2015-05-14 17:21:16 +03:00
data = iio_priv ( indio_dev ) ;
i2c_set_clientdata ( client , indio_dev ) ;
data - > client = client ;
mutex_init ( & data - > mutex ) ;
data - > vcc = devm_regulator_get ( & client - > dev , " VCC " ) ;
if ( IS_ERR ( data - > vcc ) )
return PTR_ERR ( data - > vcc ) ;
2015-08-29 00:59:55 +03:00
indio_dev - > num_channels = ARRAY_SIZE ( m62332_channels ) ;
2015-05-14 17:21:16 +03:00
indio_dev - > channels = m62332_channels ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > info = & m62332_info ;
ret = iio_map_array_register ( indio_dev , client - > dev . platform_data ) ;
if ( ret < 0 )
return ret ;
ret = iio_device_register ( indio_dev ) ;
if ( ret < 0 )
goto err ;
return 0 ;
err :
iio_map_array_unregister ( indio_dev ) ;
2015-08-29 00:59:57 +03:00
2015-05-14 17:21:16 +03:00
return ret ;
}
static int m62332_remove ( struct i2c_client * client )
{
struct iio_dev * indio_dev = i2c_get_clientdata ( client ) ;
iio_device_unregister ( indio_dev ) ;
iio_map_array_unregister ( indio_dev ) ;
2015-08-29 00:59:54 +03:00
m62332_set_value ( indio_dev , 0 , 0 ) ;
m62332_set_value ( indio_dev , 0 , 1 ) ;
2015-05-14 17:21:16 +03:00
return 0 ;
}
static const struct i2c_device_id m62332_id [ ] = {
{ " m62332 " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , m62332_id ) ;
static struct i2c_driver m62332_driver = {
. driver = {
. name = " m62332 " ,
. pm = M62332_PM_OPS ,
} ,
. probe = m62332_probe ,
. remove = m62332_remove ,
. id_table = m62332_id ,
} ;
module_i2c_driver ( m62332_driver ) ;
MODULE_AUTHOR ( " Dmitry Eremin-Solenikov " ) ;
MODULE_DESCRIPTION ( " M62332 8-bit DAC " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;