2017-12-05 17:55:59 +03:00
// SPDX-License-Identifier: GPL-2.0
2016-11-15 18:30:57 +03:00
/*
* This file is part of STM32 ADC driver
*
* Copyright ( C ) 2016 , STMicroelectronics - All Rights Reserved
* Author : Fabrice Gasnier < fabrice . gasnier @ st . com > .
*
* Inspired from : fsl - imx25 - tsadc
*
*/
# include <linux/clk.h>
# include <linux/interrupt.h>
# include <linux/irqchip/chained_irq.h>
# include <linux/irqdesc.h>
# include <linux/irqdomain.h>
2019-07-03 13:08:15 +03:00
# include <linux/mfd/syscon.h>
2016-11-15 18:30:57 +03:00
# include <linux/module.h>
# include <linux/of_device.h>
2018-11-20 13:12:31 +03:00
# include <linux/pm_runtime.h>
2019-07-03 13:08:15 +03:00
# include <linux/regmap.h>
2016-11-15 18:30:57 +03:00
# include <linux/regulator/consumer.h>
# include <linux/slab.h>
# include "stm32-adc-core.h"
2018-11-20 13:12:31 +03:00
# define STM32_ADC_CORE_SLEEP_DELAY_MS 2000
2019-07-03 13:08:15 +03:00
/* SYSCFG registers */
# define STM32MP1_SYSCFG_PMCSETR 0x04
# define STM32MP1_SYSCFG_PMCCLRR 0x44
/* SYSCFG bit fields */
# define STM32MP1_SYSCFG_ANASWVDD_MASK BIT(9)
/* SYSCFG capability flags */
# define HAS_VBOOSTER BIT(0)
# define HAS_ANASWVDD BIT(1)
2017-05-29 12:28:18 +03:00
/**
2019-09-20 14:50:06 +03:00
* struct stm32_adc_common_regs - stm32 common registers
2017-05-29 12:28:18 +03:00
* @ csr : common status register offset
2018-11-20 13:12:31 +03:00
* @ ccr : common control register offset
2019-09-20 14:50:06 +03:00
* @ eoc1_msk : adc1 end of conversion flag in @ csr
* @ eoc2_msk : adc2 end of conversion flag in @ csr
* @ eoc3_msk : adc3 end of conversion flag in @ csr
2019-09-17 15:38:16 +03:00
* @ ier : interrupt enable register offset for each adc
* @ eocie_msk : end of conversion interrupt enable mask in @ ier
2017-05-29 12:28:18 +03:00
*/
struct stm32_adc_common_regs {
u32 csr ;
2018-11-20 13:12:31 +03:00
u32 ccr ;
2017-05-29 12:28:18 +03:00
u32 eoc1_msk ;
u32 eoc2_msk ;
u32 eoc3_msk ;
2019-09-17 15:38:16 +03:00
u32 ier ;
u32 eocie_msk ;
2017-05-29 12:28:18 +03:00
} ;
struct stm32_adc_priv ;
/**
2019-09-20 14:50:06 +03:00
* struct stm32_adc_priv_cfg - stm32 core compatible configuration data
2017-05-29 12:28:18 +03:00
* @ regs : common registers for all instances
* @ clk_sel : clock selection routine
2018-05-02 10:44:50 +03:00
* @ max_clk_rate_hz : maximum analog clock rate ( Hz , from datasheet )
2019-07-03 13:08:15 +03:00
* @ has_syscfg : SYSCFG capability flags
2017-05-29 12:28:18 +03:00
*/
struct stm32_adc_priv_cfg {
const struct stm32_adc_common_regs * regs ;
int ( * clk_sel ) ( struct platform_device * , struct stm32_adc_priv * ) ;
2018-05-02 10:44:50 +03:00
u32 max_clk_rate_hz ;
2019-07-03 13:08:15 +03:00
unsigned int has_syscfg ;
2017-05-29 12:28:18 +03:00
} ;
2016-11-15 18:30:57 +03:00
/**
* struct stm32_adc_priv - stm32 ADC core private data
2018-05-02 10:44:50 +03:00
* @ irq : irq ( s ) for ADC block
2016-11-15 18:30:57 +03:00
* @ domain : irq domain reference
* @ aclk : clock reference for the analog circuitry
2017-05-29 12:28:20 +03:00
* @ bclk : bus clock common for all ADCs , depends on part used
2019-10-28 19:11:48 +03:00
* @ max_clk_rate : desired maximum clock rate
2019-07-03 13:08:15 +03:00
* @ booster : booster supply reference
* @ vdd : vdd supply reference
2019-06-19 15:29:55 +03:00
* @ vdda : vdda analog supply reference
2016-11-15 18:30:57 +03:00
* @ vref : regulator reference
2019-07-03 13:08:15 +03:00
* @ vdd_uv : vdd supply voltage ( microvolts )
* @ vdda_uv : vdda supply voltage ( microvolts )
2017-05-29 12:28:18 +03:00
* @ cfg : compatible configuration data
2016-11-15 18:30:57 +03:00
* @ common : common data for all ADC instances
2018-11-20 13:12:31 +03:00
* @ ccr_bak : backup CCR in low power mode
2019-07-03 13:08:15 +03:00
* @ syscfg : reference to syscon , system control registers
2016-11-15 18:30:57 +03:00
*/
struct stm32_adc_priv {
2018-05-02 10:44:50 +03:00
int irq [ STM32_ADC_MAX_ADCS ] ;
2016-11-15 18:30:57 +03:00
struct irq_domain * domain ;
struct clk * aclk ;
2017-05-29 12:28:20 +03:00
struct clk * bclk ;
2019-10-28 19:11:48 +03:00
u32 max_clk_rate ;
2019-07-03 13:08:15 +03:00
struct regulator * booster ;
struct regulator * vdd ;
2019-06-19 15:29:55 +03:00
struct regulator * vdda ;
2016-11-15 18:30:57 +03:00
struct regulator * vref ;
2019-07-03 13:08:15 +03:00
int vdd_uv ;
int vdda_uv ;
2017-05-29 12:28:18 +03:00
const struct stm32_adc_priv_cfg * cfg ;
2016-11-15 18:30:57 +03:00
struct stm32_adc_common common ;
2018-11-20 13:12:31 +03:00
u32 ccr_bak ;
2019-07-03 13:08:15 +03:00
struct regmap * syscfg ;
2016-11-15 18:30:57 +03:00
} ;
static struct stm32_adc_priv * to_stm32_adc_priv ( struct stm32_adc_common * com )
{
return container_of ( com , struct stm32_adc_priv , common ) ;
}
/* STM32F4 ADC internal common clock prescaler division ratios */
static int stm32f4_pclk_div [ ] = { 2 , 4 , 6 , 8 } ;
/**
* stm32f4_adc_clk_sel ( ) - Select stm32f4 ADC common clock prescaler
2019-09-20 14:50:06 +03:00
* @ pdev : platform device
2016-11-15 18:30:57 +03:00
* @ priv : stm32 ADC core private data
* Select clock prescaler used for analog conversions , before using ADC .
*/
static int stm32f4_adc_clk_sel ( struct platform_device * pdev ,
struct stm32_adc_priv * priv )
{
unsigned long rate ;
u32 val ;
int i ;
2017-05-29 12:28:17 +03:00
/* stm32f4 has one clk input for analog (mandatory), enforce it here */
if ( ! priv - > aclk ) {
dev_err ( & pdev - > dev , " No 'adc' clock found \n " ) ;
return - ENOENT ;
}
2016-11-15 18:30:57 +03:00
rate = clk_get_rate ( priv - > aclk ) ;
2017-10-18 14:40:12 +03:00
if ( ! rate ) {
dev_err ( & pdev - > dev , " Invalid clock rate: 0 \n " ) ;
return - EINVAL ;
}
2016-11-15 18:30:57 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( stm32f4_pclk_div ) ; i + + ) {
2019-10-28 19:11:48 +03:00
if ( ( rate / stm32f4_pclk_div [ i ] ) < = priv - > max_clk_rate )
2016-11-15 18:30:57 +03:00
break ;
}
2017-05-29 12:28:17 +03:00
if ( i > = ARRAY_SIZE ( stm32f4_pclk_div ) ) {
dev_err ( & pdev - > dev , " adc clk selection failed \n " ) ;
2016-11-15 18:30:57 +03:00
return - EINVAL ;
2017-05-29 12:28:17 +03:00
}
2016-11-15 18:30:57 +03:00
2017-07-24 19:10:38 +03:00
priv - > common . rate = rate / stm32f4_pclk_div [ i ] ;
2016-11-15 18:30:57 +03:00
val = readl_relaxed ( priv - > common . base + STM32F4_ADC_CCR ) ;
val & = ~ STM32F4_ADC_ADCPRE_MASK ;
val | = i < < STM32F4_ADC_ADCPRE_SHIFT ;
writel_relaxed ( val , priv - > common . base + STM32F4_ADC_CCR ) ;
dev_dbg ( & pdev - > dev , " Using analog clock source at %ld kHz \n " ,
2017-07-24 19:10:38 +03:00
priv - > common . rate / 1000 ) ;
2016-11-15 18:30:57 +03:00
return 0 ;
}
2017-05-29 12:28:20 +03:00
/**
* struct stm32h7_adc_ck_spec - specification for stm32h7 adc clock
* @ ckmode : ADC clock mode , Async or sync with prescaler .
* @ presc : prescaler bitfield for async clock mode
* @ div : prescaler division ratio
*/
struct stm32h7_adc_ck_spec {
u32 ckmode ;
u32 presc ;
int div ;
} ;
2017-06-28 16:06:50 +03:00
static const struct stm32h7_adc_ck_spec stm32h7_adc_ckmodes_spec [ ] = {
2017-05-29 12:28:20 +03:00
/* 00: CK_ADC[1..3]: Asynchronous clock modes */
{ 0 , 0 , 1 } ,
{ 0 , 1 , 2 } ,
{ 0 , 2 , 4 } ,
{ 0 , 3 , 6 } ,
{ 0 , 4 , 8 } ,
{ 0 , 5 , 10 } ,
{ 0 , 6 , 12 } ,
{ 0 , 7 , 16 } ,
{ 0 , 8 , 32 } ,
{ 0 , 9 , 64 } ,
{ 0 , 10 , 128 } ,
{ 0 , 11 , 256 } ,
/* HCLK used: Synchronous clock modes (1, 2 or 4 prescaler) */
{ 1 , 0 , 1 } ,
{ 2 , 0 , 2 } ,
{ 3 , 0 , 4 } ,
} ;
static int stm32h7_adc_clk_sel ( struct platform_device * pdev ,
struct stm32_adc_priv * priv )
{
u32 ckmode , presc , val ;
unsigned long rate ;
int i , div ;
/* stm32h7 bus clock is common for all ADC instances (mandatory) */
if ( ! priv - > bclk ) {
dev_err ( & pdev - > dev , " No 'bus' clock found \n " ) ;
return - ENOENT ;
}
/*
* stm32h7 can use either ' bus ' or ' adc ' clock for analog circuitry .
* So , choice is to have bus clock mandatory and adc clock optional .
* If optional ' adc ' clock has been found , then try to use it first .
*/
if ( priv - > aclk ) {
/*
* Asynchronous clock modes ( e . g . ckmode = = 0 )
* From spec : PLL output musn ' t exceed max rate
*/
rate = clk_get_rate ( priv - > aclk ) ;
2017-10-18 14:40:12 +03:00
if ( ! rate ) {
dev_err ( & pdev - > dev , " Invalid adc clock rate: 0 \n " ) ;
return - EINVAL ;
}
2017-05-29 12:28:20 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( stm32h7_adc_ckmodes_spec ) ; i + + ) {
ckmode = stm32h7_adc_ckmodes_spec [ i ] . ckmode ;
presc = stm32h7_adc_ckmodes_spec [ i ] . presc ;
div = stm32h7_adc_ckmodes_spec [ i ] . div ;
if ( ckmode )
continue ;
2019-10-28 19:11:48 +03:00
if ( ( rate / div ) < = priv - > max_clk_rate )
2017-05-29 12:28:20 +03:00
goto out ;
}
}
/* Synchronous clock modes (e.g. ckmode is 1, 2 or 3) */
rate = clk_get_rate ( priv - > bclk ) ;
2017-10-18 14:40:12 +03:00
if ( ! rate ) {
dev_err ( & pdev - > dev , " Invalid bus clock rate: 0 \n " ) ;
return - EINVAL ;
}
2017-05-29 12:28:20 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( stm32h7_adc_ckmodes_spec ) ; i + + ) {
ckmode = stm32h7_adc_ckmodes_spec [ i ] . ckmode ;
presc = stm32h7_adc_ckmodes_spec [ i ] . presc ;
div = stm32h7_adc_ckmodes_spec [ i ] . div ;
if ( ! ckmode )
continue ;
2019-10-28 19:11:48 +03:00
if ( ( rate / div ) < = priv - > max_clk_rate )
2017-05-29 12:28:20 +03:00
goto out ;
}
dev_err ( & pdev - > dev , " adc clk selection failed \n " ) ;
return - EINVAL ;
out :
/* rate used later by each ADC instance to control BOOST mode */
2017-07-24 19:10:38 +03:00
priv - > common . rate = rate / div ;
2017-05-29 12:28:20 +03:00
/* Set common clock mode and prescaler */
val = readl_relaxed ( priv - > common . base + STM32H7_ADC_CCR ) ;
val & = ~ ( STM32H7_CKMODE_MASK | STM32H7_PRESC_MASK ) ;
val | = ckmode < < STM32H7_CKMODE_SHIFT ;
val | = presc < < STM32H7_PRESC_SHIFT ;
writel_relaxed ( val , priv - > common . base + STM32H7_ADC_CCR ) ;
dev_dbg ( & pdev - > dev , " Using %s clock/%d source at %ld kHz \n " ,
2017-07-24 19:10:38 +03:00
ckmode ? " bus " : " adc " , div , priv - > common . rate / 1000 ) ;
2017-05-29 12:28:20 +03:00
return 0 ;
}
2017-05-29 12:28:18 +03:00
/* STM32F4 common registers definitions */
static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
. csr = STM32F4_ADC_CSR ,
2018-11-20 13:12:31 +03:00
. ccr = STM32F4_ADC_CCR ,
2019-12-02 12:02:19 +03:00
. eoc1_msk = STM32F4_EOC1 | STM32F4_OVR1 ,
. eoc2_msk = STM32F4_EOC2 | STM32F4_OVR2 ,
. eoc3_msk = STM32F4_EOC3 | STM32F4_OVR3 ,
2019-09-17 15:38:16 +03:00
. ier = STM32F4_ADC_CR1 ,
2019-12-02 12:02:19 +03:00
. eocie_msk = STM32F4_EOCIE | STM32F4_OVRIE ,
2017-05-29 12:28:18 +03:00
} ;
2017-05-29 12:28:20 +03:00
/* STM32H7 common registers definitions */
static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
. csr = STM32H7_ADC_CSR ,
2018-11-20 13:12:31 +03:00
. ccr = STM32H7_ADC_CCR ,
2019-12-02 12:02:19 +03:00
. eoc1_msk = STM32H7_EOC_MST | STM32H7_OVR_MST ,
. eoc2_msk = STM32H7_EOC_SLV | STM32H7_OVR_SLV ,
2019-09-17 15:38:16 +03:00
. ier = STM32H7_ADC_IER ,
2019-12-02 12:02:19 +03:00
. eocie_msk = STM32H7_EOCIE | STM32H7_OVRIE ,
2017-05-29 12:28:20 +03:00
} ;
2019-09-17 15:38:16 +03:00
static const unsigned int stm32_adc_offset [ STM32_ADC_MAX_ADCS ] = {
0 , STM32_ADC_OFFSET , STM32_ADC_OFFSET * 2 ,
} ;
static unsigned int stm32_adc_eoc_enabled ( struct stm32_adc_priv * priv ,
unsigned int adc )
{
u32 ier , offset = stm32_adc_offset [ adc ] ;
ier = readl_relaxed ( priv - > common . base + offset + priv - > cfg - > regs - > ier ) ;
return ier & priv - > cfg - > regs - > eocie_msk ;
}
2016-11-15 18:30:57 +03:00
/* ADC common interrupt for all instances */
static void stm32_adc_irq_handler ( struct irq_desc * desc )
{
struct stm32_adc_priv * priv = irq_desc_get_handler_data ( desc ) ;
struct irq_chip * chip = irq_desc_get_chip ( desc ) ;
u32 status ;
chained_irq_enter ( chip , desc ) ;
2017-05-29 12:28:18 +03:00
status = readl_relaxed ( priv - > common . base + priv - > cfg - > regs - > csr ) ;
2016-11-15 18:30:57 +03:00
2019-09-17 15:38:16 +03:00
/*
* End of conversion may be handled by using IRQ or DMA . There may be a
* race here when two conversions complete at the same time on several
* ADCs . EOC may be read ' set ' for several ADCs , with :
* - an ADC configured to use DMA ( EOC triggers the DMA request , and
* is then automatically cleared by DR read in hardware )
* - an ADC configured to use IRQs ( EOCIE bit is set . The handler must
* be called in this case )
* So both EOC status bit in CSR and EOCIE control bit must be checked
* before invoking the interrupt handler ( e . g . call ISR only for
* IRQ - enabled ADCs ) .
*/
if ( status & priv - > cfg - > regs - > eoc1_msk & &
stm32_adc_eoc_enabled ( priv , 0 ) )
2016-11-15 18:30:57 +03:00
generic_handle_irq ( irq_find_mapping ( priv - > domain , 0 ) ) ;
2019-09-17 15:38:16 +03:00
if ( status & priv - > cfg - > regs - > eoc2_msk & &
stm32_adc_eoc_enabled ( priv , 1 ) )
2016-11-15 18:30:57 +03:00
generic_handle_irq ( irq_find_mapping ( priv - > domain , 1 ) ) ;
2019-09-17 15:38:16 +03:00
if ( status & priv - > cfg - > regs - > eoc3_msk & &
stm32_adc_eoc_enabled ( priv , 2 ) )
2016-11-15 18:30:57 +03:00
generic_handle_irq ( irq_find_mapping ( priv - > domain , 2 ) ) ;
chained_irq_exit ( chip , desc ) ;
} ;
static int stm32_adc_domain_map ( struct irq_domain * d , unsigned int irq ,
irq_hw_number_t hwirq )
{
irq_set_chip_data ( irq , d - > host_data ) ;
irq_set_chip_and_handler ( irq , & dummy_irq_chip , handle_level_irq ) ;
return 0 ;
}
static void stm32_adc_domain_unmap ( struct irq_domain * d , unsigned int irq )
{
irq_set_chip_and_handler ( irq , NULL , NULL ) ;
irq_set_chip_data ( irq , NULL ) ;
}
static const struct irq_domain_ops stm32_adc_domain_ops = {
. map = stm32_adc_domain_map ,
. unmap = stm32_adc_domain_unmap ,
. xlate = irq_domain_xlate_onecell ,
} ;
static int stm32_adc_irq_probe ( struct platform_device * pdev ,
struct stm32_adc_priv * priv )
{
struct device_node * np = pdev - > dev . of_node ;
2018-05-02 10:44:50 +03:00
unsigned int i ;
for ( i = 0 ; i < STM32_ADC_MAX_ADCS ; i + + ) {
priv - > irq [ i ] = platform_get_irq ( pdev , i ) ;
if ( priv - > irq [ i ] < 0 ) {
/*
* At least one interrupt must be provided , make others
* optional :
* - stm32f4 / h7 shares a common interrupt .
* - stm32mp1 , has one line per ADC ( either for ADC1 ,
* ADC2 or both ) .
*/
if ( i & & priv - > irq [ i ] = = - ENXIO )
continue ;
2016-11-15 18:30:57 +03:00
2018-05-02 10:44:50 +03:00
return priv - > irq [ i ] ;
}
2016-11-15 18:30:57 +03:00
}
priv - > domain = irq_domain_add_simple ( np , STM32_ADC_MAX_ADCS , 0 ,
& stm32_adc_domain_ops ,
priv ) ;
if ( ! priv - > domain ) {
dev_err ( & pdev - > dev , " Failed to add irq domain \n " ) ;
return - ENOMEM ;
}
2018-05-02 10:44:50 +03:00
for ( i = 0 ; i < STM32_ADC_MAX_ADCS ; i + + ) {
if ( priv - > irq [ i ] < 0 )
continue ;
irq_set_chained_handler ( priv - > irq [ i ] , stm32_adc_irq_handler ) ;
irq_set_handler_data ( priv - > irq [ i ] , priv ) ;
}
2016-11-15 18:30:57 +03:00
return 0 ;
}
static void stm32_adc_irq_remove ( struct platform_device * pdev ,
struct stm32_adc_priv * priv )
{
int hwirq ;
2018-05-02 10:44:50 +03:00
unsigned int i ;
2016-11-15 18:30:57 +03:00
for ( hwirq = 0 ; hwirq < STM32_ADC_MAX_ADCS ; hwirq + + )
irq_dispose_mapping ( irq_find_mapping ( priv - > domain , hwirq ) ) ;
irq_domain_remove ( priv - > domain ) ;
2018-05-02 10:44:50 +03:00
for ( i = 0 ; i < STM32_ADC_MAX_ADCS ; i + + ) {
if ( priv - > irq [ i ] < 0 )
continue ;
irq_set_chained_handler ( priv - > irq [ i ] , NULL ) ;
}
2016-11-15 18:30:57 +03:00
}
2019-07-03 13:08:15 +03:00
static int stm32_adc_core_switches_supply_en ( struct stm32_adc_priv * priv ,
struct device * dev )
{
int ret ;
/*
* On STM32H7 and STM32MP1 , the ADC inputs are multiplexed with analog
* switches ( via PCSEL ) which have reduced performances when their
* supply is below 2.7 V ( vdda by default ) :
* - Voltage booster can be used , to get full ADC performances
* ( increases power consumption ) .
* - Vdd can be used to supply them , if above 2.7 V ( STM32MP1 only ) .
*
* Recommended settings for ANASWVDD and EN_BOOSTER :
* - vdda < 2.7 V but vdd > 2.7 V : ANASWVDD = 1 , EN_BOOSTER = 0 ( stm32mp1 )
* - vdda < 2.7 V and vdd < 2.7 V : ANASWVDD = 0 , EN_BOOSTER = 1
* - vdda > = 2.7 V : ANASWVDD = 0 , EN_BOOSTER = 0 ( default )
*/
if ( priv - > vdda_uv < 2700000 ) {
if ( priv - > syscfg & & priv - > vdd_uv > 2700000 ) {
ret = regulator_enable ( priv - > vdd ) ;
if ( ret < 0 ) {
dev_err ( dev , " vdd enable failed %d \n " , ret ) ;
return ret ;
}
ret = regmap_write ( priv - > syscfg ,
STM32MP1_SYSCFG_PMCSETR ,
STM32MP1_SYSCFG_ANASWVDD_MASK ) ;
if ( ret < 0 ) {
regulator_disable ( priv - > vdd ) ;
dev_err ( dev , " vdd select failed, %d \n " , ret ) ;
return ret ;
}
dev_dbg ( dev , " analog switches supplied by vdd \n " ) ;
return 0 ;
}
if ( priv - > booster ) {
/*
* This is optional , as this is a trade - off between
* analog performance and power consumption .
*/
ret = regulator_enable ( priv - > booster ) ;
if ( ret < 0 ) {
dev_err ( dev , " booster enable failed %d \n " , ret ) ;
return ret ;
}
dev_dbg ( dev , " analog switches supplied by booster \n " ) ;
return 0 ;
}
}
/* Fallback using vdda (default), nothing to do */
dev_dbg ( dev , " analog switches supplied by vdda (%d uV) \n " ,
priv - > vdda_uv ) ;
return 0 ;
}
static void stm32_adc_core_switches_supply_dis ( struct stm32_adc_priv * priv )
{
if ( priv - > vdda_uv < 2700000 ) {
if ( priv - > syscfg & & priv - > vdd_uv > 2700000 ) {
regmap_write ( priv - > syscfg , STM32MP1_SYSCFG_PMCCLRR ,
STM32MP1_SYSCFG_ANASWVDD_MASK ) ;
regulator_disable ( priv - > vdd ) ;
return ;
}
if ( priv - > booster )
regulator_disable ( priv - > booster ) ;
}
}
2018-11-20 13:12:31 +03:00
static int stm32_adc_core_hw_start ( struct device * dev )
{
struct stm32_adc_common * common = dev_get_drvdata ( dev ) ;
struct stm32_adc_priv * priv = to_stm32_adc_priv ( common ) ;
int ret ;
2019-06-19 15:29:55 +03:00
ret = regulator_enable ( priv - > vdda ) ;
if ( ret < 0 ) {
dev_err ( dev , " vdda enable failed %d \n " , ret ) ;
return ret ;
}
2019-07-03 13:08:15 +03:00
ret = regulator_get_voltage ( priv - > vdda ) ;
if ( ret < 0 ) {
dev_err ( dev , " vdda get voltage failed, %d \n " , ret ) ;
goto err_vdda_disable ;
}
priv - > vdda_uv = ret ;
ret = stm32_adc_core_switches_supply_en ( priv , dev ) ;
if ( ret < 0 )
goto err_vdda_disable ;
2018-11-20 13:12:31 +03:00
ret = regulator_enable ( priv - > vref ) ;
if ( ret < 0 ) {
dev_err ( dev , " vref enable failed \n " ) ;
2019-07-03 13:08:15 +03:00
goto err_switches_dis ;
2018-11-20 13:12:31 +03:00
}
if ( priv - > bclk ) {
ret = clk_prepare_enable ( priv - > bclk ) ;
if ( ret < 0 ) {
dev_err ( dev , " bus clk enable failed \n " ) ;
goto err_regulator_disable ;
}
}
if ( priv - > aclk ) {
ret = clk_prepare_enable ( priv - > aclk ) ;
if ( ret < 0 ) {
dev_err ( dev , " adc clk enable failed \n " ) ;
goto err_bclk_disable ;
}
}
writel_relaxed ( priv - > ccr_bak , priv - > common . base + priv - > cfg - > regs - > ccr ) ;
return 0 ;
err_bclk_disable :
if ( priv - > bclk )
clk_disable_unprepare ( priv - > bclk ) ;
err_regulator_disable :
regulator_disable ( priv - > vref ) ;
2019-07-03 13:08:15 +03:00
err_switches_dis :
stm32_adc_core_switches_supply_dis ( priv ) ;
2019-06-19 15:29:55 +03:00
err_vdda_disable :
regulator_disable ( priv - > vdda ) ;
2018-11-20 13:12:31 +03:00
return ret ;
}
static void stm32_adc_core_hw_stop ( struct device * dev )
{
struct stm32_adc_common * common = dev_get_drvdata ( dev ) ;
struct stm32_adc_priv * priv = to_stm32_adc_priv ( common ) ;
/* Backup CCR that may be lost (depends on power state to achieve) */
priv - > ccr_bak = readl_relaxed ( priv - > common . base + priv - > cfg - > regs - > ccr ) ;
if ( priv - > aclk )
clk_disable_unprepare ( priv - > aclk ) ;
if ( priv - > bclk )
clk_disable_unprepare ( priv - > bclk ) ;
regulator_disable ( priv - > vref ) ;
2019-07-03 13:08:15 +03:00
stm32_adc_core_switches_supply_dis ( priv ) ;
2019-06-19 15:29:55 +03:00
regulator_disable ( priv - > vdda ) ;
2018-11-20 13:12:31 +03:00
}
2019-07-03 13:08:15 +03:00
static int stm32_adc_core_switches_probe ( struct device * dev ,
struct stm32_adc_priv * priv )
{
struct device_node * np = dev - > of_node ;
int ret ;
/* Analog switches supply can be controlled by syscfg (optional) */
priv - > syscfg = syscon_regmap_lookup_by_phandle ( np , " st,syscfg " ) ;
if ( IS_ERR ( priv - > syscfg ) ) {
ret = PTR_ERR ( priv - > syscfg ) ;
if ( ret ! = - ENODEV ) {
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " Can't probe syscfg: %d \n " , ret ) ;
return ret ;
}
priv - > syscfg = NULL ;
}
/* Booster can be used to supply analog switches (optional) */
if ( priv - > cfg - > has_syscfg & HAS_VBOOSTER & &
of_property_read_bool ( np , " booster-supply " ) ) {
priv - > booster = devm_regulator_get_optional ( dev , " booster " ) ;
if ( IS_ERR ( priv - > booster ) ) {
ret = PTR_ERR ( priv - > booster ) ;
if ( ret ! = - ENODEV ) {
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " can't get booster %d \n " ,
ret ) ;
return ret ;
}
priv - > booster = NULL ;
}
}
/* Vdd can be used to supply analog switches (optional) */
if ( priv - > cfg - > has_syscfg & HAS_ANASWVDD & &
of_property_read_bool ( np , " vdd-supply " ) ) {
priv - > vdd = devm_regulator_get_optional ( dev , " vdd " ) ;
if ( IS_ERR ( priv - > vdd ) ) {
ret = PTR_ERR ( priv - > vdd ) ;
if ( ret ! = - ENODEV ) {
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " can't get vdd %d \n " , ret ) ;
return ret ;
}
priv - > vdd = NULL ;
}
}
if ( priv - > vdd ) {
ret = regulator_enable ( priv - > vdd ) ;
if ( ret < 0 ) {
dev_err ( dev , " vdd enable failed %d \n " , ret ) ;
return ret ;
}
ret = regulator_get_voltage ( priv - > vdd ) ;
if ( ret < 0 ) {
dev_err ( dev , " vdd get voltage failed %d \n " , ret ) ;
regulator_disable ( priv - > vdd ) ;
return ret ;
}
priv - > vdd_uv = ret ;
regulator_disable ( priv - > vdd ) ;
}
return 0 ;
}
2016-11-15 18:30:57 +03:00
static int stm32_adc_probe ( struct platform_device * pdev )
{
struct stm32_adc_priv * priv ;
2017-05-29 12:28:18 +03:00
struct device * dev = & pdev - > dev ;
2016-11-15 18:30:57 +03:00
struct device_node * np = pdev - > dev . of_node ;
struct resource * res ;
2019-10-28 19:11:48 +03:00
u32 max_rate ;
2016-11-15 18:30:57 +03:00
int ret ;
if ( ! pdev - > dev . of_node )
return - ENODEV ;
priv = devm_kzalloc ( & pdev - > dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
2018-11-20 13:12:31 +03:00
platform_set_drvdata ( pdev , & priv - > common ) ;
2016-11-15 18:30:57 +03:00
2017-05-29 12:28:18 +03:00
priv - > cfg = ( const struct stm32_adc_priv_cfg * )
of_match_device ( dev - > driver - > of_match_table , dev ) - > data ;
2016-11-15 18:30:57 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
priv - > common . base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( priv - > common . base ) )
return PTR_ERR ( priv - > common . base ) ;
2017-01-26 17:28:33 +03:00
priv - > common . phys_base = res - > start ;
2016-11-15 18:30:57 +03:00
2019-06-19 15:29:55 +03:00
priv - > vdda = devm_regulator_get ( & pdev - > dev , " vdda " ) ;
if ( IS_ERR ( priv - > vdda ) ) {
ret = PTR_ERR ( priv - > vdda ) ;
if ( ret ! = - EPROBE_DEFER )
dev_err ( & pdev - > dev , " vdda get failed, %d \n " , ret ) ;
return ret ;
}
2016-11-15 18:30:57 +03:00
priv - > vref = devm_regulator_get ( & pdev - > dev , " vref " ) ;
if ( IS_ERR ( priv - > vref ) ) {
ret = PTR_ERR ( priv - > vref ) ;
2020-01-13 16:18:59 +03:00
if ( ret ! = - EPROBE_DEFER )
dev_err ( & pdev - > dev , " vref get failed, %d \n " , ret ) ;
2016-11-15 18:30:57 +03:00
return ret ;
}
priv - > aclk = devm_clk_get ( & pdev - > dev , " adc " ) ;
if ( IS_ERR ( priv - > aclk ) ) {
ret = PTR_ERR ( priv - > aclk ) ;
2018-11-20 13:12:31 +03:00
if ( ret ! = - ENOENT ) {
2020-01-13 16:18:59 +03:00
if ( ret ! = - EPROBE_DEFER )
dev_err ( & pdev - > dev , " Can't get 'adc' clock \n " ) ;
2018-11-20 13:12:31 +03:00
return ret ;
2017-05-29 12:28:17 +03:00
}
2018-11-20 13:12:31 +03:00
priv - > aclk = NULL ;
2016-11-15 18:30:57 +03:00
}
2017-05-29 12:28:20 +03:00
priv - > bclk = devm_clk_get ( & pdev - > dev , " bus " ) ;
if ( IS_ERR ( priv - > bclk ) ) {
ret = PTR_ERR ( priv - > bclk ) ;
2018-11-20 13:12:31 +03:00
if ( ret ! = - ENOENT ) {
2020-01-13 16:18:59 +03:00
if ( ret ! = - EPROBE_DEFER )
dev_err ( & pdev - > dev , " Can't get 'bus' clock \n " ) ;
2018-11-20 13:12:31 +03:00
return ret ;
2017-05-29 12:28:20 +03:00
}
2018-11-20 13:12:31 +03:00
priv - > bclk = NULL ;
2017-05-29 12:28:20 +03:00
}
2019-07-03 13:08:15 +03:00
ret = stm32_adc_core_switches_probe ( dev , priv ) ;
if ( ret )
return ret ;
2018-11-20 13:12:31 +03:00
pm_runtime_get_noresume ( dev ) ;
pm_runtime_set_active ( dev ) ;
pm_runtime_set_autosuspend_delay ( dev , STM32_ADC_CORE_SLEEP_DELAY_MS ) ;
pm_runtime_use_autosuspend ( dev ) ;
pm_runtime_enable ( dev ) ;
ret = stm32_adc_core_hw_start ( dev ) ;
if ( ret )
goto err_pm_stop ;
ret = regulator_get_voltage ( priv - > vref ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " vref get voltage failed, %d \n " , ret ) ;
goto err_hw_stop ;
2017-05-29 12:28:20 +03:00
}
2018-11-20 13:12:31 +03:00
priv - > common . vref_mv = ret / 1000 ;
dev_dbg ( & pdev - > dev , " vref+=%dmV \n " , priv - > common . vref_mv ) ;
2017-05-29 12:28:20 +03:00
2019-10-28 19:11:48 +03:00
ret = of_property_read_u32 ( pdev - > dev . of_node , " st,max-clk-rate-hz " ,
& max_rate ) ;
if ( ! ret )
priv - > max_clk_rate = min ( max_rate , priv - > cfg - > max_clk_rate_hz ) ;
else
priv - > max_clk_rate = priv - > cfg - > max_clk_rate_hz ;
2017-05-29 12:28:18 +03:00
ret = priv - > cfg - > clk_sel ( pdev , priv ) ;
2017-05-29 12:28:17 +03:00
if ( ret < 0 )
2018-11-20 13:12:31 +03:00
goto err_hw_stop ;
2016-11-15 18:30:57 +03:00
ret = stm32_adc_irq_probe ( pdev , priv ) ;
if ( ret < 0 )
2018-11-20 13:12:31 +03:00
goto err_hw_stop ;
2016-11-15 18:30:57 +03:00
ret = of_platform_populate ( np , NULL , NULL , & pdev - > dev ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " failed to populate DT children \n " ) ;
goto err_irq_remove ;
}
2018-11-20 13:12:31 +03:00
pm_runtime_mark_last_busy ( dev ) ;
pm_runtime_put_autosuspend ( dev ) ;
2016-11-15 18:30:57 +03:00
return 0 ;
err_irq_remove :
stm32_adc_irq_remove ( pdev , priv ) ;
2018-11-20 13:12:31 +03:00
err_hw_stop :
stm32_adc_core_hw_stop ( dev ) ;
err_pm_stop :
pm_runtime_disable ( dev ) ;
pm_runtime_set_suspended ( dev ) ;
pm_runtime_put_noidle ( dev ) ;
2016-11-15 18:30:57 +03:00
return ret ;
}
static int stm32_adc_remove ( struct platform_device * pdev )
{
struct stm32_adc_common * common = platform_get_drvdata ( pdev ) ;
struct stm32_adc_priv * priv = to_stm32_adc_priv ( common ) ;
2018-11-20 13:12:31 +03:00
pm_runtime_get_sync ( & pdev - > dev ) ;
2016-11-15 18:30:57 +03:00
of_platform_depopulate ( & pdev - > dev ) ;
stm32_adc_irq_remove ( pdev , priv ) ;
2018-11-20 13:12:31 +03:00
stm32_adc_core_hw_stop ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
pm_runtime_set_suspended ( & pdev - > dev ) ;
pm_runtime_put_noidle ( & pdev - > dev ) ;
2016-11-15 18:30:57 +03:00
return 0 ;
}
2018-11-20 13:12:31 +03:00
# if defined(CONFIG_PM)
static int stm32_adc_core_runtime_suspend ( struct device * dev )
{
stm32_adc_core_hw_stop ( dev ) ;
return 0 ;
}
static int stm32_adc_core_runtime_resume ( struct device * dev )
{
return stm32_adc_core_hw_start ( dev ) ;
}
# endif
static const struct dev_pm_ops stm32_adc_core_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( pm_runtime_force_suspend ,
pm_runtime_force_resume )
SET_RUNTIME_PM_OPS ( stm32_adc_core_runtime_suspend ,
stm32_adc_core_runtime_resume ,
NULL )
} ;
2017-05-29 12:28:18 +03:00
static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
. regs = & stm32f4_adc_common_regs ,
. clk_sel = stm32f4_adc_clk_sel ,
2018-05-02 10:44:50 +03:00
. max_clk_rate_hz = 36000000 ,
2017-05-29 12:28:18 +03:00
} ;
2017-05-29 12:28:20 +03:00
static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
. regs = & stm32h7_adc_common_regs ,
. clk_sel = stm32h7_adc_clk_sel ,
2018-05-02 10:44:50 +03:00
. max_clk_rate_hz = 36000000 ,
2019-07-03 13:08:15 +03:00
. has_syscfg = HAS_VBOOSTER ,
2018-05-02 10:44:50 +03:00
} ;
static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
. regs = & stm32h7_adc_common_regs ,
. clk_sel = stm32h7_adc_clk_sel ,
. max_clk_rate_hz = 40000000 ,
2019-07-03 13:08:15 +03:00
. has_syscfg = HAS_VBOOSTER | HAS_ANASWVDD ,
2017-05-29 12:28:20 +03:00
} ;
2016-11-15 18:30:57 +03:00
static const struct of_device_id stm32_adc_of_match [ ] = {
2017-05-29 12:28:18 +03:00
{
. compatible = " st,stm32f4-adc-core " ,
. data = ( void * ) & stm32f4_adc_priv_cfg
2017-05-29 12:28:20 +03:00
} , {
. compatible = " st,stm32h7-adc-core " ,
. data = ( void * ) & stm32h7_adc_priv_cfg
2018-05-02 10:44:50 +03:00
} , {
. compatible = " st,stm32mp1-adc-core " ,
. data = ( void * ) & stm32mp1_adc_priv_cfg
2017-05-29 12:28:18 +03:00
} , {
} ,
2016-11-15 18:30:57 +03:00
} ;
MODULE_DEVICE_TABLE ( of , stm32_adc_of_match ) ;
static struct platform_driver stm32_adc_driver = {
. probe = stm32_adc_probe ,
. remove = stm32_adc_remove ,
. driver = {
. name = " stm32-adc-core " ,
. of_match_table = stm32_adc_of_match ,
2018-11-20 13:12:31 +03:00
. pm = & stm32_adc_core_pm_ops ,
2016-11-15 18:30:57 +03:00
} ,
} ;
module_platform_driver ( stm32_adc_driver ) ;
MODULE_AUTHOR ( " Fabrice Gasnier <fabrice.gasnier@st.com> " ) ;
MODULE_DESCRIPTION ( " STMicroelectronics STM32 ADC core driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform:stm32-adc-core " ) ;