162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2017 BayLibre, SAS
362306a36Sopenharmony_ci * Author: Neil Armstrong <narmstrong@baylibre.com>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * SPDX-License-Identifier: GPL-2.0+
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/platform_device.h>
962306a36Sopenharmony_ci#include <linux/pm_domain.h>
1062306a36Sopenharmony_ci#include <linux/bitfield.h>
1162306a36Sopenharmony_ci#include <linux/regmap.h>
1262306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci#include <linux/reset.h>
1562306a36Sopenharmony_ci#include <linux/clk.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* AO Offsets */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define AO_RTI_GEN_PWR_SLEEP0		(0x3a << 2)
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define GEN_PWR_VPU_HDMI		BIT(8)
2362306a36Sopenharmony_ci#define GEN_PWR_VPU_HDMI_ISO		BIT(9)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* HHI Offsets */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define HHI_MEM_PD_REG0			(0x40 << 2)
2862306a36Sopenharmony_ci#define HHI_VPU_MEM_PD_REG0		(0x41 << 2)
2962306a36Sopenharmony_ci#define HHI_VPU_MEM_PD_REG1		(0x42 << 2)
3062306a36Sopenharmony_ci#define HHI_VPU_MEM_PD_REG2		(0x4d << 2)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct meson_gx_pwrc_vpu {
3362306a36Sopenharmony_ci	struct generic_pm_domain genpd;
3462306a36Sopenharmony_ci	struct regmap *regmap_ao;
3562306a36Sopenharmony_ci	struct regmap *regmap_hhi;
3662306a36Sopenharmony_ci	struct reset_control *rstc;
3762306a36Sopenharmony_ci	struct clk *vpu_clk;
3862306a36Sopenharmony_ci	struct clk *vapb_clk;
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic inline
4262306a36Sopenharmony_cistruct meson_gx_pwrc_vpu *genpd_to_pd(struct generic_pm_domain *d)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	return container_of(d, struct meson_gx_pwrc_vpu, genpd);
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
5062306a36Sopenharmony_ci	int i;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
5362306a36Sopenharmony_ci			   GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
5462306a36Sopenharmony_ci	udelay(20);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/* Power Down Memories */
5762306a36Sopenharmony_ci	for (i = 0; i < 32; i += 2) {
5862306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
5962306a36Sopenharmony_ci				   0x3 << i, 0x3 << i);
6062306a36Sopenharmony_ci		udelay(5);
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci	for (i = 0; i < 32; i += 2) {
6362306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
6462306a36Sopenharmony_ci				   0x3 << i, 0x3 << i);
6562306a36Sopenharmony_ci		udelay(5);
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci	for (i = 8; i < 16; i++) {
6862306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
6962306a36Sopenharmony_ci				   BIT(i), BIT(i));
7062306a36Sopenharmony_ci		udelay(5);
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci	udelay(20);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
7562306a36Sopenharmony_ci			   GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	msleep(20);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	clk_disable_unprepare(pd->vpu_clk);
8062306a36Sopenharmony_ci	clk_disable_unprepare(pd->vapb_clk);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
8862306a36Sopenharmony_ci	int i;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
9162306a36Sopenharmony_ci			   GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
9262306a36Sopenharmony_ci	udelay(20);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/* Power Down Memories */
9562306a36Sopenharmony_ci	for (i = 0; i < 32; i += 2) {
9662306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
9762306a36Sopenharmony_ci				   0x3 << i, 0x3 << i);
9862306a36Sopenharmony_ci		udelay(5);
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci	for (i = 0; i < 32; i += 2) {
10162306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
10262306a36Sopenharmony_ci				   0x3 << i, 0x3 << i);
10362306a36Sopenharmony_ci		udelay(5);
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci	for (i = 0; i < 32; i += 2) {
10662306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
10762306a36Sopenharmony_ci				   0x3 << i, 0x3 << i);
10862306a36Sopenharmony_ci		udelay(5);
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci	for (i = 8; i < 16; i++) {
11162306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
11262306a36Sopenharmony_ci				   BIT(i), BIT(i));
11362306a36Sopenharmony_ci		udelay(5);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci	udelay(20);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
11862306a36Sopenharmony_ci			   GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	msleep(20);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	clk_disable_unprepare(pd->vpu_clk);
12362306a36Sopenharmony_ci	clk_disable_unprepare(pd->vapb_clk);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return 0;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	int ret;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	ret = clk_prepare_enable(pd->vpu_clk);
13362306a36Sopenharmony_ci	if (ret)
13462306a36Sopenharmony_ci		return ret;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	ret = clk_prepare_enable(pd->vapb_clk);
13762306a36Sopenharmony_ci	if (ret)
13862306a36Sopenharmony_ci		clk_disable_unprepare(pd->vpu_clk);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	return ret;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
14662306a36Sopenharmony_ci	int ret;
14762306a36Sopenharmony_ci	int i;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
15062306a36Sopenharmony_ci			   GEN_PWR_VPU_HDMI, 0);
15162306a36Sopenharmony_ci	udelay(20);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* Power Up Memories */
15462306a36Sopenharmony_ci	for (i = 0; i < 32; i += 2) {
15562306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
15662306a36Sopenharmony_ci				   0x3 << i, 0);
15762306a36Sopenharmony_ci		udelay(5);
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	for (i = 0; i < 32; i += 2) {
16162306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
16262306a36Sopenharmony_ci				   0x3 << i, 0);
16362306a36Sopenharmony_ci		udelay(5);
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	for (i = 8; i < 16; i++) {
16762306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
16862306a36Sopenharmony_ci				   BIT(i), 0);
16962306a36Sopenharmony_ci		udelay(5);
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci	udelay(20);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	ret = reset_control_assert(pd->rstc);
17462306a36Sopenharmony_ci	if (ret)
17562306a36Sopenharmony_ci		return ret;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
17862306a36Sopenharmony_ci			   GEN_PWR_VPU_HDMI_ISO, 0);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	ret = reset_control_deassert(pd->rstc);
18162306a36Sopenharmony_ci	if (ret)
18262306a36Sopenharmony_ci		return ret;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	ret = meson_gx_pwrc_vpu_setup_clk(pd);
18562306a36Sopenharmony_ci	if (ret)
18662306a36Sopenharmony_ci		return ret;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	return 0;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
19462306a36Sopenharmony_ci	int ret;
19562306a36Sopenharmony_ci	int i;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
19862306a36Sopenharmony_ci			   GEN_PWR_VPU_HDMI, 0);
19962306a36Sopenharmony_ci	udelay(20);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* Power Up Memories */
20262306a36Sopenharmony_ci	for (i = 0; i < 32; i += 2) {
20362306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
20462306a36Sopenharmony_ci				   0x3 << i, 0);
20562306a36Sopenharmony_ci		udelay(5);
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	for (i = 0; i < 32; i += 2) {
20962306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
21062306a36Sopenharmony_ci				   0x3 << i, 0);
21162306a36Sopenharmony_ci		udelay(5);
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	for (i = 0; i < 32; i += 2) {
21562306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
21662306a36Sopenharmony_ci				   0x3 << i, 0);
21762306a36Sopenharmony_ci		udelay(5);
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	for (i = 8; i < 16; i++) {
22162306a36Sopenharmony_ci		regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
22262306a36Sopenharmony_ci				   BIT(i), 0);
22362306a36Sopenharmony_ci		udelay(5);
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci	udelay(20);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	ret = reset_control_assert(pd->rstc);
22862306a36Sopenharmony_ci	if (ret)
22962306a36Sopenharmony_ci		return ret;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
23262306a36Sopenharmony_ci			   GEN_PWR_VPU_HDMI_ISO, 0);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	ret = reset_control_deassert(pd->rstc);
23562306a36Sopenharmony_ci	if (ret)
23662306a36Sopenharmony_ci		return ret;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	ret = meson_gx_pwrc_vpu_setup_clk(pd);
23962306a36Sopenharmony_ci	if (ret)
24062306a36Sopenharmony_ci		return ret;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	return 0;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic bool meson_gx_pwrc_vpu_get_power(struct meson_gx_pwrc_vpu *pd)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	u32 reg;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	regmap_read(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, &reg);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return (reg & GEN_PWR_VPU_HDMI);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic struct meson_gx_pwrc_vpu vpu_hdmi_pd = {
25562306a36Sopenharmony_ci	.genpd = {
25662306a36Sopenharmony_ci		.name = "vpu_hdmi",
25762306a36Sopenharmony_ci		.power_off = meson_gx_pwrc_vpu_power_off,
25862306a36Sopenharmony_ci		.power_on = meson_gx_pwrc_vpu_power_on,
25962306a36Sopenharmony_ci	},
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = {
26362306a36Sopenharmony_ci	.genpd = {
26462306a36Sopenharmony_ci		.name = "vpu_hdmi",
26562306a36Sopenharmony_ci		.power_off = meson_g12a_pwrc_vpu_power_off,
26662306a36Sopenharmony_ci		.power_on = meson_g12a_pwrc_vpu_power_on,
26762306a36Sopenharmony_ci	},
26862306a36Sopenharmony_ci};
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	const struct meson_gx_pwrc_vpu *vpu_pd_match;
27362306a36Sopenharmony_ci	struct regmap *regmap_ao, *regmap_hhi;
27462306a36Sopenharmony_ci	struct meson_gx_pwrc_vpu *vpu_pd;
27562306a36Sopenharmony_ci	struct device_node *parent_np;
27662306a36Sopenharmony_ci	struct reset_control *rstc;
27762306a36Sopenharmony_ci	struct clk *vpu_clk;
27862306a36Sopenharmony_ci	struct clk *vapb_clk;
27962306a36Sopenharmony_ci	bool powered_off;
28062306a36Sopenharmony_ci	int ret;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	vpu_pd_match = of_device_get_match_data(&pdev->dev);
28362306a36Sopenharmony_ci	if (!vpu_pd_match) {
28462306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to get match data\n");
28562306a36Sopenharmony_ci		return -ENODEV;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL);
28962306a36Sopenharmony_ci	if (!vpu_pd)
29062306a36Sopenharmony_ci		return -ENOMEM;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd));
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	parent_np = of_get_parent(pdev->dev.of_node);
29562306a36Sopenharmony_ci	regmap_ao = syscon_node_to_regmap(parent_np);
29662306a36Sopenharmony_ci	of_node_put(parent_np);
29762306a36Sopenharmony_ci	if (IS_ERR(regmap_ao)) {
29862306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to get regmap\n");
29962306a36Sopenharmony_ci		return PTR_ERR(regmap_ao);
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	regmap_hhi = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
30362306a36Sopenharmony_ci						     "amlogic,hhi-sysctrl");
30462306a36Sopenharmony_ci	if (IS_ERR(regmap_hhi)) {
30562306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to get HHI regmap\n");
30662306a36Sopenharmony_ci		return PTR_ERR(regmap_hhi);
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	rstc = devm_reset_control_array_get_exclusive(&pdev->dev);
31062306a36Sopenharmony_ci	if (IS_ERR(rstc))
31162306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
31262306a36Sopenharmony_ci				     "failed to get reset lines\n");
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	vpu_clk = devm_clk_get(&pdev->dev, "vpu");
31562306a36Sopenharmony_ci	if (IS_ERR(vpu_clk)) {
31662306a36Sopenharmony_ci		dev_err(&pdev->dev, "vpu clock request failed\n");
31762306a36Sopenharmony_ci		return PTR_ERR(vpu_clk);
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	vapb_clk = devm_clk_get(&pdev->dev, "vapb");
32162306a36Sopenharmony_ci	if (IS_ERR(vapb_clk)) {
32262306a36Sopenharmony_ci		dev_err(&pdev->dev, "vapb clock request failed\n");
32362306a36Sopenharmony_ci		return PTR_ERR(vapb_clk);
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	vpu_pd->regmap_ao = regmap_ao;
32762306a36Sopenharmony_ci	vpu_pd->regmap_hhi = regmap_hhi;
32862306a36Sopenharmony_ci	vpu_pd->rstc = rstc;
32962306a36Sopenharmony_ci	vpu_pd->vpu_clk = vpu_clk;
33062306a36Sopenharmony_ci	vpu_pd->vapb_clk = vapb_clk;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	platform_set_drvdata(pdev, vpu_pd);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	/* If already powered, sync the clock states */
33762306a36Sopenharmony_ci	if (!powered_off) {
33862306a36Sopenharmony_ci		ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd);
33962306a36Sopenharmony_ci		if (ret)
34062306a36Sopenharmony_ci			return ret;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	vpu_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON;
34462306a36Sopenharmony_ci	pm_genpd_init(&vpu_pd->genpd, NULL, powered_off);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return of_genpd_add_provider_simple(pdev->dev.of_node,
34762306a36Sopenharmony_ci					    &vpu_pd->genpd);
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev);
35362306a36Sopenharmony_ci	bool powered_off;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
35662306a36Sopenharmony_ci	if (!powered_off)
35762306a36Sopenharmony_ci		vpu_pd->genpd.power_off(&vpu_pd->genpd);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
36162306a36Sopenharmony_ci	{ .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd },
36262306a36Sopenharmony_ci	{
36362306a36Sopenharmony_ci	  .compatible = "amlogic,meson-g12a-pwrc-vpu",
36462306a36Sopenharmony_ci	  .data = &vpu_hdmi_pd_g12a
36562306a36Sopenharmony_ci	},
36662306a36Sopenharmony_ci	{ /* sentinel */ }
36762306a36Sopenharmony_ci};
36862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, meson_gx_pwrc_vpu_match_table);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic struct platform_driver meson_gx_pwrc_vpu_driver = {
37162306a36Sopenharmony_ci	.probe	= meson_gx_pwrc_vpu_probe,
37262306a36Sopenharmony_ci	.shutdown = meson_gx_pwrc_vpu_shutdown,
37362306a36Sopenharmony_ci	.driver = {
37462306a36Sopenharmony_ci		.name		= "meson_gx_pwrc_vpu",
37562306a36Sopenharmony_ci		.of_match_table	= meson_gx_pwrc_vpu_match_table,
37662306a36Sopenharmony_ci	},
37762306a36Sopenharmony_ci};
37862306a36Sopenharmony_cimodule_platform_driver(meson_gx_pwrc_vpu_driver);
37962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
380