WIP FPC-III support
[linux/fpc-iii.git] / drivers / pwm / pwm-litex.c
blobf2644f22ca672011a6b8f86b42d2182a68cc50c4
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2019 Antmicro <www.antmicro.com>
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
7 * as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <linux/clk.h>
20 #include <linux/err.h>
21 #include <linux/io.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/of.h>
25 #include <linux/of_address.h>
26 #include <linux/platform_device.h>
27 #include <linux/pwm.h>
28 #include <linux/slab.h>
29 #include <linux/stmp_device.h>
30 #include <linux/litex.h>
32 #define REG_EN_ENABLE 0x1
33 #define REG_EN_DISABLE 0x0
35 #define ENABLE_REG_OFFSET 0x0
36 #define WIDTH_REG_OFFSET 0x4
37 #define PERIOD_REG_OFFSET 0x14
39 struct litex_pwm_chip {
40 struct pwm_chip chip;
41 unsigned int clock;
42 void __iomem *base;
43 void __iomem *width;
44 void __iomem *period;
45 void __iomem *enable;
48 #define to_litex_pwm_chip(_chip) container_of(_chip, struct litex_pwm_chip, chip)
50 static int litex_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
51 int duty_ns, int period_ns)
53 struct litex_pwm_chip *litex = to_litex_pwm_chip(chip);
54 unsigned long period_cycles, duty_cycles;
55 unsigned long long c;
57 /* Calculate period cycles */
58 c = (unsigned long long)litex->clock * (unsigned long long)period_ns;
59 do_div(c, NSEC_PER_SEC);
60 period_cycles = c;
62 /* Calculate duty cycles */
63 c *= duty_ns;
64 do_div(c, period_ns);
65 duty_cycles = c;
67 /* Apply values to registers */
68 litex_write32(litex->width, duty_cycles);
69 litex_write32(litex->period, period_cycles);
71 return 0;
74 static int litex_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
76 struct litex_pwm_chip *litex = to_litex_pwm_chip(chip);
78 litex_write8(litex->enable, REG_EN_ENABLE);
79 return 0;
82 static void litex_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
84 struct litex_pwm_chip *litex = to_litex_pwm_chip(chip);
86 litex_write8(litex->enable, REG_EN_DISABLE);
89 static const struct pwm_ops litex_pwm_ops = {
90 .config = litex_pwm_config,
91 .enable = litex_pwm_enable,
92 .disable = litex_pwm_disable,
93 .owner = THIS_MODULE,
96 static int litex_pwm_probe(struct platform_device *pdev)
98 struct device_node *node = pdev->dev.of_node;
99 struct litex_pwm_chip *litex;
100 struct resource *res;
101 int ret;
103 if (!node) {
104 dev_err(&pdev->dev, "Fail on obtaining device node\n");
105 return -ENOMEM;
108 litex = devm_kzalloc(&pdev->dev, sizeof(*litex), GFP_KERNEL);
110 if (!litex) {
111 dev_err(&pdev->dev, "Fail on memory allocation\n");
112 return -ENOMEM;
115 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
116 if (!res) {
117 dev_err(&pdev->dev, "Device is busy\n");
118 return -EBUSY;
121 litex->base = devm_ioremap_resource(&pdev->dev, res);
122 if (IS_ERR(litex->base)) {
123 dev_err(&pdev->dev, "Fail to get base address\n");
124 return -EIO;
127 ret = of_property_read_u32(node, "clock", &(litex->clock));
128 if (ret < 0) {
129 dev_err(&pdev->dev, "No clock record in the dts file\n");
130 return -ENODEV;
133 litex->width = litex->base + WIDTH_REG_OFFSET;
134 litex->period = litex->base + PERIOD_REG_OFFSET;
135 litex->enable = litex->base + ENABLE_REG_OFFSET;
137 litex->chip.dev = &pdev->dev;
138 litex->chip.ops = &litex_pwm_ops;
139 litex->chip.base = -1;
140 litex->chip.npwm = 1;
142 ret = pwmchip_add(&litex->chip);
143 if (ret < 0) {
144 dev_err(&pdev->dev, "Failed to add pwm chip %d\n", ret);
145 return ret;
148 platform_set_drvdata(pdev, litex);
150 return 0;
153 static int litex_pwm_remove(struct platform_device *pdev)
155 struct litex_pwm_chip *litex = platform_get_drvdata(pdev);
157 return pwmchip_remove(&litex->chip);
160 static const struct of_device_id litex_of_match[] = {
161 { .compatible = "litex,pwm" },
164 MODULE_DEVICE_TABLE(of, litex_of_match);
166 static struct platform_driver litex_pwm_driver = {
167 .driver = {
168 .name = "litex-pwm",
169 .of_match_table = of_match_ptr(litex_of_match)
171 .probe = litex_pwm_probe,
172 .remove = litex_pwm_remove,
174 module_platform_driver(litex_pwm_driver);
176 MODULE_DESCRIPTION("LiteX PWM driver");
177 MODULE_AUTHOR("Antmicro <www.antmicro.com>");
178 MODULE_LICENSE("GPL v2");