Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.16-rc2 266 lines 5.8 kB view raw
1/* 2 * Actions Semi Owl Smart Power System (SPS) 3 * 4 * Copyright 2012 Actions Semi Inc. 5 * Author: Actions Semi, Inc. 6 * 7 * Copyright (c) 2017 Andreas Färber 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14 15#include <linux/of_address.h> 16#include <linux/of_platform.h> 17#include <linux/pm_domain.h> 18#include <linux/soc/actions/owl-sps.h> 19#include <dt-bindings/power/owl-s500-powergate.h> 20#include <dt-bindings/power/owl-s700-powergate.h> 21 22struct owl_sps_domain_info { 23 const char *name; 24 int pwr_bit; 25 int ack_bit; 26 unsigned int genpd_flags; 27}; 28 29struct owl_sps_info { 30 unsigned num_domains; 31 const struct owl_sps_domain_info *domains; 32}; 33 34struct owl_sps { 35 struct device *dev; 36 const struct owl_sps_info *info; 37 void __iomem *base; 38 struct genpd_onecell_data genpd_data; 39 struct generic_pm_domain *domains[]; 40}; 41 42#define to_owl_pd(gpd) container_of(gpd, struct owl_sps_domain, genpd) 43 44struct owl_sps_domain { 45 struct generic_pm_domain genpd; 46 const struct owl_sps_domain_info *info; 47 struct owl_sps *sps; 48}; 49 50static int owl_sps_set_power(struct owl_sps_domain *pd, bool enable) 51{ 52 u32 pwr_mask, ack_mask; 53 54 ack_mask = BIT(pd->info->ack_bit); 55 pwr_mask = BIT(pd->info->pwr_bit); 56 57 return owl_sps_set_pg(pd->sps->base, pwr_mask, ack_mask, enable); 58} 59 60static int owl_sps_power_on(struct generic_pm_domain *domain) 61{ 62 struct owl_sps_domain *pd = to_owl_pd(domain); 63 64 dev_dbg(pd->sps->dev, "%s power on", pd->info->name); 65 66 return owl_sps_set_power(pd, true); 67} 68 69static int owl_sps_power_off(struct generic_pm_domain *domain) 70{ 71 struct owl_sps_domain *pd = to_owl_pd(domain); 72 73 dev_dbg(pd->sps->dev, "%s power off", pd->info->name); 74 75 return owl_sps_set_power(pd, false); 76} 77 78static int owl_sps_init_domain(struct owl_sps *sps, int index) 79{ 80 struct owl_sps_domain *pd; 81 82 pd = devm_kzalloc(sps->dev, sizeof(*pd), GFP_KERNEL); 83 if (!pd) 84 return -ENOMEM; 85 86 pd->info = &sps->info->domains[index]; 87 pd->sps = sps; 88 89 pd->genpd.name = pd->info->name; 90 pd->genpd.power_on = owl_sps_power_on; 91 pd->genpd.power_off = owl_sps_power_off; 92 pd->genpd.flags = pd->info->genpd_flags; 93 pm_genpd_init(&pd->genpd, NULL, false); 94 95 sps->genpd_data.domains[index] = &pd->genpd; 96 97 return 0; 98} 99 100static int owl_sps_probe(struct platform_device *pdev) 101{ 102 const struct of_device_id *match; 103 const struct owl_sps_info *sps_info; 104 struct owl_sps *sps; 105 int i, ret; 106 107 if (!pdev->dev.of_node) { 108 dev_err(&pdev->dev, "no device node\n"); 109 return -ENODEV; 110 } 111 112 match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); 113 if (!match || !match->data) { 114 dev_err(&pdev->dev, "unknown compatible or missing data\n"); 115 return -EINVAL; 116 } 117 118 sps_info = match->data; 119 120 sps = devm_kzalloc(&pdev->dev, sizeof(*sps) + 121 sps_info->num_domains * sizeof(sps->domains[0]), 122 GFP_KERNEL); 123 if (!sps) 124 return -ENOMEM; 125 126 sps->base = of_io_request_and_map(pdev->dev.of_node, 0, "owl-sps"); 127 if (IS_ERR(sps->base)) { 128 dev_err(&pdev->dev, "failed to map sps registers\n"); 129 return PTR_ERR(sps->base); 130 } 131 132 sps->dev = &pdev->dev; 133 sps->info = sps_info; 134 sps->genpd_data.domains = sps->domains; 135 sps->genpd_data.num_domains = sps_info->num_domains; 136 137 for (i = 0; i < sps_info->num_domains; i++) { 138 ret = owl_sps_init_domain(sps, i); 139 if (ret) 140 return ret; 141 } 142 143 ret = of_genpd_add_provider_onecell(pdev->dev.of_node, &sps->genpd_data); 144 if (ret) { 145 dev_err(&pdev->dev, "failed to add provider (%d)", ret); 146 return ret; 147 } 148 149 return 0; 150} 151 152static const struct owl_sps_domain_info s500_sps_domains[] = { 153 [S500_PD_VDE] = { 154 .name = "VDE", 155 .pwr_bit = 0, 156 .ack_bit = 16, 157 }, 158 [S500_PD_VCE_SI] = { 159 .name = "VCE_SI", 160 .pwr_bit = 1, 161 .ack_bit = 17, 162 }, 163 [S500_PD_USB2_1] = { 164 .name = "USB2_1", 165 .pwr_bit = 2, 166 .ack_bit = 18, 167 }, 168 [S500_PD_CPU2] = { 169 .name = "CPU2", 170 .pwr_bit = 5, 171 .ack_bit = 21, 172 .genpd_flags = GENPD_FLAG_ALWAYS_ON, 173 }, 174 [S500_PD_CPU3] = { 175 .name = "CPU3", 176 .pwr_bit = 6, 177 .ack_bit = 22, 178 .genpd_flags = GENPD_FLAG_ALWAYS_ON, 179 }, 180 [S500_PD_DMA] = { 181 .name = "DMA", 182 .pwr_bit = 8, 183 .ack_bit = 12, 184 }, 185 [S500_PD_DS] = { 186 .name = "DS", 187 .pwr_bit = 9, 188 .ack_bit = 13, 189 }, 190 [S500_PD_USB3] = { 191 .name = "USB3", 192 .pwr_bit = 10, 193 .ack_bit = 14, 194 }, 195 [S500_PD_USB2_0] = { 196 .name = "USB2_0", 197 .pwr_bit = 11, 198 .ack_bit = 15, 199 }, 200}; 201 202static const struct owl_sps_info s500_sps_info = { 203 .num_domains = ARRAY_SIZE(s500_sps_domains), 204 .domains = s500_sps_domains, 205}; 206 207static const struct owl_sps_domain_info s700_sps_domains[] = { 208 [S700_PD_VDE] = { 209 .name = "VDE", 210 .pwr_bit = 0, 211 }, 212 [S700_PD_VCE_SI] = { 213 .name = "VCE_SI", 214 .pwr_bit = 1, 215 }, 216 [S700_PD_USB2_1] = { 217 .name = "USB2_1", 218 .pwr_bit = 2, 219 }, 220 [S700_PD_HDE] = { 221 .name = "HDE", 222 .pwr_bit = 7, 223 }, 224 [S700_PD_DMA] = { 225 .name = "DMA", 226 .pwr_bit = 8, 227 }, 228 [S700_PD_DS] = { 229 .name = "DS", 230 .pwr_bit = 9, 231 }, 232 [S700_PD_USB3] = { 233 .name = "USB3", 234 .pwr_bit = 10, 235 }, 236 [S700_PD_USB2_0] = { 237 .name = "USB2_0", 238 .pwr_bit = 11, 239 }, 240}; 241 242static const struct owl_sps_info s700_sps_info = { 243 .num_domains = ARRAY_SIZE(s700_sps_domains), 244 .domains = s700_sps_domains, 245}; 246 247static const struct of_device_id owl_sps_of_matches[] = { 248 { .compatible = "actions,s500-sps", .data = &s500_sps_info }, 249 { .compatible = "actions,s700-sps", .data = &s700_sps_info }, 250 { } 251}; 252 253static struct platform_driver owl_sps_platform_driver = { 254 .probe = owl_sps_probe, 255 .driver = { 256 .name = "owl-sps", 257 .of_match_table = owl_sps_of_matches, 258 .suppress_bind_attrs = true, 259 }, 260}; 261 262static int __init owl_sps_init(void) 263{ 264 return platform_driver_register(&owl_sps_platform_driver); 265} 266postcore_initcall(owl_sps_init);