aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-mtk-disp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pwm/pwm-mtk-disp.c')
-rw-r--r--drivers/pwm/pwm-mtk-disp.c87
1 files changed, 72 insertions, 15 deletions
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index 0ad3385298c0..893940d45f0d 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -18,30 +18,40 @@
18#include <linux/io.h> 18#include <linux/io.h>
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/of.h> 20#include <linux/of.h>
21#include <linux/of_device.h>
21#include <linux/platform_device.h> 22#include <linux/platform_device.h>
22#include <linux/pwm.h> 23#include <linux/pwm.h>
23#include <linux/slab.h> 24#include <linux/slab.h>
24 25
25#define DISP_PWM_EN 0x00 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#define PWM_CLKDIV_SHIFT 16 28#define PWM_CLKDIV_SHIFT 16
33#define PWM_CLKDIV_MAX 0x3ff 29#define PWM_CLKDIV_MAX 0x3ff
34#define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT) 30#define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT)
35 31
36#define DISP_PWM_CON_1 0x14
37#define PWM_PERIOD_BIT_WIDTH 12 32#define PWM_PERIOD_BIT_WIDTH 12
38#define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1) 33#define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1)
39 34
40#define PWM_HIGH_WIDTH_SHIFT 16 35#define PWM_HIGH_WIDTH_SHIFT 16
41#define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT) 36#define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT)
42 37
38struct 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
43struct mtk_disp_pwm { 52struct mtk_disp_pwm {
44 struct pwm_chip chip; 53 struct pwm_chip chip;
54 const struct mtk_pwm_data *data;
45 struct clk *clk_main; 55 struct clk *clk_main;
46 struct clk *clk_mm; 56 struct clk *clk_mm;
47 void __iomem *base; 57 void __iomem *base;
@@ -106,12 +116,21 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
106 return err; 116 return err;
107 } 117 }
108 118
109 mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_0, PWM_CLKDIV_MASK, 119 mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
120 PWM_CLKDIV_MASK,
110 clk_div << PWM_CLKDIV_SHIFT); 121 clk_div << PWM_CLKDIV_SHIFT);
111 mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_1, 122 mtk_disp_pwm_update_bits(mdp, mdp->data->con1,
112 PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, value); 123 PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK,
113 mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 1); 124 value);
114 mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 0); 125
126 if (mdp->data->has_commit) {
127 mtk_disp_pwm_update_bits(mdp, mdp->data->commit,
128 mdp->data->commit_mask,
129 mdp->data->commit_mask);
130 mtk_disp_pwm_update_bits(mdp, mdp->data->commit,
131 mdp->data->commit_mask,
132 0x0);
133 }
115 134
116 clk_disable(mdp->clk_mm); 135 clk_disable(mdp->clk_mm);
117 clk_disable(mdp->clk_main); 136 clk_disable(mdp->clk_main);
@@ -134,7 +153,8 @@ static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
134 return err; 153 return err;
135 } 154 }
136 155
137 mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 1); 156 mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
157 mdp->data->enable_mask);
138 158
139 return 0; 159 return 0;
140} 160}
@@ -143,7 +163,8 @@ static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
143{ 163{
144 struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); 164 struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
145 165
146 mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 0); 166 mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
167 0x0);
147 168
148 clk_disable(mdp->clk_mm); 169 clk_disable(mdp->clk_mm);
149 clk_disable(mdp->clk_main); 170 clk_disable(mdp->clk_main);
@@ -166,6 +187,8 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
166 if (!mdp) 187 if (!mdp)
167 return -ENOMEM; 188 return -ENOMEM;
168 189
190 mdp->data = of_device_get_match_data(&pdev->dev);
191
169 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 192 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
170 mdp->base = devm_ioremap_resource(&pdev->dev, r); 193 mdp->base = devm_ioremap_resource(&pdev->dev, r);
171 if (IS_ERR(mdp->base)) 194 if (IS_ERR(mdp->base))
@@ -200,6 +223,19 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
200 223
201 platform_set_drvdata(pdev, mdp); 224 platform_set_drvdata(pdev, mdp);
202 225
226 /*
227 * For MT2701, disable double buffer before writing register
228 * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH.
229 */
230 if (!mdp->data->has_commit) {
231 mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
232 mdp->data->bls_debug_mask,
233 mdp->data->bls_debug_mask);
234 mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
235 mdp->data->con0_sel,
236 mdp->data->con0_sel);
237 }
238
203 return 0; 239 return 0;
204 240
205disable_clk_mm: 241disable_clk_mm:
@@ -221,9 +257,30 @@ static int mtk_disp_pwm_remove(struct platform_device *pdev)
221 return ret; 257 return ret;
222} 258}
223 259
260static const struct mtk_pwm_data mt2701_pwm_data = {
261 .enable_mask = BIT(16),
262 .con0 = 0xa8,
263 .con0_sel = 0x2,
264 .con1 = 0xac,
265 .has_commit = false,
266 .bls_debug = 0xb0,
267 .bls_debug_mask = 0x3,
268};
269
270static const struct mtk_pwm_data mt8173_pwm_data = {
271 .enable_mask = BIT(0),
272 .con0 = 0x10,
273 .con0_sel = 0x0,
274 .con1 = 0x14,
275 .has_commit = true,
276 .commit = 0x8,
277 .commit_mask = 0x1,
278};
279
224static const struct of_device_id mtk_disp_pwm_of_match[] = { 280static const struct of_device_id mtk_disp_pwm_of_match[] = {
225 { .compatible = "mediatek,mt8173-disp-pwm" }, 281 { .compatible = "mediatek,mt2701-disp-pwm", .data = &mt2701_pwm_data},
226 { .compatible = "mediatek,mt6595-disp-pwm" }, 282 { .compatible = "mediatek,mt6595-disp-pwm", .data = &mt8173_pwm_data},
283 { .compatible = "mediatek,mt8173-disp-pwm", .data = &mt8173_pwm_data},
227 { } 284 { }
228}; 285};
229MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match); 286MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match);