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