19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2a245ccebSSascha Hauer /* 3261995ddSAxel Lin * drivers/pwm/pwm-vt8500.c 4a245ccebSSascha Hauer * 563e1ed23STony Prisk * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> 6a245ccebSSascha Hauer * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> 7a245ccebSSascha Hauer */ 8a245ccebSSascha Hauer 9a245ccebSSascha Hauer #include <linux/module.h> 10a245ccebSSascha Hauer #include <linux/kernel.h> 11a245ccebSSascha Hauer #include <linux/platform_device.h> 12a245ccebSSascha Hauer #include <linux/slab.h> 13a245ccebSSascha Hauer #include <linux/err.h> 14a245ccebSSascha Hauer #include <linux/io.h> 15a245ccebSSascha Hauer #include <linux/pwm.h> 16a245ccebSSascha Hauer #include <linux/delay.h> 1763e1ed23STony Prisk #include <linux/clk.h> 18a245ccebSSascha Hauer 19a245ccebSSascha Hauer #include <asm/div64.h> 20a245ccebSSascha Hauer 2163e1ed23STony Prisk #include <linux/of.h> 2263e1ed23STony Prisk #include <linux/of_device.h> 2363e1ed23STony Prisk #include <linux/of_address.h> 2463e1ed23STony Prisk 2563e1ed23STony Prisk /* 2663e1ed23STony Prisk * SoC architecture allocates register space for 4 PWMs but only 2763e1ed23STony Prisk * 2 are currently implemented. 2863e1ed23STony Prisk */ 2963e1ed23STony Prisk #define VT8500_NR_PWMS 2 30a245ccebSSascha Hauer 318ab432caSTony Prisk #define REG_CTRL(pwm) (((pwm) << 4) + 0x00) 328ab432caSTony Prisk #define REG_SCALAR(pwm) (((pwm) << 4) + 0x04) 338ab432caSTony Prisk #define REG_PERIOD(pwm) (((pwm) << 4) + 0x08) 348ab432caSTony Prisk #define REG_DUTY(pwm) (((pwm) << 4) + 0x0C) 358ab432caSTony Prisk #define REG_STATUS 0x40 368ab432caSTony Prisk 378ab432caSTony Prisk #define CTRL_ENABLE BIT(0) 388ab432caSTony Prisk #define CTRL_INVERT BIT(1) 398ab432caSTony Prisk #define CTRL_AUTOLOAD BIT(2) 408ab432caSTony Prisk #define CTRL_STOP_IMM BIT(3) 418ab432caSTony Prisk #define CTRL_LOAD_PRESCALE BIT(4) 428ab432caSTony Prisk #define CTRL_LOAD_PERIOD BIT(5) 438ab432caSTony Prisk 448ab432caSTony Prisk #define STATUS_CTRL_UPDATE BIT(0) 458ab432caSTony Prisk #define STATUS_SCALAR_UPDATE BIT(1) 468ab432caSTony Prisk #define STATUS_PERIOD_UPDATE BIT(2) 478ab432caSTony Prisk #define STATUS_DUTY_UPDATE BIT(3) 488ab432caSTony Prisk #define STATUS_ALL_UPDATE 0x0F 498ab432caSTony Prisk 50a245ccebSSascha Hauer struct vt8500_chip { 51a245ccebSSascha Hauer struct pwm_chip chip; 52a245ccebSSascha Hauer void __iomem *base; 5363e1ed23STony Prisk struct clk *clk; 54a245ccebSSascha Hauer }; 55a245ccebSSascha Hauer 56a245ccebSSascha Hauer #define to_vt8500_chip(chip) container_of(chip, struct vt8500_chip, chip) 57a245ccebSSascha Hauer 58a245ccebSSascha Hauer #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) 59e9d866d5SUwe Kleine-König static inline void vt8500_pwm_busy_wait(struct vt8500_chip *vt8500, int nr, u8 bitmask) 60a245ccebSSascha Hauer { 61a245ccebSSascha Hauer int loops = msecs_to_loops(10); 628ab432caSTony Prisk u32 mask = bitmask << (nr << 8); 638ab432caSTony Prisk 648ab432caSTony Prisk while ((readl(vt8500->base + REG_STATUS) & mask) && --loops) 65a245ccebSSascha Hauer cpu_relax(); 66a245ccebSSascha Hauer 67a245ccebSSascha Hauer if (unlikely(!loops)) 688ab432caSTony Prisk dev_warn(vt8500->chip.dev, "Waiting for status bits 0x%x to clear timed out\n", 698ab432caSTony Prisk mask); 70a245ccebSSascha Hauer } 71a245ccebSSascha Hauer 72a245ccebSSascha Hauer static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 7314d89565SUwe Kleine-König u64 duty_ns, u64 period_ns) 74a245ccebSSascha Hauer { 75a245ccebSSascha Hauer struct vt8500_chip *vt8500 = to_vt8500_chip(chip); 76a245ccebSSascha Hauer unsigned long long c; 77a245ccebSSascha Hauer unsigned long period_cycles, prescale, pv, dc; 78422470a8STony Prisk int err; 798ab432caSTony Prisk u32 val; 80422470a8STony Prisk 81422470a8STony Prisk err = clk_enable(vt8500->clk); 82422470a8STony Prisk if (err < 0) { 83422470a8STony Prisk dev_err(chip->dev, "failed to enable clock\n"); 84422470a8STony Prisk return err; 85422470a8STony Prisk } 86a245ccebSSascha Hauer 8763e1ed23STony Prisk c = clk_get_rate(vt8500->clk); 88a245ccebSSascha Hauer c = c * period_ns; 89a245ccebSSascha Hauer do_div(c, 1000000000); 90a245ccebSSascha Hauer period_cycles = c; 91a245ccebSSascha Hauer 92a245ccebSSascha Hauer if (period_cycles < 1) 93a245ccebSSascha Hauer period_cycles = 1; 94a245ccebSSascha Hauer prescale = (period_cycles - 1) / 4096; 95a245ccebSSascha Hauer pv = period_cycles / (prescale + 1) - 1; 96a245ccebSSascha Hauer if (pv > 4095) 97a245ccebSSascha Hauer pv = 4095; 98a245ccebSSascha Hauer 99422470a8STony Prisk if (prescale > 1023) { 100422470a8STony Prisk clk_disable(vt8500->clk); 101a245ccebSSascha Hauer return -EINVAL; 102422470a8STony Prisk } 103a245ccebSSascha Hauer 104a245ccebSSascha Hauer c = (unsigned long long)pv * duty_ns; 10514d89565SUwe Kleine-König 10614d89565SUwe Kleine-König dc = div64_u64(c, period_ns); 107a245ccebSSascha Hauer 1088ab432caSTony Prisk writel(prescale, vt8500->base + REG_SCALAR(pwm->hwpwm)); 109e9d866d5SUwe Kleine-König vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_SCALAR_UPDATE); 110a245ccebSSascha Hauer 1118ab432caSTony Prisk writel(pv, vt8500->base + REG_PERIOD(pwm->hwpwm)); 112e9d866d5SUwe Kleine-König vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_PERIOD_UPDATE); 113a245ccebSSascha Hauer 1148ab432caSTony Prisk writel(dc, vt8500->base + REG_DUTY(pwm->hwpwm)); 115e9d866d5SUwe Kleine-König vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_DUTY_UPDATE); 1168ab432caSTony Prisk 1178ab432caSTony Prisk val = readl(vt8500->base + REG_CTRL(pwm->hwpwm)); 1188ab432caSTony Prisk val |= CTRL_AUTOLOAD; 1198ab432caSTony Prisk writel(val, vt8500->base + REG_CTRL(pwm->hwpwm)); 120e9d866d5SUwe Kleine-König vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE); 121a245ccebSSascha Hauer 122422470a8STony Prisk clk_disable(vt8500->clk); 123a245ccebSSascha Hauer return 0; 124a245ccebSSascha Hauer } 125a245ccebSSascha Hauer 126a245ccebSSascha Hauer static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 127a245ccebSSascha Hauer { 128a245ccebSSascha Hauer struct vt8500_chip *vt8500 = to_vt8500_chip(chip); 1298ab432caSTony Prisk int err; 1308ab432caSTony Prisk u32 val; 131a245ccebSSascha Hauer 13263e1ed23STony Prisk err = clk_enable(vt8500->clk); 1332f9569f7STony Prisk if (err < 0) { 13463e1ed23STony Prisk dev_err(chip->dev, "failed to enable clock\n"); 13563e1ed23STony Prisk return err; 136422470a8STony Prisk } 13763e1ed23STony Prisk 1388ab432caSTony Prisk val = readl(vt8500->base + REG_CTRL(pwm->hwpwm)); 1398ab432caSTony Prisk val |= CTRL_ENABLE; 1408ab432caSTony Prisk writel(val, vt8500->base + REG_CTRL(pwm->hwpwm)); 141e9d866d5SUwe Kleine-König vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE); 1428ab432caSTony Prisk 143a245ccebSSascha Hauer return 0; 144a245ccebSSascha Hauer } 145a245ccebSSascha Hauer 146a245ccebSSascha Hauer static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 147a245ccebSSascha Hauer { 148a245ccebSSascha Hauer struct vt8500_chip *vt8500 = to_vt8500_chip(chip); 1498ab432caSTony Prisk u32 val; 150a245ccebSSascha Hauer 1518ab432caSTony Prisk val = readl(vt8500->base + REG_CTRL(pwm->hwpwm)); 1528ab432caSTony Prisk val &= ~CTRL_ENABLE; 1538ab432caSTony Prisk writel(val, vt8500->base + REG_CTRL(pwm->hwpwm)); 154e9d866d5SUwe Kleine-König vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE); 15563e1ed23STony Prisk 15663e1ed23STony Prisk clk_disable(vt8500->clk); 157a245ccebSSascha Hauer } 158a245ccebSSascha Hauer 1593ccb1c17STony Prisk static int vt8500_pwm_set_polarity(struct pwm_chip *chip, 1603ccb1c17STony Prisk struct pwm_device *pwm, 1613ccb1c17STony Prisk enum pwm_polarity polarity) 1623ccb1c17STony Prisk { 1633ccb1c17STony Prisk struct vt8500_chip *vt8500 = to_vt8500_chip(chip); 1643ccb1c17STony Prisk u32 val; 1653ccb1c17STony Prisk 1663ccb1c17STony Prisk val = readl(vt8500->base + REG_CTRL(pwm->hwpwm)); 1673ccb1c17STony Prisk 1683ccb1c17STony Prisk if (polarity == PWM_POLARITY_INVERSED) 1693ccb1c17STony Prisk val |= CTRL_INVERT; 1703ccb1c17STony Prisk else 1713ccb1c17STony Prisk val &= ~CTRL_INVERT; 1723ccb1c17STony Prisk 1733ccb1c17STony Prisk writel(val, vt8500->base + REG_CTRL(pwm->hwpwm)); 174e9d866d5SUwe Kleine-König vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE); 1753ccb1c17STony Prisk 1763ccb1c17STony Prisk return 0; 1773ccb1c17STony Prisk } 1783ccb1c17STony Prisk 17914d89565SUwe Kleine-König static int vt8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 18014d89565SUwe Kleine-König const struct pwm_state *state) 18114d89565SUwe Kleine-König { 18214d89565SUwe Kleine-König int err; 18314d89565SUwe Kleine-König bool enabled = pwm->state.enabled; 18414d89565SUwe Kleine-König 18514d89565SUwe Kleine-König if (state->polarity != pwm->state.polarity) { 18614d89565SUwe Kleine-König /* 18714d89565SUwe Kleine-König * Changing the polarity of a running PWM is only allowed when 18814d89565SUwe Kleine-König * the PWM driver implements ->apply(). 18914d89565SUwe Kleine-König */ 19014d89565SUwe Kleine-König if (enabled) { 19114d89565SUwe Kleine-König vt8500_pwm_disable(chip, pwm); 19214d89565SUwe Kleine-König 19314d89565SUwe Kleine-König enabled = false; 19414d89565SUwe Kleine-König } 19514d89565SUwe Kleine-König 19614d89565SUwe Kleine-König err = vt8500_pwm_set_polarity(chip, pwm, state->polarity); 19714d89565SUwe Kleine-König if (err) 19814d89565SUwe Kleine-König return err; 19914d89565SUwe Kleine-König } 20014d89565SUwe Kleine-König 20114d89565SUwe Kleine-König if (!state->enabled) { 20214d89565SUwe Kleine-König if (enabled) 20314d89565SUwe Kleine-König vt8500_pwm_disable(chip, pwm); 20414d89565SUwe Kleine-König 20514d89565SUwe Kleine-König return 0; 20614d89565SUwe Kleine-König } 20714d89565SUwe Kleine-König 20814d89565SUwe Kleine-König /* 20914d89565SUwe Kleine-König * We cannot skip calling ->config even if state->period == 21014d89565SUwe Kleine-König * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle 21114d89565SUwe Kleine-König * because we might have exited early in the last call to 21214d89565SUwe Kleine-König * pwm_apply_state because of !state->enabled and so the two values in 21314d89565SUwe Kleine-König * pwm->state might not be configured in hardware. 21414d89565SUwe Kleine-König */ 21514d89565SUwe Kleine-König err = vt8500_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period); 21614d89565SUwe Kleine-König if (err) 21714d89565SUwe Kleine-König return err; 21814d89565SUwe Kleine-König 21914d89565SUwe Kleine-König if (!enabled) 22014d89565SUwe Kleine-König err = vt8500_pwm_enable(chip, pwm); 22114d89565SUwe Kleine-König 22214d89565SUwe Kleine-König return err; 22314d89565SUwe Kleine-König } 22414d89565SUwe Kleine-König 225b2ec9efcSBhumika Goyal static const struct pwm_ops vt8500_pwm_ops = { 22614d89565SUwe Kleine-König .apply = vt8500_pwm_apply, 227a245ccebSSascha Hauer .owner = THIS_MODULE, 228a245ccebSSascha Hauer }; 229a245ccebSSascha Hauer 23063e1ed23STony Prisk static const struct of_device_id vt8500_pwm_dt_ids[] = { 23163e1ed23STony Prisk { .compatible = "via,vt8500-pwm", }, 23263e1ed23STony Prisk { /* Sentinel */ } 23363e1ed23STony Prisk }; 23463e1ed23STony Prisk MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids); 23563e1ed23STony Prisk 23663e1ed23STony Prisk static int vt8500_pwm_probe(struct platform_device *pdev) 237a245ccebSSascha Hauer { 238635d324eSzhaoxiao struct vt8500_chip *vt8500; 23963e1ed23STony Prisk struct device_node *np = pdev->dev.of_node; 240a245ccebSSascha Hauer int ret; 241a245ccebSSascha Hauer 24263e1ed23STony Prisk if (!np) { 24363e1ed23STony Prisk dev_err(&pdev->dev, "invalid devicetree node\n"); 24463e1ed23STony Prisk return -EINVAL; 24563e1ed23STony Prisk } 24663e1ed23STony Prisk 247635d324eSzhaoxiao vt8500 = devm_kzalloc(&pdev->dev, sizeof(*vt8500), GFP_KERNEL); 248635d324eSzhaoxiao if (vt8500 == NULL) 249a245ccebSSascha Hauer return -ENOMEM; 250a245ccebSSascha Hauer 251635d324eSzhaoxiao vt8500->chip.dev = &pdev->dev; 252635d324eSzhaoxiao vt8500->chip.ops = &vt8500_pwm_ops; 253635d324eSzhaoxiao vt8500->chip.npwm = VT8500_NR_PWMS; 254a245ccebSSascha Hauer 255635d324eSzhaoxiao vt8500->clk = devm_clk_get(&pdev->dev, NULL); 256635d324eSzhaoxiao if (IS_ERR(vt8500->clk)) { 25763e1ed23STony Prisk dev_err(&pdev->dev, "clock source not specified\n"); 258635d324eSzhaoxiao return PTR_ERR(vt8500->clk); 25963e1ed23STony Prisk } 26063e1ed23STony Prisk 261635d324eSzhaoxiao vt8500->base = devm_platform_ioremap_resource(pdev, 0); 262635d324eSzhaoxiao if (IS_ERR(vt8500->base)) 263635d324eSzhaoxiao return PTR_ERR(vt8500->base); 264a245ccebSSascha Hauer 265635d324eSzhaoxiao ret = clk_prepare(vt8500->clk); 26663e1ed23STony Prisk if (ret < 0) { 26763e1ed23STony Prisk dev_err(&pdev->dev, "failed to prepare clock\n"); 268a245ccebSSascha Hauer return ret; 26963e1ed23STony Prisk } 27063e1ed23STony Prisk 271635d324eSzhaoxiao ret = pwmchip_add(&vt8500->chip); 27263e1ed23STony Prisk if (ret < 0) { 27363e1ed23STony Prisk dev_err(&pdev->dev, "failed to add PWM chip\n"); 274635d324eSzhaoxiao clk_unprepare(vt8500->clk); 27563e1ed23STony Prisk return ret; 27663e1ed23STony Prisk } 277a245ccebSSascha Hauer 278635d324eSzhaoxiao platform_set_drvdata(pdev, vt8500); 279a245ccebSSascha Hauer return ret; 280a245ccebSSascha Hauer } 281a245ccebSSascha Hauer 282*22e1d1f4SUwe Kleine-König static void vt8500_pwm_remove(struct platform_device *pdev) 283a245ccebSSascha Hauer { 284635d324eSzhaoxiao struct vt8500_chip *vt8500 = platform_get_drvdata(pdev); 285a245ccebSSascha Hauer 286635d324eSzhaoxiao pwmchip_remove(&vt8500->chip); 287a245ccebSSascha Hauer 288635d324eSzhaoxiao clk_unprepare(vt8500->clk); 289a245ccebSSascha Hauer } 290a245ccebSSascha Hauer 29163e1ed23STony Prisk static struct platform_driver vt8500_pwm_driver = { 29263e1ed23STony Prisk .probe = vt8500_pwm_probe, 293*22e1d1f4SUwe Kleine-König .remove_new = vt8500_pwm_remove, 294a245ccebSSascha Hauer .driver = { 295a245ccebSSascha Hauer .name = "vt8500-pwm", 29663e1ed23STony Prisk .of_match_table = vt8500_pwm_dt_ids, 297a245ccebSSascha Hauer }, 298a245ccebSSascha Hauer }; 29963e1ed23STony Prisk module_platform_driver(vt8500_pwm_driver); 300a245ccebSSascha Hauer 30163e1ed23STony Prisk MODULE_DESCRIPTION("VT8500 PWM Driver"); 30263e1ed23STony Prisk MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); 30363e1ed23STony Prisk MODULE_LICENSE("GPL v2"); 304