linux/drivers/soc/actions/owl-sps.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Actions Semi Owl Smart Power System (SPS)
   4 *
   5 * Copyright 2012 Actions Semi Inc.
   6 * Author: Actions Semi, Inc.
   7 *
   8 * Copyright (c) 2017 Andreas Färber
   9 */
  10
  11#include <linux/of_address.h>
  12#include <linux/of_platform.h>
  13#include <linux/pm_domain.h>
  14#include <linux/soc/actions/owl-sps.h>
  15#include <dt-bindings/power/owl-s500-powergate.h>
  16#include <dt-bindings/power/owl-s700-powergate.h>
  17#include <dt-bindings/power/owl-s900-powergate.h>
  18
  19struct owl_sps_domain_info {
  20        const char *name;
  21        int pwr_bit;
  22        int ack_bit;
  23        unsigned int genpd_flags;
  24};
  25
  26struct owl_sps_info {
  27        unsigned num_domains;
  28        const struct owl_sps_domain_info *domains;
  29};
  30
  31struct owl_sps {
  32        struct device *dev;
  33        const struct owl_sps_info *info;
  34        void __iomem *base;
  35        struct genpd_onecell_data genpd_data;
  36        struct generic_pm_domain *domains[];
  37};
  38
  39#define to_owl_pd(gpd) container_of(gpd, struct owl_sps_domain, genpd)
  40
  41struct owl_sps_domain {
  42        struct generic_pm_domain genpd;
  43        const struct owl_sps_domain_info *info;
  44        struct owl_sps *sps;
  45};
  46
  47static int owl_sps_set_power(struct owl_sps_domain *pd, bool enable)
  48{
  49        u32 pwr_mask, ack_mask;
  50
  51        ack_mask = BIT(pd->info->ack_bit);
  52        pwr_mask = BIT(pd->info->pwr_bit);
  53
  54        return owl_sps_set_pg(pd->sps->base, pwr_mask, ack_mask, enable);
  55}
  56
  57static int owl_sps_power_on(struct generic_pm_domain *domain)
  58{
  59        struct owl_sps_domain *pd = to_owl_pd(domain);
  60
  61        dev_dbg(pd->sps->dev, "%s power on", pd->info->name);
  62
  63        return owl_sps_set_power(pd, true);
  64}
  65
  66static int owl_sps_power_off(struct generic_pm_domain *domain)
  67{
  68        struct owl_sps_domain *pd = to_owl_pd(domain);
  69
  70        dev_dbg(pd->sps->dev, "%s power off", pd->info->name);
  71
  72        return owl_sps_set_power(pd, false);
  73}
  74
  75static int owl_sps_init_domain(struct owl_sps *sps, int index)
  76{
  77        struct owl_sps_domain *pd;
  78
  79        pd = devm_kzalloc(sps->dev, sizeof(*pd), GFP_KERNEL);
  80        if (!pd)
  81                return -ENOMEM;
  82
  83        pd->info = &sps->info->domains[index];
  84        pd->sps = sps;
  85
  86        pd->genpd.name = pd->info->name;
  87        pd->genpd.power_on = owl_sps_power_on;
  88        pd->genpd.power_off = owl_sps_power_off;
  89        pd->genpd.flags = pd->info->genpd_flags;
  90        pm_genpd_init(&pd->genpd, NULL, false);
  91
  92        sps->genpd_data.domains[index] = &pd->genpd;
  93
  94        return 0;
  95}
  96
  97static int owl_sps_probe(struct platform_device *pdev)
  98{
  99        const struct of_device_id *match;
 100        const struct owl_sps_info *sps_info;
 101        struct owl_sps *sps;
 102        int i, ret;
 103
 104        if (!pdev->dev.of_node) {
 105                dev_err(&pdev->dev, "no device node\n");
 106                return -ENODEV;
 107        }
 108
 109        match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
 110        if (!match || !match->data) {
 111                dev_err(&pdev->dev, "unknown compatible or missing data\n");
 112                return -EINVAL;
 113        }
 114
 115        sps_info = match->data;
 116
 117        sps = devm_kzalloc(&pdev->dev,
 118                           struct_size(sps, domains, sps_info->num_domains),
 119                           GFP_KERNEL);
 120        if (!sps)
 121                return -ENOMEM;
 122
 123        sps->base = of_io_request_and_map(pdev->dev.of_node, 0, "owl-sps");
 124        if (IS_ERR(sps->base)) {
 125                dev_err(&pdev->dev, "failed to map sps registers\n");
 126                return PTR_ERR(sps->base);
 127        }
 128
 129        sps->dev = &pdev->dev;
 130        sps->info = sps_info;
 131        sps->genpd_data.domains = sps->domains;
 132        sps->genpd_data.num_domains = sps_info->num_domains;
 133
 134        for (i = 0; i < sps_info->num_domains; i++) {
 135                ret = owl_sps_init_domain(sps, i);
 136                if (ret)
 137                        return ret;
 138        }
 139
 140        ret = of_genpd_add_provider_onecell(pdev->dev.of_node, &sps->genpd_data);
 141        if (ret) {
 142                dev_err(&pdev->dev, "failed to add provider (%d)", ret);
 143                return ret;
 144        }
 145
 146        return 0;
 147}
 148
 149static const struct owl_sps_domain_info s500_sps_domains[] = {
 150        [S500_PD_VDE] = {
 151                .name = "VDE",
 152                .pwr_bit = 0,
 153                .ack_bit = 16,
 154        },
 155        [S500_PD_VCE_SI] = {
 156                .name = "VCE_SI",
 157                .pwr_bit = 1,
 158                .ack_bit = 17,
 159        },
 160        [S500_PD_USB2_1] = {
 161                .name = "USB2_1",
 162                .pwr_bit = 2,
 163                .ack_bit = 18,
 164        },
 165        [S500_PD_CPU2] = {
 166                .name = "CPU2",
 167                .pwr_bit = 5,
 168                .ack_bit = 21,
 169                .genpd_flags = GENPD_FLAG_ALWAYS_ON,
 170        },
 171        [S500_PD_CPU3] = {
 172                .name = "CPU3",
 173                .pwr_bit = 6,
 174                .ack_bit = 22,
 175                .genpd_flags = GENPD_FLAG_ALWAYS_ON,
 176        },
 177        [S500_PD_DMA] = {
 178                .name = "DMA",
 179                .pwr_bit = 8,
 180                .ack_bit = 12,
 181        },
 182        [S500_PD_DS] = {
 183                .name = "DS",
 184                .pwr_bit = 9,
 185                .ack_bit = 13,
 186        },
 187        [S500_PD_USB3] = {
 188                .name = "USB3",
 189                .pwr_bit = 10,
 190                .ack_bit = 14,
 191        },
 192        [S500_PD_USB2_0] = {
 193                .name = "USB2_0",
 194                .pwr_bit = 11,
 195                .ack_bit = 15,
 196        },
 197};
 198
 199static const struct owl_sps_info s500_sps_info = {
 200        .num_domains = ARRAY_SIZE(s500_sps_domains),
 201        .domains = s500_sps_domains,
 202};
 203
 204static const struct owl_sps_domain_info s700_sps_domains[] = {
 205        [S700_PD_VDE] = {
 206                .name = "VDE",
 207                .pwr_bit = 0,
 208        },
 209        [S700_PD_VCE_SI] = {
 210                .name = "VCE_SI",
 211                .pwr_bit = 1,
 212        },
 213        [S700_PD_USB2_1] = {
 214                .name = "USB2_1",
 215                .pwr_bit = 2,
 216        },
 217        [S700_PD_HDE] = {
 218                .name = "HDE",
 219                .pwr_bit = 7,
 220        },
 221        [S700_PD_DMA] = {
 222                .name = "DMA",
 223                .pwr_bit = 8,
 224        },
 225        [S700_PD_DS] = {
 226                .name = "DS",
 227                .pwr_bit = 9,
 228        },
 229        [S700_PD_USB3] = {
 230                .name = "USB3",
 231                .pwr_bit = 10,
 232        },
 233        [S700_PD_USB2_0] = {
 234                .name = "USB2_0",
 235                .pwr_bit = 11,
 236        },
 237};
 238
 239static const struct owl_sps_info s700_sps_info = {
 240        .num_domains = ARRAY_SIZE(s700_sps_domains),
 241        .domains = s700_sps_domains,
 242};
 243
 244static const struct owl_sps_domain_info s900_sps_domains[] = {
 245        [S900_PD_GPU_B] = {
 246                .name = "GPU_B",
 247                .pwr_bit = 3,
 248        },
 249        [S900_PD_VCE] = {
 250                .name = "VCE",
 251                .pwr_bit = 4,
 252        },
 253        [S900_PD_SENSOR] = {
 254                .name = "SENSOR",
 255                .pwr_bit = 5,
 256        },
 257        [S900_PD_VDE] = {
 258                .name = "VDE",
 259                .pwr_bit = 6,
 260        },
 261        [S900_PD_HDE] = {
 262                .name = "HDE",
 263                .pwr_bit = 7,
 264        },
 265        [S900_PD_USB3] = {
 266                .name = "USB3",
 267                .pwr_bit = 8,
 268        },
 269        [S900_PD_DDR0] = {
 270                .name = "DDR0",
 271                .pwr_bit = 9,
 272        },
 273        [S900_PD_DDR1] = {
 274                .name = "DDR1",
 275                .pwr_bit = 10,
 276        },
 277        [S900_PD_DE] = {
 278                .name = "DE",
 279                .pwr_bit = 13,
 280        },
 281        [S900_PD_NAND] = {
 282                .name = "NAND",
 283                .pwr_bit = 14,
 284        },
 285        [S900_PD_USB2_H0] = {
 286                .name = "USB2_H0",
 287                .pwr_bit = 15,
 288        },
 289        [S900_PD_USB2_H1] = {
 290                .name = "USB2_H1",
 291                .pwr_bit = 16,
 292        },
 293};
 294
 295static const struct owl_sps_info s900_sps_info = {
 296        .num_domains = ARRAY_SIZE(s900_sps_domains),
 297        .domains = s900_sps_domains,
 298};
 299
 300static const struct of_device_id owl_sps_of_matches[] = {
 301        { .compatible = "actions,s500-sps", .data = &s500_sps_info },
 302        { .compatible = "actions,s700-sps", .data = &s700_sps_info },
 303        { .compatible = "actions,s900-sps", .data = &s900_sps_info },
 304        { }
 305};
 306
 307static struct platform_driver owl_sps_platform_driver = {
 308        .probe = owl_sps_probe,
 309        .driver = {
 310                .name = "owl-sps",
 311                .of_match_table = owl_sps_of_matches,
 312                .suppress_bind_attrs = true,
 313        },
 314};
 315
 316static int __init owl_sps_init(void)
 317{
 318        return platform_driver_register(&owl_sps_platform_driver);
 319}
 320postcore_initcall(owl_sps_init);
 321