diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 59a525a..a567346 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -97,6 +97,7 @@
#define MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT BIT(23)
#define MAX_CLKS 3
+#define MAX_SUBSYS_CLKS 10
#define MAX_STEPS 4
@@ -145,6 +146,8 @@ struct bus_prot {
* @sram_pdn_bits: The mask for sram power control bits.
* @sram_pdn_ack_bits: The mask for sram power control acked bits.
* @basic_clk_name: The basic clocks required by this power domain.
+ * @subsys_clk_prefix: The prefix name of the clocks need to be enabled
+ * before releasing bus protection.
* @caps: The flag for active wake-up action.
* @bp_table: The mask table for multiple step bus protection.
*/@@ -155,6 +158,7 @@ struct scp_domain_data {
u32 sram_pdn_bits;
u32 sram_pdn_ack_bits;
const char *basic_clk_name[MAX_CLKS];
+ const char *subsys_clk_prefix;
u8 caps;
struct bus_prot bp_table[MAX_STEPS];
};@@ -165,6 +169,7 @@ struct scp_domain {
struct generic_pm_domain genpd;
struct scp *scp;
struct clk *clk[MAX_CLKS];
+ struct clk *subsys_clk[MAX_SUBSYS_CLKS];
const struct scp_domain_data *data;
struct regulator *supply;
};@@ -425,16 +430,22 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
val |= PWR_RST_B_BIT;
writel(val, ctl_addr);
- ret = scpsys_sram_enable(scpd, ctl_addr);
+ ret = scpsys_clk_enable(scpd->subsys_clk, MAX_SUBSYS_CLKS);
if (ret < 0)
goto err_pwr_ack;
+ ret = scpsys_sram_enable(scpd, ctl_addr);
+ if (ret < 0)
+ goto err_sram;
+
ret = scpsys_bus_protect_disable(scpd);
if (ret < 0)
- goto err_pwr_ack;
+ goto err_sram;
return 0;
+err_sram:
+ scpsys_clk_disable(scpd->subsys_clk, MAX_SUBSYS_CLKS);
err_pwr_ack:
scpsys_clk_disable(scpd->clk, MAX_CLKS);
err_clk:
@@ -461,6 +472,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
if (ret < 0)
goto out;
+ scpsys_clk_disable(scpd->subsys_clk, MAX_SUBSYS_CLKS);
+
/* subsys power off */
val = readl(ctl_addr);
val |= PWR_ISO_BIT;
@@ -498,6 +511,39 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
return ret;
}
+static int init_subsys_clks(struct platform_device *pdev,
+ const char *prefix, struct clk **clk)
+{
+ struct device_node *node = pdev->dev.of_node;
+ u32 prefix_len, sub_clk_cnt = 0;
+ struct property *prop;
+ const char *clk_name;
+
+ prefix_len = strlen(prefix);
+
+ of_property_for_each_string(node, "clock-names", prop, clk_name) {
+ if (!strncmp(clk_name, prefix, prefix_len) &&
+ (clk_name[prefix_len] == '-')) {
+ if (sub_clk_cnt >= MAX_SUBSYS_CLKS) {
+ dev_err(&pdev->dev,
+ "subsys clk out of range %d\n",
+ sub_clk_cnt);
+ return -EINVAL;
+ }
+
+ clk[sub_clk_cnt] = devm_clk_get(&pdev->dev,
+ clk_name);
+
+ if (IS_ERR(clk[sub_clk_cnt]))
+ return PTR_ERR(clk[sub_clk_cnt]);
+
+ sub_clk_cnt++;
+ }
+ }
+
+ return sub_clk_cnt;
+}
+
static int init_basic_clks(struct platform_device *pdev, struct clk **clk,
const char * const *name)
{@@ -596,6 +642,14 @@ static struct scp *init_scp(struct platform_device *pdev,
if (ret)
return ERR_PTR(ret);
+ if (data->subsys_clk_prefix) {
+ ret = init_subsys_clks(pdev,
+ data->subsys_clk_prefix,
+ scpd->subsys_clk);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ }
+
genpd->name = data->name;
genpd->power_off = scpsys_power_off;
genpd->power_on = scpsys_power_on;--
1.8.1.1.dirty
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel