root/drivers/pwm/pwm-hibvt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_hibvt_pwm_chip
  2. hibvt_pwm_set_bits
  3. hibvt_pwm_enable
  4. hibvt_pwm_disable
  5. hibvt_pwm_config
  6. hibvt_pwm_set_polarity
  7. hibvt_pwm_get_state
  8. hibvt_pwm_apply
  9. hibvt_pwm_probe
  10. hibvt_pwm_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * PWM Controller Driver for HiSilicon BVT SoCs
   4  *
   5  * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
   6  */
   7 
   8 #include <linux/bitops.h>
   9 #include <linux/clk.h>
  10 #include <linux/delay.h>
  11 #include <linux/io.h>
  12 #include <linux/module.h>
  13 #include <linux/of_device.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/pwm.h>
  16 #include <linux/reset.h>
  17 
  18 #define PWM_CFG0_ADDR(x)    (((x) * 0x20) + 0x0)
  19 #define PWM_CFG1_ADDR(x)    (((x) * 0x20) + 0x4)
  20 #define PWM_CFG2_ADDR(x)    (((x) * 0x20) + 0x8)
  21 #define PWM_CTRL_ADDR(x)    (((x) * 0x20) + 0xC)
  22 
  23 #define PWM_ENABLE_SHIFT    0
  24 #define PWM_ENABLE_MASK     BIT(0)
  25 
  26 #define PWM_POLARITY_SHIFT  1
  27 #define PWM_POLARITY_MASK   BIT(1)
  28 
  29 #define PWM_KEEP_SHIFT      2
  30 #define PWM_KEEP_MASK       BIT(2)
  31 
  32 #define PWM_PERIOD_MASK     GENMASK(31, 0)
  33 #define PWM_DUTY_MASK       GENMASK(31, 0)
  34 
  35 struct hibvt_pwm_chip {
  36         struct pwm_chip chip;
  37         struct clk *clk;
  38         void __iomem *base;
  39         struct reset_control *rstc;
  40         const struct hibvt_pwm_soc *soc;
  41 };
  42 
  43 struct hibvt_pwm_soc {
  44         u32 num_pwms;
  45         bool quirk_force_enable;
  46 };
  47 
  48 static const struct hibvt_pwm_soc hi3516cv300_soc_info = {
  49         .num_pwms = 4,
  50 };
  51 
  52 static const struct hibvt_pwm_soc hi3519v100_soc_info = {
  53         .num_pwms = 8,
  54 };
  55 
  56 static const struct hibvt_pwm_soc hi3559v100_shub_soc_info = {
  57         .num_pwms = 8,
  58         .quirk_force_enable = true,
  59 };
  60 
  61 static const struct hibvt_pwm_soc hi3559v100_soc_info = {
  62         .num_pwms = 2,
  63         .quirk_force_enable = true,
  64 };
  65 
  66 static inline struct hibvt_pwm_chip *to_hibvt_pwm_chip(struct pwm_chip *chip)
  67 {
  68         return container_of(chip, struct hibvt_pwm_chip, chip);
  69 }
  70 
  71 static void hibvt_pwm_set_bits(void __iomem *base, u32 offset,
  72                                         u32 mask, u32 data)
  73 {
  74         void __iomem *address = base + offset;
  75         u32 value;
  76 
  77         value = readl(address);
  78         value &= ~mask;
  79         value |= (data & mask);
  80         writel(value, address);
  81 }
  82 
  83 static void hibvt_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
  84 {
  85         struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
  86 
  87         hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
  88                         PWM_ENABLE_MASK, 0x1);
  89 }
  90 
  91 static void hibvt_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
  92 {
  93         struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
  94 
  95         hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
  96                         PWM_ENABLE_MASK, 0x0);
  97 }
  98 
  99 static void hibvt_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 100                                         int duty_cycle_ns, int period_ns)
 101 {
 102         struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
 103         u32 freq, period, duty;
 104 
 105         freq = div_u64(clk_get_rate(hi_pwm_chip->clk), 1000000);
 106 
 107         period = div_u64(freq * period_ns, 1000);
 108         duty = div_u64(period * duty_cycle_ns, period_ns);
 109 
 110         hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CFG0_ADDR(pwm->hwpwm),
 111                         PWM_PERIOD_MASK, period);
 112 
 113         hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CFG1_ADDR(pwm->hwpwm),
 114                         PWM_DUTY_MASK, duty);
 115 }
 116 
 117 static void hibvt_pwm_set_polarity(struct pwm_chip *chip,
 118                                         struct pwm_device *pwm,
 119                                         enum pwm_polarity polarity)
 120 {
 121         struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
 122 
 123         if (polarity == PWM_POLARITY_INVERSED)
 124                 hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
 125                                 PWM_POLARITY_MASK, (0x1 << PWM_POLARITY_SHIFT));
 126         else
 127                 hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
 128                                 PWM_POLARITY_MASK, (0x0 << PWM_POLARITY_SHIFT));
 129 }
 130 
 131 static void hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 132                                 struct pwm_state *state)
 133 {
 134         struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
 135         void __iomem *base;
 136         u32 freq, value;
 137 
 138         freq = div_u64(clk_get_rate(hi_pwm_chip->clk), 1000000);
 139         base = hi_pwm_chip->base;
 140 
 141         value = readl(base + PWM_CFG0_ADDR(pwm->hwpwm));
 142         state->period = div_u64(value * 1000, freq);
 143 
 144         value = readl(base + PWM_CFG1_ADDR(pwm->hwpwm));
 145         state->duty_cycle = div_u64(value * 1000, freq);
 146 
 147         value = readl(base + PWM_CTRL_ADDR(pwm->hwpwm));
 148         state->enabled = (PWM_ENABLE_MASK & value);
 149 }
 150 
 151 static int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 152                            const struct pwm_state *state)
 153 {
 154         struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
 155 
 156         if (state->polarity != pwm->state.polarity)
 157                 hibvt_pwm_set_polarity(chip, pwm, state->polarity);
 158 
 159         if (state->period != pwm->state.period ||
 160             state->duty_cycle != pwm->state.duty_cycle) {
 161                 hibvt_pwm_config(chip, pwm, state->duty_cycle, state->period);
 162 
 163                 /*
 164                  * Some implementations require the PWM to be enabled twice
 165                  * each time the duty cycle is refreshed.
 166                  */
 167                 if (hi_pwm_chip->soc->quirk_force_enable && state->enabled)
 168                         hibvt_pwm_enable(chip, pwm);
 169         }
 170 
 171         if (state->enabled != pwm->state.enabled) {
 172                 if (state->enabled)
 173                         hibvt_pwm_enable(chip, pwm);
 174                 else
 175                         hibvt_pwm_disable(chip, pwm);
 176         }
 177 
 178         return 0;
 179 }
 180 
 181 static const struct pwm_ops hibvt_pwm_ops = {
 182         .get_state = hibvt_pwm_get_state,
 183         .apply = hibvt_pwm_apply,
 184 
 185         .owner = THIS_MODULE,
 186 };
 187 
 188 static int hibvt_pwm_probe(struct platform_device *pdev)
 189 {
 190         const struct hibvt_pwm_soc *soc =
 191                                 of_device_get_match_data(&pdev->dev);
 192         struct hibvt_pwm_chip *pwm_chip;
 193         struct resource *res;
 194         int ret;
 195         int i;
 196 
 197         pwm_chip = devm_kzalloc(&pdev->dev, sizeof(*pwm_chip), GFP_KERNEL);
 198         if (pwm_chip == NULL)
 199                 return -ENOMEM;
 200 
 201         pwm_chip->clk = devm_clk_get(&pdev->dev, NULL);
 202         if (IS_ERR(pwm_chip->clk)) {
 203                 dev_err(&pdev->dev, "getting clock failed with %ld\n",
 204                                 PTR_ERR(pwm_chip->clk));
 205                 return PTR_ERR(pwm_chip->clk);
 206         }
 207 
 208         pwm_chip->chip.ops = &hibvt_pwm_ops;
 209         pwm_chip->chip.dev = &pdev->dev;
 210         pwm_chip->chip.base = -1;
 211         pwm_chip->chip.npwm = soc->num_pwms;
 212         pwm_chip->chip.of_xlate = of_pwm_xlate_with_flags;
 213         pwm_chip->chip.of_pwm_n_cells = 3;
 214         pwm_chip->soc = soc;
 215 
 216         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 217         pwm_chip->base = devm_ioremap_resource(&pdev->dev, res);
 218         if (IS_ERR(pwm_chip->base))
 219                 return PTR_ERR(pwm_chip->base);
 220 
 221         ret = clk_prepare_enable(pwm_chip->clk);
 222         if (ret < 0)
 223                 return ret;
 224 
 225         pwm_chip->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 226         if (IS_ERR(pwm_chip->rstc)) {
 227                 clk_disable_unprepare(pwm_chip->clk);
 228                 return PTR_ERR(pwm_chip->rstc);
 229         }
 230 
 231         reset_control_assert(pwm_chip->rstc);
 232         msleep(30);
 233         reset_control_deassert(pwm_chip->rstc);
 234 
 235         ret = pwmchip_add(&pwm_chip->chip);
 236         if (ret < 0) {
 237                 clk_disable_unprepare(pwm_chip->clk);
 238                 return ret;
 239         }
 240 
 241         for (i = 0; i < pwm_chip->chip.npwm; i++) {
 242                 hibvt_pwm_set_bits(pwm_chip->base, PWM_CTRL_ADDR(i),
 243                                 PWM_KEEP_MASK, (0x1 << PWM_KEEP_SHIFT));
 244         }
 245 
 246         platform_set_drvdata(pdev, pwm_chip);
 247 
 248         return 0;
 249 }
 250 
 251 static int hibvt_pwm_remove(struct platform_device *pdev)
 252 {
 253         struct hibvt_pwm_chip *pwm_chip;
 254 
 255         pwm_chip = platform_get_drvdata(pdev);
 256 
 257         reset_control_assert(pwm_chip->rstc);
 258         msleep(30);
 259         reset_control_deassert(pwm_chip->rstc);
 260 
 261         clk_disable_unprepare(pwm_chip->clk);
 262 
 263         return pwmchip_remove(&pwm_chip->chip);
 264 }
 265 
 266 static const struct of_device_id hibvt_pwm_of_match[] = {
 267         { .compatible = "hisilicon,hi3516cv300-pwm",
 268           .data = &hi3516cv300_soc_info },
 269         { .compatible = "hisilicon,hi3519v100-pwm",
 270           .data = &hi3519v100_soc_info },
 271         { .compatible = "hisilicon,hi3559v100-shub-pwm",
 272           .data = &hi3559v100_shub_soc_info },
 273         { .compatible = "hisilicon,hi3559v100-pwm",
 274           .data = &hi3559v100_soc_info },
 275         {  }
 276 };
 277 MODULE_DEVICE_TABLE(of, hibvt_pwm_of_match);
 278 
 279 static struct platform_driver hibvt_pwm_driver = {
 280         .driver = {
 281                 .name = "hibvt-pwm",
 282                 .of_match_table = hibvt_pwm_of_match,
 283         },
 284         .probe = hibvt_pwm_probe,
 285         .remove = hibvt_pwm_remove,
 286 };
 287 module_platform_driver(hibvt_pwm_driver);
 288 
 289 MODULE_AUTHOR("Jian Yuan");
 290 MODULE_DESCRIPTION("HiSilicon BVT SoCs PWM driver");
 291 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */