aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWeiqing Kong <weiqing.kong@mediatek.com>2016-07-11 04:18:08 -0400
committerThierry Reding <thierry.reding@gmail.com>2016-09-06 04:48:53 -0400
commitcd4b45ac449a01f0819b8459c451c840437aa0a3 (patch)
tree263eac4c1e15a27274f9b0f514784a1666d36ae3
parente093d06acaa99a79c6de30be22ba71faf6b78dd6 (diff)
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>
-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);