[PATCH v5 03/13] pwm: mediatek: add a property "clock-frequency"

From: Sam Shih
Date: Thu Aug 22 2019 - 09:44:16 EST


This fix mt7628 pwm during configure from userspace. The SoC
is legacy MIPS and has no complex clock tree. This patch add property
clock-frequency to the SoC specific data and legacy MIPS SoC need to
configure it in DT. This property is use for period calculation.

We will improve this fix by droping has-clks attribute and using
clock-frequency to do the same thing in a new patch.

Signed-off-by: Ryder Lee <ryder.lee@xxxxxxxxxxxx>
Signed-off-by: Sam Shih <sam.shih@xxxxxxxxxxxx>
---
Changes since v5:
1. Follow reviewer's comments
Make the changes of fix mt7628 pwm as a single patch

Changes since v4:
- Follow reviewers's comments
1. use pc->soc->has_clks to check clocks exist or not.
2. Add error message when probe() unable to get clks
- Fixes bug when SoC is old mips which has no complex clock tree.
if clocks not exist, use the new property from DT to apply period caculation;
otherwise, use clk_get_rate to get clock frequency and apply period caculation.

Change-Id: Ibbe6d7a4f80b30f60725bcbeca1d02ce7834d28c
---
drivers/pwm/pwm-mediatek.c | 39 ++++++++++++++++++++++++++++++--------
1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index ebd62629e3fe..1f18bff4800c 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -65,11 +65,13 @@ struct mtk_pwm_platform_data {
* @chip: linux PWM chip representation
* @regs: base address of PWM chip
* @clks: list of clocks
+ * @clk_freq: the fix clock frequency of legacy MIPS SoC
*/
struct mtk_pwm_chip {
struct pwm_chip chip;
void __iomem *regs;
struct clk *clks[MTK_CLK_MAX];
+ unsigned int clk_freq;
const struct mtk_pwm_platform_data *soc;
};

@@ -141,19 +143,27 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
- struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm];
+ unsigned int clk_freq;
u32 clkdiv = 0, cnt_period, cnt_duty, reg_width = PWMDWIDTH,
reg_thres = PWMTHRES;
u64 resolution;
int ret;

+ if (pc->soc->has_clks) {
+ struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm];
+
+ clk_freq = clk_get_rate(clk);
+ } else {
+ clk_freq = pc->clk_freq;
+ }
+
ret = mtk_pwm_clk_enable(chip, pwm);
if (ret < 0)
return ret;

/* Using resolution in picosecond gets accuracy higher */
resolution = (u64)NSEC_PER_SEC * 1000;
- do_div(resolution, clk_get_rate(clk));
+ do_div(resolution, clk_freq);

cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000, resolution);
while (cnt_period > 8191) {
@@ -262,13 +272,26 @@ static int mtk_pwm_probe(struct platform_device *pdev)
npwms = MTK_CLK_MAX - 2;
}

- for (i = 0; i < npwms + 2 && pc->soc->has_clks; i++) {
- pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]);
- if (IS_ERR(pc->clks[i])) {
- dev_err(&pdev->dev, "clock: %s fail: %ld\n",
- mtk_pwm_clk_name[i], PTR_ERR(pc->clks[i]));
- return PTR_ERR(pc->clks[i]);
+ if (pc->soc->has_clks) {
+ for (i = 0; i < npwms + 2 ; i++) {
+ pc->clks[i] = devm_clk_get(&pdev->dev,
+ mtk_pwm_clk_name[i]);
+ if (IS_ERR(pc->clks[i])) {
+ dev_err(&pdev->dev, "clock: %s fail: %ld\n",
+ mtk_pwm_clk_name[i],
+ PTR_ERR(pc->clks[i]));
+ return PTR_ERR(pc->clks[i]);
+ }
+ }
+ } else {
+ unsigned int clk_freq;
+
+ ret = of_property_read_u32(np, "clock-frequency", &clk_freq);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get clock_frequency\n");
+ return ret;
}
+ pc->clk_freq = clk_freq;
}

platform_set_drvdata(pdev, pc);
--
2.17.1