linux/drivers/pwm/pwm-zx.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 Sanechips Technology Co., Ltd.
   3 * Copyright 2017 Linaro Ltd.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 */
   9
  10#include <linux/clk.h>
  11#include <linux/err.h>
  12#include <linux/io.h>
  13#include <linux/kernel.h>
  14#include <linux/module.h>
  15#include <linux/platform_device.h>
  16#include <linux/pwm.h>
  17#include <linux/slab.h>
  18
  19#define ZX_PWM_MODE             0x0
  20#define ZX_PWM_CLKDIV_SHIFT     2
  21#define ZX_PWM_CLKDIV_MASK      GENMASK(11, 2)
  22#define ZX_PWM_CLKDIV(x)        (((x) << ZX_PWM_CLKDIV_SHIFT) & \
  23                                         ZX_PWM_CLKDIV_MASK)
  24#define ZX_PWM_POLAR            BIT(1)
  25#define ZX_PWM_EN               BIT(0)
  26#define ZX_PWM_PERIOD           0x4
  27#define ZX_PWM_DUTY             0x8
  28
  29#define ZX_PWM_CLKDIV_MAX       1023
  30#define ZX_PWM_PERIOD_MAX       65535
  31
  32struct zx_pwm_chip {
  33        struct pwm_chip chip;
  34        struct clk *pclk;
  35        struct clk *wclk;
  36        void __iomem *base;
  37};
  38
  39static inline struct zx_pwm_chip *to_zx_pwm_chip(struct pwm_chip *chip)
  40{
  41        return container_of(chip, struct zx_pwm_chip, chip);
  42}
  43
  44static inline u32 zx_pwm_readl(struct zx_pwm_chip *zpc, unsigned int hwpwm,
  45                               unsigned int offset)
  46{
  47        return readl(zpc->base + (hwpwm + 1) * 0x10 + offset);
  48}
  49
  50static inline void zx_pwm_writel(struct zx_pwm_chip *zpc, unsigned int hwpwm,
  51                                 unsigned int offset, u32 value)
  52{
  53        writel(value, zpc->base + (hwpwm + 1) * 0x10 + offset);
  54}
  55
  56static void zx_pwm_set_mask(struct zx_pwm_chip *zpc, unsigned int hwpwm,
  57                            unsigned int offset, u32 mask, u32 value)
  58{
  59        u32 data;
  60
  61        data = zx_pwm_readl(zpc, hwpwm, offset);
  62        data &= ~mask;
  63        data |= value & mask;
  64        zx_pwm_writel(zpc, hwpwm, offset, data);
  65}
  66
  67static void zx_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
  68                             struct pwm_state *state)
  69{
  70        struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip);
  71        unsigned long rate;
  72        unsigned int div;
  73        u32 value;
  74        u64 tmp;
  75
  76        value = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_MODE);
  77
  78        if (value & ZX_PWM_POLAR)
  79                state->polarity = PWM_POLARITY_NORMAL;
  80        else
  81                state->polarity = PWM_POLARITY_INVERSED;
  82
  83        if (value & ZX_PWM_EN)
  84                state->enabled = true;
  85        else
  86                state->enabled = false;
  87
  88        div = (value & ZX_PWM_CLKDIV_MASK) >> ZX_PWM_CLKDIV_SHIFT;
  89        rate = clk_get_rate(zpc->wclk);
  90
  91        tmp = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_PERIOD);
  92        tmp *= div * NSEC_PER_SEC;
  93        state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate);
  94
  95        tmp = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_DUTY);
  96        tmp *= div * NSEC_PER_SEC;
  97        state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate);
  98}
  99
 100static int zx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 101                         unsigned int duty_ns, unsigned int period_ns)
 102{
 103        struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip);
 104        unsigned int period_cycles, duty_cycles;
 105        unsigned long long c;
 106        unsigned int div = 1;
 107        unsigned long rate;
 108
 109        /* Find out the best divider */
 110        rate = clk_get_rate(zpc->wclk);
 111
 112        while (1) {
 113                c = rate / div;
 114                c = c * period_ns;
 115                do_div(c, NSEC_PER_SEC);
 116
 117                if (c < ZX_PWM_PERIOD_MAX)
 118                        break;
 119
 120                div++;
 121
 122                if (div > ZX_PWM_CLKDIV_MAX)
 123                        return -ERANGE;
 124        }
 125
 126        /* Calculate duty cycles */
 127        period_cycles = c;
 128        c *= duty_ns;
 129        do_div(c, period_ns);
 130        duty_cycles = c;
 131
 132        /*
 133         * If the PWM is being enabled, we have to temporarily disable it
 134         * before configuring the registers.
 135         */
 136        if (pwm_is_enabled(pwm))
 137                zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_EN, 0);
 138
 139        /* Set up registers */
 140        zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_CLKDIV_MASK,
 141                        ZX_PWM_CLKDIV(div));
 142        zx_pwm_writel(zpc, pwm->hwpwm, ZX_PWM_PERIOD, period_cycles);
 143        zx_pwm_writel(zpc, pwm->hwpwm, ZX_PWM_DUTY, duty_cycles);
 144
 145        /* Re-enable the PWM if needed */
 146        if (pwm_is_enabled(pwm))
 147                zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE,
 148                                ZX_PWM_EN, ZX_PWM_EN);
 149
 150        return 0;
 151}
 152
 153static int zx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 154                        const struct pwm_state *state)
 155{
 156        struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip);
 157        struct pwm_state cstate;
 158        int ret;
 159
 160        pwm_get_state(pwm, &cstate);
 161
 162        if (state->polarity != cstate.polarity)
 163                zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_POLAR,
 164                                (state->polarity == PWM_POLARITY_INVERSED) ?
 165                                 0 : ZX_PWM_POLAR);
 166
 167        if (state->period != cstate.period ||
 168            state->duty_cycle != cstate.duty_cycle) {
 169                ret = zx_pwm_config(chip, pwm, state->duty_cycle,
 170                                    state->period);
 171                if (ret)
 172                        return ret;
 173        }
 174
 175        if (state->enabled != cstate.enabled) {
 176                if (state->enabled) {
 177                        ret = clk_prepare_enable(zpc->wclk);
 178                        if (ret)
 179                                return ret;
 180
 181                        zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE,
 182                                        ZX_PWM_EN, ZX_PWM_EN);
 183                } else {
 184                        zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE,
 185                                        ZX_PWM_EN, 0);
 186                        clk_disable_unprepare(zpc->wclk);
 187                }
 188        }
 189
 190        return 0;
 191}
 192
 193static const struct pwm_ops zx_pwm_ops = {
 194        .apply = zx_pwm_apply,
 195        .get_state = zx_pwm_get_state,
 196        .owner = THIS_MODULE,
 197};
 198
 199static int zx_pwm_probe(struct platform_device *pdev)
 200{
 201        struct zx_pwm_chip *zpc;
 202        struct resource *res;
 203        unsigned int i;
 204        int ret;
 205
 206        zpc = devm_kzalloc(&pdev->dev, sizeof(*zpc), GFP_KERNEL);
 207        if (!zpc)
 208                return -ENOMEM;
 209
 210        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 211        zpc->base = devm_ioremap_resource(&pdev->dev, res);
 212        if (IS_ERR(zpc->base))
 213                return PTR_ERR(zpc->base);
 214
 215        zpc->pclk = devm_clk_get(&pdev->dev, "pclk");
 216        if (IS_ERR(zpc->pclk))
 217                return PTR_ERR(zpc->pclk);
 218
 219        zpc->wclk = devm_clk_get(&pdev->dev, "wclk");
 220        if (IS_ERR(zpc->wclk))
 221                return PTR_ERR(zpc->wclk);
 222
 223        ret = clk_prepare_enable(zpc->pclk);
 224        if (ret)
 225                return ret;
 226
 227        zpc->chip.dev = &pdev->dev;
 228        zpc->chip.ops = &zx_pwm_ops;
 229        zpc->chip.base = -1;
 230        zpc->chip.npwm = 4;
 231        zpc->chip.of_xlate = of_pwm_xlate_with_flags;
 232        zpc->chip.of_pwm_n_cells = 3;
 233
 234        /*
 235         * PWM devices may be enabled by firmware, and let's disable all of
 236         * them initially to save power.
 237         */
 238        for (i = 0; i < zpc->chip.npwm; i++)
 239                zx_pwm_set_mask(zpc, i, ZX_PWM_MODE, ZX_PWM_EN, 0);
 240
 241        ret = pwmchip_add(&zpc->chip);
 242        if (ret < 0) {
 243                dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
 244                return ret;
 245        }
 246
 247        platform_set_drvdata(pdev, zpc);
 248
 249        return 0;
 250}
 251
 252static int zx_pwm_remove(struct platform_device *pdev)
 253{
 254        struct zx_pwm_chip *zpc = platform_get_drvdata(pdev);
 255        int ret;
 256
 257        ret = pwmchip_remove(&zpc->chip);
 258        clk_disable_unprepare(zpc->pclk);
 259
 260        return ret;
 261}
 262
 263static const struct of_device_id zx_pwm_dt_ids[] = {
 264        { .compatible = "zte,zx296718-pwm", },
 265        { /* sentinel */ }
 266};
 267MODULE_DEVICE_TABLE(of, zx_pwm_dt_ids);
 268
 269static struct platform_driver zx_pwm_driver = {
 270        .driver = {
 271                .name = "zx-pwm",
 272                .of_match_table = zx_pwm_dt_ids,
 273        },
 274        .probe = zx_pwm_probe,
 275        .remove = zx_pwm_remove,
 276};
 277module_platform_driver(zx_pwm_driver);
 278
 279MODULE_ALIAS("platform:zx-pwm");
 280MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
 281MODULE_DESCRIPTION("ZTE ZX PWM Driver");
 282MODULE_LICENSE("GPL v2");
 283