diff options
author | Simon Glass <sjg@chromium.org> | 2016-01-30 16:37:46 -0700 |
---|---|---|
committer | Tom Warren <twarren@nvidia.com> | 2016-02-16 09:17:50 -0700 |
commit | 7429b9623b9d636d6fc686db3af29cc79d901bc6 (patch) | |
tree | c23044441fa103b396b04044dac40234e3ef5769 | |
parent | 651827c0fc3d91e0a6f2170890a11bc77557ee2e (diff) | |
download | u-boot-imx-7429b9623b9d636d6fc686db3af29cc79d901bc6.zip u-boot-imx-7429b9623b9d636d6fc686db3af29cc79d901bc6.tar.gz u-boot-imx-7429b9623b9d636d6fc686db3af29cc79d901bc6.tar.bz2 |
tegra: pwm: Add a driver for the tegra PWM
This PWM supports four channels. The driver always uses the 32KHz clock,
and adjusts the duty cycle accordingly.
Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Tom Warren <twarren@nvidia.com>
-rw-r--r-- | arch/arm/include/asm/arch-tegra/pwm.h | 2 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 3 | ||||
-rw-r--r-- | drivers/pwm/tegra_pwm.c | 85 |
3 files changed, 90 insertions, 0 deletions
diff --git a/arch/arm/include/asm/arch-tegra/pwm.h b/arch/arm/include/asm/arch-tegra/pwm.h index 92dced4..eb2e465 100644 --- a/arch/arm/include/asm/arch-tegra/pwm.h +++ b/arch/arm/include/asm/arch-tegra/pwm.h @@ -27,6 +27,7 @@ struct pwm_ctlr { #define PWM_DIVIDER_SHIFT 0 #define PWM_DIVIDER_MASK (0x1FFF << PWM_DIVIDER_SHIFT) +#ifndef CONFIG_PWM /** * Program the PWM with the given parameters. * @@ -56,5 +57,6 @@ int pwm_request(const void *blob, int node, const char *prop_name); * @return 0 if ok, -1 if the device tree node was not found or invalid. */ int pwm_init(const void *blob); +#endif #endif /* __ASM_ARCH_TEGRA_PWM_H */ diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index b6d8c16..fd414b1 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -13,3 +13,6 @@ obj-$(CONFIG_DM_PWM) += pwm-uclass.o obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o +ifdef CONFIG_DM_PWM +obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o +endif diff --git a/drivers/pwm/tegra_pwm.c b/drivers/pwm/tegra_pwm.c new file mode 100644 index 0000000..10e1fdc --- /dev/null +++ b/drivers/pwm/tegra_pwm.c @@ -0,0 +1,85 @@ +/* + * Copyright 2016 Google Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <pwm.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/pwm.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct tegra_pwm_priv { + struct pwm_ctlr *regs; +}; + +static int tegra_pwm_set_config(struct udevice *dev, uint channel, + uint period_ns, uint duty_ns) +{ + struct tegra_pwm_priv *priv = dev_get_priv(dev); + struct pwm_ctlr *regs = priv->regs; + uint pulse_width; + u32 reg; + + if (channel >= 4) + return -EINVAL; + debug("%s: Configure '%s' channel %u\n", __func__, dev->name, channel); + /* We ignore the period here and just use 32KHz */ + clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ, 32768); + + pulse_width = duty_ns * 255 / period_ns; + + reg = pulse_width << PWM_WIDTH_SHIFT; + reg |= 1 << PWM_DIVIDER_SHIFT; + writel(reg, ®s[channel].control); + debug("%s: pulse_width=%u\n", __func__, pulse_width); + + return 0; +} + +static int tegra_pwm_set_enable(struct udevice *dev, uint channel, bool enable) +{ + struct tegra_pwm_priv *priv = dev_get_priv(dev); + struct pwm_ctlr *regs = priv->regs; + + if (channel >= 4) + return -EINVAL; + debug("%s: Enable '%s' channel %u\n", __func__, dev->name, channel); + clrsetbits_le32(®s[channel].control, PWM_ENABLE_MASK, + enable ? PWM_ENABLE_MASK : 0); + + return 0; +} + +static int tegra_pwm_ofdata_to_platdata(struct udevice *dev) +{ + struct tegra_pwm_priv *priv = dev_get_priv(dev); + + priv->regs = (struct pwm_ctlr *)dev_get_addr(dev); + + return 0; +} + +static const struct pwm_ops tegra_pwm_ops = { + .set_config = tegra_pwm_set_config, + .set_enable = tegra_pwm_set_enable, +}; + +static const struct udevice_id tegra_pwm_ids[] = { + { .compatible = "nvidia,tegra124-pwm" }, + { .compatible = "nvidia,tegra20-pwm" }, + { } +}; + +U_BOOT_DRIVER(tegra_pwm) = { + .name = "tegra_pwm", + .id = UCLASS_PWM, + .of_match = tegra_pwm_ids, + .ops = &tegra_pwm_ops, + .ofdata_to_platdata = tegra_pwm_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct tegra_pwm_priv), +}; |