18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PWM Controller Driver for HiSilicon BVT SoCs
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/bitops.h>
98c2ecf20Sopenharmony_ci#include <linux/clk.h>
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/io.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/of_device.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
158c2ecf20Sopenharmony_ci#include <linux/pwm.h>
168c2ecf20Sopenharmony_ci#include <linux/reset.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define PWM_CFG0_ADDR(x)    (((x) * 0x20) + 0x0)
198c2ecf20Sopenharmony_ci#define PWM_CFG1_ADDR(x)    (((x) * 0x20) + 0x4)
208c2ecf20Sopenharmony_ci#define PWM_CFG2_ADDR(x)    (((x) * 0x20) + 0x8)
218c2ecf20Sopenharmony_ci#define PWM_CTRL_ADDR(x)    (((x) * 0x20) + 0xC)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define PWM_ENABLE_SHIFT    0
248c2ecf20Sopenharmony_ci#define PWM_ENABLE_MASK     BIT(0)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define PWM_POLARITY_SHIFT  1
278c2ecf20Sopenharmony_ci#define PWM_POLARITY_MASK   BIT(1)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define PWM_KEEP_SHIFT      2
308c2ecf20Sopenharmony_ci#define PWM_KEEP_MASK       BIT(2)
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define PWM_PERIOD_MASK     GENMASK(31, 0)
338c2ecf20Sopenharmony_ci#define PWM_DUTY_MASK       GENMASK(31, 0)
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct hibvt_pwm_chip {
368c2ecf20Sopenharmony_ci	struct pwm_chip	chip;
378c2ecf20Sopenharmony_ci	struct clk *clk;
388c2ecf20Sopenharmony_ci	void __iomem *base;
398c2ecf20Sopenharmony_ci	struct reset_control *rstc;
408c2ecf20Sopenharmony_ci	const struct hibvt_pwm_soc *soc;
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistruct hibvt_pwm_soc {
448c2ecf20Sopenharmony_ci	u32 num_pwms;
458c2ecf20Sopenharmony_ci	bool quirk_force_enable;
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic const struct hibvt_pwm_soc hi3516cv300_soc_info = {
498c2ecf20Sopenharmony_ci	.num_pwms = 4,
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic const struct hibvt_pwm_soc hi3519v100_soc_info = {
538c2ecf20Sopenharmony_ci	.num_pwms = 8,
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic const struct hibvt_pwm_soc hi3559v100_shub_soc_info = {
578c2ecf20Sopenharmony_ci	.num_pwms = 8,
588c2ecf20Sopenharmony_ci	.quirk_force_enable = true,
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic const struct hibvt_pwm_soc hi3559v100_soc_info = {
628c2ecf20Sopenharmony_ci	.num_pwms = 2,
638c2ecf20Sopenharmony_ci	.quirk_force_enable = true,
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic inline struct hibvt_pwm_chip *to_hibvt_pwm_chip(struct pwm_chip *chip)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	return container_of(chip, struct hibvt_pwm_chip, chip);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic void hibvt_pwm_set_bits(void __iomem *base, u32 offset,
728c2ecf20Sopenharmony_ci					u32 mask, u32 data)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	void __iomem *address = base + offset;
758c2ecf20Sopenharmony_ci	u32 value;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	value = readl(address);
788c2ecf20Sopenharmony_ci	value &= ~mask;
798c2ecf20Sopenharmony_ci	value |= (data & mask);
808c2ecf20Sopenharmony_ci	writel(value, address);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic void hibvt_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
888c2ecf20Sopenharmony_ci			PWM_ENABLE_MASK, 0x1);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic void hibvt_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
968c2ecf20Sopenharmony_ci			PWM_ENABLE_MASK, 0x0);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void hibvt_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
1008c2ecf20Sopenharmony_ci					int duty_cycle_ns, int period_ns)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
1038c2ecf20Sopenharmony_ci	u32 freq, period, duty;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	freq = div_u64(clk_get_rate(hi_pwm_chip->clk), 1000000);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	period = div_u64(freq * period_ns, 1000);
1088c2ecf20Sopenharmony_ci	duty = div_u64(period * duty_cycle_ns, period_ns);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CFG0_ADDR(pwm->hwpwm),
1118c2ecf20Sopenharmony_ci			PWM_PERIOD_MASK, period);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CFG1_ADDR(pwm->hwpwm),
1148c2ecf20Sopenharmony_ci			PWM_DUTY_MASK, duty);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void hibvt_pwm_set_polarity(struct pwm_chip *chip,
1188c2ecf20Sopenharmony_ci					struct pwm_device *pwm,
1198c2ecf20Sopenharmony_ci					enum pwm_polarity polarity)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (polarity == PWM_POLARITY_INVERSED)
1248c2ecf20Sopenharmony_ci		hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
1258c2ecf20Sopenharmony_ci				PWM_POLARITY_MASK, (0x1 << PWM_POLARITY_SHIFT));
1268c2ecf20Sopenharmony_ci	else
1278c2ecf20Sopenharmony_ci		hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
1288c2ecf20Sopenharmony_ci				PWM_POLARITY_MASK, (0x0 << PWM_POLARITY_SHIFT));
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic void hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
1328c2ecf20Sopenharmony_ci				struct pwm_state *state)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
1358c2ecf20Sopenharmony_ci	void __iomem *base;
1368c2ecf20Sopenharmony_ci	u32 freq, value;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	freq = div_u64(clk_get_rate(hi_pwm_chip->clk), 1000000);
1398c2ecf20Sopenharmony_ci	base = hi_pwm_chip->base;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	value = readl(base + PWM_CFG0_ADDR(pwm->hwpwm));
1428c2ecf20Sopenharmony_ci	state->period = div_u64(value * 1000, freq);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	value = readl(base + PWM_CFG1_ADDR(pwm->hwpwm));
1458c2ecf20Sopenharmony_ci	state->duty_cycle = div_u64(value * 1000, freq);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	value = readl(base + PWM_CTRL_ADDR(pwm->hwpwm));
1488c2ecf20Sopenharmony_ci	state->enabled = (PWM_ENABLE_MASK & value);
1498c2ecf20Sopenharmony_ci	state->polarity = (PWM_POLARITY_MASK & value) ? PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
1538c2ecf20Sopenharmony_ci			   const struct pwm_state *state)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (state->polarity != pwm->state.polarity)
1588c2ecf20Sopenharmony_ci		hibvt_pwm_set_polarity(chip, pwm, state->polarity);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (state->period != pwm->state.period ||
1618c2ecf20Sopenharmony_ci	    state->duty_cycle != pwm->state.duty_cycle) {
1628c2ecf20Sopenharmony_ci		hibvt_pwm_config(chip, pwm, state->duty_cycle, state->period);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci		/*
1658c2ecf20Sopenharmony_ci		 * Some implementations require the PWM to be enabled twice
1668c2ecf20Sopenharmony_ci		 * each time the duty cycle is refreshed.
1678c2ecf20Sopenharmony_ci		 */
1688c2ecf20Sopenharmony_ci		if (hi_pwm_chip->soc->quirk_force_enable && state->enabled)
1698c2ecf20Sopenharmony_ci			hibvt_pwm_enable(chip, pwm);
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (state->enabled != pwm->state.enabled) {
1738c2ecf20Sopenharmony_ci		if (state->enabled)
1748c2ecf20Sopenharmony_ci			hibvt_pwm_enable(chip, pwm);
1758c2ecf20Sopenharmony_ci		else
1768c2ecf20Sopenharmony_ci			hibvt_pwm_disable(chip, pwm);
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return 0;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic const struct pwm_ops hibvt_pwm_ops = {
1838c2ecf20Sopenharmony_ci	.get_state = hibvt_pwm_get_state,
1848c2ecf20Sopenharmony_ci	.apply = hibvt_pwm_apply,
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
1878c2ecf20Sopenharmony_ci};
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic int hibvt_pwm_probe(struct platform_device *pdev)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	const struct hibvt_pwm_soc *soc =
1928c2ecf20Sopenharmony_ci				of_device_get_match_data(&pdev->dev);
1938c2ecf20Sopenharmony_ci	struct hibvt_pwm_chip *pwm_chip;
1948c2ecf20Sopenharmony_ci	struct resource *res;
1958c2ecf20Sopenharmony_ci	int ret;
1968c2ecf20Sopenharmony_ci	int i;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	pwm_chip = devm_kzalloc(&pdev->dev, sizeof(*pwm_chip), GFP_KERNEL);
1998c2ecf20Sopenharmony_ci	if (pwm_chip == NULL)
2008c2ecf20Sopenharmony_ci		return -ENOMEM;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	pwm_chip->clk = devm_clk_get(&pdev->dev, NULL);
2038c2ecf20Sopenharmony_ci	if (IS_ERR(pwm_chip->clk)) {
2048c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "getting clock failed with %ld\n",
2058c2ecf20Sopenharmony_ci				PTR_ERR(pwm_chip->clk));
2068c2ecf20Sopenharmony_ci		return PTR_ERR(pwm_chip->clk);
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	pwm_chip->chip.ops = &hibvt_pwm_ops;
2108c2ecf20Sopenharmony_ci	pwm_chip->chip.dev = &pdev->dev;
2118c2ecf20Sopenharmony_ci	pwm_chip->chip.base = -1;
2128c2ecf20Sopenharmony_ci	pwm_chip->chip.npwm = soc->num_pwms;
2138c2ecf20Sopenharmony_ci	pwm_chip->chip.of_xlate = of_pwm_xlate_with_flags;
2148c2ecf20Sopenharmony_ci	pwm_chip->chip.of_pwm_n_cells = 3;
2158c2ecf20Sopenharmony_ci	pwm_chip->soc = soc;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2188c2ecf20Sopenharmony_ci	pwm_chip->base = devm_ioremap_resource(&pdev->dev, res);
2198c2ecf20Sopenharmony_ci	if (IS_ERR(pwm_chip->base))
2208c2ecf20Sopenharmony_ci		return PTR_ERR(pwm_chip->base);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(pwm_chip->clk);
2238c2ecf20Sopenharmony_ci	if (ret < 0)
2248c2ecf20Sopenharmony_ci		return ret;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	pwm_chip->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
2278c2ecf20Sopenharmony_ci	if (IS_ERR(pwm_chip->rstc)) {
2288c2ecf20Sopenharmony_ci		clk_disable_unprepare(pwm_chip->clk);
2298c2ecf20Sopenharmony_ci		return PTR_ERR(pwm_chip->rstc);
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	reset_control_assert(pwm_chip->rstc);
2338c2ecf20Sopenharmony_ci	msleep(30);
2348c2ecf20Sopenharmony_ci	reset_control_deassert(pwm_chip->rstc);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	ret = pwmchip_add(&pwm_chip->chip);
2378c2ecf20Sopenharmony_ci	if (ret < 0) {
2388c2ecf20Sopenharmony_ci		clk_disable_unprepare(pwm_chip->clk);
2398c2ecf20Sopenharmony_ci		return ret;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	for (i = 0; i < pwm_chip->chip.npwm; i++) {
2438c2ecf20Sopenharmony_ci		hibvt_pwm_set_bits(pwm_chip->base, PWM_CTRL_ADDR(i),
2448c2ecf20Sopenharmony_ci				PWM_KEEP_MASK, (0x1 << PWM_KEEP_SHIFT));
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, pwm_chip);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return 0;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic int hibvt_pwm_remove(struct platform_device *pdev)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct hibvt_pwm_chip *pwm_chip;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	pwm_chip = platform_get_drvdata(pdev);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	reset_control_assert(pwm_chip->rstc);
2598c2ecf20Sopenharmony_ci	msleep(30);
2608c2ecf20Sopenharmony_ci	reset_control_deassert(pwm_chip->rstc);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	clk_disable_unprepare(pwm_chip->clk);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	return pwmchip_remove(&pwm_chip->chip);
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic const struct of_device_id hibvt_pwm_of_match[] = {
2688c2ecf20Sopenharmony_ci	{ .compatible = "hisilicon,hi3516cv300-pwm",
2698c2ecf20Sopenharmony_ci	  .data = &hi3516cv300_soc_info },
2708c2ecf20Sopenharmony_ci	{ .compatible = "hisilicon,hi3519v100-pwm",
2718c2ecf20Sopenharmony_ci	  .data = &hi3519v100_soc_info },
2728c2ecf20Sopenharmony_ci	{ .compatible = "hisilicon,hi3559v100-shub-pwm",
2738c2ecf20Sopenharmony_ci	  .data = &hi3559v100_shub_soc_info },
2748c2ecf20Sopenharmony_ci	{ .compatible = "hisilicon,hi3559v100-pwm",
2758c2ecf20Sopenharmony_ci	  .data = &hi3559v100_soc_info },
2768c2ecf20Sopenharmony_ci	{  }
2778c2ecf20Sopenharmony_ci};
2788c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, hibvt_pwm_of_match);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic struct platform_driver hibvt_pwm_driver = {
2818c2ecf20Sopenharmony_ci	.driver = {
2828c2ecf20Sopenharmony_ci		.name = "hibvt-pwm",
2838c2ecf20Sopenharmony_ci		.of_match_table = hibvt_pwm_of_match,
2848c2ecf20Sopenharmony_ci	},
2858c2ecf20Sopenharmony_ci	.probe = hibvt_pwm_probe,
2868c2ecf20Sopenharmony_ci	.remove	= hibvt_pwm_remove,
2878c2ecf20Sopenharmony_ci};
2888c2ecf20Sopenharmony_cimodule_platform_driver(hibvt_pwm_driver);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jian Yuan");
2918c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HiSilicon BVT SoCs PWM driver");
2928c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
293