linux/drivers/soc/zte/zx2967_pm_domains.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2017 ZTE Ltd.
   4 *
   5 * Author: Baoyou Xie <baoyou.xie@linaro.org>
   6 */
   7
   8#include <linux/delay.h>
   9#include <linux/err.h>
  10#include <linux/io.h>
  11#include <linux/of.h>
  12
  13#include "zx2967_pm_domains.h"
  14
  15#define PCU_DM_CLKEN(zpd)       ((zpd)->reg_offset[REG_CLKEN])
  16#define PCU_DM_ISOEN(zpd)       ((zpd)->reg_offset[REG_ISOEN])
  17#define PCU_DM_RSTEN(zpd)       ((zpd)->reg_offset[REG_RSTEN])
  18#define PCU_DM_PWREN(zpd)       ((zpd)->reg_offset[REG_PWREN])
  19#define PCU_DM_ACK_SYNC(zpd)    ((zpd)->reg_offset[REG_ACK_SYNC])
  20
  21static void __iomem *pcubase;
  22
  23static int zx2967_power_on(struct generic_pm_domain *domain)
  24{
  25        struct zx2967_pm_domain *zpd = (struct zx2967_pm_domain *)domain;
  26        unsigned long loop = 1000;
  27        u32 val;
  28
  29        val = readl_relaxed(pcubase + PCU_DM_PWREN(zpd));
  30        if (zpd->polarity == PWREN)
  31                val |= BIT(zpd->bit);
  32        else
  33                val &= ~BIT(zpd->bit);
  34        writel_relaxed(val, pcubase + PCU_DM_PWREN(zpd));
  35
  36        do {
  37                udelay(1);
  38                val = readl_relaxed(pcubase + PCU_DM_ACK_SYNC(zpd))
  39                                   & BIT(zpd->bit);
  40        } while (--loop && !val);
  41
  42        if (!loop) {
  43                pr_err("Error: %s %s fail\n", __func__, domain->name);
  44                return -EIO;
  45        }
  46
  47        val = readl_relaxed(pcubase + PCU_DM_RSTEN(zpd));
  48        val |= BIT(zpd->bit);
  49        writel_relaxed(val, pcubase + PCU_DM_RSTEN(zpd));
  50        udelay(5);
  51
  52        val = readl_relaxed(pcubase + PCU_DM_ISOEN(zpd));
  53        val &= ~BIT(zpd->bit);
  54        writel_relaxed(val, pcubase + PCU_DM_ISOEN(zpd));
  55        udelay(5);
  56
  57        val = readl_relaxed(pcubase + PCU_DM_CLKEN(zpd));
  58        val |= BIT(zpd->bit);
  59        writel_relaxed(val, pcubase + PCU_DM_CLKEN(zpd));
  60        udelay(5);
  61
  62        pr_debug("poweron %s\n", domain->name);
  63
  64        return 0;
  65}
  66
  67static int zx2967_power_off(struct generic_pm_domain *domain)
  68{
  69        struct zx2967_pm_domain *zpd = (struct zx2967_pm_domain *)domain;
  70        unsigned long loop = 1000;
  71        u32 val;
  72
  73        val = readl_relaxed(pcubase + PCU_DM_CLKEN(zpd));
  74        val &= ~BIT(zpd->bit);
  75        writel_relaxed(val, pcubase + PCU_DM_CLKEN(zpd));
  76        udelay(5);
  77
  78        val = readl_relaxed(pcubase + PCU_DM_ISOEN(zpd));
  79        val |= BIT(zpd->bit);
  80        writel_relaxed(val, pcubase + PCU_DM_ISOEN(zpd));
  81        udelay(5);
  82
  83        val = readl_relaxed(pcubase + PCU_DM_RSTEN(zpd));
  84        val &= ~BIT(zpd->bit);
  85        writel_relaxed(val, pcubase + PCU_DM_RSTEN(zpd));
  86        udelay(5);
  87
  88        val = readl_relaxed(pcubase + PCU_DM_PWREN(zpd));
  89        if (zpd->polarity == PWREN)
  90                val &= ~BIT(zpd->bit);
  91        else
  92                val |= BIT(zpd->bit);
  93        writel_relaxed(val, pcubase + PCU_DM_PWREN(zpd));
  94
  95        do {
  96                udelay(1);
  97                val = readl_relaxed(pcubase + PCU_DM_ACK_SYNC(zpd))
  98                                   & BIT(zpd->bit);
  99        } while (--loop && val);
 100
 101        if (!loop) {
 102                pr_err("Error: %s %s fail\n", __func__, domain->name);
 103                return -EIO;
 104        }
 105
 106        pr_debug("poweroff %s\n", domain->name);
 107
 108        return 0;
 109}
 110
 111int zx2967_pd_probe(struct platform_device *pdev,
 112                    struct generic_pm_domain **zx_pm_domains,
 113                    int domain_num)
 114{
 115        struct genpd_onecell_data *genpd_data;
 116        struct resource *res;
 117        int i;
 118
 119        genpd_data = devm_kzalloc(&pdev->dev, sizeof(*genpd_data), GFP_KERNEL);
 120        if (!genpd_data)
 121                return -ENOMEM;
 122
 123        genpd_data->domains = zx_pm_domains;
 124        genpd_data->num_domains = domain_num;
 125
 126        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 127        pcubase = devm_ioremap_resource(&pdev->dev, res);
 128        if (IS_ERR(pcubase))
 129                return PTR_ERR(pcubase);
 130
 131        for (i = 0; i < domain_num; ++i) {
 132                zx_pm_domains[i]->power_on = zx2967_power_on;
 133                zx_pm_domains[i]->power_off = zx2967_power_off;
 134
 135                pm_genpd_init(zx_pm_domains[i], NULL, false);
 136        }
 137
 138        of_genpd_add_provider_onecell(pdev->dev.of_node, genpd_data);
 139        dev_info(&pdev->dev, "powerdomain init ok\n");
 140        return 0;
 141}
 142