2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2014-07-14 18:33:27 +04:00
/*
2016-08-16 12:35:07 +03:00
* PWM device driver for ST SoCs
*
* Copyright ( C ) 2013 - 2016 STMicroelectronics ( R & D ) Limited
2014-07-14 18:33:27 +04:00
*
2016-08-16 12:35:07 +03:00
* Author : Ajit Pal Singh < ajitpal . singh @ st . com >
* Lee Jones < lee . jones @ linaro . org >
2014-07-14 18:33:27 +04:00
*/
# include <linux/clk.h>
2016-08-16 12:35:03 +03:00
# include <linux/interrupt.h>
2014-07-14 18:33:27 +04:00
# include <linux/math64.h>
# include <linux/mfd/syscon.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <linux/pwm.h>
# include <linux/regmap.h>
2016-08-16 12:35:03 +03:00
# include <linux/sched.h>
2014-07-14 18:33:27 +04:00
# include <linux/slab.h>
# include <linux/time.h>
2016-08-16 12:35:03 +03:00
# include <linux/wait.h>
2014-07-14 18:33:27 +04:00
2016-08-16 12:34:59 +03:00
# define PWM_OUT_VAL(x) (0x00 + (4 * (x))) /* Device's Duty Cycle register */
2016-08-16 12:35:01 +03:00
# define PWM_CPT_VAL(x) (0x10 + (4 * (x))) /* Capture value */
# define PWM_CPT_EDGE(x) (0x30 + (4 * (x))) /* Edge to capture on */
2016-08-16 12:34:59 +03:00
# define STI_PWM_CTRL 0x50 /* Control/Config register */
# define STI_INT_EN 0x54 /* Interrupt Enable/Disable register */
2016-08-16 12:35:01 +03:00
# define STI_INT_STA 0x58 /* Interrupt Status register */
2016-08-16 12:35:07 +03:00
# define PWM_INT_ACK 0x5c
# define PWM_PRESCALE_LOW_MASK 0x0f
# define PWM_PRESCALE_HIGH_MASK 0xf0
# define PWM_CPT_EDGE_MASK 0x03
# define PWM_INT_ACK_MASK 0x1ff
2016-08-16 12:35:01 +03:00
2016-08-16 12:35:07 +03:00
# define STI_MAX_CPT_DEVS 4
# define CPT_DC_MAX 0xff
2014-07-14 18:33:27 +04:00
/* Regfield IDs */
enum {
2016-08-16 12:34:59 +03:00
/* Bits in PWM_CTRL*/
2014-07-14 18:33:29 +04:00
PWMCLK_PRESCALE_LOW ,
PWMCLK_PRESCALE_HIGH ,
2016-08-16 12:35:01 +03:00
CPTCLK_PRESCALE ,
2016-08-16 12:34:59 +03:00
PWM_OUT_EN ,
2016-08-16 12:35:01 +03:00
PWM_CPT_EN ,
2016-08-16 12:34:59 +03:00
PWM_CPT_INT_EN ,
2016-08-16 12:35:01 +03:00
PWM_CPT_INT_STAT ,
2014-07-14 18:33:27 +04:00
/* Keep last */
MAX_REGFIELDS
} ;
2016-08-16 12:35:07 +03:00
/*
* Each capture input can be programmed to detect rising - edge , falling - edge ,
* either edge or neither egde .
2016-08-16 12:35:01 +03:00
*/
enum sti_cpt_edge {
CPT_EDGE_DISABLED ,
CPT_EDGE_RISING ,
CPT_EDGE_FALLING ,
CPT_EDGE_BOTH ,
} ;
2016-08-16 12:35:03 +03:00
struct sti_cpt_ddata {
u32 snapshot [ 3 ] ;
unsigned int index ;
struct mutex lock ;
wait_queue_head_t wait ;
} ;
2014-07-14 18:33:27 +04:00
struct sti_pwm_compat_data {
const struct reg_field * reg_fields ;
2016-08-16 12:35:03 +03:00
unsigned int pwm_num_devs ;
unsigned int cpt_num_devs ;
2014-07-14 18:33:27 +04:00
unsigned int max_pwm_cnt ;
unsigned int max_prescale ;
} ;
struct sti_pwm_chip {
struct device * dev ;
2016-08-16 12:34:59 +03:00
struct clk * pwm_clk ;
2016-08-16 12:35:02 +03:00
struct clk * cpt_clk ;
2014-07-14 18:33:27 +04:00
struct regmap * regmap ;
struct sti_pwm_compat_data * cdata ;
2014-07-14 18:33:29 +04:00
struct regmap_field * prescale_low ;
struct regmap_field * prescale_high ;
2016-08-16 12:34:59 +03:00
struct regmap_field * pwm_out_en ;
2016-08-16 12:35:04 +03:00
struct regmap_field * pwm_cpt_en ;
2016-08-16 12:34:59 +03:00
struct regmap_field * pwm_cpt_int_en ;
2016-08-16 12:35:04 +03:00
struct regmap_field * pwm_cpt_int_stat ;
2014-07-14 18:33:27 +04:00
struct pwm_chip chip ;
2014-07-14 18:33:30 +04:00
struct pwm_device * cur ;
2015-01-29 12:04:43 +03:00
unsigned long configured ;
2014-07-14 18:33:31 +04:00
unsigned int en_count ;
struct mutex sti_pwm_lock ; /* To sync between enable/disable calls */
2014-07-14 18:33:27 +04:00
void __iomem * mmio ;
} ;
static const struct reg_field sti_pwm_regfields [ MAX_REGFIELDS ] = {
2016-08-16 12:35:07 +03:00
[ PWMCLK_PRESCALE_LOW ] = REG_FIELD ( STI_PWM_CTRL , 0 , 3 ) ,
[ PWMCLK_PRESCALE_HIGH ] = REG_FIELD ( STI_PWM_CTRL , 11 , 14 ) ,
[ CPTCLK_PRESCALE ] = REG_FIELD ( STI_PWM_CTRL , 4 , 8 ) ,
[ PWM_OUT_EN ] = REG_FIELD ( STI_PWM_CTRL , 9 , 9 ) ,
[ PWM_CPT_EN ] = REG_FIELD ( STI_PWM_CTRL , 10 , 10 ) ,
[ PWM_CPT_INT_EN ] = REG_FIELD ( STI_INT_EN , 1 , 4 ) ,
[ PWM_CPT_INT_STAT ] = REG_FIELD ( STI_INT_STA , 1 , 4 ) ,
2014-07-14 18:33:27 +04:00
} ;
static inline struct sti_pwm_chip * to_sti_pwmchip ( struct pwm_chip * chip )
{
return container_of ( chip , struct sti_pwm_chip , chip ) ;
}
/*
2014-07-14 18:33:32 +04:00
* Calculate the prescaler value corresponding to the period .
2014-07-14 18:33:27 +04:00
*/
2014-07-14 18:33:32 +04:00
static int sti_pwm_get_prescale ( struct sti_pwm_chip * pc , unsigned long period ,
unsigned int * prescale )
2014-07-14 18:33:27 +04:00
{
struct sti_pwm_compat_data * cdata = pc - > cdata ;
2016-08-16 12:35:00 +03:00
unsigned long clk_rate ;
2016-08-16 12:35:07 +03:00
unsigned long value ;
2014-07-14 18:33:32 +04:00
unsigned int ps ;
2014-07-14 18:33:27 +04:00
2016-08-16 12:35:00 +03:00
clk_rate = clk_get_rate ( pc - > pwm_clk ) ;
if ( ! clk_rate ) {
dev_err ( pc - > dev , " failed to get clock rate \n " ) ;
return - EINVAL ;
}
2014-07-14 18:33:27 +04:00
/*
2016-08-16 12:35:07 +03:00
* prescale = ( ( period_ns * clk_rate ) / ( 10 ^ 9 * ( max_pwm_cnt + 1 ) ) - 1
2014-07-14 18:33:27 +04:00
*/
2016-08-16 12:35:07 +03:00
value = NSEC_PER_SEC / clk_rate ;
value * = cdata - > max_pwm_cnt + 1 ;
2014-07-14 18:33:27 +04:00
2016-08-16 12:35:07 +03:00
if ( period % value )
2014-07-14 18:33:32 +04:00
return - EINVAL ;
2016-08-16 12:35:07 +03:00
ps = period / value - 1 ;
if ( ps > cdata - > max_prescale )
return - EINVAL ;
2014-07-14 18:33:32 +04:00
* prescale = ps ;
return 0 ;
2014-07-14 18:33:27 +04:00
}
/*
2016-08-16 12:35:07 +03:00
* For STiH4xx PWM IP , the PWM period is fixed to 256 local clock cycles . The
* only way to change the period ( apart from changing the PWM input clock ) is
* to change the PWM clock prescaler .
*
* The prescaler is of 8 bits , so 256 prescaler values and hence 256 possible
* period values are supported ( for a particular clock rate ) . The requested
* period will be applied only if it matches one of these 256 values .
2014-07-14 18:33:27 +04:00
*/
static int sti_pwm_config ( struct pwm_chip * chip , struct pwm_device * pwm ,
2016-08-16 12:35:07 +03:00
int duty_ns , int period_ns )
2014-07-14 18:33:27 +04:00
{
struct sti_pwm_chip * pc = to_sti_pwmchip ( chip ) ;
struct sti_pwm_compat_data * cdata = pc - > cdata ;
2016-08-16 12:35:07 +03:00
unsigned int ncfg , value , prescale = 0 ;
2014-07-14 18:33:30 +04:00
struct pwm_device * cur = pc - > cur ;
2014-07-14 18:33:27 +04:00
struct device * dev = pc - > dev ;
2014-07-14 18:33:30 +04:00
bool period_same = false ;
2016-08-16 12:35:07 +03:00
int ret ;
2014-07-14 18:33:30 +04:00
2015-01-29 12:04:43 +03:00
ncfg = hweight_long ( pc - > configured ) ;
2014-07-14 18:33:30 +04:00
if ( ncfg )
period_same = ( period_ns = = pwm_get_period ( cur ) ) ;
2016-08-16 12:35:07 +03:00
/*
* Allow configuration changes if one of the following conditions
* satisfy .
2016-08-16 12:34:58 +03:00
* 1. No devices have been configured .
2016-08-16 12:35:07 +03:00
* 2. Only one device has been configured and the new request is for
* the same device .
* 3. Only one device has been configured and the new request is for
* a new device and period of the new device is same as the current
* configured period .
2016-08-16 12:34:58 +03:00
* 4. More than one devices are configured and period of the new
2014-07-14 18:33:30 +04:00
* requestis the same as the current period .
2014-07-14 18:33:27 +04:00
*/
2014-07-14 18:33:30 +04:00
if ( ! ncfg | |
( ( ncfg = = 1 ) & & ( pwm - > hwpwm = = cur - > hwpwm ) ) | |
( ( ncfg = = 1 ) & & ( pwm - > hwpwm ! = cur - > hwpwm ) & & period_same ) | |
( ( ncfg > 1 ) & & period_same ) ) {
/* Enable clock before writing to PWM registers. */
2016-08-16 12:34:59 +03:00
ret = clk_enable ( pc - > pwm_clk ) ;
2014-07-14 18:33:30 +04:00
if ( ret )
return ret ;
2016-08-16 12:35:02 +03:00
ret = clk_enable ( pc - > cpt_clk ) ;
if ( ret )
return ret ;
2014-07-14 18:33:30 +04:00
if ( ! period_same ) {
2014-07-14 18:33:32 +04:00
ret = sti_pwm_get_prescale ( pc , period_ns , & prescale ) ;
if ( ret )
2014-07-14 18:33:30 +04:00
goto clk_dis ;
2016-08-16 12:35:07 +03:00
value = prescale & PWM_PRESCALE_LOW_MASK ;
ret = regmap_field_write ( pc - > prescale_low , value ) ;
2014-07-14 18:33:30 +04:00
if ( ret )
goto clk_dis ;
2016-08-16 12:35:07 +03:00
value = ( prescale & PWM_PRESCALE_HIGH_MASK ) > > 4 ;
ret = regmap_field_write ( pc - > prescale_high , value ) ;
2014-07-14 18:33:30 +04:00
if ( ret )
goto clk_dis ;
}
/*
* When PWMVal = = 0 , PWM pulse = 1 local clock cycle .
* When PWMVal = = max_pwm_count ,
* PWM pulse = ( max_pwm_count + 1 ) local cycles ,
* that is continuous pulse : signal never goes low .
*/
2016-08-16 12:35:07 +03:00
value = cdata - > max_pwm_cnt * duty_ns / period_ns ;
2014-07-14 18:33:30 +04:00
2016-08-16 12:35:07 +03:00
ret = regmap_write ( pc - > regmap , PWM_OUT_VAL ( pwm - > hwpwm ) , value ) ;
2014-07-14 18:33:30 +04:00
if ( ret )
goto clk_dis ;
2016-08-16 12:34:59 +03:00
ret = regmap_field_write ( pc - > pwm_cpt_int_en , 0 ) ;
2014-07-14 18:33:30 +04:00
2015-01-29 12:04:43 +03:00
set_bit ( pwm - > hwpwm , & pc - > configured ) ;
2014-07-14 18:33:30 +04:00
pc - > cur = pwm ;
2016-08-16 12:35:07 +03:00
dev_dbg ( dev , " prescale:%u, period:%i, duty:%i, value:%u \n " ,
prescale , period_ns , duty_ns , value ) ;
2014-07-14 18:33:30 +04:00
} else {
2014-07-14 18:33:27 +04:00
return - EINVAL ;
}
clk_dis :
2016-08-16 12:34:59 +03:00
clk_disable ( pc - > pwm_clk ) ;
2016-08-16 12:35:02 +03:00
clk_disable ( pc - > cpt_clk ) ;
2014-07-14 18:33:27 +04:00
return ret ;
}
static int sti_pwm_enable ( struct pwm_chip * chip , struct pwm_device * pwm )
{
struct sti_pwm_chip * pc = to_sti_pwmchip ( chip ) ;
struct device * dev = pc - > dev ;
2014-07-14 18:33:31 +04:00
int ret = 0 ;
2014-07-14 18:33:27 +04:00
2014-07-14 18:33:31 +04:00
/*
2016-08-16 12:35:07 +03:00
* Since we have a common enable for all PWM devices , do not enable if
* already enabled .
2014-07-14 18:33:31 +04:00
*/
mutex_lock ( & pc - > sti_pwm_lock ) ;
2016-08-16 12:35:07 +03:00
2014-07-14 18:33:31 +04:00
if ( ! pc - > en_count ) {
2016-08-16 12:34:59 +03:00
ret = clk_enable ( pc - > pwm_clk ) ;
2014-07-14 18:33:31 +04:00
if ( ret )
goto out ;
2014-07-14 18:33:27 +04:00
2016-08-16 12:35:02 +03:00
ret = clk_enable ( pc - > cpt_clk ) ;
if ( ret )
goto out ;
2016-08-16 12:34:59 +03:00
ret = regmap_field_write ( pc - > pwm_out_en , 1 ) ;
2014-07-14 18:33:31 +04:00
if ( ret ) {
2016-08-16 12:35:07 +03:00
dev_err ( dev , " failed to enable PWM device %u: %d \n " ,
pwm - > hwpwm , ret ) ;
2014-07-14 18:33:31 +04:00
goto out ;
}
}
2016-08-16 12:35:07 +03:00
2014-07-14 18:33:31 +04:00
pc - > en_count + + ;
2016-08-16 12:35:07 +03:00
2014-07-14 18:33:31 +04:00
out :
mutex_unlock ( & pc - > sti_pwm_lock ) ;
2014-07-14 18:33:27 +04:00
return ret ;
}
static void sti_pwm_disable ( struct pwm_chip * chip , struct pwm_device * pwm )
{
struct sti_pwm_chip * pc = to_sti_pwmchip ( chip ) ;
2014-07-14 18:33:31 +04:00
mutex_lock ( & pc - > sti_pwm_lock ) ;
2016-08-16 12:35:07 +03:00
2014-07-14 18:33:31 +04:00
if ( - - pc - > en_count ) {
mutex_unlock ( & pc - > sti_pwm_lock ) ;
return ;
}
2016-08-16 12:35:07 +03:00
2016-08-16 12:34:59 +03:00
regmap_field_write ( pc - > pwm_out_en , 0 ) ;
2014-07-14 18:33:27 +04:00
2016-08-16 12:34:59 +03:00
clk_disable ( pc - > pwm_clk ) ;
2016-08-16 12:35:02 +03:00
clk_disable ( pc - > cpt_clk ) ;
2016-08-16 12:35:07 +03:00
2014-07-14 18:33:31 +04:00
mutex_unlock ( & pc - > sti_pwm_lock ) ;
2014-07-14 18:33:27 +04:00
}
2015-01-29 12:04:43 +03:00
static void sti_pwm_free ( struct pwm_chip * chip , struct pwm_device * pwm )
{
struct sti_pwm_chip * pc = to_sti_pwmchip ( chip ) ;
clear_bit ( pwm - > hwpwm , & pc - > configured ) ;
}
2016-08-16 12:35:05 +03:00
static int sti_pwm_capture ( struct pwm_chip * chip , struct pwm_device * pwm ,
struct pwm_capture * result , unsigned long timeout )
{
struct sti_pwm_chip * pc = to_sti_pwmchip ( chip ) ;
struct sti_pwm_compat_data * cdata = pc - > cdata ;
struct sti_cpt_ddata * ddata = pwm_get_chip_data ( pwm ) ;
struct device * dev = pc - > dev ;
unsigned int effective_ticks ;
unsigned long long high , low ;
int ret ;
if ( pwm - > hwpwm > = cdata - > cpt_num_devs ) {
dev_err ( dev , " device %u is not valid \n " , pwm - > hwpwm ) ;
return - EINVAL ;
}
mutex_lock ( & ddata - > lock ) ;
ddata - > index = 0 ;
/* Prepare capture measurement */
regmap_write ( pc - > regmap , PWM_CPT_EDGE ( pwm - > hwpwm ) , CPT_EDGE_RISING ) ;
regmap_field_write ( pc - > pwm_cpt_int_en , BIT ( pwm - > hwpwm ) ) ;
/* Enable capture */
ret = regmap_field_write ( pc - > pwm_cpt_en , 1 ) ;
if ( ret ) {
dev_err ( dev , " failed to enable PWM capture %u: %d \n " ,
pwm - > hwpwm , ret ) ;
goto out ;
}
ret = wait_event_interruptible_timeout ( ddata - > wait , ddata - > index > 1 ,
msecs_to_jiffies ( timeout ) ) ;
regmap_write ( pc - > regmap , PWM_CPT_EDGE ( pwm - > hwpwm ) , CPT_EDGE_DISABLED ) ;
if ( ret = = - ERESTARTSYS )
goto out ;
switch ( ddata - > index ) {
case 0 :
case 1 :
/*
* Getting here could mean :
* - input signal is constant of less than 1 Hz
* - there is no input signal at all
*
* In such case the frequency is rounded down to 0
*/
result - > period = 0 ;
result - > duty_cycle = 0 ;
break ;
case 2 :
/* We have everying we need */
high = ddata - > snapshot [ 1 ] - ddata - > snapshot [ 0 ] ;
low = ddata - > snapshot [ 2 ] - ddata - > snapshot [ 1 ] ;
effective_ticks = clk_get_rate ( pc - > cpt_clk ) ;
result - > period = ( high + low ) * NSEC_PER_SEC ;
result - > period / = effective_ticks ;
result - > duty_cycle = high * NSEC_PER_SEC ;
result - > duty_cycle / = effective_ticks ;
break ;
default :
dev_err ( dev , " internal error \n " ) ;
break ;
}
out :
/* Disable capture */
regmap_field_write ( pc - > pwm_cpt_en , 0 ) ;
mutex_unlock ( & ddata - > lock ) ;
return ret ;
}
2022-05-06 17:09:52 +03:00
static int sti_pwm_apply ( struct pwm_chip * chip , struct pwm_device * pwm ,
const struct pwm_state * state )
{
int err ;
if ( state - > polarity ! = PWM_POLARITY_NORMAL )
return - EINVAL ;
if ( ! state - > enabled ) {
if ( pwm - > state . enabled )
sti_pwm_disable ( chip , pwm ) ;
return 0 ;
}
err = sti_pwm_config ( pwm - > chip , pwm , state - > duty_cycle , state - > period ) ;
if ( err )
return err ;
if ( ! pwm - > state . enabled )
err = sti_pwm_enable ( chip , pwm ) ;
return err ;
}
2014-07-14 18:33:27 +04:00
static const struct pwm_ops sti_pwm_ops = {
2016-08-16 12:35:05 +03:00
. capture = sti_pwm_capture ,
2022-05-06 17:09:52 +03:00
. apply = sti_pwm_apply ,
2015-01-29 12:04:43 +03:00
. free = sti_pwm_free ,
2014-07-14 18:33:27 +04:00
. owner = THIS_MODULE ,
} ;
2016-08-16 12:35:04 +03:00
static irqreturn_t sti_pwm_interrupt ( int irq , void * data )
{
struct sti_pwm_chip * pc = data ;
struct device * dev = pc - > dev ;
struct sti_cpt_ddata * ddata ;
int devicenum ;
unsigned int cpt_int_stat ;
unsigned int reg ;
int ret = IRQ_NONE ;
ret = regmap_field_read ( pc - > pwm_cpt_int_stat , & cpt_int_stat ) ;
if ( ret )
return ret ;
while ( cpt_int_stat ) {
devicenum = ffs ( cpt_int_stat ) - 1 ;
ddata = pwm_get_chip_data ( & pc - > chip . pwms [ devicenum ] ) ;
/*
* Capture input :
* _______ _______
* | | | |
* __ | | _________________ | | ________
* ^ 0 ^ 1 ^ 2
*
2016-08-16 12:35:07 +03:00
* Capture start by the first available rising edge . When a
* capture event occurs , capture value ( CPT_VALx ) is stored ,
* index incremented , capture edge changed .
2016-08-16 12:35:04 +03:00
*
2016-08-16 12:35:07 +03:00
* After the capture , if the index > 1 , we have collected the
* necessary data so we signal the thread waiting for it and
* disable the capture by setting capture edge to none
2016-08-16 12:35:04 +03:00
*/
regmap_read ( pc - > regmap ,
PWM_CPT_VAL ( devicenum ) ,
& ddata - > snapshot [ ddata - > index ] ) ;
switch ( ddata - > index ) {
case 0 :
case 1 :
regmap_read ( pc - > regmap , PWM_CPT_EDGE ( devicenum ) , & reg ) ;
reg ^ = PWM_CPT_EDGE_MASK ;
regmap_write ( pc - > regmap , PWM_CPT_EDGE ( devicenum ) , reg ) ;
ddata - > index + + ;
break ;
2016-08-16 12:35:07 +03:00
2016-08-16 12:35:04 +03:00
case 2 :
regmap_write ( pc - > regmap ,
PWM_CPT_EDGE ( devicenum ) ,
CPT_EDGE_DISABLED ) ;
wake_up ( & ddata - > wait ) ;
break ;
2016-08-16 12:35:07 +03:00
2016-08-16 12:35:04 +03:00
default :
dev_err ( dev , " Internal error \n " ) ;
}
cpt_int_stat & = ~ BIT_MASK ( devicenum ) ;
ret = IRQ_HANDLED ;
}
/* Just ACK everything */
regmap_write ( pc - > regmap , PWM_INT_ACK , PWM_INT_ACK_MASK ) ;
return ret ;
}
2014-07-14 18:33:27 +04:00
static int sti_pwm_probe_dt ( struct sti_pwm_chip * pc )
{
struct device * dev = pc - > dev ;
const struct reg_field * reg_fields ;
struct device_node * np = dev - > of_node ;
struct sti_pwm_compat_data * cdata = pc - > cdata ;
2016-08-16 12:34:58 +03:00
u32 num_devs ;
2016-08-16 12:35:03 +03:00
int ret ;
2014-07-14 18:33:27 +04:00
2016-08-16 12:35:03 +03:00
ret = of_property_read_u32 ( np , " st,pwm-num-chan " , & num_devs ) ;
if ( ! ret )
cdata - > pwm_num_devs = num_devs ;
ret = of_property_read_u32 ( np , " st,capture-num-chan " , & num_devs ) ;
if ( ! ret )
cdata - > cpt_num_devs = num_devs ;
2014-07-14 18:33:27 +04:00
2016-08-16 12:35:06 +03:00
if ( ! cdata - > pwm_num_devs & & ! cdata - > cpt_num_devs ) {
dev_err ( dev , " No channels configured \n " ) ;
return - EINVAL ;
}
2014-07-14 18:33:27 +04:00
reg_fields = cdata - > reg_fields ;
2014-07-14 18:33:29 +04:00
pc - > prescale_low = devm_regmap_field_alloc ( dev , pc - > regmap ,
reg_fields [ PWMCLK_PRESCALE_LOW ] ) ;
if ( IS_ERR ( pc - > prescale_low ) )
return PTR_ERR ( pc - > prescale_low ) ;
pc - > prescale_high = devm_regmap_field_alloc ( dev , pc - > regmap ,
reg_fields [ PWMCLK_PRESCALE_HIGH ] ) ;
if ( IS_ERR ( pc - > prescale_high ) )
return PTR_ERR ( pc - > prescale_high ) ;
2014-07-14 18:33:27 +04:00
2016-08-16 12:34:59 +03:00
pc - > pwm_out_en = devm_regmap_field_alloc ( dev , pc - > regmap ,
reg_fields [ PWM_OUT_EN ] ) ;
if ( IS_ERR ( pc - > pwm_out_en ) )
return PTR_ERR ( pc - > pwm_out_en ) ;
2016-08-16 12:35:05 +03:00
pc - > pwm_cpt_en = devm_regmap_field_alloc ( dev , pc - > regmap ,
reg_fields [ PWM_CPT_EN ] ) ;
if ( IS_ERR ( pc - > pwm_cpt_en ) )
return PTR_ERR ( pc - > pwm_cpt_en ) ;
2016-08-16 12:34:59 +03:00
pc - > pwm_cpt_int_en = devm_regmap_field_alloc ( dev , pc - > regmap ,
2016-08-16 12:35:07 +03:00
reg_fields [ PWM_CPT_INT_EN ] ) ;
2016-08-16 12:34:59 +03:00
if ( IS_ERR ( pc - > pwm_cpt_int_en ) )
return PTR_ERR ( pc - > pwm_cpt_int_en ) ;
2014-07-14 18:33:27 +04:00
2016-08-16 12:35:04 +03:00
pc - > pwm_cpt_int_stat = devm_regmap_field_alloc ( dev , pc - > regmap ,
reg_fields [ PWM_CPT_INT_STAT ] ) ;
if ( PTR_ERR_OR_ZERO ( pc - > pwm_cpt_int_stat ) )
return PTR_ERR ( pc - > pwm_cpt_int_stat ) ;
2014-07-14 18:33:27 +04:00
return 0 ;
}
static const struct regmap_config sti_pwm_regmap_config = {
. reg_bits = 32 ,
. val_bits = 32 ,
. reg_stride = 4 ,
} ;
static int sti_pwm_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct sti_pwm_compat_data * cdata ;
struct sti_pwm_chip * pc ;
2016-08-16 12:35:03 +03:00
unsigned int i ;
2016-08-16 12:35:04 +03:00
int irq , ret ;
2014-07-14 18:33:27 +04:00
pc = devm_kzalloc ( dev , sizeof ( * pc ) , GFP_KERNEL ) ;
if ( ! pc )
return - ENOMEM ;
cdata = devm_kzalloc ( dev , sizeof ( * cdata ) , GFP_KERNEL ) ;
if ( ! cdata )
return - ENOMEM ;
2019-12-29 11:05:46 +03:00
pc - > mmio = devm_platform_ioremap_resource ( pdev , 0 ) ;
2014-07-14 18:33:27 +04:00
if ( IS_ERR ( pc - > mmio ) )
return PTR_ERR ( pc - > mmio ) ;
pc - > regmap = devm_regmap_init_mmio ( dev , pc - > mmio ,
& sti_pwm_regmap_config ) ;
if ( IS_ERR ( pc - > regmap ) )
return PTR_ERR ( pc - > regmap ) ;
2016-08-16 12:35:04 +03:00
irq = platform_get_irq ( pdev , 0 ) ;
2019-07-30 21:15:36 +03:00
if ( irq < 0 )
2016-08-16 12:35:04 +03:00
return irq ;
ret = devm_request_irq ( & pdev - > dev , irq , sti_pwm_interrupt , 0 ,
pdev - > name , pc ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " Failed to request IRQ \n " ) ;
return ret ;
}
2014-07-14 18:33:27 +04:00
/*
* Setup PWM data with default values : some values could be replaced
* with specific ones provided from Device Tree .
*/
2016-08-16 12:35:07 +03:00
cdata - > reg_fields = sti_pwm_regfields ;
2014-07-14 18:33:27 +04:00
cdata - > max_prescale = 0xff ;
2016-08-16 12:35:07 +03:00
cdata - > max_pwm_cnt = 255 ;
2016-08-16 12:35:06 +03:00
cdata - > pwm_num_devs = 0 ;
2016-08-16 12:35:03 +03:00
cdata - > cpt_num_devs = 0 ;
2014-07-14 18:33:27 +04:00
pc - > cdata = cdata ;
pc - > dev = dev ;
2014-07-14 18:33:31 +04:00
pc - > en_count = 0 ;
mutex_init ( & pc - > sti_pwm_lock ) ;
2014-07-14 18:33:27 +04:00
ret = sti_pwm_probe_dt ( pc ) ;
if ( ret )
return ret ;
2020-11-11 21:24:29 +03:00
if ( cdata - > pwm_num_devs ) {
pc - > pwm_clk = of_clk_get_by_name ( dev - > of_node , " pwm " ) ;
if ( IS_ERR ( pc - > pwm_clk ) ) {
dev_err ( dev , " failed to get PWM clock \n " ) ;
return PTR_ERR ( pc - > pwm_clk ) ;
}
2014-07-14 18:33:27 +04:00
2020-11-11 21:24:29 +03:00
ret = clk_prepare ( pc - > pwm_clk ) ;
if ( ret ) {
dev_err ( dev , " failed to prepare clock \n " ) ;
return ret ;
}
2014-07-14 18:33:27 +04:00
}
2020-11-11 21:24:29 +03:00
if ( cdata - > cpt_num_devs ) {
pc - > cpt_clk = of_clk_get_by_name ( dev - > of_node , " capture " ) ;
if ( IS_ERR ( pc - > cpt_clk ) ) {
dev_err ( dev , " failed to get PWM capture clock \n " ) ;
return PTR_ERR ( pc - > cpt_clk ) ;
}
2016-08-16 12:35:02 +03:00
2020-11-11 21:24:29 +03:00
ret = clk_prepare ( pc - > cpt_clk ) ;
if ( ret ) {
dev_err ( dev , " failed to prepare clock \n " ) ;
return ret ;
}
2016-08-16 12:35:02 +03:00
}
2014-07-14 18:33:27 +04:00
pc - > chip . dev = dev ;
pc - > chip . ops = & sti_pwm_ops ;
2016-08-16 12:35:03 +03:00
pc - > chip . npwm = pc - > cdata - > pwm_num_devs ;
2014-07-14 18:33:27 +04:00
ret = pwmchip_add ( & pc - > chip ) ;
if ( ret < 0 ) {
2016-08-16 12:34:59 +03:00
clk_unprepare ( pc - > pwm_clk ) ;
2016-08-16 12:35:02 +03:00
clk_unprepare ( pc - > cpt_clk ) ;
2014-07-14 18:33:27 +04:00
return ret ;
}
2016-08-16 12:35:03 +03:00
for ( i = 0 ; i < cdata - > cpt_num_devs ; i + + ) {
struct sti_cpt_ddata * ddata ;
ddata = devm_kzalloc ( dev , sizeof ( * ddata ) , GFP_KERNEL ) ;
if ( ! ddata )
return - ENOMEM ;
init_waitqueue_head ( & ddata - > wait ) ;
mutex_init ( & ddata - > lock ) ;
pwm_set_chip_data ( & pc - > chip . pwms [ i ] , ddata ) ;
}
2014-07-14 18:33:27 +04:00
platform_set_drvdata ( pdev , pc ) ;
return 0 ;
}
static int sti_pwm_remove ( struct platform_device * pdev )
{
struct sti_pwm_chip * pc = platform_get_drvdata ( pdev ) ;
2021-03-30 15:37:42 +03:00
pwmchip_remove ( & pc - > chip ) ;
2014-07-14 18:33:27 +04:00
2016-08-16 12:34:59 +03:00
clk_unprepare ( pc - > pwm_clk ) ;
2016-08-16 12:35:02 +03:00
clk_unprepare ( pc - > cpt_clk ) ;
2014-07-14 18:33:27 +04:00
2021-03-30 15:37:42 +03:00
return 0 ;
2014-07-14 18:33:27 +04:00
}
static const struct of_device_id sti_pwm_of_match [ ] = {
{ . compatible = " st,sti-pwm " , } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , sti_pwm_of_match ) ;
static struct platform_driver sti_pwm_driver = {
. driver = {
. name = " sti-pwm " ,
. of_match_table = sti_pwm_of_match ,
} ,
. probe = sti_pwm_probe ,
. remove = sti_pwm_remove ,
} ;
module_platform_driver ( sti_pwm_driver ) ;
MODULE_AUTHOR ( " Ajit Pal Singh <ajitpal.singh@st.com> " ) ;
MODULE_DESCRIPTION ( " STMicroelectronics ST PWM driver " ) ;
MODULE_LICENSE ( " GPL " ) ;