Merge remote-tracking branch 'pwm/for-next'
[deliverable/linux.git] / drivers / pwm / pwm-mtk-disp.c
index 0ad3385298c00e4d9798718d263a4d9c3f0ced04..893940d45f0d0859d5aaeaa6cd70ff67bb5dd34b 100644 (file)
 #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);
This page took 0.02543 seconds and 5 git commands to generate.