1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <pwm.h> 10 #include <asm/io.h> 11 #include <asm/arch/clock.h> 12 #include <asm/arch/pwm.h> 13 14 DECLARE_GLOBAL_DATA_PTR; 15 16 struct tegra_pwm_priv { 17 struct pwm_ctlr *regs; 18 }; 19 20 static int tegra_pwm_set_config(struct udevice *dev, uint channel, 21 uint period_ns, uint duty_ns) 22 { 23 struct tegra_pwm_priv *priv = dev_get_priv(dev); 24 struct pwm_ctlr *regs = priv->regs; 25 uint pulse_width; 26 u32 reg; 27 28 if (channel >= 4) 29 return -EINVAL; 30 debug("%s: Configure '%s' channel %u\n", __func__, dev->name, channel); 31 /* We ignore the period here and just use 32KHz */ 32 clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ, 32768); 33 34 pulse_width = duty_ns * 255 / period_ns; 35 36 reg = pulse_width << PWM_WIDTH_SHIFT; 37 reg |= 1 << PWM_DIVIDER_SHIFT; 38 writel(reg, ®s[channel].control); 39 debug("%s: pulse_width=%u\n", __func__, pulse_width); 40 41 return 0; 42 } 43 44 static int tegra_pwm_set_enable(struct udevice *dev, uint channel, bool enable) 45 { 46 struct tegra_pwm_priv *priv = dev_get_priv(dev); 47 struct pwm_ctlr *regs = priv->regs; 48 49 if (channel >= 4) 50 return -EINVAL; 51 debug("%s: Enable '%s' channel %u\n", __func__, dev->name, channel); 52 clrsetbits_le32(®s[channel].control, PWM_ENABLE_MASK, 53 enable ? PWM_ENABLE_MASK : 0); 54 55 return 0; 56 } 57 58 static int tegra_pwm_ofdata_to_platdata(struct udevice *dev) 59 { 60 struct tegra_pwm_priv *priv = dev_get_priv(dev); 61 62 priv->regs = (struct pwm_ctlr *)dev_get_addr(dev); 63 64 return 0; 65 } 66 67 static const struct pwm_ops tegra_pwm_ops = { 68 .set_config = tegra_pwm_set_config, 69 .set_enable = tegra_pwm_set_enable, 70 }; 71 72 static const struct udevice_id tegra_pwm_ids[] = { 73 { .compatible = "nvidia,tegra124-pwm" }, 74 { .compatible = "nvidia,tegra20-pwm" }, 75 { } 76 }; 77 78 U_BOOT_DRIVER(tegra_pwm) = { 79 .name = "tegra_pwm", 80 .id = UCLASS_PWM, 81 .of_match = tegra_pwm_ids, 82 .ops = &tegra_pwm_ops, 83 .ofdata_to_platdata = tegra_pwm_ofdata_to_platdata, 84 .priv_auto_alloc_size = sizeof(struct tegra_pwm_priv), 85 }; 86