2019-06-01 11:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-02-26 20:29:07 +04:00
/*
* MEN 16 z188 Analog to Digial Converter
*
* Copyright ( C ) 2014 MEN Mikroelektronik GmbH ( www . men . de )
* Author : Johannes Thumshirn < johannes . thumshirn @ men . de >
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/mcb.h>
2014-03-04 00:46:49 +04:00
# include <linux/io.h>
2014-02-26 20:29:07 +04:00
# include <linux/iio/iio.h>
# define Z188_ADC_MAX_CHAN 8
# define Z188_ADC_GAIN 0x0700000
# define Z188_MODE_VOLTAGE BIT(27)
# define Z188_CFG_AUTO 0x1
# define Z188_CTRL_REG 0x40
# define ADC_DATA(x) (((x) >> 2) & 0x7ffffc)
# define ADC_OVR(x) ((x) & 0x1)
struct z188_adc {
struct resource * mem ;
void __iomem * base ;
} ;
# define Z188_ADC_CHANNEL(idx) { \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. channel = ( idx ) , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
}
static const struct iio_chan_spec z188_adc_iio_channels [ ] = {
Z188_ADC_CHANNEL ( 0 ) ,
Z188_ADC_CHANNEL ( 1 ) ,
Z188_ADC_CHANNEL ( 2 ) ,
Z188_ADC_CHANNEL ( 3 ) ,
Z188_ADC_CHANNEL ( 4 ) ,
Z188_ADC_CHANNEL ( 5 ) ,
Z188_ADC_CHANNEL ( 6 ) ,
Z188_ADC_CHANNEL ( 7 ) ,
} ;
static int z188_iio_read_raw ( struct iio_dev * iio_dev ,
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long info )
{
struct z188_adc * adc = iio_priv ( iio_dev ) ;
int ret ;
u16 tmp ;
switch ( info ) {
case IIO_CHAN_INFO_RAW :
tmp = readw ( adc - > base + chan - > channel * 4 ) ;
if ( ADC_OVR ( tmp ) ) {
dev_info ( & iio_dev - > dev ,
" Oversampling error on ADC channel %d \n " ,
chan - > channel ) ;
return - EIO ;
}
* val = ADC_DATA ( tmp ) ;
ret = IIO_VAL_INT ;
break ;
default :
ret = - EINVAL ;
break ;
}
return ret ;
}
2016-09-16 13:55:25 +03:00
static const struct iio_info z188_adc_info = {
2014-02-26 20:29:07 +04:00
. read_raw = & z188_iio_read_raw ,
} ;
static void men_z188_config_channels ( void __iomem * addr )
{
int i ;
u32 cfg ;
u32 ctl ;
ctl = readl ( addr + Z188_CTRL_REG ) ;
ctl | = Z188_CFG_AUTO ;
writel ( ctl , addr + Z188_CTRL_REG ) ;
for ( i = 0 ; i < Z188_ADC_MAX_CHAN ; i + + ) {
cfg = readl ( addr + i ) ;
cfg & = ~ Z188_ADC_GAIN ;
cfg | = Z188_MODE_VOLTAGE ;
writel ( cfg , addr + i ) ;
}
}
static int men_z188_probe ( struct mcb_device * dev ,
const struct mcb_device_id * id )
{
struct z188_adc * adc ;
struct iio_dev * indio_dev ;
struct resource * mem ;
2022-01-29 11:32:47 +03:00
int ret ;
2014-02-26 20:29:07 +04:00
indio_dev = devm_iio_device_alloc ( & dev - > dev , sizeof ( struct z188_adc ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
adc = iio_priv ( indio_dev ) ;
indio_dev - > name = " z188-adc " ;
indio_dev - > info = & z188_adc_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > channels = z188_adc_iio_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( z188_adc_iio_channels ) ;
mem = mcb_request_mem ( dev , " z188-adc " ) ;
2014-03-28 12:33:00 +04:00
if ( IS_ERR ( mem ) )
return PTR_ERR ( mem ) ;
2014-02-26 20:29:07 +04:00
adc - > base = ioremap ( mem - > start , resource_size ( mem ) ) ;
if ( adc - > base = = NULL )
goto err ;
men_z188_config_channels ( adc - > base ) ;
adc - > mem = mem ;
mcb_set_drvdata ( dev , indio_dev ) ;
2022-01-29 11:32:47 +03:00
ret = iio_device_register ( indio_dev ) ;
if ( ret )
goto err_unmap ;
return 0 ;
2014-02-26 20:29:07 +04:00
2022-01-29 11:32:47 +03:00
err_unmap :
iounmap ( adc - > base ) ;
2014-02-26 20:29:07 +04:00
err :
mcb_release_mem ( mem ) ;
return - ENXIO ;
}
static void men_z188_remove ( struct mcb_device * dev )
{
struct iio_dev * indio_dev = mcb_get_drvdata ( dev ) ;
struct z188_adc * adc = iio_priv ( indio_dev ) ;
iio_device_unregister ( indio_dev ) ;
iounmap ( adc - > base ) ;
mcb_release_mem ( adc - > mem ) ;
}
static const struct mcb_device_id men_z188_ids [ ] = {
{ . device = 0xbc } ,
2014-11-10 11:04:06 +03:00
{ }
2014-02-26 20:29:07 +04:00
} ;
MODULE_DEVICE_TABLE ( mcb , men_z188_ids ) ;
static struct mcb_driver men_z188_driver = {
. driver = {
. name = " z188-adc " ,
. owner = THIS_MODULE ,
} ,
. probe = men_z188_probe ,
. remove = men_z188_remove ,
. id_table = men_z188_ids ,
} ;
module_mcb_driver ( men_z188_driver ) ;
MODULE_AUTHOR ( " Johannes Thumshirn <johannes.thumshirn@men.de> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " IIO ADC driver for MEN 16z188 ADC Core " ) ;
MODULE_ALIAS ( " mcb:16z188 " ) ;
2019-10-16 13:01:58 +03:00
MODULE_IMPORT_NS ( MCB ) ;