Add a simple driver which implements the standard PWM uclass interface. Signed-off-by: Simon Glass <sjg@chromium.org>master
parent
fc760cb8c4
commit
0e23fd81a5
@ -0,0 +1,41 @@ |
|||||||
|
/*
|
||||||
|
* (C) Copyright 2016 Google, Inc |
||||||
|
* (C) Copyright 2008-2014 Rockchip Electronics |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef _ASM_ARCH_PWM_H |
||||||
|
#define _ASM_ARCH_PWM_H |
||||||
|
|
||||||
|
struct rk3288_pwm { |
||||||
|
u32 cnt; |
||||||
|
u32 period_hpr; |
||||||
|
u32 duty_lpr; |
||||||
|
u32 ctrl; |
||||||
|
}; |
||||||
|
check_member(rk3288_pwm, ctrl, 0xc); |
||||||
|
|
||||||
|
#define RK_PWM_DISABLE (0 << 0) |
||||||
|
#define RK_PWM_ENABLE (1 << 0) |
||||||
|
|
||||||
|
#define PWM_ONE_SHOT (0 << 1) |
||||||
|
#define PWM_CONTINUOUS (1 << 1) |
||||||
|
#define RK_PWM_CAPTURE (1 << 2) |
||||||
|
|
||||||
|
#define PWM_DUTY_POSTIVE (1 << 3) |
||||||
|
#define PWM_DUTY_NEGATIVE (0 << 3) |
||||||
|
|
||||||
|
#define PWM_INACTIVE_POSTIVE (1 << 4) |
||||||
|
#define PWM_INACTIVE_NEGATIVE (0 << 4) |
||||||
|
|
||||||
|
#define PWM_OUTPUT_LEFT (0 << 5) |
||||||
|
#define PWM_OUTPUT_CENTER (1 << 5) |
||||||
|
|
||||||
|
#define PWM_LP_ENABLE (1 << 8) |
||||||
|
#define PWM_LP_DISABLE (0 << 8) |
||||||
|
|
||||||
|
#define PWM_SEL_SCALE_CLK (1 << 9) |
||||||
|
#define PWM_SEL_SRC_CLK (0 << 9) |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,103 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Google, Inc |
||||||
|
* Written by Simon Glass <sjg@chromium.org> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <div64.h> |
||||||
|
#include <dm.h> |
||||||
|
#include <pwm.h> |
||||||
|
#include <regmap.h> |
||||||
|
#include <syscon.h> |
||||||
|
#include <asm/io.h> |
||||||
|
#include <asm/arch/clock.h> |
||||||
|
#include <asm/arch/cru_rk3288.h> |
||||||
|
#include <asm/arch/grf_rk3288.h> |
||||||
|
#include <asm/arch/pwm.h> |
||||||
|
#include <power/regulator.h> |
||||||
|
|
||||||
|
DECLARE_GLOBAL_DATA_PTR; |
||||||
|
|
||||||
|
struct rk_pwm_priv { |
||||||
|
struct rk3288_pwm *regs; |
||||||
|
struct rk3288_grf *grf; |
||||||
|
}; |
||||||
|
|
||||||
|
static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns, |
||||||
|
uint duty_ns) |
||||||
|
{ |
||||||
|
struct rk_pwm_priv *priv = dev_get_priv(dev); |
||||||
|
struct rk3288_pwm *regs = priv->regs; |
||||||
|
unsigned long period, duty; |
||||||
|
|
||||||
|
debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns); |
||||||
|
writel(PWM_SEL_SRC_CLK | PWM_OUTPUT_LEFT | PWM_LP_DISABLE | |
||||||
|
PWM_CONTINUOUS | PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE | |
||||||
|
RK_PWM_DISABLE, |
||||||
|
®s->ctrl); |
||||||
|
|
||||||
|
period = lldiv((uint64_t)(PD_BUS_PCLK_HZ / 1000) * period_ns, 1000000); |
||||||
|
duty = lldiv((uint64_t)(PD_BUS_PCLK_HZ / 1000) * duty_ns, 1000000); |
||||||
|
|
||||||
|
writel(period, ®s->period_hpr); |
||||||
|
writel(duty, ®s->duty_lpr); |
||||||
|
debug("%s: period=%lu, duty=%lu\n", __func__, period, duty); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable) |
||||||
|
{ |
||||||
|
struct rk_pwm_priv *priv = dev_get_priv(dev); |
||||||
|
struct rk3288_pwm *regs = priv->regs; |
||||||
|
|
||||||
|
debug("%s: Enable '%s'\n", __func__, dev->name); |
||||||
|
clrsetbits_le32(®s->ctrl, RK_PWM_ENABLE, enable ? RK_PWM_ENABLE : 0); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int rk_pwm_ofdata_to_platdata(struct udevice *dev) |
||||||
|
{ |
||||||
|
struct rk_pwm_priv *priv = dev_get_priv(dev); |
||||||
|
struct regmap *map; |
||||||
|
|
||||||
|
priv->regs = (struct rk3288_pwm *)dev_get_addr(dev); |
||||||
|
map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_GRF); |
||||||
|
if (IS_ERR(map)) |
||||||
|
return PTR_ERR(map); |
||||||
|
priv->grf = regmap_get_range(map, 0); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int rk_pwm_probe(struct udevice *dev) |
||||||
|
{ |
||||||
|
struct rk_pwm_priv *priv = dev_get_priv(dev); |
||||||
|
|
||||||
|
rk_setreg(&priv->grf->soc_con2, 1 << 0); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static const struct pwm_ops rk_pwm_ops = { |
||||||
|
.set_config = rk_pwm_set_config, |
||||||
|
.set_enable = rk_pwm_set_enable, |
||||||
|
}; |
||||||
|
|
||||||
|
static const struct udevice_id rk_pwm_ids[] = { |
||||||
|
{ .compatible = "rockchip,rk3288-pwm" }, |
||||||
|
{ } |
||||||
|
}; |
||||||
|
|
||||||
|
U_BOOT_DRIVER(rk_pwm) = { |
||||||
|
.name = "rk_pwm", |
||||||
|
.id = UCLASS_PWM, |
||||||
|
.of_match = rk_pwm_ids, |
||||||
|
.ops = &rk_pwm_ops, |
||||||
|
.ofdata_to_platdata = rk_pwm_ofdata_to_platdata, |
||||||
|
.probe = rk_pwm_probe, |
||||||
|
.priv_auto_alloc_size = sizeof(struct rk_pwm_priv), |
||||||
|
}; |
Loading…
Reference in new issue