1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2015 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <dm.h>
8 #include <errno.h>
9 #include <pwm.h>
10 #include <asm/test.h>
11 
12 enum {
13 	NUM_CHANNELS	= 3,
14 };
15 
16 /**
17  * struct sandbox_pwm_chan - a sandbox PWM channel
18  *
19  * @period_ns: Period of the PWM in nanoseconds
20  * @duty_ns: Current duty cycle of the PWM in nanoseconds
21  * @enable: true if the PWM is enabled
22  * @polarity: true if the PWM polarity is active high
23  */
24 struct sandbox_pwm_chan {
25 	uint period_ns;
26 	uint duty_ns;
27 	bool enable;
28 	bool polarity;
29 };
30 
31 struct sandbox_pwm_priv {
32 	struct sandbox_pwm_chan chan[NUM_CHANNELS];
33 };
34 
sandbox_pwm_get_config(struct udevice * dev,uint channel,uint * period_nsp,uint * duty_nsp,bool * enablep,bool * polarityp)35 int sandbox_pwm_get_config(struct udevice *dev, uint channel, uint *period_nsp,
36 			   uint *duty_nsp, bool *enablep, bool *polarityp)
37 {
38 	struct sandbox_pwm_priv *priv = dev_get_priv(dev);
39 	struct sandbox_pwm_chan *chan;
40 
41 	if (channel >= NUM_CHANNELS)
42 		return -ENOSPC;
43 	chan = &priv->chan[channel];
44 	*period_nsp = chan->period_ns;
45 	*duty_nsp = chan->duty_ns;
46 	*enablep = chan->enable;
47 	*polarityp = chan->polarity;
48 
49 	return 0;
50 }
51 
sandbox_pwm_set_config(struct udevice * dev,uint channel,uint period_ns,uint duty_ns)52 static int sandbox_pwm_set_config(struct udevice *dev, uint channel,
53 				  uint period_ns, uint duty_ns)
54 {
55 	struct sandbox_pwm_priv *priv = dev_get_priv(dev);
56 	struct sandbox_pwm_chan *chan;
57 
58 	if (channel >= NUM_CHANNELS)
59 		return -ENOSPC;
60 	chan = &priv->chan[channel];
61 
62 	if (channel == 2) {
63 		/* Pretend to have some fixed period */
64 		chan->period_ns = 4096;
65 		chan->duty_ns =  duty_ns * 4096 / period_ns;
66 	} else {
67 		chan->period_ns = period_ns;
68 		chan->duty_ns = duty_ns;
69 	}
70 
71 	return 0;
72 }
73 
sandbox_pwm_set_enable(struct udevice * dev,uint channel,bool enable)74 static int sandbox_pwm_set_enable(struct udevice *dev, uint channel,
75 				  bool enable)
76 {
77 	struct sandbox_pwm_priv *priv = dev_get_priv(dev);
78 	struct sandbox_pwm_chan *chan;
79 
80 	if (channel >= NUM_CHANNELS)
81 		return -ENOSPC;
82 	chan = &priv->chan[channel];
83 	chan->enable = enable;
84 
85 	return 0;
86 }
87 
sandbox_pwm_set_invert(struct udevice * dev,uint channel,bool polarity)88 static int sandbox_pwm_set_invert(struct udevice *dev, uint channel,
89 				  bool polarity)
90 {
91 	struct sandbox_pwm_priv *priv = dev_get_priv(dev);
92 	struct sandbox_pwm_chan *chan;
93 
94 	if (channel >= NUM_CHANNELS)
95 		return -ENOSPC;
96 	chan = &priv->chan[channel];
97 	chan->polarity = polarity;
98 
99 	return 0;
100 }
101 
102 static const struct pwm_ops sandbox_pwm_ops = {
103 	.set_config	= sandbox_pwm_set_config,
104 	.set_enable	= sandbox_pwm_set_enable,
105 	.set_invert	= sandbox_pwm_set_invert,
106 };
107 
108 static const struct udevice_id sandbox_pwm_ids[] = {
109 	{ .compatible = "sandbox,pwm" },
110 	{ }
111 };
112 
113 U_BOOT_DRIVER(warm_pwm_sandbox) = {
114 	.name		= "pwm_sandbox",
115 	.id		= UCLASS_PWM,
116 	.of_match	= sandbox_pwm_ids,
117 	.ops		= &sandbox_pwm_ops,
118 	.priv_auto	= sizeof(struct sandbox_pwm_priv),
119 };
120