Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pwm: Add MediaTek MT2701 display PWM driver support

Use the mtk_pwm_data struction to define different registers
and add MT2701 specific register operations, such as MT2701
doesn't have commit register, needs to disable double buffer
before writing register, and needs to select manual mode
and use PWM_PERIOD/PWM_HIGH_WIDTH.

Signed-off-by: Weiqing Kong <weiqing.kong@mediatek.com>
[thierry.reding@gmail.com: use of_device_get_match_data()]
[thierry.reding@gmail.com: parameterize more consistently]
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>

authored by

Weiqing Kong and committed by
Thierry Reding
cd4b45ac e093d06a

+72 -15
+72 -15
drivers/pwm/pwm-mtk-disp.c
··· 18 18 #include <linux/io.h> 19 19 #include <linux/module.h> 20 20 #include <linux/of.h> 21 + #include <linux/of_device.h> 21 22 #include <linux/platform_device.h> 22 23 #include <linux/pwm.h> 23 24 #include <linux/slab.h> 24 25 25 26 #define DISP_PWM_EN 0x00 26 - #define PWM_ENABLE_MASK BIT(0) 27 27 28 - #define DISP_PWM_COMMIT 0x08 29 - #define PWM_COMMIT_MASK BIT(0) 30 - 31 - #define DISP_PWM_CON_0 0x10 32 28 #define PWM_CLKDIV_SHIFT 16 33 29 #define PWM_CLKDIV_MAX 0x3ff 34 30 #define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT) 35 31 36 - #define DISP_PWM_CON_1 0x14 37 32 #define PWM_PERIOD_BIT_WIDTH 12 38 33 #define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1) 39 34 40 35 #define PWM_HIGH_WIDTH_SHIFT 16 41 36 #define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT) 42 37 38 + struct mtk_pwm_data { 39 + u32 enable_mask; 40 + unsigned int con0; 41 + u32 con0_sel; 42 + unsigned int con1; 43 + 44 + bool has_commit; 45 + unsigned int commit; 46 + unsigned int commit_mask; 47 + 48 + unsigned int bls_debug; 49 + u32 bls_debug_mask; 50 + }; 51 + 43 52 struct mtk_disp_pwm { 44 53 struct pwm_chip chip; 54 + const struct mtk_pwm_data *data; 45 55 struct clk *clk_main; 46 56 struct clk *clk_mm; 47 57 void __iomem *base; ··· 116 106 return err; 117 107 } 118 108 119 - mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_0, PWM_CLKDIV_MASK, 109 + mtk_disp_pwm_update_bits(mdp, mdp->data->con0, 110 + PWM_CLKDIV_MASK, 120 111 clk_div << PWM_CLKDIV_SHIFT); 121 - mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_1, 122 - PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, value); 123 - mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 1); 124 - mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 0); 112 + mtk_disp_pwm_update_bits(mdp, mdp->data->con1, 113 + PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, 114 + value); 115 + 116 + if (mdp->data->has_commit) { 117 + mtk_disp_pwm_update_bits(mdp, mdp->data->commit, 118 + mdp->data->commit_mask, 119 + mdp->data->commit_mask); 120 + mtk_disp_pwm_update_bits(mdp, mdp->data->commit, 121 + mdp->data->commit_mask, 122 + 0x0); 123 + } 125 124 126 125 clk_disable(mdp->clk_mm); 127 126 clk_disable(mdp->clk_main); ··· 153 134 return err; 154 135 } 155 136 156 - mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 1); 137 + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, 138 + mdp->data->enable_mask); 157 139 158 140 return 0; 159 141 } ··· 163 143 { 164 144 struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); 165 145 166 - mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 0); 146 + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, 147 + 0x0); 167 148 168 149 clk_disable(mdp->clk_mm); 169 150 clk_disable(mdp->clk_main); ··· 186 165 mdp = devm_kzalloc(&pdev->dev, sizeof(*mdp), GFP_KERNEL); 187 166 if (!mdp) 188 167 return -ENOMEM; 168 + 169 + mdp->data = of_device_get_match_data(&pdev->dev); 189 170 190 171 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 191 172 mdp->base = devm_ioremap_resource(&pdev->dev, r); ··· 223 200 224 201 platform_set_drvdata(pdev, mdp); 225 202 203 + /* 204 + * For MT2701, disable double buffer before writing register 205 + * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH. 206 + */ 207 + if (!mdp->data->has_commit) { 208 + mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug, 209 + mdp->data->bls_debug_mask, 210 + mdp->data->bls_debug_mask); 211 + mtk_disp_pwm_update_bits(mdp, mdp->data->con0, 212 + mdp->data->con0_sel, 213 + mdp->data->con0_sel); 214 + } 215 + 226 216 return 0; 227 217 228 218 disable_clk_mm: ··· 257 221 return ret; 258 222 } 259 223 224 + static const struct mtk_pwm_data mt2701_pwm_data = { 225 + .enable_mask = BIT(16), 226 + .con0 = 0xa8, 227 + .con0_sel = 0x2, 228 + .con1 = 0xac, 229 + .has_commit = false, 230 + .bls_debug = 0xb0, 231 + .bls_debug_mask = 0x3, 232 + }; 233 + 234 + static const struct mtk_pwm_data mt8173_pwm_data = { 235 + .enable_mask = BIT(0), 236 + .con0 = 0x10, 237 + .con0_sel = 0x0, 238 + .con1 = 0x14, 239 + .has_commit = true, 240 + .commit = 0x8, 241 + .commit_mask = 0x1, 242 + }; 243 + 260 244 static const struct of_device_id mtk_disp_pwm_of_match[] = { 261 - { .compatible = "mediatek,mt8173-disp-pwm" }, 262 - { .compatible = "mediatek,mt6595-disp-pwm" }, 245 + { .compatible = "mediatek,mt2701-disp-pwm", .data = &mt2701_pwm_data}, 246 + { .compatible = "mediatek,mt6595-disp-pwm", .data = &mt8173_pwm_data}, 247 + { .compatible = "mediatek,mt8173-disp-pwm", .data = &mt8173_pwm_data}, 263 248 { } 264 249 }; 265 250 MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match);