2 * Copyright 2016 Google Inc.
4 * SPDX-License-Identifier: GPL-2.0+
11 #include <asm/arch/clk.h>
12 #include <asm/arch/clock.h>
13 #include <asm/arch/pwm.h>
15 DECLARE_GLOBAL_DATA_PTR
;
17 struct exynos_pwm_priv
{
18 struct s5p_timer
*regs
;
21 static int exynos_pwm_set_config(struct udevice
*dev
, uint channel
,
22 uint period_ns
, uint duty_ns
)
24 struct exynos_pwm_priv
*priv
= dev_get_priv(dev
);
25 struct s5p_timer
*regs
= priv
->regs
;
26 unsigned int offset
, prescaler
;
27 uint div
= 4, rate
, rate_ns
;
33 debug("%s: Configure '%s' channel %u, period_ns %u, duty_ns %u\n",
34 __func__
, dev
->name
, channel
, period_ns
, duty_ns
);
36 val
= readl(®s
->tcfg0
);
37 prescaler
= (channel
< 2 ? val
: (val
>> 8)) & 0xff;
38 div
= (readl(®s
->tcfg1
) >> MUX_DIV_SHIFT(channel
)) & 0xf;
40 rate
= get_pwm_clk() / ((prescaler
+ 1) * (1 << div
));
41 debug("%s: pwm_clk %lu, rate %u\n", __func__
, get_pwm_clk(), rate
);
44 rate_ns
= 1000000000 / rate
;
45 tcnt
= period_ns
/ rate_ns
;
46 tcmp
= duty_ns
/ rate_ns
;
47 debug("%s: tcnt %u, tcmp %u\n", __func__
, tcnt
, tcmp
);
49 writel(tcnt
, ®s
->tcntb0
+ offset
);
50 writel(tcmp
, ®s
->tcmpb0
+ offset
);
53 tcon
= readl(®s
->tcon
);
54 tcon
|= TCON_UPDATE(channel
);
56 tcon
|= TCON_AUTO_RELOAD(channel
);
58 tcon
|= TCON4_AUTO_RELOAD
;
59 writel(tcon
, ®s
->tcon
);
61 tcon
&= ~TCON_UPDATE(channel
);
62 writel(tcon
, ®s
->tcon
);
67 static int exynos_pwm_set_enable(struct udevice
*dev
, uint channel
,
70 struct exynos_pwm_priv
*priv
= dev_get_priv(dev
);
71 struct s5p_timer
*regs
= priv
->regs
;
76 debug("%s: Enable '%s' channel %u\n", __func__
, dev
->name
, channel
);
77 mask
= TCON_START(channel
);
78 clrsetbits_le32(®s
->tcon
, mask
, enable
? mask
: 0);
83 static int exynos_pwm_probe(struct udevice
*dev
)
85 struct exynos_pwm_priv
*priv
= dev_get_priv(dev
);
86 struct s5p_timer
*regs
= priv
->regs
;
88 writel(PRESCALER_0
| PRESCALER_1
<< 8, ®s
->tcfg0
);
93 static int exynos_pwm_ofdata_to_platdata(struct udevice
*dev
)
95 struct exynos_pwm_priv
*priv
= dev_get_priv(dev
);
97 priv
->regs
= (struct s5p_timer
*)devfdt_get_addr(dev
);
102 static const struct pwm_ops exynos_pwm_ops
= {
103 .set_config
= exynos_pwm_set_config
,
104 .set_enable
= exynos_pwm_set_enable
,
107 static const struct udevice_id exynos_channels
[] = {
108 { .compatible
= "samsung,exynos4210-pwm" },
112 U_BOOT_DRIVER(exynos_pwm
) = {
113 .name
= "exynos_pwm",
115 .of_match
= exynos_channels
,
116 .ops
= &exynos_pwm_ops
,
117 .probe
= exynos_pwm_probe
,
118 .ofdata_to_platdata
= exynos_pwm_ofdata_to_platdata
,
119 .priv_auto_alloc_size
= sizeof(struct exynos_pwm_priv
),