18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * R-Car MSTP clocks
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Ideas On Board SPRL
68c2ecf20Sopenharmony_ci * Copyright (C) 2015 Glider bvba
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/clk.h>
128c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
138c2ecf20Sopenharmony_ci#include <linux/clkdev.h>
148c2ecf20Sopenharmony_ci#include <linux/clk/renesas.h>
158c2ecf20Sopenharmony_ci#include <linux/device.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci#include <linux/of.h>
188c2ecf20Sopenharmony_ci#include <linux/of_address.h>
198c2ecf20Sopenharmony_ci#include <linux/pm_clock.h>
208c2ecf20Sopenharmony_ci#include <linux/pm_domain.h>
218c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * MSTP clocks. We can't use standard gate clocks as we need to poll on the
258c2ecf20Sopenharmony_ci * status register when enabling the clock.
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define MSTP_MAX_CLOCKS		32
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/**
318c2ecf20Sopenharmony_ci * struct mstp_clock_group - MSTP gating clocks group
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * @data: clock specifier translation for clocks in this group
348c2ecf20Sopenharmony_ci * @smstpcr: module stop control register
358c2ecf20Sopenharmony_ci * @mstpsr: module stop status register (optional)
368c2ecf20Sopenharmony_ci * @lock: protects writes to SMSTPCR
378c2ecf20Sopenharmony_ci * @width_8bit: registers are 8-bit, not 32-bit
388c2ecf20Sopenharmony_ci * @clks: clocks in this group
398c2ecf20Sopenharmony_ci */
408c2ecf20Sopenharmony_cistruct mstp_clock_group {
418c2ecf20Sopenharmony_ci	struct clk_onecell_data data;
428c2ecf20Sopenharmony_ci	void __iomem *smstpcr;
438c2ecf20Sopenharmony_ci	void __iomem *mstpsr;
448c2ecf20Sopenharmony_ci	spinlock_t lock;
458c2ecf20Sopenharmony_ci	bool width_8bit;
468c2ecf20Sopenharmony_ci	struct clk *clks[];
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/**
508c2ecf20Sopenharmony_ci * struct mstp_clock - MSTP gating clock
518c2ecf20Sopenharmony_ci * @hw: handle between common and hardware-specific interfaces
528c2ecf20Sopenharmony_ci * @bit_index: control bit index
538c2ecf20Sopenharmony_ci * @group: MSTP clocks group
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_cistruct mstp_clock {
568c2ecf20Sopenharmony_ci	struct clk_hw hw;
578c2ecf20Sopenharmony_ci	u32 bit_index;
588c2ecf20Sopenharmony_ci	struct mstp_clock_group *group;
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic inline u32 cpg_mstp_read(struct mstp_clock_group *group,
648c2ecf20Sopenharmony_ci				u32 __iomem *reg)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	return group->width_8bit ? readb(reg) : readl(reg);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic inline void cpg_mstp_write(struct mstp_clock_group *group, u32 val,
708c2ecf20Sopenharmony_ci				  u32 __iomem *reg)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	group->width_8bit ? writeb(val, reg) : writel(val, reg);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct mstp_clock *clock = to_mstp_clock(hw);
788c2ecf20Sopenharmony_ci	struct mstp_clock_group *group = clock->group;
798c2ecf20Sopenharmony_ci	u32 bitmask = BIT(clock->bit_index);
808c2ecf20Sopenharmony_ci	unsigned long flags;
818c2ecf20Sopenharmony_ci	unsigned int i;
828c2ecf20Sopenharmony_ci	u32 value;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	spin_lock_irqsave(&group->lock, flags);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	value = cpg_mstp_read(group, group->smstpcr);
878c2ecf20Sopenharmony_ci	if (enable)
888c2ecf20Sopenharmony_ci		value &= ~bitmask;
898c2ecf20Sopenharmony_ci	else
908c2ecf20Sopenharmony_ci		value |= bitmask;
918c2ecf20Sopenharmony_ci	cpg_mstp_write(group, value, group->smstpcr);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	if (!group->mstpsr) {
948c2ecf20Sopenharmony_ci		/* dummy read to ensure write has completed */
958c2ecf20Sopenharmony_ci		cpg_mstp_read(group, group->smstpcr);
968c2ecf20Sopenharmony_ci		barrier_data(group->smstpcr);
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&group->lock, flags);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (!enable || !group->mstpsr)
1028c2ecf20Sopenharmony_ci		return 0;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	for (i = 1000; i > 0; --i) {
1058c2ecf20Sopenharmony_ci		if (!(cpg_mstp_read(group, group->mstpsr) & bitmask))
1068c2ecf20Sopenharmony_ci			break;
1078c2ecf20Sopenharmony_ci		cpu_relax();
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (!i) {
1118c2ecf20Sopenharmony_ci		pr_err("%s: failed to enable %p[%d]\n", __func__,
1128c2ecf20Sopenharmony_ci		       group->smstpcr, clock->bit_index);
1138c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return 0;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int cpg_mstp_clock_enable(struct clk_hw *hw)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	return cpg_mstp_clock_endisable(hw, true);
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic void cpg_mstp_clock_disable(struct clk_hw *hw)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	cpg_mstp_clock_endisable(hw, false);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	struct mstp_clock *clock = to_mstp_clock(hw);
1328c2ecf20Sopenharmony_ci	struct mstp_clock_group *group = clock->group;
1338c2ecf20Sopenharmony_ci	u32 value;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (group->mstpsr)
1368c2ecf20Sopenharmony_ci		value = cpg_mstp_read(group, group->mstpsr);
1378c2ecf20Sopenharmony_ci	else
1388c2ecf20Sopenharmony_ci		value = cpg_mstp_read(group, group->smstpcr);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return !(value & BIT(clock->bit_index));
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic const struct clk_ops cpg_mstp_clock_ops = {
1448c2ecf20Sopenharmony_ci	.enable = cpg_mstp_clock_enable,
1458c2ecf20Sopenharmony_ci	.disable = cpg_mstp_clock_disable,
1468c2ecf20Sopenharmony_ci	.is_enabled = cpg_mstp_clock_is_enabled,
1478c2ecf20Sopenharmony_ci};
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic struct clk * __init cpg_mstp_clock_register(const char *name,
1508c2ecf20Sopenharmony_ci	const char *parent_name, unsigned int index,
1518c2ecf20Sopenharmony_ci	struct mstp_clock_group *group)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct clk_init_data init;
1548c2ecf20Sopenharmony_ci	struct mstp_clock *clock;
1558c2ecf20Sopenharmony_ci	struct clk *clk;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	clock = kzalloc(sizeof(*clock), GFP_KERNEL);
1588c2ecf20Sopenharmony_ci	if (!clock)
1598c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	init.name = name;
1628c2ecf20Sopenharmony_ci	init.ops = &cpg_mstp_clock_ops;
1638c2ecf20Sopenharmony_ci	init.flags = CLK_SET_RATE_PARENT;
1648c2ecf20Sopenharmony_ci	/* INTC-SYS is the module clock of the GIC, and must not be disabled */
1658c2ecf20Sopenharmony_ci	if (!strcmp(name, "intc-sys")) {
1668c2ecf20Sopenharmony_ci		pr_debug("MSTP %s setting CLK_IS_CRITICAL\n", name);
1678c2ecf20Sopenharmony_ci		init.flags |= CLK_IS_CRITICAL;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci	init.parent_names = &parent_name;
1708c2ecf20Sopenharmony_ci	init.num_parents = 1;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	clock->bit_index = index;
1738c2ecf20Sopenharmony_ci	clock->group = group;
1748c2ecf20Sopenharmony_ci	clock->hw.init = &init;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	clk = clk_register(NULL, &clock->hw);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (IS_ERR(clk))
1798c2ecf20Sopenharmony_ci		kfree(clock);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	return clk;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic void __init cpg_mstp_clocks_init(struct device_node *np)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct mstp_clock_group *group;
1878c2ecf20Sopenharmony_ci	const char *idxname;
1888c2ecf20Sopenharmony_ci	struct clk **clks;
1898c2ecf20Sopenharmony_ci	unsigned int i;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	group = kzalloc(struct_size(group, clks, MSTP_MAX_CLOCKS), GFP_KERNEL);
1928c2ecf20Sopenharmony_ci	if (!group)
1938c2ecf20Sopenharmony_ci		return;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	clks = group->clks;
1968c2ecf20Sopenharmony_ci	spin_lock_init(&group->lock);
1978c2ecf20Sopenharmony_ci	group->data.clks = clks;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	group->smstpcr = of_iomap(np, 0);
2008c2ecf20Sopenharmony_ci	group->mstpsr = of_iomap(np, 1);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (group->smstpcr == NULL) {
2038c2ecf20Sopenharmony_ci		pr_err("%s: failed to remap SMSTPCR\n", __func__);
2048c2ecf20Sopenharmony_ci		kfree(group);
2058c2ecf20Sopenharmony_ci		return;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if (of_device_is_compatible(np, "renesas,r7s72100-mstp-clocks"))
2098c2ecf20Sopenharmony_ci		group->width_8bit = true;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	for (i = 0; i < MSTP_MAX_CLOCKS; ++i)
2128c2ecf20Sopenharmony_ci		clks[i] = ERR_PTR(-ENOENT);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (of_find_property(np, "clock-indices", &i))
2158c2ecf20Sopenharmony_ci		idxname = "clock-indices";
2168c2ecf20Sopenharmony_ci	else
2178c2ecf20Sopenharmony_ci		idxname = "renesas,clock-indices";
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	for (i = 0; i < MSTP_MAX_CLOCKS; ++i) {
2208c2ecf20Sopenharmony_ci		const char *parent_name;
2218c2ecf20Sopenharmony_ci		const char *name;
2228c2ecf20Sopenharmony_ci		u32 clkidx;
2238c2ecf20Sopenharmony_ci		int ret;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		/* Skip clocks with no name. */
2268c2ecf20Sopenharmony_ci		ret = of_property_read_string_index(np, "clock-output-names",
2278c2ecf20Sopenharmony_ci						    i, &name);
2288c2ecf20Sopenharmony_ci		if (ret < 0 || strlen(name) == 0)
2298c2ecf20Sopenharmony_ci			continue;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci		parent_name = of_clk_get_parent_name(np, i);
2328c2ecf20Sopenharmony_ci		ret = of_property_read_u32_index(np, idxname, i, &clkidx);
2338c2ecf20Sopenharmony_ci		if (parent_name == NULL || ret < 0)
2348c2ecf20Sopenharmony_ci			break;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		if (clkidx >= MSTP_MAX_CLOCKS) {
2378c2ecf20Sopenharmony_ci			pr_err("%s: invalid clock %pOFn %s index %u\n",
2388c2ecf20Sopenharmony_ci			       __func__, np, name, clkidx);
2398c2ecf20Sopenharmony_ci			continue;
2408c2ecf20Sopenharmony_ci		}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		clks[clkidx] = cpg_mstp_clock_register(name, parent_name,
2438c2ecf20Sopenharmony_ci						       clkidx, group);
2448c2ecf20Sopenharmony_ci		if (!IS_ERR(clks[clkidx])) {
2458c2ecf20Sopenharmony_ci			group->data.clk_num = max(group->data.clk_num,
2468c2ecf20Sopenharmony_ci						  clkidx + 1);
2478c2ecf20Sopenharmony_ci			/*
2488c2ecf20Sopenharmony_ci			 * Register a clkdev to let board code retrieve the
2498c2ecf20Sopenharmony_ci			 * clock by name and register aliases for non-DT
2508c2ecf20Sopenharmony_ci			 * devices.
2518c2ecf20Sopenharmony_ci			 *
2528c2ecf20Sopenharmony_ci			 * FIXME: Remove this when all devices that require a
2538c2ecf20Sopenharmony_ci			 * clock will be instantiated from DT.
2548c2ecf20Sopenharmony_ci			 */
2558c2ecf20Sopenharmony_ci			clk_register_clkdev(clks[clkidx], name, NULL);
2568c2ecf20Sopenharmony_ci		} else {
2578c2ecf20Sopenharmony_ci			pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
2588c2ecf20Sopenharmony_ci			       __func__, np, name, PTR_ERR(clks[clkidx]));
2598c2ecf20Sopenharmony_ci		}
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	of_clk_add_provider(np, of_clk_src_onecell_get, &group->data);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ciCLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ciint cpg_mstp_attach_dev(struct generic_pm_domain *unused, struct device *dev)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
2698c2ecf20Sopenharmony_ci	struct of_phandle_args clkspec;
2708c2ecf20Sopenharmony_ci	struct clk *clk;
2718c2ecf20Sopenharmony_ci	int i = 0;
2728c2ecf20Sopenharmony_ci	int error;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
2758c2ecf20Sopenharmony_ci					   &clkspec)) {
2768c2ecf20Sopenharmony_ci		if (of_device_is_compatible(clkspec.np,
2778c2ecf20Sopenharmony_ci					    "renesas,cpg-mstp-clocks"))
2788c2ecf20Sopenharmony_ci			goto found;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		/* BSC on r8a73a4/sh73a0 uses zb_clk instead of an mstp clock */
2818c2ecf20Sopenharmony_ci		if (of_node_name_eq(clkspec.np, "zb_clk"))
2828c2ecf20Sopenharmony_ci			goto found;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		of_node_put(clkspec.np);
2858c2ecf20Sopenharmony_ci		i++;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return 0;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cifound:
2918c2ecf20Sopenharmony_ci	clk = of_clk_get_from_provider(&clkspec);
2928c2ecf20Sopenharmony_ci	of_node_put(clkspec.np);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (IS_ERR(clk))
2958c2ecf20Sopenharmony_ci		return PTR_ERR(clk);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	error = pm_clk_create(dev);
2988c2ecf20Sopenharmony_ci	if (error)
2998c2ecf20Sopenharmony_ci		goto fail_put;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	error = pm_clk_add_clk(dev, clk);
3028c2ecf20Sopenharmony_ci	if (error)
3038c2ecf20Sopenharmony_ci		goto fail_destroy;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	return 0;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cifail_destroy:
3088c2ecf20Sopenharmony_ci	pm_clk_destroy(dev);
3098c2ecf20Sopenharmony_cifail_put:
3108c2ecf20Sopenharmony_ci	clk_put(clk);
3118c2ecf20Sopenharmony_ci	return error;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_civoid cpg_mstp_detach_dev(struct generic_pm_domain *unused, struct device *dev)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	if (!pm_clk_no_clocks(dev))
3178c2ecf20Sopenharmony_ci		pm_clk_destroy(dev);
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_civoid __init cpg_mstp_add_clk_domain(struct device_node *np)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct generic_pm_domain *pd;
3238c2ecf20Sopenharmony_ci	u32 ncells;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "#power-domain-cells", &ncells)) {
3268c2ecf20Sopenharmony_ci		pr_warn("%pOF lacks #power-domain-cells\n", np);
3278c2ecf20Sopenharmony_ci		return;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
3318c2ecf20Sopenharmony_ci	if (!pd)
3328c2ecf20Sopenharmony_ci		return;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	pd->name = np->name;
3358c2ecf20Sopenharmony_ci	pd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ALWAYS_ON |
3368c2ecf20Sopenharmony_ci		    GENPD_FLAG_ACTIVE_WAKEUP;
3378c2ecf20Sopenharmony_ci	pd->attach_dev = cpg_mstp_attach_dev;
3388c2ecf20Sopenharmony_ci	pd->detach_dev = cpg_mstp_detach_dev;
3398c2ecf20Sopenharmony_ci	pm_genpd_init(pd, &pm_domain_always_on_gov, false);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	of_genpd_add_provider_simple(np, pd);
3428c2ecf20Sopenharmony_ci}
343