1 // SPDX-License-Identifier: GPL-2.0
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>
22 #include <linux/kernel.h>
23 #include <linux/module.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
{
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
;
57 /* Calculate period cycles */
58 c
= (unsigned long long)litex
->clock
* (unsigned long long)period_ns
;
59 do_div(c
, NSEC_PER_SEC
);
62 /* Calculate duty cycles */
67 /* Apply values to registers */
68 litex_write32(litex
->width
, duty_cycles
);
69 litex_write32(litex
->period
, period_cycles
);
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
);
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
,
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
;
104 dev_err(&pdev
->dev
, "Fail on obtaining device node\n");
108 litex
= devm_kzalloc(&pdev
->dev
, sizeof(*litex
), GFP_KERNEL
);
111 dev_err(&pdev
->dev
, "Fail on memory allocation\n");
115 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
117 dev_err(&pdev
->dev
, "Device is busy\n");
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");
127 ret
= of_property_read_u32(node
, "clock", &(litex
->clock
));
129 dev_err(&pdev
->dev
, "No clock record in the dts file\n");
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
);
144 dev_err(&pdev
->dev
, "Failed to add pwm chip %d\n", ret
);
148 platform_set_drvdata(pdev
, litex
);
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
= {
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");