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