@ -18,30 +18,40 @@
# include <linux/io.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/platform_device.h>
# include <linux/pwm.h>
# include <linux/slab.h>
# define DISP_PWM_EN 0x00
# define PWM_ENABLE_MASK BIT(0)
# define DISP_PWM_COMMIT 0x08
# define PWM_COMMIT_MASK BIT(0)
# define DISP_PWM_CON_0 0x10
# define PWM_CLKDIV_SHIFT 16
# define PWM_CLKDIV_MAX 0x3ff
# define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT)
# define DISP_PWM_CON_1 0x14
# define PWM_PERIOD_BIT_WIDTH 12
# define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1)
# define PWM_HIGH_WIDTH_SHIFT 16
# define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT)
struct mtk_pwm_data {
u32 enable_mask ;
unsigned int con0 ;
u32 con0_sel ;
unsigned int con1 ;
bool has_commit ;
unsigned int commit ;
unsigned int commit_mask ;
unsigned int bls_debug ;
u32 bls_debug_mask ;
} ;
struct mtk_disp_pwm {
struct pwm_chip chip ;
const struct mtk_pwm_data * data ;
struct clk * clk_main ;
struct clk * clk_mm ;
void __iomem * base ;
@ -106,12 +116,21 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
return err ;
}
mtk_disp_pwm_update_bits ( mdp , DISP_PWM_CON_0 , PWM_CLKDIV_MASK ,
mtk_disp_pwm_update_bits ( mdp , mdp - > data - > con0 ,
PWM_CLKDIV_MASK ,
clk_div < < PWM_CLKDIV_SHIFT ) ;
mtk_disp_pwm_update_bits ( mdp , DISP_PWM_CON_1 ,
PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK , value ) ;
mtk_disp_pwm_update_bits ( mdp , DISP_PWM_COMMIT , PWM_COMMIT_MASK , 1 ) ;
mtk_disp_pwm_update_bits ( mdp , DISP_PWM_COMMIT , PWM_COMMIT_MASK , 0 ) ;
mtk_disp_pwm_update_bits ( mdp , mdp - > data - > con1 ,
PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK ,
value ) ;
if ( mdp - > data - > has_commit ) {
mtk_disp_pwm_update_bits ( mdp , mdp - > data - > commit ,
mdp - > data - > commit_mask ,
mdp - > data - > commit_mask ) ;
mtk_disp_pwm_update_bits ( mdp , mdp - > data - > commit ,
mdp - > data - > commit_mask ,
0x0 ) ;
}
clk_disable ( mdp - > clk_mm ) ;
clk_disable ( mdp - > clk_main ) ;
@ -134,7 +153,8 @@ static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
return err ;
}
mtk_disp_pwm_update_bits ( mdp , DISP_PWM_EN , PWM_ENABLE_MASK , 1 ) ;
mtk_disp_pwm_update_bits ( mdp , DISP_PWM_EN , mdp - > data - > enable_mask ,
mdp - > data - > enable_mask ) ;
return 0 ;
}
@ -143,7 +163,8 @@ static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct mtk_disp_pwm * mdp = to_mtk_disp_pwm ( chip ) ;
mtk_disp_pwm_update_bits ( mdp , DISP_PWM_EN , PWM_ENABLE_MASK , 0 ) ;
mtk_disp_pwm_update_bits ( mdp , DISP_PWM_EN , mdp - > data - > enable_mask ,
0x0 ) ;
clk_disable ( mdp - > clk_mm ) ;
clk_disable ( mdp - > clk_main ) ;
@ -166,6 +187,8 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
if ( ! mdp )
return - ENOMEM ;
mdp - > data = of_device_get_match_data ( & pdev - > dev ) ;
r = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
mdp - > base = devm_ioremap_resource ( & pdev - > dev , r ) ;
if ( IS_ERR ( mdp - > base ) )
@ -200,6 +223,19 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
platform_set_drvdata ( pdev , mdp ) ;
/*
* For MT2701 , disable double buffer before writing register
* and select manual mode and use PWM_PERIOD / PWM_HIGH_WIDTH .
*/
if ( ! mdp - > data - > has_commit ) {
mtk_disp_pwm_update_bits ( mdp , mdp - > data - > bls_debug ,
mdp - > data - > bls_debug_mask ,
mdp - > data - > bls_debug_mask ) ;
mtk_disp_pwm_update_bits ( mdp , mdp - > data - > con0 ,
mdp - > data - > con0_sel ,
mdp - > data - > con0_sel ) ;
}
return 0 ;
disable_clk_mm :
@ -221,9 +257,30 @@ static int mtk_disp_pwm_remove(struct platform_device *pdev)
return ret ;
}
static const struct mtk_pwm_data mt2701_pwm_data = {
. enable_mask = BIT ( 16 ) ,
. con0 = 0xa8 ,
. con0_sel = 0x2 ,
. con1 = 0xac ,
. has_commit = false ,
. bls_debug = 0xb0 ,
. bls_debug_mask = 0x3 ,
} ;
static const struct mtk_pwm_data mt8173_pwm_data = {
. enable_mask = BIT ( 0 ) ,
. con0 = 0x10 ,
. con0_sel = 0x0 ,
. con1 = 0x14 ,
. has_commit = true ,
. commit = 0x8 ,
. commit_mask = 0x1 ,
} ;
static const struct of_device_id mtk_disp_pwm_of_match [ ] = {
{ . compatible = " mediatek,mt8173-disp-pwm " } ,
{ . compatible = " mediatek,mt6595-disp-pwm " } ,
{ . compatible = " mediatek,mt2701-disp-pwm " , . data = & mt2701_pwm_data } ,
{ . compatible = " mediatek,mt6595-disp-pwm " , . data = & mt8173_pwm_data } ,
{ . compatible = " mediatek,mt8173-disp-pwm " , . data = & mt8173_pwm_data } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , mtk_disp_pwm_of_match ) ;