2019-05-20 10:19:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2014-01-26 09:39:00 +04:00
/*
* Freescale Vybrid vf610 ADC driver
*
* Copyright 2013 Freescale Semiconductor , Inc .
*/
2022-05-31 17:23:53 +03:00
# include <linux/mod_devicetable.h>
2014-01-26 09:39:00 +04:00
# include <linux/module.h>
2022-10-04 16:49:03 +03:00
# include <linux/mutex.h>
2022-05-31 17:23:53 +03:00
# include <linux/property.h>
2014-01-26 09:39:00 +04:00
# include <linux/platform_device.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/io.h>
# include <linux/clk.h>
# include <linux/completion.h>
# include <linux/regulator/consumer.h>
# include <linux/err.h>
# include <linux/iio/iio.h>
2015-08-17 18:51:40 +03:00
# include <linux/iio/buffer.h>
2014-01-26 09:39:00 +04:00
# include <linux/iio/sysfs.h>
2015-08-17 18:51:40 +03:00
# include <linux/iio/trigger.h>
# include <linux/iio/trigger_consumer.h>
# include <linux/iio/triggered_buffer.h>
2014-01-26 09:39:00 +04:00
/* This will be the driver name the kernel reports */
# define DRIVER_NAME "vf610-adc"
/* Vybrid/IMX ADC registers */
# define VF610_REG_ADC_HC0 0x00
# define VF610_REG_ADC_HC1 0x04
# define VF610_REG_ADC_HS 0x08
# define VF610_REG_ADC_R0 0x0c
# define VF610_REG_ADC_R1 0x10
# define VF610_REG_ADC_CFG 0x14
# define VF610_REG_ADC_GC 0x18
# define VF610_REG_ADC_GS 0x1c
# define VF610_REG_ADC_CV 0x20
# define VF610_REG_ADC_OFS 0x24
# define VF610_REG_ADC_CAL 0x28
# define VF610_REG_ADC_PCTL 0x30
/* Configuration register field define */
# define VF610_ADC_MODE_BIT8 0x00
# define VF610_ADC_MODE_BIT10 0x04
# define VF610_ADC_MODE_BIT12 0x08
# define VF610_ADC_MODE_MASK 0x0c
# define VF610_ADC_BUSCLK2_SEL 0x01
# define VF610_ADC_ALTCLK_SEL 0x02
# define VF610_ADC_ADACK_SEL 0x03
# define VF610_ADC_ADCCLK_MASK 0x03
# define VF610_ADC_CLK_DIV2 0x20
# define VF610_ADC_CLK_DIV4 0x40
# define VF610_ADC_CLK_DIV8 0x60
# define VF610_ADC_CLK_MASK 0x60
# define VF610_ADC_ADLSMP_LONG 0x10
2015-07-14 16:53:22 +03:00
# define VF610_ADC_ADSTS_SHORT 0x100
# define VF610_ADC_ADSTS_NORMAL 0x200
# define VF610_ADC_ADSTS_LONG 0x300
2014-01-26 09:39:00 +04:00
# define VF610_ADC_ADSTS_MASK 0x300
# define VF610_ADC_ADLPC_EN 0x80
# define VF610_ADC_ADHSC_EN 0x400
2017-07-06 12:06:41 +03:00
# define VF610_ADC_REFSEL_VALT 0x800
2014-01-26 09:39:00 +04:00
# define VF610_ADC_REFSEL_VBG 0x1000
# define VF610_ADC_ADTRG_HARD 0x2000
# define VF610_ADC_AVGS_8 0x4000
# define VF610_ADC_AVGS_16 0x8000
# define VF610_ADC_AVGS_32 0xC000
# define VF610_ADC_AVGS_MASK 0xC000
# define VF610_ADC_OVWREN 0x10000
/* General control register field define */
# define VF610_ADC_ADACKEN 0x1
# define VF610_ADC_DMAEN 0x2
# define VF610_ADC_ACREN 0x4
# define VF610_ADC_ACFGT 0x8
# define VF610_ADC_ACFE 0x10
# define VF610_ADC_AVGEN 0x20
# define VF610_ADC_ADCON 0x40
# define VF610_ADC_CAL 0x80
/* Other field define */
2014-09-19 16:58:00 +04:00
# define VF610_ADC_ADCHC(x) ((x) & 0x1F)
2014-01-26 09:39:00 +04:00
# define VF610_ADC_AIEN (0x1 << 7)
# define VF610_ADC_CONV_DISABLE 0x1F
# define VF610_ADC_HS_COCO0 0x1
# define VF610_ADC_CALF 0x2
# define VF610_ADC_TIMEOUT msecs_to_jiffies(100)
2015-07-14 16:53:22 +03:00
# define DEFAULT_SAMPLE_TIME 1000
2015-10-19 18:54:36 +03:00
/* V at 25°C of 696 mV */
# define VF610_VTEMP25_3V0 950
/* V at 25°C of 699 mV */
# define VF610_VTEMP25_3V3 867
/* Typical sensor slope coefficient at all temperatures */
# define VF610_TEMP_SLOPE_COEFF 1840
2014-01-26 09:39:00 +04:00
enum clk_sel {
VF610_ADCIOC_BUSCLK_SET ,
VF610_ADCIOC_ALTCLK_SET ,
VF610_ADCIOC_ADACK_SET ,
} ;
enum vol_ref {
VF610_ADCIOC_VR_VREF_SET ,
VF610_ADCIOC_VR_VALT_SET ,
VF610_ADCIOC_VR_VBG_SET ,
} ;
enum average_sel {
VF610_ADC_SAMPLE_1 ,
VF610_ADC_SAMPLE_4 ,
VF610_ADC_SAMPLE_8 ,
VF610_ADC_SAMPLE_16 ,
VF610_ADC_SAMPLE_32 ,
} ;
2015-05-27 15:47:51 +03:00
enum conversion_mode_sel {
VF610_ADC_CONV_NORMAL ,
VF610_ADC_CONV_HIGH_SPEED ,
VF610_ADC_CONV_LOW_POWER ,
} ;
2015-07-14 16:53:22 +03:00
enum lst_adder_sel {
VF610_ADCK_CYCLES_3 ,
VF610_ADCK_CYCLES_5 ,
VF610_ADCK_CYCLES_7 ,
VF610_ADCK_CYCLES_9 ,
VF610_ADCK_CYCLES_13 ,
VF610_ADCK_CYCLES_17 ,
VF610_ADCK_CYCLES_21 ,
VF610_ADCK_CYCLES_25 ,
} ;
2014-01-26 09:39:00 +04:00
struct vf610_adc_feature {
enum clk_sel clk_sel ;
enum vol_ref vol_ref ;
2015-05-27 15:47:51 +03:00
enum conversion_mode_sel conv_mode ;
2014-01-26 09:39:00 +04:00
int clk_div ;
int sample_rate ;
int res_mode ;
2015-07-14 16:53:22 +03:00
u32 lst_adder_index ;
u32 default_sample_time ;
2014-01-26 09:39:00 +04:00
bool calibration ;
bool ovwren ;
} ;
struct vf610_adc {
struct device * dev ;
void __iomem * regs ;
struct clk * clk ;
2022-10-04 16:49:03 +03:00
/* lock to protect against multiple access to the device */
struct mutex lock ;
2014-01-26 09:39:00 +04:00
u32 vref_uv ;
u32 value ;
struct regulator * vref ;
2015-05-27 15:47:51 +03:00
u32 max_adck_rate [ 3 ] ;
2014-01-26 09:39:00 +04:00
struct vf610_adc_feature adc_feature ;
2015-03-24 15:47:47 +03:00
u32 sample_freq_avail [ 5 ] ;
2014-01-26 09:39:00 +04:00
struct completion completion ;
2021-05-01 20:01:11 +03:00
/* Ensure the timestamp is naturally aligned */
struct {
u16 chan ;
s64 timestamp __aligned ( 8 ) ;
} scan ;
2014-01-26 09:39:00 +04:00
} ;
2015-03-24 15:47:47 +03:00
static const u32 vf610_hw_avgs [ ] = { 1 , 4 , 8 , 16 , 32 } ;
2015-07-14 16:53:22 +03:00
static const u32 vf610_lst_adder [ ] = { 3 , 5 , 7 , 9 , 13 , 17 , 21 , 25 } ;
2015-03-24 15:47:47 +03:00
static inline void vf610_adc_calculate_rates ( struct vf610_adc * info )
{
2015-05-27 15:47:51 +03:00
struct vf610_adc_feature * adc_feature = & info - > adc_feature ;
2015-03-24 15:47:47 +03:00
unsigned long adck_rate , ipg_rate = clk_get_rate ( info - > clk ) ;
2015-07-14 16:53:22 +03:00
u32 adck_period , lst_addr_min ;
2015-05-27 15:47:51 +03:00
int divisor , i ;
adck_rate = info - > max_adck_rate [ adc_feature - > conv_mode ] ;
if ( adck_rate ) {
/* calculate clk divider which is within specification */
divisor = ipg_rate / adck_rate ;
adc_feature - > clk_div = 1 < < fls ( divisor + 1 ) ;
} else {
/* fall-back value using a safe divisor */
adc_feature - > clk_div = 8 ;
}
2015-03-24 15:47:47 +03:00
2015-10-19 10:43:52 +03:00
adck_rate = ipg_rate / adc_feature - > clk_div ;
2015-07-14 16:53:22 +03:00
/*
* Determine the long sample time adder value to be used based
* on the default minimum sample time provided .
*/
adck_period = NSEC_PER_SEC / adck_rate ;
lst_addr_min = adc_feature - > default_sample_time / adck_period ;
for ( i = 0 ; i < ARRAY_SIZE ( vf610_lst_adder ) ; i + + ) {
if ( vf610_lst_adder [ i ] > lst_addr_min ) {
adc_feature - > lst_adder_index = i ;
break ;
}
}
2015-03-24 15:47:47 +03:00
/*
* Calculate ADC sample frequencies
* Sample time unit is ADCK cycles . ADCK clk source is ipg clock ,
* which is the same as bus clock .
*
* ADC conversion time = SFCAdder + AverageNum x ( BCT + LSTAdder )
* SFCAdder : fixed to 6 ADCK cycles
* AverageNum : 1 , 4 , 8 , 16 , 32 samples for hardware average .
* BCT ( Base Conversion Time ) : fixed to 25 ADCK cycles for 12 bit mode
2015-07-14 16:53:22 +03:00
* LSTAdder ( Long Sample Time ) : 3 , 5 , 7 , 9 , 13 , 17 , 21 , 25 ADCK cycles
2015-03-24 15:47:47 +03:00
*/
for ( i = 0 ; i < ARRAY_SIZE ( vf610_hw_avgs ) ; i + + )
info - > sample_freq_avail [ i ] =
2015-07-14 16:53:22 +03:00
adck_rate / ( 6 + vf610_hw_avgs [ i ] *
( 25 + vf610_lst_adder [ adc_feature - > lst_adder_index ] ) ) ;
2015-03-24 15:47:47 +03:00
}
2014-01-26 09:39:00 +04:00
static inline void vf610_adc_cfg_init ( struct vf610_adc * info )
{
2015-03-24 15:47:47 +03:00
struct vf610_adc_feature * adc_feature = & info - > adc_feature ;
2014-01-26 09:39:00 +04:00
/* set default Configuration for ADC controller */
2015-03-24 15:47:47 +03:00
adc_feature - > clk_sel = VF610_ADCIOC_BUSCLK_SET ;
adc_feature - > vol_ref = VF610_ADCIOC_VR_VREF_SET ;
adc_feature - > calibration = true ;
adc_feature - > ovwren = true ;
adc_feature - > res_mode = 12 ;
adc_feature - > sample_rate = 1 ;
2014-01-26 09:39:00 +04:00
2015-05-27 15:47:51 +03:00
adc_feature - > conv_mode = VF610_ADC_CONV_LOW_POWER ;
2014-01-26 09:39:00 +04:00
2015-03-24 15:47:47 +03:00
vf610_adc_calculate_rates ( info ) ;
2014-01-26 09:39:00 +04:00
}
static void vf610_adc_cfg_post_set ( struct vf610_adc * info )
{
struct vf610_adc_feature * adc_feature = & info - > adc_feature ;
int cfg_data = 0 ;
int gc_data = 0 ;
switch ( adc_feature - > clk_sel ) {
case VF610_ADCIOC_ALTCLK_SET :
cfg_data | = VF610_ADC_ALTCLK_SEL ;
break ;
case VF610_ADCIOC_ADACK_SET :
cfg_data | = VF610_ADC_ADACK_SEL ;
break ;
default :
break ;
}
/* low power set for calibration */
cfg_data | = VF610_ADC_ADLPC_EN ;
/* enable high speed for calibration */
cfg_data | = VF610_ADC_ADHSC_EN ;
/* voltage reference */
switch ( adc_feature - > vol_ref ) {
case VF610_ADCIOC_VR_VREF_SET :
break ;
case VF610_ADCIOC_VR_VALT_SET :
cfg_data | = VF610_ADC_REFSEL_VALT ;
break ;
case VF610_ADCIOC_VR_VBG_SET :
cfg_data | = VF610_ADC_REFSEL_VBG ;
break ;
default :
dev_err ( info - > dev , " error voltage reference \n " ) ;
}
/* data overwrite enable */
if ( adc_feature - > ovwren )
cfg_data | = VF610_ADC_OVWREN ;
writel ( cfg_data , info - > regs + VF610_REG_ADC_CFG ) ;
writel ( gc_data , info - > regs + VF610_REG_ADC_GC ) ;
}
static void vf610_adc_calibration ( struct vf610_adc * info )
{
int adc_gc , hc_cfg ;
if ( ! info - > adc_feature . calibration )
return ;
/* enable calibration interrupt */
hc_cfg = VF610_ADC_AIEN | VF610_ADC_CONV_DISABLE ;
writel ( hc_cfg , info - > regs + VF610_REG_ADC_HC0 ) ;
adc_gc = readl ( info - > regs + VF610_REG_ADC_GC ) ;
writel ( adc_gc | VF610_ADC_CAL , info - > regs + VF610_REG_ADC_GC ) ;
2015-02-02 11:35:20 +03:00
if ( ! wait_for_completion_timeout ( & info - > completion , VF610_ADC_TIMEOUT ) )
2014-01-26 09:39:00 +04:00
dev_err ( info - > dev , " Timeout for adc calibration \n " ) ;
adc_gc = readl ( info - > regs + VF610_REG_ADC_GS ) ;
if ( adc_gc & VF610_ADC_CALF )
dev_err ( info - > dev , " ADC calibration failed \n " ) ;
info - > adc_feature . calibration = false ;
}
static void vf610_adc_cfg_set ( struct vf610_adc * info )
{
struct vf610_adc_feature * adc_feature = & ( info - > adc_feature ) ;
int cfg_data ;
cfg_data = readl ( info - > regs + VF610_REG_ADC_CFG ) ;
cfg_data & = ~ VF610_ADC_ADLPC_EN ;
2015-05-27 15:47:51 +03:00
if ( adc_feature - > conv_mode = = VF610_ADC_CONV_LOW_POWER )
2014-01-26 09:39:00 +04:00
cfg_data | = VF610_ADC_ADLPC_EN ;
cfg_data & = ~ VF610_ADC_ADHSC_EN ;
2015-05-27 15:47:51 +03:00
if ( adc_feature - > conv_mode = = VF610_ADC_CONV_HIGH_SPEED )
cfg_data | = VF610_ADC_ADHSC_EN ;
2014-01-26 09:39:00 +04:00
writel ( cfg_data , info - > regs + VF610_REG_ADC_CFG ) ;
}
static void vf610_adc_sample_set ( struct vf610_adc * info )
{
struct vf610_adc_feature * adc_feature = & ( info - > adc_feature ) ;
int cfg_data , gc_data ;
cfg_data = readl ( info - > regs + VF610_REG_ADC_CFG ) ;
gc_data = readl ( info - > regs + VF610_REG_ADC_GC ) ;
/* resolution mode */
cfg_data & = ~ VF610_ADC_MODE_MASK ;
switch ( adc_feature - > res_mode ) {
case 8 :
cfg_data | = VF610_ADC_MODE_BIT8 ;
break ;
case 10 :
cfg_data | = VF610_ADC_MODE_BIT10 ;
break ;
case 12 :
cfg_data | = VF610_ADC_MODE_BIT12 ;
break ;
default :
dev_err ( info - > dev , " error resolution mode \n " ) ;
break ;
}
/* clock select and clock divider */
cfg_data & = ~ ( VF610_ADC_CLK_MASK | VF610_ADC_ADCCLK_MASK ) ;
switch ( adc_feature - > clk_div ) {
case 1 :
break ;
case 2 :
cfg_data | = VF610_ADC_CLK_DIV2 ;
break ;
case 4 :
cfg_data | = VF610_ADC_CLK_DIV4 ;
break ;
case 8 :
cfg_data | = VF610_ADC_CLK_DIV8 ;
break ;
case 16 :
switch ( adc_feature - > clk_sel ) {
case VF610_ADCIOC_BUSCLK_SET :
cfg_data | = VF610_ADC_BUSCLK2_SEL | VF610_ADC_CLK_DIV8 ;
break ;
default :
dev_err ( info - > dev , " error clk divider \n " ) ;
break ;
}
break ;
}
2015-07-14 16:53:22 +03:00
/*
* Set ADLSMP and ADSTS based on the Long Sample Time Adder value
* determined .
*/
switch ( adc_feature - > lst_adder_index ) {
case VF610_ADCK_CYCLES_3 :
break ;
case VF610_ADCK_CYCLES_5 :
cfg_data | = VF610_ADC_ADSTS_SHORT ;
break ;
case VF610_ADCK_CYCLES_7 :
cfg_data | = VF610_ADC_ADSTS_NORMAL ;
break ;
case VF610_ADCK_CYCLES_9 :
cfg_data | = VF610_ADC_ADSTS_LONG ;
break ;
case VF610_ADCK_CYCLES_13 :
cfg_data | = VF610_ADC_ADLSMP_LONG ;
break ;
case VF610_ADCK_CYCLES_17 :
cfg_data | = VF610_ADC_ADLSMP_LONG ;
cfg_data | = VF610_ADC_ADSTS_SHORT ;
break ;
case VF610_ADCK_CYCLES_21 :
cfg_data | = VF610_ADC_ADLSMP_LONG ;
cfg_data | = VF610_ADC_ADSTS_NORMAL ;
break ;
case VF610_ADCK_CYCLES_25 :
cfg_data | = VF610_ADC_ADLSMP_LONG ;
cfg_data | = VF610_ADC_ADSTS_NORMAL ;
break ;
default :
dev_err ( info - > dev , " error in sample time select \n " ) ;
}
2014-01-26 09:39:00 +04:00
/* update hardware average selection */
cfg_data & = ~ VF610_ADC_AVGS_MASK ;
gc_data & = ~ VF610_ADC_AVGEN ;
switch ( adc_feature - > sample_rate ) {
case VF610_ADC_SAMPLE_1 :
break ;
case VF610_ADC_SAMPLE_4 :
gc_data | = VF610_ADC_AVGEN ;
break ;
case VF610_ADC_SAMPLE_8 :
gc_data | = VF610_ADC_AVGEN ;
cfg_data | = VF610_ADC_AVGS_8 ;
break ;
case VF610_ADC_SAMPLE_16 :
gc_data | = VF610_ADC_AVGEN ;
cfg_data | = VF610_ADC_AVGS_16 ;
break ;
case VF610_ADC_SAMPLE_32 :
gc_data | = VF610_ADC_AVGEN ;
cfg_data | = VF610_ADC_AVGS_32 ;
break ;
default :
dev_err ( info - > dev ,
" error hardware sample average select \n " ) ;
}
writel ( cfg_data , info - > regs + VF610_REG_ADC_CFG ) ;
writel ( gc_data , info - > regs + VF610_REG_ADC_GC ) ;
}
static void vf610_adc_hw_init ( struct vf610_adc * info )
{
/* CFG: Feature set */
vf610_adc_cfg_post_set ( info ) ;
vf610_adc_sample_set ( info ) ;
/* adc calibration */
vf610_adc_calibration ( info ) ;
/* CFG: power and speed set */
vf610_adc_cfg_set ( info ) ;
}
2015-05-27 15:47:51 +03:00
static int vf610_set_conversion_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan ,
unsigned int mode )
{
struct vf610_adc * info = iio_priv ( indio_dev ) ;
2022-10-04 16:49:03 +03:00
mutex_lock ( & info - > lock ) ;
2015-05-27 15:47:51 +03:00
info - > adc_feature . conv_mode = mode ;
vf610_adc_calculate_rates ( info ) ;
vf610_adc_hw_init ( info ) ;
2022-10-04 16:49:03 +03:00
mutex_unlock ( & info - > lock ) ;
2015-05-27 15:47:51 +03:00
return 0 ;
}
static int vf610_get_conversion_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
{
struct vf610_adc * info = iio_priv ( indio_dev ) ;
return info - > adc_feature . conv_mode ;
}
static const char * const vf610_conv_modes [ ] = { " normal " , " high-speed " ,
" low-power " } ;
static const struct iio_enum vf610_conversion_mode = {
. items = vf610_conv_modes ,
. num_items = ARRAY_SIZE ( vf610_conv_modes ) ,
. get = vf610_get_conversion_mode ,
. set = vf610_set_conversion_mode ,
} ;
static const struct iio_chan_spec_ext_info vf610_ext_info [ ] = {
IIO_ENUM ( " conversion_mode " , IIO_SHARED_BY_DIR , & vf610_conversion_mode ) ,
{ } ,
} ;
# define VF610_ADC_CHAN(_idx, _chan_type) { \
. type = ( _chan_type ) , \
. indexed = 1 , \
. channel = ( _idx ) , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) , \
. ext_info = vf610_ext_info , \
2015-08-17 18:51:40 +03:00
. scan_index = ( _idx ) , \
. scan_type = { \
. sign = ' u ' , \
. realbits = 12 , \
. storagebits = 16 , \
} , \
2015-05-27 15:47:51 +03:00
}
# define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \
. type = ( _chan_type ) , \
. channel = ( _idx ) , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) , \
2015-08-17 18:51:40 +03:00
. scan_index = ( _idx ) , \
. scan_type = { \
. sign = ' u ' , \
. realbits = 12 , \
. storagebits = 16 , \
} , \
2015-05-27 15:47:51 +03:00
}
static const struct iio_chan_spec vf610_adc_iio_channels [ ] = {
VF610_ADC_CHAN ( 0 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 1 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 2 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 3 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 4 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 5 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 6 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 7 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 8 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 9 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 10 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 11 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 12 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 13 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 14 , IIO_VOLTAGE ) ,
VF610_ADC_CHAN ( 15 , IIO_VOLTAGE ) ,
VF610_ADC_TEMPERATURE_CHAN ( 26 , IIO_TEMP ) ,
2015-08-17 18:51:40 +03:00
IIO_CHAN_SOFT_TIMESTAMP ( 32 ) ,
2015-05-27 15:47:51 +03:00
/* sentinel */
} ;
2014-01-26 09:39:00 +04:00
static int vf610_adc_read_data ( struct vf610_adc * info )
{
int result ;
result = readl ( info - > regs + VF610_REG_ADC_R0 ) ;
switch ( info - > adc_feature . res_mode ) {
case 8 :
result & = 0xFF ;
break ;
case 10 :
result & = 0x3FF ;
break ;
case 12 :
result & = 0xFFF ;
break ;
default :
break ;
}
return result ;
}
static irqreturn_t vf610_adc_isr ( int irq , void * dev_id )
{
2017-04-01 17:06:14 +03:00
struct iio_dev * indio_dev = dev_id ;
2015-08-17 18:51:40 +03:00
struct vf610_adc * info = iio_priv ( indio_dev ) ;
2014-01-26 09:39:00 +04:00
int coco ;
coco = readl ( info - > regs + VF610_REG_ADC_HS ) ;
if ( coco & VF610_ADC_HS_COCO0 ) {
info - > value = vf610_adc_read_data ( info ) ;
2015-08-17 18:51:40 +03:00
if ( iio_buffer_enabled ( indio_dev ) ) {
2021-05-01 20:01:11 +03:00
info - > scan . chan = info - > value ;
2015-08-17 18:51:40 +03:00
iio_push_to_buffers_with_timestamp ( indio_dev ,
2021-05-01 20:01:11 +03:00
& info - > scan ,
2016-03-09 21:05:49 +03:00
iio_get_time_ns ( indio_dev ) ) ;
2015-08-17 18:51:40 +03:00
iio_trigger_notify_done ( indio_dev - > trig ) ;
} else
complete ( & info - > completion ) ;
2014-01-26 09:39:00 +04:00
}
return IRQ_HANDLED ;
}
2015-03-24 15:47:47 +03:00
static ssize_t vf610_show_samp_freq_avail ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct vf610_adc * info = iio_priv ( dev_to_iio_dev ( dev ) ) ;
size_t len = 0 ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( info - > sample_freq_avail ) ; i + + )
len + = scnprintf ( buf + len , PAGE_SIZE - len ,
" %u " , info - > sample_freq_avail [ i ] ) ;
/* replace trailing space by newline */
buf [ len - 1 ] = ' \n ' ;
return len ;
}
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL ( vf610_show_samp_freq_avail ) ;
2014-01-26 09:39:00 +04:00
static struct attribute * vf610_attributes [ ] = {
2015-03-24 15:47:47 +03:00
& iio_dev_attr_sampling_frequency_available . dev_attr . attr ,
2014-01-26 09:39:00 +04:00
NULL
} ;
static const struct attribute_group vf610_attribute_group = {
. attrs = vf610_attributes ,
} ;
2022-10-04 16:49:02 +03:00
static int vf610_read_sample ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int * val )
{
struct vf610_adc * info = iio_priv ( indio_dev ) ;
unsigned int hc_cfg ;
int ret ;
2022-10-04 16:49:03 +03:00
ret = iio_device_claim_direct_mode ( indio_dev ) ;
if ( ret )
return ret ;
2022-10-04 16:49:02 +03:00
2022-10-04 16:49:03 +03:00
mutex_lock ( & info - > lock ) ;
2022-10-04 16:49:02 +03:00
reinit_completion ( & info - > completion ) ;
hc_cfg = VF610_ADC_ADCHC ( chan - > channel ) ;
hc_cfg | = VF610_ADC_AIEN ;
writel ( hc_cfg , info - > regs + VF610_REG_ADC_HC0 ) ;
ret = wait_for_completion_interruptible_timeout ( & info - > completion ,
VF610_ADC_TIMEOUT ) ;
if ( ret = = 0 ) {
ret = - ETIMEDOUT ;
goto out_unlock ;
}
if ( ret < 0 )
goto out_unlock ;
switch ( chan - > type ) {
case IIO_VOLTAGE :
* val = info - > value ;
break ;
case IIO_TEMP :
/*
* Calculate in degree Celsius times 1000
* Using the typical sensor slope of 1.84 mV / ° C
* and VREFH_ADC at 3.3 V , V at 25 ° C of 699 mV
*/
* val = 25000 - ( ( int ) info - > value - VF610_VTEMP25_3V3 ) *
1000000 / VF610_TEMP_SLOPE_COEFF ;
break ;
default :
ret = - EINVAL ;
break ;
}
out_unlock :
2022-10-04 16:49:03 +03:00
mutex_unlock ( & info - > lock ) ;
iio_device_release_direct_mode ( indio_dev ) ;
2022-10-04 16:49:02 +03:00
return ret ;
}
2014-01-26 09:39:00 +04:00
static int vf610_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long mask )
{
struct vf610_adc * info = iio_priv ( indio_dev ) ;
2014-01-04 02:02:00 +04:00
long ret ;
2014-01-26 09:39:00 +04:00
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
2014-09-19 16:58:00 +04:00
case IIO_CHAN_INFO_PROCESSED :
2022-10-04 16:49:02 +03:00
ret = vf610_read_sample ( indio_dev , chan , val ) ;
if ( ret < 0 )
2014-01-26 09:39:00 +04:00
return ret ;
2014-09-19 16:58:00 +04:00
2014-01-26 09:39:00 +04:00
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
* val = info - > vref_uv / 1000 ;
* val2 = info - > adc_feature . res_mode ;
return IIO_VAL_FRACTIONAL_LOG2 ;
case IIO_CHAN_INFO_SAMP_FREQ :
2015-03-24 15:47:47 +03:00
* val = info - > sample_freq_avail [ info - > adc_feature . sample_rate ] ;
2014-01-26 09:39:00 +04:00
* val2 = 0 ;
return IIO_VAL_INT ;
default :
break ;
}
return - EINVAL ;
}
static int vf610_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long mask )
{
struct vf610_adc * info = iio_priv ( indio_dev ) ;
int i ;
switch ( mask ) {
2016-04-14 22:36:35 +03:00
case IIO_CHAN_INFO_SAMP_FREQ :
for ( i = 0 ;
i < ARRAY_SIZE ( info - > sample_freq_avail ) ;
i + + )
if ( val = = info - > sample_freq_avail [ i ] ) {
info - > adc_feature . sample_rate = i ;
vf610_adc_sample_set ( info ) ;
return 0 ;
}
break ;
2014-01-26 09:39:00 +04:00
2016-04-14 22:36:35 +03:00
default :
break ;
2014-01-26 09:39:00 +04:00
}
return - EINVAL ;
}
2015-08-17 18:51:40 +03:00
static int vf610_adc_buffer_postenable ( struct iio_dev * indio_dev )
{
struct vf610_adc * info = iio_priv ( indio_dev ) ;
unsigned int channel ;
int val ;
val = readl ( info - > regs + VF610_REG_ADC_GC ) ;
val | = VF610_ADC_ADCON ;
writel ( val , info - > regs + VF610_REG_ADC_GC ) ;
channel = find_first_bit ( indio_dev - > active_scan_mask ,
indio_dev - > masklength ) ;
val = VF610_ADC_ADCHC ( channel ) ;
val | = VF610_ADC_AIEN ;
writel ( val , info - > regs + VF610_REG_ADC_HC0 ) ;
return 0 ;
}
static int vf610_adc_buffer_predisable ( struct iio_dev * indio_dev )
{
struct vf610_adc * info = iio_priv ( indio_dev ) ;
unsigned int hc_cfg = 0 ;
2015-09-22 05:16:48 +03:00
int val ;
2015-08-17 18:51:40 +03:00
val = readl ( info - > regs + VF610_REG_ADC_GC ) ;
val & = ~ VF610_ADC_ADCON ;
writel ( val , info - > regs + VF610_REG_ADC_GC ) ;
hc_cfg | = VF610_ADC_CONV_DISABLE ;
hc_cfg & = ~ VF610_ADC_AIEN ;
writel ( hc_cfg , info - > regs + VF610_REG_ADC_HC0 ) ;
2020-05-25 14:38:53 +03:00
return 0 ;
2015-08-17 18:51:40 +03:00
}
static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
. postenable = & vf610_adc_buffer_postenable ,
. predisable = & vf610_adc_buffer_predisable ,
. validate_scan_mask = & iio_validate_scan_mask_onehot ,
} ;
2014-01-26 09:39:00 +04:00
static int vf610_adc_reg_access ( struct iio_dev * indio_dev ,
unsigned reg , unsigned writeval ,
unsigned * readval )
{
struct vf610_adc * info = iio_priv ( indio_dev ) ;
if ( ( readval = = NULL ) | |
2015-07-16 09:49:09 +03:00
( ( reg % 4 ) | | ( reg > VF610_REG_ADC_PCTL ) ) )
2014-01-26 09:39:00 +04:00
return - EINVAL ;
* readval = readl ( info - > regs + reg ) ;
return 0 ;
}
static const struct iio_info vf610_adc_iio_info = {
. read_raw = & vf610_read_raw ,
. write_raw = & vf610_write_raw ,
. debugfs_reg_access = & vf610_adc_reg_access ,
. attrs = & vf610_attribute_group ,
} ;
static const struct of_device_id vf610_adc_match [ ] = {
{ . compatible = " fsl,vf610-adc " , } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , vf610_adc_match ) ;
static int vf610_adc_probe ( struct platform_device * pdev )
{
2022-05-31 17:23:53 +03:00
struct device * dev = & pdev - > dev ;
2014-01-26 09:39:00 +04:00
struct vf610_adc * info ;
struct iio_dev * indio_dev ;
int irq ;
int ret ;
indio_dev = devm_iio_device_alloc ( & pdev - > dev , sizeof ( struct vf610_adc ) ) ;
if ( ! indio_dev ) {
dev_err ( & pdev - > dev , " Failed allocating iio device \n " ) ;
return - ENOMEM ;
}
info = iio_priv ( indio_dev ) ;
info - > dev = & pdev - > dev ;
2019-10-13 19:43:49 +03:00
info - > regs = devm_platform_ioremap_resource ( pdev , 0 ) ;
2014-01-26 09:39:00 +04:00
if ( IS_ERR ( info - > regs ) )
return PTR_ERR ( info - > regs ) ;
irq = platform_get_irq ( pdev , 0 ) ;
2019-07-30 21:15:19 +03:00
if ( irq < 0 )
2014-10-03 05:25:22 +04:00
return irq ;
2014-01-26 09:39:00 +04:00
ret = devm_request_irq ( info - > dev , irq ,
vf610_adc_isr , 0 ,
2015-08-17 18:51:40 +03:00
dev_name ( & pdev - > dev ) , indio_dev ) ;
2014-01-26 09:39:00 +04:00
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " failed requesting irq, irq = %d \n " , irq ) ;
return ret ;
}
info - > clk = devm_clk_get ( & pdev - > dev , " adc " ) ;
if ( IS_ERR ( info - > clk ) ) {
dev_err ( & pdev - > dev , " failed getting clock, err = %ld \n " ,
PTR_ERR ( info - > clk ) ) ;
2014-10-03 05:25:23 +04:00
return PTR_ERR ( info - > clk ) ;
2014-01-26 09:39:00 +04:00
}
info - > vref = devm_regulator_get ( & pdev - > dev , " vref " ) ;
if ( IS_ERR ( info - > vref ) )
return PTR_ERR ( info - > vref ) ;
ret = regulator_enable ( info - > vref ) ;
if ( ret )
return ret ;
info - > vref_uv = regulator_get_voltage ( info - > vref ) ;
2022-05-31 17:23:53 +03:00
device_property_read_u32_array ( dev , " fsl,adck-max-frequency " , info - > max_adck_rate , 3 ) ;
2015-05-27 15:47:51 +03:00
2022-05-31 17:23:53 +03:00
info - > adc_feature . default_sample_time = DEFAULT_SAMPLE_TIME ;
device_property_read_u32 ( dev , " min-sample-time " , & info - > adc_feature . default_sample_time ) ;
2015-07-14 16:53:22 +03:00
2014-01-26 09:39:00 +04:00
platform_set_drvdata ( pdev , indio_dev ) ;
init_completion ( & info - > completion ) ;
indio_dev - > name = dev_name ( & pdev - > dev ) ;
indio_dev - > info = & vf610_adc_iio_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > channels = vf610_adc_iio_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( vf610_adc_iio_channels ) ;
ret = clk_prepare_enable ( info - > clk ) ;
if ( ret ) {
dev_err ( & pdev - > dev ,
" Could not prepare or enable the clock. \n " ) ;
goto error_adc_clk_enable ;
}
vf610_adc_cfg_init ( info ) ;
vf610_adc_hw_init ( info ) ;
2015-08-17 18:51:40 +03:00
ret = iio_triggered_buffer_setup ( indio_dev , & iio_pollfunc_store_time ,
NULL , & iio_triggered_buffer_setup_ops ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " Couldn't initialise the buffer \n " ) ;
goto error_iio_device_register ;
}
2022-10-04 16:49:03 +03:00
mutex_init ( & info - > lock ) ;
2014-01-26 09:39:00 +04:00
ret = iio_device_register ( indio_dev ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " Couldn't register the device. \n " ) ;
2015-08-17 18:51:40 +03:00
goto error_adc_buffer_init ;
2014-01-26 09:39:00 +04:00
}
return 0 ;
2015-08-17 18:51:40 +03:00
error_adc_buffer_init :
iio_triggered_buffer_cleanup ( indio_dev ) ;
2014-01-26 09:39:00 +04:00
error_iio_device_register :
clk_disable_unprepare ( info - > clk ) ;
error_adc_clk_enable :
regulator_disable ( info - > vref ) ;
return ret ;
}
2023-09-19 20:49:10 +03:00
static void vf610_adc_remove ( struct platform_device * pdev )
2014-01-26 09:39:00 +04:00
{
struct iio_dev * indio_dev = platform_get_drvdata ( pdev ) ;
struct vf610_adc * info = iio_priv ( indio_dev ) ;
iio_device_unregister ( indio_dev ) ;
2015-08-17 18:51:40 +03:00
iio_triggered_buffer_cleanup ( indio_dev ) ;
2014-01-26 09:39:00 +04:00
regulator_disable ( info - > vref ) ;
clk_disable_unprepare ( info - > clk ) ;
}
static int vf610_adc_suspend ( struct device * dev )
{
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
struct vf610_adc * info = iio_priv ( indio_dev ) ;
int hc_cfg ;
/* ADC controller enters to stop mode */
hc_cfg = readl ( info - > regs + VF610_REG_ADC_HC0 ) ;
hc_cfg | = VF610_ADC_CONV_DISABLE ;
writel ( hc_cfg , info - > regs + VF610_REG_ADC_HC0 ) ;
clk_disable_unprepare ( info - > clk ) ;
regulator_disable ( info - > vref ) ;
return 0 ;
}
static int vf610_adc_resume ( struct device * dev )
{
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
struct vf610_adc * info = iio_priv ( indio_dev ) ;
int ret ;
ret = regulator_enable ( info - > vref ) ;
if ( ret )
return ret ;
ret = clk_prepare_enable ( info - > clk ) ;
if ( ret )
2014-10-03 05:25:24 +04:00
goto disable_reg ;
2014-01-26 09:39:00 +04:00
vf610_adc_hw_init ( info ) ;
return 0 ;
2014-10-03 05:25:24 +04:00
disable_reg :
regulator_disable ( info - > vref ) ;
return ret ;
2014-01-26 09:39:00 +04:00
}
2022-01-30 22:31:12 +03:00
static DEFINE_SIMPLE_DEV_PM_OPS ( vf610_adc_pm_ops , vf610_adc_suspend ,
vf610_adc_resume ) ;
2014-01-26 09:39:00 +04:00
static struct platform_driver vf610_adc_driver = {
. probe = vf610_adc_probe ,
2023-09-19 20:49:10 +03:00
. remove_new = vf610_adc_remove ,
2014-01-26 09:39:00 +04:00
. driver = {
. name = DRIVER_NAME ,
. of_match_table = vf610_adc_match ,
2022-01-30 22:31:12 +03:00
. pm = pm_sleep_ptr ( & vf610_adc_pm_ops ) ,
2014-01-26 09:39:00 +04:00
} ,
} ;
module_platform_driver ( vf610_adc_driver ) ;
MODULE_AUTHOR ( " Fugang Duan <B38611@freescale.com> " ) ;
MODULE_DESCRIPTION ( " Freescale VF610 ADC driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;