2019-08-14 20:46:11 +08:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2019 Spreadtrum Communications Inc .
*/
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/math64.h>
2023-07-14 11:48:50 -06:00
# include <linux/mod_devicetable.h>
2019-08-14 20:46:11 +08:00
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/pwm.h>
# define SPRD_PWM_PRESCALE 0x0
# define SPRD_PWM_MOD 0x4
# define SPRD_PWM_DUTY 0x8
# define SPRD_PWM_ENABLE 0x18
# define SPRD_PWM_MOD_MAX GENMASK(7, 0)
# define SPRD_PWM_DUTY_MSK GENMASK(15, 0)
# define SPRD_PWM_PRESCALE_MSK GENMASK(7, 0)
# define SPRD_PWM_ENABLE_BIT BIT(0)
# define SPRD_PWM_CHN_NUM 4
# define SPRD_PWM_REGS_SHIFT 5
# define SPRD_PWM_CHN_CLKS_NUM 2
# define SPRD_PWM_CHN_OUTPUT_CLK 1
struct sprd_pwm_chn {
struct clk_bulk_data clks [ SPRD_PWM_CHN_CLKS_NUM ] ;
u32 clk_rate ;
} ;
struct sprd_pwm_chip {
void __iomem * base ;
struct sprd_pwm_chn chn [ SPRD_PWM_CHN_NUM ] ;
} ;
2023-09-29 18:19:14 +02:00
static inline struct sprd_pwm_chip * sprd_pwm_from_chip ( struct pwm_chip * chip )
{
2024-02-14 10:32:37 +01:00
return pwmchip_get_drvdata ( chip ) ;
2023-09-29 18:19:14 +02:00
}
2019-08-14 20:46:11 +08:00
/*
* The list of clocks required by PWM channels , and each channel has 2 clocks :
* enable clock and pwm clock .
*/
static const char * const sprd_pwm_clks [ ] = {
" enable0 " , " pwm0 " ,
" enable1 " , " pwm1 " ,
" enable2 " , " pwm2 " ,
" enable3 " , " pwm3 " ,
} ;
static u32 sprd_pwm_read ( struct sprd_pwm_chip * spc , u32 hwid , u32 reg )
{
u32 offset = reg + ( hwid < < SPRD_PWM_REGS_SHIFT ) ;
return readl_relaxed ( spc - > base + offset ) ;
}
static void sprd_pwm_write ( struct sprd_pwm_chip * spc , u32 hwid ,
u32 reg , u32 val )
{
u32 offset = reg + ( hwid < < SPRD_PWM_REGS_SHIFT ) ;
writel_relaxed ( val , spc - > base + offset ) ;
}
2022-12-02 19:35:26 +01:00
static int sprd_pwm_get_state ( struct pwm_chip * chip , struct pwm_device * pwm ,
struct pwm_state * state )
2019-08-14 20:46:11 +08:00
{
2023-09-29 18:19:14 +02:00
struct sprd_pwm_chip * spc = sprd_pwm_from_chip ( chip ) ;
2019-08-14 20:46:11 +08:00
struct sprd_pwm_chn * chn = & spc - > chn [ pwm - > hwpwm ] ;
u32 val , duty , prescale ;
u64 tmp ;
int ret ;
/*
* The clocks to PWM channel has to be enabled first before
* reading to the registers .
*/
ret = clk_bulk_prepare_enable ( SPRD_PWM_CHN_CLKS_NUM , chn - > clks ) ;
if ( ret ) {
2024-02-14 10:32:36 +01:00
dev_err ( pwmchip_parent ( chip ) , " failed to enable pwm%u clocks \n " ,
2019-08-14 20:46:11 +08:00
pwm - > hwpwm ) ;
2022-12-02 19:35:35 +01:00
return ret ;
2019-08-14 20:46:11 +08:00
}
val = sprd_pwm_read ( spc , pwm - > hwpwm , SPRD_PWM_ENABLE ) ;
if ( val & SPRD_PWM_ENABLE_BIT )
state - > enabled = true ;
else
state - > enabled = false ;
/*
* The hardware provides a counter that is feed by the source clock .
* The period length is ( PRESCALE + 1 ) * MOD counter steps .
* The duty cycle length is ( PRESCALE + 1 ) * DUTY counter steps .
* Thus the period_ns and duty_ns calculation formula should be :
* period_ns = NSEC_PER_SEC * ( prescale + 1 ) * mod / clk_rate
* duty_ns = NSEC_PER_SEC * ( prescale + 1 ) * duty / clk_rate
*/
val = sprd_pwm_read ( spc , pwm - > hwpwm , SPRD_PWM_PRESCALE ) ;
prescale = val & SPRD_PWM_PRESCALE_MSK ;
tmp = ( prescale + 1 ) * NSEC_PER_SEC * SPRD_PWM_MOD_MAX ;
state - > period = DIV_ROUND_CLOSEST_ULL ( tmp , chn - > clk_rate ) ;
val = sprd_pwm_read ( spc , pwm - > hwpwm , SPRD_PWM_DUTY ) ;
duty = val & SPRD_PWM_DUTY_MSK ;
tmp = ( prescale + 1 ) * NSEC_PER_SEC * duty ;
state - > duty_cycle = DIV_ROUND_CLOSEST_ULL ( tmp , chn - > clk_rate ) ;
2023-03-22 22:45:43 +01:00
state - > polarity = PWM_POLARITY_NORMAL ;
2019-08-14 20:46:11 +08:00
/* Disable PWM clocks if the PWM channel is not in enable state. */
if ( ! state - > enabled )
clk_bulk_disable_unprepare ( SPRD_PWM_CHN_CLKS_NUM , chn - > clks ) ;
2022-12-02 19:35:26 +01:00
return 0 ;
2019-08-14 20:46:11 +08:00
}
static int sprd_pwm_config ( struct sprd_pwm_chip * spc , struct pwm_device * pwm ,
int duty_ns , int period_ns )
{
struct sprd_pwm_chn * chn = & spc - > chn [ pwm - > hwpwm ] ;
u32 prescale , duty ;
u64 tmp ;
/*
* The hardware provides a counter that is feed by the source clock .
* The period length is ( PRESCALE + 1 ) * MOD counter steps .
* The duty cycle length is ( PRESCALE + 1 ) * DUTY counter steps .
*
* To keep the maths simple we ' re always using MOD = SPRD_PWM_MOD_MAX .
* The value for PRESCALE is selected such that the resulting period
* gets the maximal length not bigger than the requested one with the
* given settings ( MOD = SPRD_PWM_MOD_MAX and input clock ) .
*/
duty = duty_ns * SPRD_PWM_MOD_MAX / period_ns ;
tmp = ( u64 ) chn - > clk_rate * period_ns ;
do_div ( tmp , NSEC_PER_SEC ) ;
prescale = DIV_ROUND_CLOSEST_ULL ( tmp , SPRD_PWM_MOD_MAX ) - 1 ;
if ( prescale > SPRD_PWM_PRESCALE_MSK )
prescale = SPRD_PWM_PRESCALE_MSK ;
/*
* Note : Writing DUTY triggers the hardware to actually apply the
* values written to MOD and DUTY to the output , so must keep writing
* DUTY last .
*
* The hardware can ensures that current running period is completed
* before changing a new configuration to avoid mixed settings .
*/
sprd_pwm_write ( spc , pwm - > hwpwm , SPRD_PWM_PRESCALE , prescale ) ;
sprd_pwm_write ( spc , pwm - > hwpwm , SPRD_PWM_MOD , SPRD_PWM_MOD_MAX ) ;
sprd_pwm_write ( spc , pwm - > hwpwm , SPRD_PWM_DUTY , duty ) ;
return 0 ;
}
static int sprd_pwm_apply ( struct pwm_chip * chip , struct pwm_device * pwm ,
2019-08-24 17:37:07 +02:00
const struct pwm_state * state )
2019-08-14 20:46:11 +08:00
{
2023-09-29 18:19:14 +02:00
struct sprd_pwm_chip * spc = sprd_pwm_from_chip ( chip ) ;
2019-08-14 20:46:11 +08:00
struct sprd_pwm_chn * chn = & spc - > chn [ pwm - > hwpwm ] ;
struct pwm_state * cstate = & pwm - > state ;
int ret ;
2021-03-12 09:59:16 +01:00
if ( state - > polarity ! = PWM_POLARITY_NORMAL )
return - EINVAL ;
2019-08-14 20:46:11 +08:00
if ( state - > enabled ) {
if ( ! cstate - > enabled ) {
/*
* The clocks to PWM channel has to be enabled first
* before writing to the registers .
*/
ret = clk_bulk_prepare_enable ( SPRD_PWM_CHN_CLKS_NUM ,
chn - > clks ) ;
if ( ret ) {
2024-02-14 10:32:36 +01:00
dev_err ( pwmchip_parent ( chip ) ,
2019-08-14 20:46:11 +08:00
" failed to enable pwm%u clocks \n " ,
pwm - > hwpwm ) ;
return ret ;
}
}
2021-07-01 10:27:51 +02:00
ret = sprd_pwm_config ( spc , pwm , state - > duty_cycle ,
state - > period ) ;
if ( ret )
return ret ;
2019-08-14 20:46:11 +08:00
sprd_pwm_write ( spc , pwm - > hwpwm , SPRD_PWM_ENABLE , 1 ) ;
} else if ( cstate - > enabled ) {
/*
* Note : After setting SPRD_PWM_ENABLE to zero , the controller
* will not wait for current period to be completed , instead it
* will stop the PWM channel immediately .
*/
sprd_pwm_write ( spc , pwm - > hwpwm , SPRD_PWM_ENABLE , 0 ) ;
clk_bulk_disable_unprepare ( SPRD_PWM_CHN_CLKS_NUM , chn - > clks ) ;
}
return 0 ;
}
static const struct pwm_ops sprd_pwm_ops = {
. apply = sprd_pwm_apply ,
. get_state = sprd_pwm_get_state ,
} ;
2024-02-14 10:32:35 +01:00
static int sprd_pwm_clk_init ( struct device * dev ,
struct sprd_pwm_chn chn [ SPRD_PWM_CHN_NUM ] )
2019-08-14 20:46:11 +08:00
{
struct clk * clk_pwm ;
int ret , i ;
for ( i = 0 ; i < SPRD_PWM_CHN_NUM ; i + + ) {
int j ;
for ( j = 0 ; j < SPRD_PWM_CHN_CLKS_NUM ; + + j )
2024-02-14 10:32:35 +01:00
chn [ i ] . clks [ j ] . id =
2019-08-14 20:46:11 +08:00
sprd_pwm_clks [ i * SPRD_PWM_CHN_CLKS_NUM + j ] ;
2024-02-14 10:32:35 +01:00
ret = devm_clk_bulk_get ( dev , SPRD_PWM_CHN_CLKS_NUM ,
chn [ i ] . clks ) ;
2019-08-14 20:46:11 +08:00
if ( ret ) {
if ( ret = = - ENOENT )
break ;
2024-02-14 10:32:35 +01:00
return dev_err_probe ( dev , ret ,
2020-08-26 16:47:46 +02:00
" failed to get channel clocks \n " ) ;
2019-08-14 20:46:11 +08:00
}
2024-02-14 10:32:35 +01:00
clk_pwm = chn [ i ] . clks [ SPRD_PWM_CHN_OUTPUT_CLK ] . clk ;
chn [ i ] . clk_rate = clk_get_rate ( clk_pwm ) ;
2019-08-14 20:46:11 +08:00
}
2023-09-29 18:19:15 +02:00
if ( ! i )
2024-02-14 10:32:35 +01:00
return dev_err_probe ( dev , - ENODEV , " no available PWM channels \n " ) ;
2019-08-14 20:46:11 +08:00
2024-02-14 10:32:35 +01:00
return i ;
2019-08-14 20:46:11 +08:00
}
static int sprd_pwm_probe ( struct platform_device * pdev )
{
2024-02-14 10:32:37 +01:00
struct pwm_chip * chip ;
2019-08-14 20:46:11 +08:00
struct sprd_pwm_chip * spc ;
2024-02-14 10:32:35 +01:00
struct sprd_pwm_chn chn [ SPRD_PWM_CHN_NUM ] ;
int ret , npwm ;
npwm = sprd_pwm_clk_init ( & pdev - > dev , chn ) ;
if ( npwm < 0 )
return npwm ;
2019-08-14 20:46:11 +08:00
2024-02-14 10:32:37 +01:00
chip = devm_pwmchip_alloc ( & pdev - > dev , npwm , sizeof ( * spc ) ) ;
if ( IS_ERR ( chip ) )
return PTR_ERR ( chip ) ;
spc = sprd_pwm_from_chip ( chip ) ;
2019-08-14 20:46:11 +08:00
spc - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( spc - > base ) )
return PTR_ERR ( spc - > base ) ;
2024-02-14 10:32:35 +01:00
memcpy ( spc - > chn , chn , sizeof ( chn ) ) ;
2019-08-14 20:46:11 +08:00
2024-02-14 10:32:37 +01:00
chip - > ops = & sprd_pwm_ops ;
2019-08-14 20:46:11 +08:00
2024-02-14 10:32:37 +01:00
ret = devm_pwmchip_add ( & pdev - > dev , chip ) ;
2019-08-14 20:46:11 +08:00
if ( ret )
dev_err ( & pdev - > dev , " failed to add PWM chip \n " ) ;
return ret ;
}
static const struct of_device_id sprd_pwm_of_match [ ] = {
{ . compatible = " sprd,ums512-pwm " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , sprd_pwm_of_match ) ;
static struct platform_driver sprd_pwm_driver = {
. driver = {
. name = " sprd-pwm " ,
. of_match_table = sprd_pwm_of_match ,
} ,
. probe = sprd_pwm_probe ,
} ;
module_platform_driver ( sprd_pwm_driver ) ;
MODULE_DESCRIPTION ( " Spreadtrum PWM Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;