1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2016 Google Inc. 4 */ 5 6#include <common.h> 7#include <dm.h> 8#include <log.h> 9#include <pwm.h> 10#include <asm/io.h> 11#include <asm/arch/clock.h> 12#include <asm/arch/pwm.h> 13 14struct tegra_pwm_priv { 15 struct pwm_ctlr *regs; 16}; 17 18static int tegra_pwm_set_config(struct udevice *dev, uint channel, 19 uint period_ns, uint duty_ns) 20{ 21 struct tegra_pwm_priv *priv = dev_get_priv(dev); 22 struct pwm_ctlr *regs = priv->regs; 23 const u32 pwm_max_freq = dev_get_driver_data(dev); 24 uint pulse_width; 25 u32 reg; 26 27 if (channel >= 4) 28 return -EINVAL; 29 debug("%s: Configure '%s' channel %u\n", __func__, dev->name, channel); 30 31 clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_PERIPH, pwm_max_freq); 32 33 pulse_width = duty_ns * 255 / period_ns; 34 35 reg = pulse_width << PWM_WIDTH_SHIFT; 36 reg |= 1 << PWM_DIVIDER_SHIFT; 37 reg |= PWM_ENABLE_MASK; 38 writel(reg, ®s[channel].control); 39 debug("%s: pulse_width=%u\n", __func__, pulse_width); 40 41 return 0; 42} 43 44static 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 58static int tegra_pwm_of_to_plat(struct udevice *dev) 59{ 60 struct tegra_pwm_priv *priv = dev_get_priv(dev); 61 62 priv->regs = dev_read_addr_ptr(dev); 63 64 return 0; 65} 66 67static const struct pwm_ops tegra_pwm_ops = { 68 .set_config = tegra_pwm_set_config, 69 .set_enable = tegra_pwm_set_enable, 70}; 71 72static const struct udevice_id tegra_pwm_ids[] = { 73 { .compatible = "nvidia,tegra20-pwm", .data = 48 * 1000000 }, 74 { .compatible = "nvidia,tegra114-pwm", .data = 408 * 1000000 }, 75 { } 76}; 77 78U_BOOT_DRIVER(tegra_pwm) = { 79 .name = "tegra_pwm", 80 .id = UCLASS_PWM, 81 .of_match = tegra_pwm_ids, 82 .ops = &tegra_pwm_ops, 83 .of_to_plat = tegra_pwm_of_to_plat, 84 .priv_auto = sizeof(struct tegra_pwm_priv), 85}; 86