1 // SPDX-License-Identifier: GPL-2.0+
2 
3 #include <common.h>
4 #include <cros_ec.h>
5 #include <dm.h>
6 #include <errno.h>
7 #include <log.h>
8 #include <pwm.h>
9 
10 struct cros_ec_pwm_priv {
11 	bool enabled;
12 	uint duty;
13 };
14 
cros_ec_pwm_set_config(struct udevice * dev,uint channel,uint period_ns,uint duty_ns)15 static int cros_ec_pwm_set_config(struct udevice *dev, uint channel,
16 				  uint period_ns, uint duty_ns)
17 {
18 	struct cros_ec_pwm_priv *priv = dev_get_priv(dev);
19 	uint duty;
20 	int ret;
21 
22 	debug("%s: period_ns=%u, duty_ns=%u asked\n", __func__,
23 	      period_ns, duty_ns);
24 
25 	/* No way to set the period, only a relative duty cycle */
26 	duty = EC_PWM_MAX_DUTY * duty_ns / period_ns;
27 	if (duty > EC_PWM_MAX_DUTY)
28 		duty = EC_PWM_MAX_DUTY;
29 
30 	if (!priv->enabled) {
31 		priv->duty = duty;
32 		debug("%s: duty=%#x to-be-set\n", __func__, duty);
33 		return 0;
34 	}
35 
36 	ret = cros_ec_set_pwm_duty(dev->parent, channel, duty);
37 	if (ret) {
38 		debug("%s: duty=%#x failed\n", __func__, duty);
39 		return ret;
40 	}
41 
42 	priv->duty = duty;
43 	debug("%s: duty=%#x set\n", __func__, duty);
44 
45 	return 0;
46 }
47 
cros_ec_pwm_set_enable(struct udevice * dev,uint channel,bool enable)48 static int cros_ec_pwm_set_enable(struct udevice *dev, uint channel,
49 				  bool enable)
50 {
51 	struct cros_ec_pwm_priv *priv = dev_get_priv(dev);
52 	int ret;
53 
54 	ret = cros_ec_set_pwm_duty(dev->parent, channel,
55 				   enable ? priv->duty : 0);
56 	if (ret) {
57 		debug("%s: enable=%d failed\n", __func__, enable);
58 		return ret;
59 	}
60 
61 	priv->enabled = enable;
62 	debug("%s: enable=%d (duty=%#x) set\n", __func__,
63 	      enable, priv->duty);
64 
65 	return 0;
66 }
67 
68 static const struct pwm_ops cros_ec_pwm_ops = {
69 	.set_config	= cros_ec_pwm_set_config,
70 	.set_enable	= cros_ec_pwm_set_enable,
71 };
72 
73 static const struct udevice_id cros_ec_pwm_ids[] = {
74 	{ .compatible = "google,cros-ec-pwm" },
75 	{ }
76 };
77 
78 U_BOOT_DRIVER(cros_ec_pwm) = {
79 	.name	= "cros_ec_pwm",
80 	.id	= UCLASS_PWM,
81 	.of_match = cros_ec_pwm_ids,
82 	.ops	= &cros_ec_pwm_ops,
83 	.priv_auto = sizeof(struct cros_ec_pwm_priv),
84 };
85