blob: becd902cc2a0743aeab3b3c7f3f02bfe60d37bad [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Heiko Schocher2b387762014-07-18 06:07:19 +02002/*
3 * (C) Copyright 2014
4 * Heiko Schocher, DENX Software Engineering, hs@denx.de.
5 *
Robert P. J. Day1f8378a2016-09-13 08:35:18 -04006 * Basic support for the pwm module on imx6.
Heiko Schocher2b387762014-07-18 06:07:19 +02007 */
8
9#include <common.h>
10#include <div64.h>
Heiko Schocher00aa0662019-05-28 06:51:52 +020011#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Heiko Schocher2b387762014-07-18 06:07:19 +020013#include <pwm.h>
14#include <asm/arch/imx-regs.h>
15#include <asm/io.h>
16#include "pwm-imx-util.h"
17
18int pwm_init(int pwm_id, int div, int invert)
19{
20 struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
21
Axel Linecae6442015-05-23 15:16:48 +080022 if (!pwm)
23 return -1;
24
Heiko Schocher2b387762014-07-18 06:07:19 +020025 writel(0, &pwm->ir);
26 return 0;
27}
Tommaso Merciai20b9c1d2022-03-26 12:19:06 +010028#include <clk.h>
Heiko Schocher2b387762014-07-18 06:07:19 +020029
Heiko Schocher00aa0662019-05-28 06:51:52 +020030int pwm_config_internal(struct pwm_regs *pwm, unsigned long period_cycles,
31 unsigned long duty_cycles, unsigned long prescale)
Heiko Schocher2b387762014-07-18 06:07:19 +020032{
Heiko Schocher2b387762014-07-18 06:07:19 +020033 u32 cr;
34
Heiko Schocher00aa0662019-05-28 06:51:52 +020035 writel(0, &pwm->ir);
Heiko Schocher2b387762014-07-18 06:07:19 +020036 cr = PWMCR_PRESCALER(prescale) |
37 PWMCR_DOZEEN | PWMCR_WAITEN |
38 PWMCR_DBGEN | PWMCR_CLKSRC_IPG_HIGH;
39
40 writel(cr, &pwm->cr);
41 /* set duty cycles */
42 writel(duty_cycles, &pwm->sar);
43 /* set period cycles */
44 writel(period_cycles, &pwm->pr);
45 return 0;
46}
47
Heiko Schocher00aa0662019-05-28 06:51:52 +020048int pwm_config(int pwm_id, int duty_ns, int period_ns)
49{
50 struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
51 unsigned long period_cycles, duty_cycles, prescale;
52
53 if (!pwm)
54 return -1;
55
56 pwm_imx_get_parms(period_ns, duty_ns, &period_cycles, &duty_cycles,
57 &prescale);
58
59 return pwm_config_internal(pwm, period_cycles, duty_cycles, prescale);
60}
61
Heiko Schocher2b387762014-07-18 06:07:19 +020062int pwm_enable(int pwm_id)
63{
64 struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
65
Axel Linecae6442015-05-23 15:16:48 +080066 if (!pwm)
67 return -1;
68
Heiko Schocher2b387762014-07-18 06:07:19 +020069 setbits_le32(&pwm->cr, PWMCR_EN);
70 return 0;
71}
72
73void pwm_disable(int pwm_id)
74{
75 struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
76
Axel Linecae6442015-05-23 15:16:48 +080077 if (!pwm)
78 return;
79
Heiko Schocher2b387762014-07-18 06:07:19 +020080 clrbits_le32(&pwm->cr, PWMCR_EN);
81}
Heiko Schocher00aa0662019-05-28 06:51:52 +020082
83#if defined(CONFIG_DM_PWM)
84struct imx_pwm_priv {
85 struct pwm_regs *regs;
86 bool invert;
Tommaso Merciai20b9c1d2022-03-26 12:19:06 +010087 struct clk per_clk;
88 struct clk ipg_clk;
Heiko Schocher00aa0662019-05-28 06:51:52 +020089};
90
91static int imx_pwm_set_invert(struct udevice *dev, uint channel,
92 bool polarity)
93{
94 struct imx_pwm_priv *priv = dev_get_priv(dev);
95
96 debug("%s: polarity=%u\n", __func__, polarity);
97 priv->invert = polarity;
98
99 return 0;
100}
101
102static int imx_pwm_set_config(struct udevice *dev, uint channel,
103 uint period_ns, uint duty_ns)
104{
105 struct imx_pwm_priv *priv = dev_get_priv(dev);
106 struct pwm_regs *regs = priv->regs;
107 unsigned long period_cycles, duty_cycles, prescale;
108
109 debug("%s: Config '%s' channel: %d\n", __func__, dev->name, channel);
110
111 pwm_imx_get_parms(period_ns, duty_ns, &period_cycles, &duty_cycles,
112 &prescale);
113
114 return pwm_config_internal(regs, period_cycles, duty_cycles, prescale);
115};
116
117static int imx_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
118{
119 struct imx_pwm_priv *priv = dev_get_priv(dev);
120 struct pwm_regs *regs = priv->regs;
121
122 debug("%s: Enable '%s' state: %d\n", __func__, dev->name, enable);
123
124 if (enable)
125 setbits_le32(&regs->cr, PWMCR_EN);
126 else
127 clrbits_le32(&regs->cr, PWMCR_EN);
128
129 return 0;
130};
131
Simon Glassaad29ae2020-12-03 16:55:21 -0700132static int imx_pwm_of_to_plat(struct udevice *dev)
Heiko Schocher00aa0662019-05-28 06:51:52 +0200133{
Tommaso Merciai20b9c1d2022-03-26 12:19:06 +0100134 int ret;
Heiko Schocher00aa0662019-05-28 06:51:52 +0200135 struct imx_pwm_priv *priv = dev_get_priv(dev);
136
Masahiro Yamada1096ae12020-07-17 14:36:46 +0900137 priv->regs = dev_read_addr_ptr(dev);
Heiko Schocher00aa0662019-05-28 06:51:52 +0200138
Tommaso Merciai20b9c1d2022-03-26 12:19:06 +0100139 ret = clk_get_by_name(dev, "per", &priv->per_clk);
140 if (ret) {
141 printf("Failed to get per_clk\n");
142 return ret;
143 }
144
145 ret = clk_get_by_name(dev, "ipg", &priv->ipg_clk);
146 if (ret) {
147 printf("Failed to get ipg_clk\n");
148 return ret;
149 }
150
Heiko Schocher00aa0662019-05-28 06:51:52 +0200151 return 0;
152}
153
154static int imx_pwm_probe(struct udevice *dev)
155{
Tommaso Merciai20b9c1d2022-03-26 12:19:06 +0100156 int ret;
157 struct imx_pwm_priv *priv = dev_get_priv(dev);
158
159 ret = clk_enable(&priv->per_clk);
160 if (ret) {
161 printf("Failed to enable per_clk\n");
162 return ret;
163 }
164
165 ret = clk_enable(&priv->ipg_clk);
166 if (ret) {
167 printf("Failed to enable ipg_clk\n");
168 return ret;
169 }
170
Heiko Schocher00aa0662019-05-28 06:51:52 +0200171 return 0;
172}
173
174static const struct pwm_ops imx_pwm_ops = {
175 .set_invert = imx_pwm_set_invert,
176 .set_config = imx_pwm_set_config,
177 .set_enable = imx_pwm_set_enable,
178};
179
180static const struct udevice_id imx_pwm_ids[] = {
181 { .compatible = "fsl,imx27-pwm" },
182 { }
183};
184
185U_BOOT_DRIVER(imx_pwm) = {
186 .name = "imx_pwm",
187 .id = UCLASS_PWM,
188 .of_match = imx_pwm_ids,
189 .ops = &imx_pwm_ops,
Simon Glassaad29ae2020-12-03 16:55:21 -0700190 .of_to_plat = imx_pwm_of_to_plat,
Heiko Schocher00aa0662019-05-28 06:51:52 +0200191 .probe = imx_pwm_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700192 .priv_auto = sizeof(struct imx_pwm_priv),
Heiko Schocher00aa0662019-05-28 06:51:52 +0200193};
194#endif