brintos

brintos / linux-shallow public Read only

0
0
Text · 8.0 KiB · 98b0c24 Raw
376 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * BCM63xx Power Domain Controller Driver4 *5 * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>6 */7 8#include <dt-bindings/soc/bcm6318-pm.h>9#include <dt-bindings/soc/bcm6328-pm.h>10#include <dt-bindings/soc/bcm6362-pm.h>11#include <dt-bindings/soc/bcm63268-pm.h>12#include <linux/io.h>13#include <linux/module.h>14#include <linux/platform_device.h>15#include <linux/pm_domain.h>16#include <linux/of.h>17 18struct bcm63xx_power_dev {19	struct generic_pm_domain genpd;20	struct bcm63xx_power *power;21	uint32_t mask;22};23 24struct bcm63xx_power {25	void __iomem *base;26	spinlock_t lock;27	struct bcm63xx_power_dev *dev;28	struct genpd_onecell_data genpd_data;29	struct generic_pm_domain **genpd;30};31 32struct bcm63xx_power_data {33	const char * const name;34	uint8_t bit;35	unsigned int flags;36};37 38static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on)39{40	struct bcm63xx_power *power = pmd->power;41 42	if (!pmd->mask) {43		*is_on = false;44		return -EINVAL;45	}46 47	*is_on = !(__raw_readl(power->base) & pmd->mask);48 49	return 0;50}51 52static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on)53{54	struct bcm63xx_power *power = pmd->power;55	unsigned long flags;56	uint32_t val;57 58	if (!pmd->mask)59		return -EINVAL;60 61	spin_lock_irqsave(&power->lock, flags);62	val = __raw_readl(power->base);63	if (on)64		val &= ~pmd->mask;65	else66		val |= pmd->mask;67	__raw_writel(val, power->base);68	spin_unlock_irqrestore(&power->lock, flags);69 70	return 0;71}72 73static int bcm63xx_power_on(struct generic_pm_domain *genpd)74{75	struct bcm63xx_power_dev *pmd = container_of(genpd,76		struct bcm63xx_power_dev, genpd);77 78	return bcm63xx_power_set_state(pmd, true);79}80 81static int bcm63xx_power_off(struct generic_pm_domain *genpd)82{83	struct bcm63xx_power_dev *pmd = container_of(genpd,84		struct bcm63xx_power_dev, genpd);85 86	return bcm63xx_power_set_state(pmd, false);87}88 89static int bcm63xx_power_probe(struct platform_device *pdev)90{91	struct device *dev = &pdev->dev;92	struct device_node *np = dev->of_node;93	const struct bcm63xx_power_data *entry, *table;94	struct bcm63xx_power *power;95	unsigned int ndom;96	uint8_t max_bit = 0;97	int ret;98 99	power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);100	if (!power)101		return -ENOMEM;102 103	power->base = devm_platform_ioremap_resource(pdev, 0);104	if (IS_ERR(power->base))105		return PTR_ERR(power->base);106 107	table = of_device_get_match_data(dev);108	if (!table)109		return -EINVAL;110 111	power->genpd_data.num_domains = 0;112	ndom = 0;113	for (entry = table; entry->name; entry++) {114		max_bit = max(max_bit, entry->bit);115		ndom++;116	}117 118	if (!ndom)119		return -ENODEV;120 121	power->genpd_data.num_domains = max_bit + 1;122 123	power->dev = devm_kcalloc(dev, power->genpd_data.num_domains,124				  sizeof(struct bcm63xx_power_dev),125				  GFP_KERNEL);126	if (!power->dev)127		return -ENOMEM;128 129	power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains,130				    sizeof(struct generic_pm_domain *),131				    GFP_KERNEL);132	if (!power->genpd)133		return -ENOMEM;134 135	power->genpd_data.domains = power->genpd;136 137	ndom = 0;138	for (entry = table; entry->name; entry++) {139		struct bcm63xx_power_dev *pmd = &power->dev[ndom];140		bool is_on;141 142		pmd->power = power;143		pmd->mask = BIT(entry->bit);144		pmd->genpd.name = entry->name;145		pmd->genpd.flags = entry->flags;146 147		ret = bcm63xx_power_get_state(pmd, &is_on);148		if (ret)149			dev_warn(dev, "unable to get current state for %s\n",150				 pmd->genpd.name);151 152		pmd->genpd.power_on = bcm63xx_power_on;153		pmd->genpd.power_off = bcm63xx_power_off;154 155		pm_genpd_init(&pmd->genpd, NULL, !is_on);156		power->genpd[entry->bit] = &pmd->genpd;157 158		ndom++;159	}160 161	spin_lock_init(&power->lock);162 163	ret = of_genpd_add_provider_onecell(np, &power->genpd_data);164	if (ret) {165		dev_err(dev, "failed to register genpd driver: %d\n", ret);166		return ret;167	}168 169	dev_info(dev, "registered %u power domains\n", ndom);170 171	return 0;172}173 174static const struct bcm63xx_power_data bcm6318_power_domains[] = {175	{176		.name = "pcie",177		.bit = BCM6318_POWER_DOMAIN_PCIE,178	}, {179		.name = "usb",180		.bit = BCM6318_POWER_DOMAIN_USB,181	}, {182		.name = "ephy0",183		.bit = BCM6318_POWER_DOMAIN_EPHY0,184	}, {185		.name = "ephy1",186		.bit = BCM6318_POWER_DOMAIN_EPHY1,187	}, {188		.name = "ephy2",189		.bit = BCM6318_POWER_DOMAIN_EPHY2,190	}, {191		.name = "ephy3",192		.bit = BCM6318_POWER_DOMAIN_EPHY3,193	}, {194		.name = "ldo2p5",195		.bit = BCM6318_POWER_DOMAIN_LDO2P5,196		.flags = GENPD_FLAG_ALWAYS_ON,197	}, {198		.name = "ldo2p9",199		.bit = BCM6318_POWER_DOMAIN_LDO2P9,200		.flags = GENPD_FLAG_ALWAYS_ON,201	}, {202		.name = "sw1p0",203		.bit = BCM6318_POWER_DOMAIN_SW1P0,204		.flags = GENPD_FLAG_ALWAYS_ON,205	}, {206		.name = "pad",207		.bit = BCM6318_POWER_DOMAIN_PAD,208		.flags = GENPD_FLAG_ALWAYS_ON,209	}, {210		/* sentinel */211	},212};213 214static const struct bcm63xx_power_data bcm6328_power_domains[] = {215	{216		.name = "adsl2-mips",217		.bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS,218	}, {219		.name = "adsl2-phy",220		.bit = BCM6328_POWER_DOMAIN_ADSL2_PHY,221	}, {222		.name = "adsl2-afe",223		.bit = BCM6328_POWER_DOMAIN_ADSL2_AFE,224	}, {225		.name = "sar",226		.bit = BCM6328_POWER_DOMAIN_SAR,227	}, {228		.name = "pcm",229		.bit = BCM6328_POWER_DOMAIN_PCM,230	}, {231		.name = "usbd",232		.bit = BCM6328_POWER_DOMAIN_USBD,233	}, {234		.name = "usbh",235		.bit = BCM6328_POWER_DOMAIN_USBH,236	}, {237		.name = "pcie",238		.bit = BCM6328_POWER_DOMAIN_PCIE,239	}, {240		.name = "robosw",241		.bit = BCM6328_POWER_DOMAIN_ROBOSW,242	}, {243		.name = "ephy",244		.bit = BCM6328_POWER_DOMAIN_EPHY,245	}, {246		/* sentinel */247	},248};249 250static const struct bcm63xx_power_data bcm6362_power_domains[] = {251	{252		.name = "sar",253		.bit = BCM6362_POWER_DOMAIN_SAR,254	}, {255		.name = "ipsec",256		.bit = BCM6362_POWER_DOMAIN_IPSEC,257	}, {258		.name = "mips",259		.bit = BCM6362_POWER_DOMAIN_MIPS,260		.flags = GENPD_FLAG_ALWAYS_ON,261	}, {262		.name = "dect",263		.bit = BCM6362_POWER_DOMAIN_DECT,264	}, {265		.name = "usbh",266		.bit = BCM6362_POWER_DOMAIN_USBH,267	}, {268		.name = "usbd",269		.bit = BCM6362_POWER_DOMAIN_USBD,270	}, {271		.name = "robosw",272		.bit = BCM6362_POWER_DOMAIN_ROBOSW,273	}, {274		.name = "pcm",275		.bit = BCM6362_POWER_DOMAIN_PCM,276	}, {277		.name = "periph",278		.bit = BCM6362_POWER_DOMAIN_PERIPH,279		.flags = GENPD_FLAG_ALWAYS_ON,280	}, {281		.name = "adsl-phy",282		.bit = BCM6362_POWER_DOMAIN_ADSL_PHY,283	}, {284		.name = "gmii-pads",285		.bit = BCM6362_POWER_DOMAIN_GMII_PADS,286	}, {287		.name = "fap",288		.bit = BCM6362_POWER_DOMAIN_FAP,289	}, {290		.name = "pcie",291		.bit = BCM6362_POWER_DOMAIN_PCIE,292	}, {293		.name = "wlan-pads",294		.bit = BCM6362_POWER_DOMAIN_WLAN_PADS,295	}, {296		/* sentinel */297	},298};299 300static const struct bcm63xx_power_data bcm63268_power_domains[] = {301	{302		.name = "sar",303		.bit = BCM63268_POWER_DOMAIN_SAR,304	}, {305		.name = "ipsec",306		.bit = BCM63268_POWER_DOMAIN_IPSEC,307	}, {308		.name = "mips",309		.bit = BCM63268_POWER_DOMAIN_MIPS,310		.flags = GENPD_FLAG_ALWAYS_ON,311	}, {312		.name = "dect",313		.bit = BCM63268_POWER_DOMAIN_DECT,314	}, {315		.name = "usbh",316		.bit = BCM63268_POWER_DOMAIN_USBH,317	}, {318		.name = "usbd",319		.bit = BCM63268_POWER_DOMAIN_USBD,320	}, {321		.name = "robosw",322		.bit = BCM63268_POWER_DOMAIN_ROBOSW,323	}, {324		.name = "pcm",325		.bit = BCM63268_POWER_DOMAIN_PCM,326	}, {327		.name = "periph",328		.bit = BCM63268_POWER_DOMAIN_PERIPH,329		.flags = GENPD_FLAG_ALWAYS_ON,330	}, {331		.name = "vdsl-phy",332		.bit = BCM63268_POWER_DOMAIN_VDSL_PHY,333	}, {334		.name = "vdsl-mips",335		.bit = BCM63268_POWER_DOMAIN_VDSL_MIPS,336	}, {337		.name = "fap",338		.bit = BCM63268_POWER_DOMAIN_FAP,339	}, {340		.name = "pcie",341		.bit = BCM63268_POWER_DOMAIN_PCIE,342	}, {343		.name = "wlan-pads",344		.bit = BCM63268_POWER_DOMAIN_WLAN_PADS,345	}, {346		/* sentinel */347	},348};349 350static const struct of_device_id bcm63xx_power_of_match[] = {351	{352		.compatible = "brcm,bcm6318-power-controller",353		.data = &bcm6318_power_domains,354	}, {355		.compatible = "brcm,bcm6328-power-controller",356		.data = &bcm6328_power_domains,357	}, {358		.compatible = "brcm,bcm6362-power-controller",359		.data = &bcm6362_power_domains,360	}, {361		.compatible = "brcm,bcm63268-power-controller",362		.data = &bcm63268_power_domains,363	}, {364		/* sentinel */365	}366};367 368static struct platform_driver bcm63xx_power_driver = {369	.driver = {370		.name = "bcm63xx-power-controller",371		.of_match_table = bcm63xx_power_of_match,372	},373	.probe  = bcm63xx_power_probe,374};375builtin_platform_driver(bcm63xx_power_driver);376