0001
0002
0003
0004
0005
0006
0007
0008 #include <dt-bindings/soc/bcm6318-pm.h>
0009 #include <dt-bindings/soc/bcm6328-pm.h>
0010 #include <dt-bindings/soc/bcm6362-pm.h>
0011 #include <dt-bindings/soc/bcm63268-pm.h>
0012 #include <linux/io.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/pm_domain.h>
0016 #include <linux/of.h>
0017 #include <linux/of_device.h>
0018
0019 struct bcm63xx_power_dev {
0020 struct generic_pm_domain genpd;
0021 struct bcm63xx_power *power;
0022 uint32_t mask;
0023 };
0024
0025 struct bcm63xx_power {
0026 void __iomem *base;
0027 spinlock_t lock;
0028 struct bcm63xx_power_dev *dev;
0029 struct genpd_onecell_data genpd_data;
0030 struct generic_pm_domain **genpd;
0031 };
0032
0033 struct bcm63xx_power_data {
0034 const char * const name;
0035 uint8_t bit;
0036 unsigned int flags;
0037 };
0038
0039 static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on)
0040 {
0041 struct bcm63xx_power *power = pmd->power;
0042
0043 if (!pmd->mask) {
0044 *is_on = false;
0045 return -EINVAL;
0046 }
0047
0048 *is_on = !(__raw_readl(power->base) & pmd->mask);
0049
0050 return 0;
0051 }
0052
0053 static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on)
0054 {
0055 struct bcm63xx_power *power = pmd->power;
0056 unsigned long flags;
0057 uint32_t val;
0058
0059 if (!pmd->mask)
0060 return -EINVAL;
0061
0062 spin_lock_irqsave(&power->lock, flags);
0063 val = __raw_readl(power->base);
0064 if (on)
0065 val &= ~pmd->mask;
0066 else
0067 val |= pmd->mask;
0068 __raw_writel(val, power->base);
0069 spin_unlock_irqrestore(&power->lock, flags);
0070
0071 return 0;
0072 }
0073
0074 static int bcm63xx_power_on(struct generic_pm_domain *genpd)
0075 {
0076 struct bcm63xx_power_dev *pmd = container_of(genpd,
0077 struct bcm63xx_power_dev, genpd);
0078
0079 return bcm63xx_power_set_state(pmd, true);
0080 }
0081
0082 static int bcm63xx_power_off(struct generic_pm_domain *genpd)
0083 {
0084 struct bcm63xx_power_dev *pmd = container_of(genpd,
0085 struct bcm63xx_power_dev, genpd);
0086
0087 return bcm63xx_power_set_state(pmd, false);
0088 }
0089
0090 static int bcm63xx_power_probe(struct platform_device *pdev)
0091 {
0092 struct device *dev = &pdev->dev;
0093 struct device_node *np = dev->of_node;
0094 const struct bcm63xx_power_data *entry, *table;
0095 struct bcm63xx_power *power;
0096 unsigned int ndom;
0097 uint8_t max_bit = 0;
0098 int ret;
0099
0100 power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
0101 if (!power)
0102 return -ENOMEM;
0103
0104 power->base = devm_platform_ioremap_resource(pdev, 0);
0105 if (IS_ERR(power->base))
0106 return PTR_ERR(power->base);
0107
0108 table = of_device_get_match_data(dev);
0109 if (!table)
0110 return -EINVAL;
0111
0112 power->genpd_data.num_domains = 0;
0113 ndom = 0;
0114 for (entry = table; entry->name; entry++) {
0115 max_bit = max(max_bit, entry->bit);
0116 ndom++;
0117 }
0118
0119 if (!ndom)
0120 return -ENODEV;
0121
0122 power->genpd_data.num_domains = max_bit + 1;
0123
0124 power->dev = devm_kcalloc(dev, power->genpd_data.num_domains,
0125 sizeof(struct bcm63xx_power_dev),
0126 GFP_KERNEL);
0127 if (!power->dev)
0128 return -ENOMEM;
0129
0130 power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains,
0131 sizeof(struct generic_pm_domain *),
0132 GFP_KERNEL);
0133 if (!power->genpd)
0134 return -ENOMEM;
0135
0136 power->genpd_data.domains = power->genpd;
0137
0138 ndom = 0;
0139 for (entry = table; entry->name; entry++) {
0140 struct bcm63xx_power_dev *pmd = &power->dev[ndom];
0141 bool is_on;
0142
0143 pmd->power = power;
0144 pmd->mask = BIT(entry->bit);
0145 pmd->genpd.name = entry->name;
0146 pmd->genpd.flags = entry->flags;
0147
0148 ret = bcm63xx_power_get_state(pmd, &is_on);
0149 if (ret)
0150 dev_warn(dev, "unable to get current state for %s\n",
0151 pmd->genpd.name);
0152
0153 pmd->genpd.power_on = bcm63xx_power_on;
0154 pmd->genpd.power_off = bcm63xx_power_off;
0155
0156 pm_genpd_init(&pmd->genpd, NULL, !is_on);
0157 power->genpd[entry->bit] = &pmd->genpd;
0158
0159 ndom++;
0160 }
0161
0162 spin_lock_init(&power->lock);
0163
0164 ret = of_genpd_add_provider_onecell(np, &power->genpd_data);
0165 if (ret) {
0166 dev_err(dev, "failed to register genpd driver: %d\n", ret);
0167 return ret;
0168 }
0169
0170 dev_info(dev, "registered %u power domains\n", ndom);
0171
0172 return 0;
0173 }
0174
0175 static const struct bcm63xx_power_data bcm6318_power_domains[] = {
0176 {
0177 .name = "pcie",
0178 .bit = BCM6318_POWER_DOMAIN_PCIE,
0179 }, {
0180 .name = "usb",
0181 .bit = BCM6318_POWER_DOMAIN_USB,
0182 }, {
0183 .name = "ephy0",
0184 .bit = BCM6318_POWER_DOMAIN_EPHY0,
0185 }, {
0186 .name = "ephy1",
0187 .bit = BCM6318_POWER_DOMAIN_EPHY1,
0188 }, {
0189 .name = "ephy2",
0190 .bit = BCM6318_POWER_DOMAIN_EPHY2,
0191 }, {
0192 .name = "ephy3",
0193 .bit = BCM6318_POWER_DOMAIN_EPHY3,
0194 }, {
0195 .name = "ldo2p5",
0196 .bit = BCM6318_POWER_DOMAIN_LDO2P5,
0197 .flags = GENPD_FLAG_ALWAYS_ON,
0198 }, {
0199 .name = "ldo2p9",
0200 .bit = BCM6318_POWER_DOMAIN_LDO2P9,
0201 .flags = GENPD_FLAG_ALWAYS_ON,
0202 }, {
0203 .name = "sw1p0",
0204 .bit = BCM6318_POWER_DOMAIN_SW1P0,
0205 .flags = GENPD_FLAG_ALWAYS_ON,
0206 }, {
0207 .name = "pad",
0208 .bit = BCM6318_POWER_DOMAIN_PAD,
0209 .flags = GENPD_FLAG_ALWAYS_ON,
0210 }, {
0211
0212 },
0213 };
0214
0215 static const struct bcm63xx_power_data bcm6328_power_domains[] = {
0216 {
0217 .name = "adsl2-mips",
0218 .bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS,
0219 }, {
0220 .name = "adsl2-phy",
0221 .bit = BCM6328_POWER_DOMAIN_ADSL2_PHY,
0222 }, {
0223 .name = "adsl2-afe",
0224 .bit = BCM6328_POWER_DOMAIN_ADSL2_AFE,
0225 }, {
0226 .name = "sar",
0227 .bit = BCM6328_POWER_DOMAIN_SAR,
0228 }, {
0229 .name = "pcm",
0230 .bit = BCM6328_POWER_DOMAIN_PCM,
0231 }, {
0232 .name = "usbd",
0233 .bit = BCM6328_POWER_DOMAIN_USBD,
0234 }, {
0235 .name = "usbh",
0236 .bit = BCM6328_POWER_DOMAIN_USBH,
0237 }, {
0238 .name = "pcie",
0239 .bit = BCM6328_POWER_DOMAIN_PCIE,
0240 }, {
0241 .name = "robosw",
0242 .bit = BCM6328_POWER_DOMAIN_ROBOSW,
0243 }, {
0244 .name = "ephy",
0245 .bit = BCM6328_POWER_DOMAIN_EPHY,
0246 }, {
0247
0248 },
0249 };
0250
0251 static const struct bcm63xx_power_data bcm6362_power_domains[] = {
0252 {
0253 .name = "sar",
0254 .bit = BCM6362_POWER_DOMAIN_SAR,
0255 }, {
0256 .name = "ipsec",
0257 .bit = BCM6362_POWER_DOMAIN_IPSEC,
0258 }, {
0259 .name = "mips",
0260 .bit = BCM6362_POWER_DOMAIN_MIPS,
0261 .flags = GENPD_FLAG_ALWAYS_ON,
0262 }, {
0263 .name = "dect",
0264 .bit = BCM6362_POWER_DOMAIN_DECT,
0265 }, {
0266 .name = "usbh",
0267 .bit = BCM6362_POWER_DOMAIN_USBH,
0268 }, {
0269 .name = "usbd",
0270 .bit = BCM6362_POWER_DOMAIN_USBD,
0271 }, {
0272 .name = "robosw",
0273 .bit = BCM6362_POWER_DOMAIN_ROBOSW,
0274 }, {
0275 .name = "pcm",
0276 .bit = BCM6362_POWER_DOMAIN_PCM,
0277 }, {
0278 .name = "periph",
0279 .bit = BCM6362_POWER_DOMAIN_PERIPH,
0280 .flags = GENPD_FLAG_ALWAYS_ON,
0281 }, {
0282 .name = "adsl-phy",
0283 .bit = BCM6362_POWER_DOMAIN_ADSL_PHY,
0284 }, {
0285 .name = "gmii-pads",
0286 .bit = BCM6362_POWER_DOMAIN_GMII_PADS,
0287 }, {
0288 .name = "fap",
0289 .bit = BCM6362_POWER_DOMAIN_FAP,
0290 }, {
0291 .name = "pcie",
0292 .bit = BCM6362_POWER_DOMAIN_PCIE,
0293 }, {
0294 .name = "wlan-pads",
0295 .bit = BCM6362_POWER_DOMAIN_WLAN_PADS,
0296 }, {
0297
0298 },
0299 };
0300
0301 static const struct bcm63xx_power_data bcm63268_power_domains[] = {
0302 {
0303 .name = "sar",
0304 .bit = BCM63268_POWER_DOMAIN_SAR,
0305 }, {
0306 .name = "ipsec",
0307 .bit = BCM63268_POWER_DOMAIN_IPSEC,
0308 }, {
0309 .name = "mips",
0310 .bit = BCM63268_POWER_DOMAIN_MIPS,
0311 .flags = GENPD_FLAG_ALWAYS_ON,
0312 }, {
0313 .name = "dect",
0314 .bit = BCM63268_POWER_DOMAIN_DECT,
0315 }, {
0316 .name = "usbh",
0317 .bit = BCM63268_POWER_DOMAIN_USBH,
0318 }, {
0319 .name = "usbd",
0320 .bit = BCM63268_POWER_DOMAIN_USBD,
0321 }, {
0322 .name = "robosw",
0323 .bit = BCM63268_POWER_DOMAIN_ROBOSW,
0324 }, {
0325 .name = "pcm",
0326 .bit = BCM63268_POWER_DOMAIN_PCM,
0327 }, {
0328 .name = "periph",
0329 .bit = BCM63268_POWER_DOMAIN_PERIPH,
0330 .flags = GENPD_FLAG_ALWAYS_ON,
0331 }, {
0332 .name = "vdsl-phy",
0333 .bit = BCM63268_POWER_DOMAIN_VDSL_PHY,
0334 }, {
0335 .name = "vdsl-mips",
0336 .bit = BCM63268_POWER_DOMAIN_VDSL_MIPS,
0337 }, {
0338 .name = "fap",
0339 .bit = BCM63268_POWER_DOMAIN_FAP,
0340 }, {
0341 .name = "pcie",
0342 .bit = BCM63268_POWER_DOMAIN_PCIE,
0343 }, {
0344 .name = "wlan-pads",
0345 .bit = BCM63268_POWER_DOMAIN_WLAN_PADS,
0346 }, {
0347
0348 },
0349 };
0350
0351 static const struct of_device_id bcm63xx_power_of_match[] = {
0352 {
0353 .compatible = "brcm,bcm6318-power-controller",
0354 .data = &bcm6318_power_domains,
0355 }, {
0356 .compatible = "brcm,bcm6328-power-controller",
0357 .data = &bcm6328_power_domains,
0358 }, {
0359 .compatible = "brcm,bcm6362-power-controller",
0360 .data = &bcm6362_power_domains,
0361 }, {
0362 .compatible = "brcm,bcm63268-power-controller",
0363 .data = &bcm63268_power_domains,
0364 }, {
0365
0366 }
0367 };
0368
0369 static struct platform_driver bcm63xx_power_driver = {
0370 .driver = {
0371 .name = "bcm63xx-power-controller",
0372 .of_match_table = bcm63xx_power_of_match,
0373 },
0374 .probe = bcm63xx_power_probe,
0375 };
0376 builtin_platform_driver(bcm63xx_power_driver);