script: build: enable building extcon-usb-fixed module
[platform/kernel/linux-rpi.git] / drivers / pwm / pwm-rp1.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * pwm-rp1.c
4  *
5  * Raspberry Pi RP1 PWM.
6  *
7  * Copyright © 2023 Raspberry Pi Ltd.
8  *
9  * Author: Naushir Patuck (naush@raspberrypi.com)
10  *
11  * Based on the pwm-bcm2835 driver by:
12  * Bart Tanghe <bart.tanghe@thomasmore.be>
13  */
14
15 #include <linux/bitops.h>
16 #include <linux/clk.h>
17 #include <linux/err.h>
18 #include <linux/io.h>
19 #include <linux/module.h>
20 #include <linux/of.h>
21 #include <linux/platform_device.h>
22 #include <linux/pwm.h>
23
24 #define PWM_GLOBAL_CTRL         0x000
25 #define PWM_CHANNEL_CTRL(x)     (0x014 + ((x) * 16))
26 #define PWM_RANGE(x)            (0x018 + ((x) * 16))
27 #define PWM_DUTY(x)             (0x020 + ((x) * 16))
28
29 /* 8:FIFO_POP_MASK + 0:Trailing edge M/S modulation */
30 #define PWM_CHANNEL_DEFAULT     (BIT(8) + BIT(0))
31 #define PWM_CHANNEL_ENABLE(x)   BIT(x)
32 #define PWM_POLARITY            BIT(3)
33 #define SET_UPDATE              BIT(31)
34 #define PWM_MODE_MASK           GENMASK(1, 0)
35
36 struct rp1_pwm {
37         struct pwm_chip chip;
38         struct device *dev;
39         void __iomem *base;
40         struct clk *clk;
41 };
42
43 static inline struct rp1_pwm *to_rp1_pwm(struct pwm_chip *chip)
44 {
45         return container_of(chip, struct rp1_pwm, chip);
46 }
47
48 static void rp1_pwm_apply_config(struct pwm_chip *chip, struct pwm_device *pwm)
49 {
50         struct rp1_pwm *pc = to_rp1_pwm(chip);
51         u32 value;
52
53         value = readl(pc->base + PWM_GLOBAL_CTRL);
54         value |= SET_UPDATE;
55         writel(value, pc->base + PWM_GLOBAL_CTRL);
56 }
57
58 static int rp1_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
59 {
60         struct rp1_pwm *pc = to_rp1_pwm(chip);
61
62         writel(PWM_CHANNEL_DEFAULT, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
63         return 0;
64 }
65
66 static void rp1_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
67 {
68         struct rp1_pwm *pc = to_rp1_pwm(chip);
69         u32 value;
70
71         value = readl(pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
72         value &= ~PWM_MODE_MASK;
73         writel(value, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
74         rp1_pwm_apply_config(chip, pwm);
75 }
76
77 static int rp1_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
78                          const struct pwm_state *state)
79 {
80         struct rp1_pwm *pc = to_rp1_pwm(chip);
81         unsigned long clk_rate = clk_get_rate(pc->clk);
82         unsigned long clk_period;
83         u32 value;
84
85         if (!clk_rate) {
86                 dev_err(pc->dev, "failed to get clock rate\n");
87                 return -EINVAL;
88         }
89
90         /* set period */
91         clk_period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, clk_rate);
92
93         writel(DIV_ROUND_CLOSEST(state->duty_cycle, clk_period),
94                pc->base + PWM_DUTY(pwm->hwpwm));
95
96         /* set duty cycle */
97         writel(DIV_ROUND_CLOSEST(state->period, clk_period),
98                pc->base + PWM_RANGE(pwm->hwpwm));
99
100         /* set polarity */
101         value = readl(pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
102         if (state->polarity == PWM_POLARITY_NORMAL)
103                 value &= ~PWM_POLARITY;
104         else
105                 value |= PWM_POLARITY;
106         writel(value, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
107
108         /* enable/disable */
109         value = readl(pc->base + PWM_GLOBAL_CTRL);
110         if (state->enabled)
111                 value |= PWM_CHANNEL_ENABLE(pwm->hwpwm);
112         else
113                 value &= ~PWM_CHANNEL_ENABLE(pwm->hwpwm);
114         writel(value, pc->base + PWM_GLOBAL_CTRL);
115
116         rp1_pwm_apply_config(chip, pwm);
117
118         return 0;
119 }
120
121 static const struct pwm_ops rp1_pwm_ops = {
122         .request = rp1_pwm_request,
123         .free = rp1_pwm_free,
124         .apply = rp1_pwm_apply,
125         .owner = THIS_MODULE,
126 };
127
128 static int rp1_pwm_probe(struct platform_device *pdev)
129 {
130         struct rp1_pwm *pc;
131         struct resource *res;
132         int ret;
133
134         pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
135         if (!pc)
136                 return -ENOMEM;
137
138         pc->dev = &pdev->dev;
139
140         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
141         pc->base = devm_ioremap_resource(&pdev->dev, res);
142         if (IS_ERR(pc->base))
143                 return PTR_ERR(pc->base);
144
145         pc->clk = devm_clk_get(&pdev->dev, NULL);
146         if (IS_ERR(pc->clk))
147                 return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
148                                      "clock not found\n");
149
150         ret = clk_prepare_enable(pc->clk);
151         if (ret)
152                 return ret;
153
154         pc->chip.dev = &pdev->dev;
155         pc->chip.ops = &rp1_pwm_ops;
156         pc->chip.base = -1;
157         pc->chip.npwm = 4;
158         pc->chip.of_xlate = of_pwm_xlate_with_flags;
159         pc->chip.of_pwm_n_cells = 3;
160
161         platform_set_drvdata(pdev, pc);
162
163         ret = pwmchip_add(&pc->chip);
164         if (ret < 0)
165                 goto add_fail;
166
167         return 0;
168
169 add_fail:
170         clk_disable_unprepare(pc->clk);
171         return ret;
172 }
173
174 static int rp1_pwm_remove(struct platform_device *pdev)
175 {
176         struct rp1_pwm *pc = platform_get_drvdata(pdev);
177
178         clk_disable_unprepare(pc->clk);
179
180         pwmchip_remove(&pc->chip);
181
182         return 0;
183 }
184
185 static const struct of_device_id rp1_pwm_of_match[] = {
186         { .compatible = "raspberrypi,rp1-pwm" },
187         { /* sentinel */ }
188 };
189 MODULE_DEVICE_TABLE(of, rp1_pwm_of_match);
190
191 static struct platform_driver rp1_pwm_driver = {
192         .driver = {
193                 .name = "rpi-pwm",
194                 .of_match_table = rp1_pwm_of_match,
195         },
196         .probe = rp1_pwm_probe,
197         .remove = rp1_pwm_remove,
198 };
199 module_platform_driver(rp1_pwm_driver);
200
201 MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com");
202 MODULE_DESCRIPTION("RP1 PWM driver");
203 MODULE_LICENSE("GPL");