Add driver for OpenCores PWM Controller. And add compatibility code
which based on StarFive SoC.
Co-developed-by: Hal Feng <hal.feng@xxxxxxxxxxxxxxxx>
Signed-off-by: Hal Feng <hal.feng@xxxxxxxxxxxxxxxx>
Signed-off-by: William Qiu <william.qiu@xxxxxxxxxxxxxxxx>
---
+static int ocores_pwm_apply(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct ocores_pwm_device *ddata = chip_to_ocores(chip);
+ u32 ctrl_data = 0;
+ u64 period_data, duty_data;
+
+ if (state->polarity != PWM_POLARITY_INVERSED)
+ return -EINVAL;
+
+ period_data = mul_u64_u32_div(state->period, ddata->clk_rate, NSEC_PER_SEC);
+ if (!period_data)
+ return -EINVAL;
+
+ if (period_data > U32_MAX)
+ period_data = U32_MAX;
+
+ ocores_pwm_writel(ddata, pwm->hwpwm, REG_OCPWM_LRC, (u32)period_data);
+
+ duty_data = mul_u64_u32_div(state->duty_cycle, ddata->clk_rate, NSEC_PER_SEC);
+ if (duty_data <= U32_MAX)
+ ocores_pwm_writel(ddata, pwm->hwpwm, REG_OCPWM_HRC, (u32)duty_data);
+ else if (duty_data > U32_MAX)
+ duty_data = U32_MAX;
+ ocores_pwm_writel(ddata, pwm->hwpwm, REG_OCPWM_HRC, (u32)duty_data);
+ else
+ return -EINVAL;
+
+ ctrl_data = ocores_pwm_readl(ddata, pwm->hwpwm, REG_OCPWM_CTRL);
+ if (state->enabled)
+ ocores_pwm_writel(ddata, pwm->hwpwm, REG_OCPWM_CTRL,
+ ctrl_data | REG_OCPWM_CNTR_EN | REG_OCPWM_CNTR_OE);
+ else
+ ocores_pwm_writel(ddata, pwm->hwpwm, REG_OCPWM_CTRL,
+ ctrl_data & ~(REG_OCPWM_CNTR_EN | REG_OCPWM_CNTR_OE));
+
+ return 0;
+}
+static int ocores_pwm_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *id;
+ struct device *dev = &pdev->dev;
+ struct ocores_pwm_device *ddata;
+ struct pwm_chip *chip;
+ struct clk *clk;
+ struct reset_control *rst;
+ int ret;
+
+ id = of_match_device(ocores_pwm_of_match, dev);
+ if (!id)
+ return -EINVAL;
+
+ chip = devm_pwmchip_alloc(&pdev->dev, 8, sizeof(*ddata));
+ if (IS_ERR(chip))
+ return -ENOMEM;
+
+ ddata = chip_to_ocores(chip);
+ ddata->data = id->data;
+ chip->ops = &ocores_pwm_ops;
+
+ ddata->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(ddata->regs))
+ return dev_err_probe(dev, PTR_ERR(ddata->regs),
+ "Unable to map IO resources\n");
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "Unable to get pwm's clock\n");
+
+ ret = devm_clk_rate_exclusive_get(dev, clk);
+ if (ret)
+ return ret;
+
+ rst = devm_reset_control_get_optional_exclusive(dev, NULL);
+ if (IS_ERR(rst))
+ return dev_err_probe(dev, PTR_ERR(rst),
+ "Unable to get pwm's reset\n");
+
+ ret = reset_control_deassert(rst);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, ocores_pwm_reset_control_assert, rst);
+ if (ret)
+ return ret;
+
+ ddata->clk_rate = clk_get_rate(clk);
+ if (ddata->clk_rate > NSEC_PER_SEC)
+ return dev_err_probe(dev, ddata->clk_rate,
+ "Unable to get clock's rate\n");
+
+ ret = devm_pwmchip_add(dev, chip);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Could not register PWM chip\n");
+
+ return 0;
+}