4731e4a1858da157885dc6c7277a6e1c536680e2
[platform/kernel/u-boot.git] / drivers / pwm / pwm-sifive.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2020 SiFive, Inc
4  * For SiFive's PWM IP block documentation please refer Chapter 14 of
5  * Reference Manual : https://static.dev.sifive.com/FU540-C000-v1.0.pdf
6  *
7  * Limitations:
8  * - When changing both duty cycle and period, we cannot prevent in
9  *   software that the output might produce a period with mixed
10  *   settings (new period length and old duty cycle).
11  * - The hardware cannot generate a 100% duty cycle.
12  * - The hardware generates only inverted output.
13  */
14
15 #include <common.h>
16 #include <clk.h>
17 #include <div64.h>
18 #include <dm.h>
19 #include <pwm.h>
20 #include <regmap.h>
21 #include <linux/io.h>
22 #include <linux/log2.h>
23 #include <linux/bitfield.h>
24
25 /* PWMCFG fields */
26 #define PWM_SIFIVE_PWMCFG_SCALE         GENMASK(3, 0)
27 #define PWM_SIFIVE_PWMCFG_STICKY        BIT(8)
28 #define PWM_SIFIVE_PWMCFG_ZERO_CMP      BIT(9)
29 #define PWM_SIFIVE_PWMCFG_DEGLITCH      BIT(10)
30 #define PWM_SIFIVE_PWMCFG_EN_ALWAYS     BIT(12)
31 #define PWM_SIFIVE_PWMCFG_EN_ONCE       BIT(13)
32 #define PWM_SIFIVE_PWMCFG_CENTER        BIT(16)
33 #define PWM_SIFIVE_PWMCFG_GANG          BIT(24)
34 #define PWM_SIFIVE_PWMCFG_IP            BIT(28)
35
36 /* PWM_SIFIVE_SIZE_PWMCMP is used to calculate offset for pwmcmpX registers */
37 #define PWM_SIFIVE_SIZE_PWMCMP          4
38 #define PWM_SIFIVE_CMPWIDTH             16
39
40 DECLARE_GLOBAL_DATA_PTR;
41
42 struct pwm_sifive_regs {
43         unsigned long cfg;
44         unsigned long cnt;
45         unsigned long pwms;
46         unsigned long cmp0;
47 };
48
49 struct pwm_sifive_data {
50         struct pwm_sifive_regs regs;
51 };
52
53 struct pwm_sifive_priv {
54         void __iomem *base;
55         ulong freq;
56         const struct pwm_sifive_data *data;
57 };
58
59 static int pwm_sifive_set_config(struct udevice *dev, uint channel,
60                                  uint period_ns, uint duty_ns)
61 {
62         struct pwm_sifive_priv *priv = dev_get_priv(dev);
63         const struct pwm_sifive_regs *regs = &priv->data->regs;
64         unsigned long scale_pow;
65         unsigned long long num;
66         u32 scale, val = 0, frac;
67
68         debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
69
70         /*
71          * The PWM unit is used with pwmzerocmp=0, so the only way to modify the
72          * period length is using pwmscale which provides the number of bits the
73          * counter is shifted before being feed to the comparators. A period
74          * lasts (1 << (PWM_SIFIVE_CMPWIDTH + pwmscale)) clock ticks.
75          * (1 << (PWM_SIFIVE_CMPWIDTH + scale)) * 10^9/rate = period
76          */
77         scale_pow = lldiv((uint64_t)priv->freq * period_ns, 1000000000);
78         scale = clamp(ilog2(scale_pow) - PWM_SIFIVE_CMPWIDTH, 0, 0xf);
79         val |= FIELD_PREP(PWM_SIFIVE_PWMCFG_SCALE, scale);
80
81         /*
82          * The problem of output producing mixed setting as mentioned at top,
83          * occurs here. To minimize the window for this problem, we are
84          * calculating the register values first and then writing them
85          * consecutively
86          */
87         num = (u64)duty_ns * (1U << PWM_SIFIVE_CMPWIDTH);
88         frac = DIV_ROUND_CLOSEST_ULL(num, period_ns);
89         frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
90
91         writel(val, priv->base + regs->cfg);
92         writel(frac, priv->base + regs->cmp0 + channel *
93                PWM_SIFIVE_SIZE_PWMCMP);
94
95         return 0;
96 }
97
98 static int pwm_sifive_set_enable(struct udevice *dev, uint channel, bool enable)
99 {
100         struct pwm_sifive_priv *priv = dev_get_priv(dev);
101         const struct pwm_sifive_regs *regs = &priv->data->regs;
102         u32 val;
103
104         debug("%s: Enable '%s'\n", __func__, dev->name);
105
106         if (enable) {
107                 val = readl(priv->base + regs->cfg);
108                 val |= PWM_SIFIVE_PWMCFG_EN_ALWAYS;
109                 writel(val, priv->base + regs->cfg);
110         } else {
111                 writel(0, priv->base + regs->cmp0 + channel *
112                        PWM_SIFIVE_SIZE_PWMCMP);
113         }
114
115         return 0;
116 }
117
118 static int pwm_sifive_ofdata_to_platdata(struct udevice *dev)
119 {
120         struct pwm_sifive_priv *priv = dev_get_priv(dev);
121
122         priv->base = dev_read_addr_ptr(dev);
123
124         return 0;
125 }
126
127 static int pwm_sifive_probe(struct udevice *dev)
128 {
129         struct pwm_sifive_priv *priv = dev_get_priv(dev);
130         struct clk clk;
131         int ret = 0;
132
133         ret = clk_get_by_index(dev, 0, &clk);
134         if (ret < 0) {
135                 debug("%s get clock fail!\n", __func__);
136                 return -EINVAL;
137         }
138
139         priv->freq = clk_get_rate(&clk);
140         priv->data = (struct pwm_sifive_data *)dev_get_driver_data(dev);
141
142         return 0;
143 }
144
145 static const struct pwm_ops pwm_sifive_ops = {
146         .set_config     = pwm_sifive_set_config,
147         .set_enable     = pwm_sifive_set_enable,
148 };
149
150 static const struct pwm_sifive_data pwm_data = {
151         .regs = {
152                 .cfg = 0x00,
153                 .cnt = 0x08,
154                 .pwms = 0x10,
155                 .cmp0 = 0x20,
156         },
157 };
158
159 static const struct udevice_id pwm_sifive_ids[] = {
160         { .compatible = "sifive,pwm0", .data = (ulong)&pwm_data},
161         { }
162 };
163
164 U_BOOT_DRIVER(pwm_sifive) = {
165         .name   = "pwm_sifive",
166         .id     = UCLASS_PWM,
167         .of_match = pwm_sifive_ids,
168         .ops    = &pwm_sifive_ops,
169         .ofdata_to_platdata     = pwm_sifive_ofdata_to_platdata,
170         .probe          = pwm_sifive_probe,
171         .priv_auto      = sizeof(struct pwm_sifive_priv),
172 };