uboot/drivers/pwm/rk_pwm.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2016 Google, Inc
   3 * Written by Simon Glass <sjg@chromium.org>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <div64.h>
  10#include <dm.h>
  11#include <pwm.h>
  12#include <regmap.h>
  13#include <syscon.h>
  14#include <asm/io.h>
  15#include <asm/arch/clock.h>
  16#include <asm/arch/cru_rk3288.h>
  17#include <asm/arch/grf_rk3288.h>
  18#include <asm/arch/pwm.h>
  19#include <power/regulator.h>
  20
  21DECLARE_GLOBAL_DATA_PTR;
  22
  23struct rk_pwm_priv {
  24        struct rk3288_pwm *regs;
  25        struct rk3288_grf *grf;
  26};
  27
  28static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
  29                             uint duty_ns)
  30{
  31        struct rk_pwm_priv *priv = dev_get_priv(dev);
  32        struct rk3288_pwm *regs = priv->regs;
  33        unsigned long period, duty;
  34
  35        debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
  36        writel(PWM_SEL_SRC_CLK | PWM_OUTPUT_LEFT | PWM_LP_DISABLE |
  37                PWM_CONTINUOUS | PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE |
  38                RK_PWM_DISABLE,
  39                &regs->ctrl);
  40
  41        period = lldiv((uint64_t)(PD_BUS_PCLK_HZ / 1000) * period_ns, 1000000);
  42        duty = lldiv((uint64_t)(PD_BUS_PCLK_HZ / 1000) * duty_ns, 1000000);
  43
  44        writel(period, &regs->period_hpr);
  45        writel(duty, &regs->duty_lpr);
  46        debug("%s: period=%lu, duty=%lu\n", __func__, period, duty);
  47
  48        return 0;
  49}
  50
  51static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
  52{
  53        struct rk_pwm_priv *priv = dev_get_priv(dev);
  54        struct rk3288_pwm *regs = priv->regs;
  55
  56        debug("%s: Enable '%s'\n", __func__, dev->name);
  57        clrsetbits_le32(&regs->ctrl, RK_PWM_ENABLE, enable ? RK_PWM_ENABLE : 0);
  58
  59        return 0;
  60}
  61
  62static int rk_pwm_ofdata_to_platdata(struct udevice *dev)
  63{
  64        struct rk_pwm_priv *priv = dev_get_priv(dev);
  65        struct regmap *map;
  66
  67        priv->regs = (struct rk3288_pwm *)dev_get_addr(dev);
  68        map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_GRF);
  69        if (IS_ERR(map))
  70                return PTR_ERR(map);
  71        priv->grf = regmap_get_range(map, 0);
  72
  73        return 0;
  74}
  75
  76static int rk_pwm_probe(struct udevice *dev)
  77{
  78        struct rk_pwm_priv *priv = dev_get_priv(dev);
  79
  80        rk_setreg(&priv->grf->soc_con2, 1 << 0);
  81
  82        return 0;
  83}
  84
  85static const struct pwm_ops rk_pwm_ops = {
  86        .set_config     = rk_pwm_set_config,
  87        .set_enable     = rk_pwm_set_enable,
  88};
  89
  90static const struct udevice_id rk_pwm_ids[] = {
  91        { .compatible = "rockchip,rk3288-pwm" },
  92        { }
  93};
  94
  95U_BOOT_DRIVER(rk_pwm) = {
  96        .name   = "rk_pwm",
  97        .id     = UCLASS_PWM,
  98        .of_match = rk_pwm_ids,
  99        .ops    = &rk_pwm_ops,
 100        .ofdata_to_platdata     = rk_pwm_ofdata_to_platdata,
 101        .probe          = rk_pwm_probe,
 102        .priv_auto_alloc_size   = sizeof(struct rk_pwm_priv),
 103};
 104