162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2013 Broadcom
462306a36Sopenharmony_ci * Copyright (C) 2020 Rafał Miłecki <rafal@milecki.pl>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <dt-bindings/soc/bcm-pmb.h>
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/of.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/pm_domain.h>
1362306a36Sopenharmony_ci#include <linux/reset/bcm63xx_pmb.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define BPCM_ID_REG					0x00
1662306a36Sopenharmony_ci#define BPCM_CAPABILITIES				0x04
1762306a36Sopenharmony_ci#define  BPCM_CAP_NUM_ZONES				0x000000ff
1862306a36Sopenharmony_ci#define  BPCM_CAP_SR_REG_BITS				0x0000ff00
1962306a36Sopenharmony_ci#define  BPCM_CAP_PLLTYPE				0x00030000
2062306a36Sopenharmony_ci#define  BPCM_CAP_UBUS					0x00080000
2162306a36Sopenharmony_ci#define BPCM_CONTROL					0x08
2262306a36Sopenharmony_ci#define BPCM_STATUS					0x0c
2362306a36Sopenharmony_ci#define BPCM_ROSC_CONTROL				0x10
2462306a36Sopenharmony_ci#define BPCM_ROSC_THRESH_H				0x14
2562306a36Sopenharmony_ci#define BPCM_ROSC_THRESHOLD_BCM6838			0x14
2662306a36Sopenharmony_ci#define BPCM_ROSC_THRESH_S				0x18
2762306a36Sopenharmony_ci#define BPCM_ROSC_COUNT_BCM6838				0x18
2862306a36Sopenharmony_ci#define BPCM_ROSC_COUNT					0x1c
2962306a36Sopenharmony_ci#define BPCM_PWD_CONTROL_BCM6838			0x1c
3062306a36Sopenharmony_ci#define BPCM_PWD_CONTROL				0x20
3162306a36Sopenharmony_ci#define BPCM_SR_CONTROL_BCM6838				0x20
3262306a36Sopenharmony_ci#define BPCM_PWD_ACCUM_CONTROL				0x24
3362306a36Sopenharmony_ci#define BPCM_SR_CONTROL					0x28
3462306a36Sopenharmony_ci#define BPCM_GLOBAL_CONTROL				0x2c
3562306a36Sopenharmony_ci#define BPCM_MISC_CONTROL				0x30
3662306a36Sopenharmony_ci#define BPCM_MISC_CONTROL2				0x34
3762306a36Sopenharmony_ci#define BPCM_SGPHY_CNTL					0x38
3862306a36Sopenharmony_ci#define BPCM_SGPHY_STATUS				0x3c
3962306a36Sopenharmony_ci#define BPCM_ZONE0					0x40
4062306a36Sopenharmony_ci#define  BPCM_ZONE_CONTROL				0x00
4162306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_MANUAL_CLK_EN		0x00000001
4262306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_MANUAL_RESET_CTL		0x00000002
4362306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_FREQ_SCALE_USED		0x00000004	/* R/O */
4462306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_DPG_CAPABLE			0x00000008	/* R/O */
4562306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_MANUAL_MEM_PWR		0x00000030
4662306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_MANUAL_ISO_CTL		0x00000040
4762306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_MANUAL_CTL			0x00000080
4862306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_DPG_CTL_EN			0x00000100
4962306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_PWR_DN_REQ			0x00000200
5062306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_PWR_UP_REQ			0x00000400
5162306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN		0x00000800
5262306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_BLK_RESET_ASSERT		0x00001000
5362306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_MEM_STBY			0x00002000
5462306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_RESERVED			0x0007c000
5562306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_PWR_CNTL_STATE		0x00f80000
5662306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_FREQ_SCALAR_DYN_SEL		0x01000000	/* R/O */
5762306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_PWR_OFF_STATE		0x02000000	/* R/O */
5862306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_PWR_ON_STATE		0x04000000	/* R/O */
5962306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_PWR_GOOD			0x08000000	/* R/O */
6062306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_DPG_PWR_STATE		0x10000000	/* R/O */
6162306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_MEM_PWR_STATE		0x20000000	/* R/O */
6262306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_ISO_STATE			0x40000000	/* R/O */
6362306a36Sopenharmony_ci#define   BPCM_ZONE_CONTROL_RESET_STATE			0x80000000	/* R/O */
6462306a36Sopenharmony_ci#define  BPCM_ZONE_CONFIG1				0x04
6562306a36Sopenharmony_ci#define  BPCM_ZONE_CONFIG2				0x08
6662306a36Sopenharmony_ci#define  BPCM_ZONE_FREQ_SCALAR_CONTROL			0x0c
6762306a36Sopenharmony_ci#define  BPCM_ZONE_SIZE					0x10
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistruct bcm_pmb {
7062306a36Sopenharmony_ci	struct device *dev;
7162306a36Sopenharmony_ci	void __iomem *base;
7262306a36Sopenharmony_ci	spinlock_t lock;
7362306a36Sopenharmony_ci	bool little_endian;
7462306a36Sopenharmony_ci	struct genpd_onecell_data genpd_onecell_data;
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct bcm_pmb_pd_data {
7862306a36Sopenharmony_ci	const char * const name;
7962306a36Sopenharmony_ci	int id;
8062306a36Sopenharmony_ci	u8 bus;
8162306a36Sopenharmony_ci	u8 device;
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistruct bcm_pmb_pm_domain {
8562306a36Sopenharmony_ci	struct bcm_pmb *pmb;
8662306a36Sopenharmony_ci	const struct bcm_pmb_pd_data *data;
8762306a36Sopenharmony_ci	struct generic_pm_domain genpd;
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int bcm_pmb_bpcm_read(struct bcm_pmb *pmb, int bus, u8 device,
9162306a36Sopenharmony_ci			     int offset, u32 *val)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	void __iomem *base = pmb->base + bus * 0x20;
9462306a36Sopenharmony_ci	unsigned long flags;
9562306a36Sopenharmony_ci	int err;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	spin_lock_irqsave(&pmb->lock, flags);
9862306a36Sopenharmony_ci	err = bpcm_rd(base, device, offset, val);
9962306a36Sopenharmony_ci	spin_unlock_irqrestore(&pmb->lock, flags);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (!err)
10262306a36Sopenharmony_ci		*val = pmb->little_endian ? le32_to_cpu(*val) : be32_to_cpu(*val);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return err;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int bcm_pmb_bpcm_write(struct bcm_pmb *pmb, int bus, u8 device,
10862306a36Sopenharmony_ci			      int offset, u32 val)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	void __iomem *base = pmb->base + bus * 0x20;
11162306a36Sopenharmony_ci	unsigned long flags;
11262306a36Sopenharmony_ci	int err;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	val = pmb->little_endian ? cpu_to_le32(val) : cpu_to_be32(val);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	spin_lock_irqsave(&pmb->lock, flags);
11762306a36Sopenharmony_ci	err = bpcm_wr(base, device, offset, val);
11862306a36Sopenharmony_ci	spin_unlock_irqrestore(&pmb->lock, flags);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return err;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int bcm_pmb_power_off_zone(struct bcm_pmb *pmb, int bus, u8 device,
12462306a36Sopenharmony_ci				  int zone)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	int offset;
12762306a36Sopenharmony_ci	u32 val;
12862306a36Sopenharmony_ci	int err;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
13362306a36Sopenharmony_ci	if (err)
13462306a36Sopenharmony_ci		return err;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	val |= BPCM_ZONE_CONTROL_PWR_DN_REQ;
13762306a36Sopenharmony_ci	val &= ~BPCM_ZONE_CONTROL_PWR_UP_REQ;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return err;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int bcm_pmb_power_on_zone(struct bcm_pmb *pmb, int bus, u8 device,
14562306a36Sopenharmony_ci				 int zone)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	int offset;
14862306a36Sopenharmony_ci	u32 val;
14962306a36Sopenharmony_ci	int err;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
15462306a36Sopenharmony_ci	if (err)
15562306a36Sopenharmony_ci		return err;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (!(val & BPCM_ZONE_CONTROL_PWR_ON_STATE)) {
15862306a36Sopenharmony_ci		val &= ~BPCM_ZONE_CONTROL_PWR_DN_REQ;
15962306a36Sopenharmony_ci		val |= BPCM_ZONE_CONTROL_DPG_CTL_EN;
16062306a36Sopenharmony_ci		val |= BPCM_ZONE_CONTROL_PWR_UP_REQ;
16162306a36Sopenharmony_ci		val |= BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN;
16262306a36Sopenharmony_ci		val |= BPCM_ZONE_CONTROL_BLK_RESET_ASSERT;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return err;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int bcm_pmb_power_off_device(struct bcm_pmb *pmb, int bus, u8 device)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	int offset;
17362306a36Sopenharmony_ci	u32 val;
17462306a36Sopenharmony_ci	int err;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/* Entire device can be powered off by powering off the 0th zone */
17762306a36Sopenharmony_ci	offset = BPCM_ZONE0 + BPCM_ZONE_CONTROL;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
18062306a36Sopenharmony_ci	if (err)
18162306a36Sopenharmony_ci		return err;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (!(val & BPCM_ZONE_CONTROL_PWR_OFF_STATE)) {
18462306a36Sopenharmony_ci		val = BPCM_ZONE_CONTROL_PWR_DN_REQ;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return err;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int bcm_pmb_power_on_device(struct bcm_pmb *pmb, int bus, u8 device)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	u32 val;
19562306a36Sopenharmony_ci	int err;
19662306a36Sopenharmony_ci	int i;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	err = bcm_pmb_bpcm_read(pmb, bus, device, BPCM_CAPABILITIES, &val);
19962306a36Sopenharmony_ci	if (err)
20062306a36Sopenharmony_ci		return err;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	for (i = 0; i < (val & BPCM_CAP_NUM_ZONES); i++) {
20362306a36Sopenharmony_ci		err = bcm_pmb_power_on_zone(pmb, bus, device, i);
20462306a36Sopenharmony_ci		if (err)
20562306a36Sopenharmony_ci			return err;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	return err;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic int bcm_pmb_power_on_sata(struct bcm_pmb *pmb, int bus, u8 device)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	int err;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	err = bcm_pmb_power_on_zone(pmb, bus, device, 0);
21662306a36Sopenharmony_ci	if (err)
21762306a36Sopenharmony_ci		return err;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* Does not apply to the BCM963158 */
22062306a36Sopenharmony_ci	err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_MISC_CONTROL, 0);
22162306a36Sopenharmony_ci	if (err)
22262306a36Sopenharmony_ci		return err;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0xffffffff);
22562306a36Sopenharmony_ci	if (err)
22662306a36Sopenharmony_ci		return err;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	return err;
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic int bcm_pmb_power_on(struct generic_pm_domain *genpd)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd);
23662306a36Sopenharmony_ci	const struct bcm_pmb_pd_data *data = pd->data;
23762306a36Sopenharmony_ci	struct bcm_pmb *pmb = pd->pmb;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	switch (data->id) {
24062306a36Sopenharmony_ci	case BCM_PMB_PCIE0:
24162306a36Sopenharmony_ci	case BCM_PMB_PCIE1:
24262306a36Sopenharmony_ci	case BCM_PMB_PCIE2:
24362306a36Sopenharmony_ci		return bcm_pmb_power_on_zone(pmb, data->bus, data->device, 0);
24462306a36Sopenharmony_ci	case BCM_PMB_HOST_USB:
24562306a36Sopenharmony_ci		return bcm_pmb_power_on_device(pmb, data->bus, data->device);
24662306a36Sopenharmony_ci	case BCM_PMB_SATA:
24762306a36Sopenharmony_ci		return bcm_pmb_power_on_sata(pmb, data->bus, data->device);
24862306a36Sopenharmony_ci	default:
24962306a36Sopenharmony_ci		dev_err(pmb->dev, "unsupported device id: %d\n", data->id);
25062306a36Sopenharmony_ci		return -EINVAL;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int bcm_pmb_power_off(struct generic_pm_domain *genpd)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd);
25762306a36Sopenharmony_ci	const struct bcm_pmb_pd_data *data = pd->data;
25862306a36Sopenharmony_ci	struct bcm_pmb *pmb = pd->pmb;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	switch (data->id) {
26162306a36Sopenharmony_ci	case BCM_PMB_PCIE0:
26262306a36Sopenharmony_ci	case BCM_PMB_PCIE1:
26362306a36Sopenharmony_ci	case BCM_PMB_PCIE2:
26462306a36Sopenharmony_ci		return bcm_pmb_power_off_zone(pmb, data->bus, data->device, 0);
26562306a36Sopenharmony_ci	case BCM_PMB_HOST_USB:
26662306a36Sopenharmony_ci		return bcm_pmb_power_off_device(pmb, data->bus, data->device);
26762306a36Sopenharmony_ci	default:
26862306a36Sopenharmony_ci		dev_err(pmb->dev, "unsupported device id: %d\n", data->id);
26962306a36Sopenharmony_ci		return -EINVAL;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic int bcm_pmb_probe(struct platform_device *pdev)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
27662306a36Sopenharmony_ci	const struct bcm_pmb_pd_data *table;
27762306a36Sopenharmony_ci	const struct bcm_pmb_pd_data *e;
27862306a36Sopenharmony_ci	struct bcm_pmb *pmb;
27962306a36Sopenharmony_ci	int max_id;
28062306a36Sopenharmony_ci	int err;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	pmb = devm_kzalloc(dev, sizeof(*pmb), GFP_KERNEL);
28362306a36Sopenharmony_ci	if (!pmb)
28462306a36Sopenharmony_ci		return -ENOMEM;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	pmb->dev = dev;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	pmb->base = devm_platform_ioremap_resource(pdev, 0);
28962306a36Sopenharmony_ci	if (IS_ERR(pmb->base))
29062306a36Sopenharmony_ci		return PTR_ERR(pmb->base);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	spin_lock_init(&pmb->lock);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	pmb->little_endian = !of_device_is_big_endian(dev->of_node);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	table = of_device_get_match_data(dev);
29762306a36Sopenharmony_ci	if (!table)
29862306a36Sopenharmony_ci		return -EINVAL;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	max_id = 0;
30162306a36Sopenharmony_ci	for (e = table; e->name; e++)
30262306a36Sopenharmony_ci		max_id = max(max_id, e->id);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	pmb->genpd_onecell_data.num_domains = max_id + 1;
30562306a36Sopenharmony_ci	pmb->genpd_onecell_data.domains =
30662306a36Sopenharmony_ci		devm_kcalloc(dev, pmb->genpd_onecell_data.num_domains,
30762306a36Sopenharmony_ci			     sizeof(struct generic_pm_domain *), GFP_KERNEL);
30862306a36Sopenharmony_ci	if (!pmb->genpd_onecell_data.domains)
30962306a36Sopenharmony_ci		return -ENOMEM;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	for (e = table; e->name; e++) {
31262306a36Sopenharmony_ci		struct bcm_pmb_pm_domain *pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		if (!pd)
31562306a36Sopenharmony_ci			return -ENOMEM;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		pd->pmb = pmb;
31862306a36Sopenharmony_ci		pd->data = e;
31962306a36Sopenharmony_ci		pd->genpd.name = e->name;
32062306a36Sopenharmony_ci		pd->genpd.power_on = bcm_pmb_power_on;
32162306a36Sopenharmony_ci		pd->genpd.power_off = bcm_pmb_power_off;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci		pm_genpd_init(&pd->genpd, NULL, true);
32462306a36Sopenharmony_ci		pmb->genpd_onecell_data.domains[e->id] = &pd->genpd;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	err = of_genpd_add_provider_onecell(dev->of_node, &pmb->genpd_onecell_data);
32862306a36Sopenharmony_ci	if (err) {
32962306a36Sopenharmony_ci		dev_err(dev, "failed to add genpd provider: %d\n", err);
33062306a36Sopenharmony_ci		return err;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return 0;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic const struct bcm_pmb_pd_data bcm_pmb_bcm4908_data[] = {
33762306a36Sopenharmony_ci	{ .name = "pcie2", .id = BCM_PMB_PCIE2, .bus = 0, .device = 2, },
33862306a36Sopenharmony_ci	{ .name = "pcie0", .id = BCM_PMB_PCIE0, .bus = 1, .device = 14, },
33962306a36Sopenharmony_ci	{ .name = "pcie1", .id = BCM_PMB_PCIE1, .bus = 1, .device = 15, },
34062306a36Sopenharmony_ci	{ .name = "usb", .id = BCM_PMB_HOST_USB, .bus = 1, .device = 17, },
34162306a36Sopenharmony_ci	{ },
34262306a36Sopenharmony_ci};
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic const struct bcm_pmb_pd_data bcm_pmb_bcm63138_data[] = {
34562306a36Sopenharmony_ci	{ .name = "sata", .id = BCM_PMB_SATA, .bus = 0, .device = 3, },
34662306a36Sopenharmony_ci	{ },
34762306a36Sopenharmony_ci};
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic const struct of_device_id bcm_pmb_of_match[] = {
35062306a36Sopenharmony_ci	{ .compatible = "brcm,bcm4908-pmb", .data = &bcm_pmb_bcm4908_data, },
35162306a36Sopenharmony_ci	{ .compatible = "brcm,bcm63138-pmb", .data = &bcm_pmb_bcm63138_data, },
35262306a36Sopenharmony_ci	{ },
35362306a36Sopenharmony_ci};
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic struct platform_driver bcm_pmb_driver = {
35662306a36Sopenharmony_ci	.driver = {
35762306a36Sopenharmony_ci		.name = "bcm-pmb",
35862306a36Sopenharmony_ci		.of_match_table = bcm_pmb_of_match,
35962306a36Sopenharmony_ci	},
36062306a36Sopenharmony_ci	.probe  = bcm_pmb_probe,
36162306a36Sopenharmony_ci};
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cibuiltin_platform_driver(bcm_pmb_driver);
364