Exemplo n.º 1
0
static int adsp_init_mmio(struct qcom_adsp *adsp,
				struct platform_device *pdev)
{
	struct device_node *syscon;
	struct resource *res;
	int ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	adsp->qdsp6ss_base = devm_ioremap(&pdev->dev, res->start,
			resource_size(res));
	if (!adsp->qdsp6ss_base) {
		dev_err(adsp->dev, "failed to map QDSP6SS registers\n");
		return -ENOMEM;
	}

	syscon = of_parse_phandle(pdev->dev.of_node, "qcom,halt-regs", 0);
	if (!syscon) {
		dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
		return -EINVAL;
	}

	adsp->halt_map = syscon_node_to_regmap(syscon);
	of_node_put(syscon);
	if (IS_ERR(adsp->halt_map))
		return PTR_ERR(adsp->halt_map);

	ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,halt-regs",
			1, &adsp->halt_lpass);
	if (ret < 0) {
		dev_err(&pdev->dev, "no offset in syscon\n");
		return ret;
	}

	return 0;
}
Exemplo n.º 2
0
static int da8xx_cfgchip_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct da8xx_cfgchip_clk_platform_data *pdata = dev->platform_data;
	const struct of_device_id *of_id;
	da8xx_cfgchip_init clk_init = NULL;
	struct regmap *regmap = NULL;

	of_id = of_match_device(da8xx_cfgchip_of_match, dev);
	if (of_id) {
		struct device_node *parent;

		clk_init = of_id->data;
		parent = of_get_parent(dev->of_node);
		regmap = syscon_node_to_regmap(parent);
		of_node_put(parent);
	} else if (pdev->id_entry && pdata) {
		clk_init = (void *)pdev->id_entry->driver_data;
		regmap = pdata->cfgchip;
	}

	if (!clk_init) {
		dev_err(dev, "unable to find driver data\n");
		return -EINVAL;
	}

	if (IS_ERR_OR_NULL(regmap)) {
		dev_err(dev, "no regmap for CFGCHIP syscon\n");
		return regmap ? PTR_ERR(regmap) : -ENOENT;
	}

	return clk_init(dev, regmap);
}
Exemplo n.º 3
0
static int lpc18xx_usb_otg_phy_probe(struct platform_device *pdev)
{
	struct phy_provider *phy_provider;
	struct lpc18xx_usb_otg_phy *lpc;

	lpc = devm_kzalloc(&pdev->dev, sizeof(*lpc), GFP_KERNEL);
	if (!lpc)
		return -ENOMEM;

	lpc->reg = syscon_node_to_regmap(pdev->dev.of_node->parent);
	if (IS_ERR(lpc->reg)) {
		dev_err(&pdev->dev, "failed to get syscon\n");
		return PTR_ERR(lpc->reg);
	}

	lpc->clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(lpc->clk)) {
		dev_err(&pdev->dev, "failed to get clock\n");
		return PTR_ERR(lpc->clk);
	}

	lpc->phy = devm_phy_create(&pdev->dev, NULL, &lpc18xx_usb_otg_phy_ops);
	if (IS_ERR(lpc->phy)) {
		dev_err(&pdev->dev, "failed to create PHY\n");
		return PTR_ERR(lpc->phy);
	}

	phy_set_drvdata(lpc->phy, lpc);

	phy_provider = devm_of_phy_provider_register(&pdev->dev,
						     of_phy_simple_xlate);

	return PTR_ERR_OR_ZERO(phy_provider);
}
Exemplo n.º 4
0
static int axg_clkc_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct regmap *map;
	int ret, i;

	/* Get the hhi system controller node if available */
	map = syscon_node_to_regmap(of_get_parent(dev->of_node));
	if (IS_ERR(map)) {
		dev_err(dev, "failed to get HHI regmap\n");
		return PTR_ERR(map);
	}

	/* Populate regmap for the regmap backed clocks */
	for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++)
		axg_clk_regmaps[i]->map = map;

	for (i = 0; i < axg_hw_onecell_data.num; i++) {
		/* array might be sparse */
		if (!axg_hw_onecell_data.hws[i])
			continue;

		ret = devm_clk_hw_register(dev, axg_hw_onecell_data.hws[i]);
		if (ret) {
			dev_err(dev, "Clock registration failed\n");
			return ret;
		}
	}

	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
					   &axg_hw_onecell_data);
}
Exemplo n.º 5
0
struct regmap *exynos_get_pmu_regmap(void)
{
	struct device_node *np = of_find_matching_node(NULL,
						      exynos_pmu_of_device_ids);
	if (np)
		return syscon_node_to_regmap(np);
	return ERR_PTR(-ENODEV);
}
Exemplo n.º 6
0
static int rockchip_dp_phy_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct phy_provider *phy_provider;
	struct rockchip_dp_phy *dp;
	struct phy *phy;
	int ret;

	if (!np)
		return -ENODEV;

	if (!dev->parent || !dev->parent->of_node)
		return -ENODEV;

	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
	if (IS_ERR(dp))
		return -ENOMEM;

	dp->dev = dev;

	dp->phy_24m = devm_clk_get(dev, "24m");
	if (IS_ERR(dp->phy_24m)) {
		dev_err(dev, "cannot get clock 24m\n");
		return PTR_ERR(dp->phy_24m);
	}

	ret = clk_set_rate(dp->phy_24m, 24000000);
	if (ret < 0) {
		dev_err(dp->dev, "cannot set clock phy_24m %d\n", ret);
		return ret;
	}

	dp->grf = syscon_node_to_regmap(dev->parent->of_node);
	if (IS_ERR(dp->grf)) {
		dev_err(dev, "rk3288-dp needs the General Register Files syscon\n");
		return PTR_ERR(dp->grf);
	}

	ret = regmap_write(dp->grf, GRF_SOC_CON12, GRF_EDP_REF_CLK_SEL_INTER |
			   GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK);
	if (ret != 0) {
		dev_err(dp->dev, "Could not config GRF edp ref clk: %d\n", ret);
		return ret;
	}

	phy = devm_phy_create(dev, np, &rockchip_dp_phy_ops);
	if (IS_ERR(phy)) {
		dev_err(dev, "failed to create phy\n");
		return PTR_ERR(phy);
	}
	phy_set_drvdata(phy, dp);

	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);

	return PTR_ERR_OR_ZERO(phy_provider);
}
Exemplo n.º 7
0
static int uniphier_clk_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct clk_hw_onecell_data *hw_data;
	const struct uniphier_clk_data *p, *data;
	struct regmap *regmap;
	struct device_node *parent;
	int clk_num = 0;

	data = of_device_get_match_data(dev);
	if (WARN_ON(!data))
		return -EINVAL;

	parent = of_get_parent(dev->of_node); /* parent should be syscon node */
	regmap = syscon_node_to_regmap(parent);
	of_node_put(parent);
	if (IS_ERR(regmap)) {
		dev_err(dev, "failed to get regmap (error %ld)\n",
			PTR_ERR(regmap));
		return PTR_ERR(regmap);
	}

	for (p = data; p->name; p++)
		clk_num = max(clk_num, p->idx + 1);

	hw_data = devm_kzalloc(dev,
			sizeof(*hw_data) + clk_num * sizeof(struct clk_hw *),
			GFP_KERNEL);
	if (!hw_data)
		return -ENOMEM;

	hw_data->num = clk_num;

	/* avoid returning NULL for unused idx */
	while (--clk_num >= 0)
		hw_data->hws[clk_num] = ERR_PTR(-EINVAL);

	for (p = data; p->name; p++) {
		struct clk_hw *hw;

		dev_dbg(dev, "register %s (index=%d)\n", p->name, p->idx);
		hw = uniphier_clk_register(dev, regmap, p);
		if (IS_ERR(hw)) {
			dev_err(dev, "failed to register %s (error %ld)\n",
				p->name, PTR_ERR(hw));
			return PTR_ERR(hw);
		}

		if (p->idx >= 0)
			hw_data->hws[p->idx] = hw;
	}

	return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
				      hw_data);
}
Exemplo n.º 8
0
int of_flash_probe_versatile(struct platform_device *pdev,
			     struct device_node *np,
			     struct map_info *map)
{
	struct device_node *sysnp;
	const struct of_device_id *devid;
	struct regmap *rmap;
	static enum versatile_flashprot versatile_flashprot;
	int ret;

	/* Not all flash chips use this protection line */
	if (!of_device_is_compatible(np, "arm,versatile-flash"))
		return 0;

	/* For first chip probed, look up the syscon regmap */
	if (!syscon_regmap) {
		sysnp = of_find_matching_node_and_match(NULL,
							syscon_match,
							&devid);
		if (!sysnp)
			return -ENODEV;

		versatile_flashprot = (enum versatile_flashprot)devid->data;
		rmap = syscon_node_to_regmap(sysnp);
		if (IS_ERR(rmap))
			return PTR_ERR(rmap);

		syscon_regmap = rmap;
	}

	switch (versatile_flashprot) {
	case INTEGRATOR_AP_FLASHPROT:
		ret = ap_flash_init(pdev);
		if (ret)
			return ret;
		map->set_vpp = ap_flash_set_vpp;
		dev_info(&pdev->dev, "Integrator/AP flash protection\n");
		break;
	case INTEGRATOR_CP_FLASHPROT:
		map->set_vpp = cp_flash_set_vpp;
		dev_info(&pdev->dev, "Integrator/CP flash protection\n");
		break;
	case VERSATILE_FLASHPROT:
	case REALVIEW_FLASHPROT:
		map->set_vpp = versatile_flash_set_vpp;
		dev_info(&pdev->dev, "versatile/realview flash protection\n");
		break;
	default:
		dev_info(&pdev->dev, "device marked as Versatile flash "
			 "but no system controller was found\n");
		break;
	}

	return 0;
}
Exemplo n.º 9
0
static int syscon_gpio_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct syscon_gpio_priv *priv;
	struct device_node *np = dev->of_node;
	int ret;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->data = of_device_get_match_data(dev);

	if (priv->data->compatible) {
		priv->syscon = syscon_regmap_lookup_by_compatible(
					priv->data->compatible);
		if (IS_ERR(priv->syscon))
			return PTR_ERR(priv->syscon);
	} else {
		priv->syscon =
			syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev");
		if (IS_ERR(priv->syscon) && np->parent)
			priv->syscon = syscon_node_to_regmap(np->parent);
		if (IS_ERR(priv->syscon))
			return PTR_ERR(priv->syscon);

		ret = of_property_read_u32_index(np, "gpio,syscon-dev", 1,
						 &priv->dreg_offset);
		if (ret)
			dev_err(dev, "can't read the data register offset!\n");

		priv->dreg_offset <<= 3;

		ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2,
						 &priv->dir_reg_offset);
		if (ret)
			dev_dbg(dev, "can't read the dir register offset!\n");

		priv->dir_reg_offset <<= 3;
	}

	priv->chip.parent = dev;
	priv->chip.owner = THIS_MODULE;
	priv->chip.label = dev_name(dev);
	priv->chip.base = -1;
	priv->chip.ngpio = priv->data->bit_count;
	priv->chip.get = syscon_gpio_get;
	if (priv->data->flags & GPIO_SYSCON_FEAT_IN)
		priv->chip.direction_input = syscon_gpio_dir_in;
	if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) {
		priv->chip.set = priv->data->set ? : syscon_gpio_set;
		priv->chip.direction_output = syscon_gpio_dir_out;
	}
Exemplo n.º 10
0
struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
{
	struct device_node *syscon_np;
	struct regmap *regmap;

	syscon_np = of_find_compatible_node(NULL, NULL, s);
	if (!syscon_np)
		return ERR_PTR(-ENODEV);

	regmap = syscon_node_to_regmap(syscon_np);

	return regmap;
}
Exemplo n.º 11
0
/* Base test of register maps */
static int dm_test_regmap_base(struct unit_test_state *uts)
{
	struct udevice *dev;
	struct regmap *map;
	ofnode node;
	int i;

	ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
	map = syscon_get_regmap(dev);
	ut_assertok_ptr(map);
	ut_asserteq(1, map->range_count);
	ut_asserteq(0x10, map->ranges[0].start);
	ut_asserteq(4, map->ranges[0].size);
	ut_asserteq(0x10, map_to_sysmem(regmap_get_range(map, 0)));

	ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev));
	map = syscon_get_regmap(dev);
	ut_assertok_ptr(map);
	ut_asserteq(4, map->range_count);
	ut_asserteq(0x20, map->ranges[0].start);
	for (i = 0; i < 4; i++) {
		const unsigned long addr = 0x20 + 8 * i;

		ut_asserteq(addr, map->ranges[i].start);
		ut_asserteq(5 + i, map->ranges[i].size);
		ut_asserteq(addr, map_to_sysmem(regmap_get_range(map, i)));
	}

	/* Check that we can't pretend a different device is a syscon */
	ut_assertok(uclass_get_device(UCLASS_I2C, 0, &dev));
	map = syscon_get_regmap(dev);
	ut_asserteq_ptr(ERR_PTR(-ENOEXEC), map);

	/* A different device can be a syscon by using Linux-compat API */
	node = ofnode_path("/syscon@2");
	ut_assert(ofnode_valid(node));

	map = syscon_node_to_regmap(node);
	ut_assertok_ptr(map);
	ut_asserteq(4, map->range_count);
	ut_asserteq(0x40, map->ranges[0].start);
	for (i = 0; i < 4; i++) {
		const unsigned long addr = 0x40 + 8 * i;

		ut_asserteq(addr, map->ranges[i].start);
		ut_asserteq(5 + i, map->ranges[i].size);
		ut_asserteq(addr, map_to_sysmem(regmap_get_range(map, i)));
	}

	return 0;
}
Exemplo n.º 12
0
static int oxnas_dwmac_probe(struct platform_device *pdev)
{
	struct plat_stmmacenet_data *plat_dat;
	struct stmmac_resources stmmac_res;
	struct device_node *sysctrl;
	struct oxnas_dwmac *dwmac;
	int ret;

	sysctrl = of_parse_phandle(pdev->dev.of_node, "oxsemi,sys-ctrl", 0);
	if (!sysctrl) {
		dev_err(&pdev->dev, "failed to get sys-ctrl node\n");
		return -EINVAL;
	}

	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
	if (ret)
		return ret;

	plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
	if (IS_ERR(plat_dat))
		return PTR_ERR(plat_dat);

	dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
	if (!dwmac)
		return -ENOMEM;

	dwmac->dev = &pdev->dev;
	plat_dat->bsp_priv = dwmac;

	dwmac->regmap = syscon_node_to_regmap(sysctrl);
	if (IS_ERR(dwmac->regmap)) {
		dev_err(&pdev->dev, "failed to have sysctrl regmap\n");
		return PTR_ERR(dwmac->regmap);
	}

	dwmac->clk = devm_clk_get(&pdev->dev, "gmac");
	if (IS_ERR(dwmac->clk))
		return PTR_ERR(dwmac->clk);

	ret = oxnas_dwmac_init(dwmac);
	if (ret)
		return ret;

	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
	if (ret)
		clk_disable_unprepare(dwmac->clk);

	return ret;
}
Exemplo n.º 13
0
static int uniphier_wdt_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct uniphier_wdt_dev *wdev;
	struct regmap *regmap;
	struct device_node *parent;
	int ret;

	wdev = devm_kzalloc(dev, sizeof(*wdev), GFP_KERNEL);
	if (!wdev)
		return -ENOMEM;

	platform_set_drvdata(pdev, wdev);

	parent = of_get_parent(dev->of_node); /* parent should be syscon node */
	regmap = syscon_node_to_regmap(parent);
	of_node_put(parent);
	if (IS_ERR(regmap))
		return PTR_ERR(regmap);

	wdev->regmap = regmap;
	wdev->wdt_dev.info = &uniphier_wdt_info;
	wdev->wdt_dev.ops = &uniphier_wdt_ops;
	wdev->wdt_dev.max_timeout = WDT_PERIOD_MAX;
	wdev->wdt_dev.min_timeout = WDT_PERIOD_MIN;
	wdev->wdt_dev.parent = dev;

	if (watchdog_init_timeout(&wdev->wdt_dev, timeout, dev) < 0) {
		wdev->wdt_dev.timeout = WDT_DEFAULT_TIMEOUT;
	}
	watchdog_set_nowayout(&wdev->wdt_dev, nowayout);
	watchdog_stop_on_reboot(&wdev->wdt_dev);

	watchdog_set_drvdata(&wdev->wdt_dev, wdev);

	uniphier_watchdog_stop(&wdev->wdt_dev);
	ret = regmap_write(wdev->regmap, WDTRSTSEL, WDTRSTSEL_RSTSEL_BOTH);
	if (ret)
		return ret;

	ret = devm_watchdog_register_device(dev, &wdev->wdt_dev);
	if (ret)
		return ret;

	dev_info(dev, "watchdog driver (timeout=%d sec, nowayout=%d)\n",
		 wdev->wdt_dev.timeout, nowayout);

	return 0;
}
Exemplo n.º 14
0
struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
					const char *property)
{
	struct device_node *syscon_np;
	struct regmap *regmap;

	syscon_np = of_parse_phandle(np, property, 0);
	if (!syscon_np)
		return ERR_PTR(-ENODEV);

	regmap = syscon_node_to_regmap(syscon_np);
	of_node_put(syscon_np);

	return regmap;
}
Exemplo n.º 15
0
/*
 * Hog the regulators needed to power up the board.
 */
static int __init __u300_init_boardpower(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct device_node *syscon_np;
	struct regmap *regmap;
	int err;

	pr_info("U300: setting up board power\n");

	syscon_np = of_parse_phandle(np, "syscon", 0);
	if (!syscon_np) {
		pr_crit("U300: no syscon node\n");
		return -ENODEV;
	}
	regmap = syscon_node_to_regmap(syscon_np);
	if (IS_ERR(regmap)) {
		pr_crit("U300: could not locate syscon regmap\n");
		return PTR_ERR(regmap);
	}

	main_power_15 = regulator_get(&pdev->dev, "vana15");

	if (IS_ERR(main_power_15)) {
		pr_err("could not get vana15");
		return PTR_ERR(main_power_15);
	}
	err = regulator_enable(main_power_15);
	if (err) {
		pr_err("could not enable vana15\n");
		return err;
	}

	/*
	 * On U300 a special system controller register pulls up the DC
	 * until the vana15 (LDO D) regulator comes up. At this point, all
	 * regulators are set and we do not need power control via
	 * DC ON anymore. This function will likely be moved whenever
	 * the rest of the U300 power management is implemented.
	 */
	pr_info("U300: disable system controller pull-up\n");
	regmap_update_bits(regmap, U300_SYSCON_PMCR,
			   U300_SYSCON_PMCR_DCON_ENABLE, 0);

	/* Register globally exported PM poweroff hook */
	pm_power_off = u300_pm_poweroff;

	return 0;
}
static int armada_3700_xtal_clock_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	const char *xtal_name = "xtal";
	struct device_node *parent;
	struct regmap *regmap;
	struct clk_hw *xtal_hw;
	unsigned int rate;
	u32 reg;
	int ret;

	xtal_hw = devm_kzalloc(&pdev->dev, sizeof(*xtal_hw), GFP_KERNEL);
	if (!xtal_hw)
		return -ENOMEM;

	platform_set_drvdata(pdev, xtal_hw);

	parent = np->parent;
	if (!parent) {
		dev_err(&pdev->dev, "no parent\n");
		return -ENODEV;
	}

	regmap = syscon_node_to_regmap(parent);
	if (IS_ERR(regmap)) {
		dev_err(&pdev->dev, "cannot get regmap\n");
		return PTR_ERR(regmap);
	}

	ret = regmap_read(regmap, NB_GPIO1_LATCH, &reg);
	if (ret) {
		dev_err(&pdev->dev, "cannot read from regmap\n");
		return ret;
	}

	if (reg & XTAL_MODE)
		rate = 40000000;
	else
		rate = 25000000;

	of_property_read_string_index(np, "clock-output-names", 0, &xtal_name);
	xtal_hw = clk_hw_register_fixed_rate(NULL, xtal_name, NULL, 0, rate);
	if (IS_ERR(xtal_hw))
		return PTR_ERR(xtal_hw);
	ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, xtal_hw);

	return ret;
}
Exemplo n.º 17
0
void __init of_sama5d2_clk_generated_setup(struct device_node *np)
{
	int num;
	u32 id;
	const char *name;
	struct clk *clk;
	unsigned int num_parents;
	const char *parent_names[GENERATED_SOURCE_MAX];
	struct device_node *gcknp;
	struct clk_range range = CLK_RANGE(0, 0);
	struct regmap *regmap;

	num_parents = of_clk_get_parent_count(np);
	if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
		return;

	of_clk_parent_fill(np, parent_names, num_parents);

	num = of_get_child_count(np);
	if (!num || num > PERIPHERAL_MAX)
		return;

	regmap = syscon_node_to_regmap(of_get_parent(np));
	if (IS_ERR(regmap))
		return;

	for_each_child_of_node(np, gcknp) {
		if (of_property_read_u32(gcknp, "reg", &id))
			continue;

		if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX)
			continue;

		if (of_property_read_string(np, "clock-output-names", &name))
			name = gcknp->name;

		of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
				      &range);

		clk = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
						  parent_names, num_parents,
						  id, &range);
		if (IS_ERR(clk))
			continue;

		of_clk_add_provider(gcknp, of_clk_src_simple_get, clk);
	}
}
Exemplo n.º 18
0
static int fsl_mqs_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct device_node *gpr_np;
	struct fsl_mqs *mqs_priv;
	int ret = 0;

	mqs_priv = devm_kzalloc(&pdev->dev, sizeof(*mqs_priv), GFP_KERNEL);
	if (!mqs_priv)
		return -ENOMEM;

	mqs_priv->pdev = pdev;
	strncpy(mqs_priv->name, np->name, sizeof(mqs_priv->name) - 1);

	gpr_np = of_parse_phandle(np, "gpr", 0);
	if (IS_ERR(gpr_np)) {
		dev_err(&pdev->dev, "failed to get gpr node by phandle\n");
		ret = PTR_ERR(gpr_np);
		goto out;
	}

	mqs_priv->gpr = syscon_node_to_regmap(gpr_np);
	if (IS_ERR(mqs_priv->gpr)) {
		dev_err(&pdev->dev, "failed to get gpr regmap\n");
		ret = PTR_ERR(mqs_priv->gpr);
		goto out;
	}

	mqs_priv->mclk = devm_clk_get(&pdev->dev, "mclk");
	if (IS_ERR(mqs_priv->mclk)) {
		dev_err(&pdev->dev, "failed to get the clock: %ld\n",
				PTR_ERR(mqs_priv->mclk));
		goto out;
	}

	dev_set_drvdata(&pdev->dev, mqs_priv);

	return snd_soc_register_codec(&pdev->dev, &soc_codec_fsl_mqs,
			&fsl_mqs_dai, 1);

out:
	if (!IS_ERR(gpr_np))
		of_node_put(gpr_np);

	return ret;
}
Exemplo n.º 19
0
int show_board_info(void)
{
	struct regmap *regmap;
	int nodeoffset, ret;
	ofnode node;
	unsigned int socinfo;

	/* find the offset of compatible node */
	nodeoffset = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
						   "amlogic,meson-gx-ao-secure");
	if (nodeoffset < 0)
		return 0;

	/* check if chip-id is available */
	if (!fdt_getprop(gd->fdt_blob, nodeoffset, "amlogic,has-chip-id", NULL))
		return 0;

	/* get regmap from the syscon node */
	node = offset_to_ofnode(nodeoffset);
	regmap = syscon_node_to_regmap(node);
	if (IS_ERR(regmap)) {
		printf("%s: failed to get regmap\n", __func__);
		return 0;
	}

	/* read soc info */
	ret = regmap_read(regmap, AO_SEC_SOCINFO_OFFSET, &socinfo);
	if (ret && !socinfo) {
		printf("%s: invalid chipid value\n", __func__);
		return 0;
	}

	/* print board information */
	print_board_model();
	printf("Soc:   Amlogic Meson %s (%s) Revision %x:%x (%x:%x)\n",
	       socinfo_to_soc_id(socinfo),
	       socinfo_to_package_id(socinfo),
	       socinfo_to_major(socinfo),
	       socinfo_to_minor(socinfo),
	       socinfo_to_pack(socinfo),
	       socinfo_to_misc(socinfo));

	return 0;
}
Exemplo n.º 20
0
static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
{
	struct device_node *np;
	void __iomem *scu_base;
	struct regmap *map;
	unsigned int ncores;
	int i;

	np = of_find_matching_node(NULL, realview_scu_match);
	if (!np) {
		pr_err("PLATSMP: No SCU base address\n");
		return;
	}
	scu_base = of_iomap(np, 0);
	of_node_put(np);
	if (!scu_base) {
		pr_err("PLATSMP: No SCU remap\n");
		return;
	}

	scu_enable(scu_base);
	ncores = scu_get_core_count(scu_base);
	pr_info("SCU: %d cores detected\n", ncores);
	for (i = 0; i < ncores; i++)
		set_cpu_possible(i, true);
	iounmap(scu_base);

	/* The syscon contains the magic SMP start address registers */
	np = of_find_matching_node(NULL, realview_syscon_match);
	if (!np) {
		pr_err("PLATSMP: No syscon match\n");
		return;
	}
	map = syscon_node_to_regmap(np);
	if (IS_ERR(map)) {
		pr_err("PLATSMP: No syscon regmap\n");
		return;
	}
	/* Put the boot address in this magic register */
	regmap_write(map, REALVIEW_SYS_FLAGSSET_OFFSET,
		     virt_to_phys(versatile_secondary_startup));
}
Exemplo n.º 21
0
/*
 * ST (system timer) module supports both clockevents and clocksource.
 */
static void __init atmel_st_timer_init(struct device_node *node)
{
	unsigned int val;
	int irq, ret;

	regmap_st = syscon_node_to_regmap(node);
	if (IS_ERR(regmap_st))
		panic(pr_fmt("Unable to get regmap\n"));

	/* Disable all timer interrupts, and clear any pending ones */
	regmap_write(regmap_st, AT91_ST_IDR,
		AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
	regmap_read(regmap_st, AT91_ST_SR, &val);

	/* Get the interrupts property */
	irq  = irq_of_parse_and_map(node, 0);
	if (!irq)
		panic(pr_fmt("Unable to get IRQ from DT\n"));

	/* Make IRQs happen for the system timer */
	ret = request_irq(irq, at91rm9200_timer_interrupt,
			  IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
			  "at91_tick", regmap_st);
	if (ret)
		panic(pr_fmt("Unable to setup IRQ\n"));

	/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
	 * directly for the clocksource and all clockevents, after adjusting
	 * its prescaler from the 1 Hz default.
	 */
	regmap_write(regmap_st, AT91_ST_RTMR, 1);

	/* Setup timer clockevent, with minimum of two ticks (important!!) */
	clkevt.cpumask = cpumask_of(0);
	clockevents_config_and_register(&clkevt, AT91_SLOW_CLOCK,
					2, AT91_ST_ALMV);

	/* register clocksource */
	clocksource_register_hz(&clk32k, AT91_SLOW_CLOCK);
}
Exemplo n.º 22
0
static int uniphier_reset_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct uniphier_reset_priv *priv;
	const struct uniphier_reset_data *p, *data;
	struct regmap *regmap;
	struct device_node *parent;
	unsigned int nr_resets = 0;

	data = of_device_get_match_data(dev);
	if (WARN_ON(!data))
		return -EINVAL;

	parent = of_get_parent(dev->of_node); /* parent should be syscon node */
	regmap = syscon_node_to_regmap(parent);
	of_node_put(parent);
	if (IS_ERR(regmap)) {
		dev_err(dev, "failed to get regmap (error %ld)\n",
			PTR_ERR(regmap));
		return PTR_ERR(regmap);
	}

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	for (p = data; p->id != UNIPHIER_RESET_ID_END; p++)
		nr_resets = max(nr_resets, p->id + 1);

	priv->rcdev.ops = &uniphier_reset_ops;
	priv->rcdev.owner = dev->driver->owner;
	priv->rcdev.of_node = dev->of_node;
	priv->rcdev.nr_resets = nr_resets;
	priv->dev = dev;
	priv->regmap = regmap;
	priv->data = data;

	return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
}
Exemplo n.º 23
0
static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
{
	struct clk *clk;
	const char *parent_name;
	const char *name = np->name;
	struct regmap *regmap;

	parent_name = of_clk_get_parent_name(np, 0);

	of_property_read_string(np, "clock-output-names", &name);

	regmap = syscon_node_to_regmap(of_get_parent(np));
	if (IS_ERR(regmap))
		return;

	clk = at91_clk_register_utmi(regmap, name, parent_name);
	if (IS_ERR(clk))
		return;

	of_clk_add_provider(np, of_clk_src_simple_get, clk);
	return;
}
Exemplo n.º 24
0
int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks,
                           int num, struct clk_onecell_data *clk_data)
{
    int i;
    struct clk *clk;
    struct regmap *regmap;

    if (!clk_data)
        return -ENOMEM;

    regmap = syscon_node_to_regmap(node);
    if (IS_ERR(regmap)) {
        pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
               PTR_ERR(regmap));
        return PTR_ERR(regmap);
    }

    for (i = 0; i < num; i++) {
        const struct mtk_gate *gate = &clks[i];

        clk = mtk_clk_register_gate(gate->name, gate->parent_name,
                                    regmap,
                                    gate->regs->set_ofs,
                                    gate->regs->clr_ofs,
                                    gate->regs->sta_ofs,
                                    gate->shift, gate->ops);

        if (IS_ERR(clk)) {
            pr_err("Failed to register clk %s: %ld\n",
                   gate->name, PTR_ERR(clk));
            continue;
        }

        clk_data->clks[gate->id] = clk;
    }

    return 0;
}
Exemplo n.º 25
0
static int uniphier_tm_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct regmap *regmap;
	struct device_node *parent;
	struct uniphier_tm_dev *tdev;
	const struct thermal_trip *trips;
	int i, ret, irq, ntrips, crit_temp = INT_MAX;

	tdev = devm_kzalloc(dev, sizeof(*tdev), GFP_KERNEL);
	if (!tdev)
		return -ENOMEM;
	tdev->dev = dev;

	tdev->data = of_device_get_match_data(dev);
	if (WARN_ON(!tdev->data))
		return -EINVAL;

	irq = platform_get_irq(pdev, 0);
	if (irq < 0)
		return irq;

	/* get regmap from syscon node */
	parent = of_get_parent(dev->of_node); /* parent should be syscon node */
	regmap = syscon_node_to_regmap(parent);
	of_node_put(parent);
	if (IS_ERR(regmap)) {
		dev_err(dev, "failed to get regmap (error %ld)\n",
			PTR_ERR(regmap));
		return PTR_ERR(regmap);
	}
	tdev->regmap = regmap;

	ret = uniphier_tm_initialize_sensor(tdev);
	if (ret) {
		dev_err(dev, "failed to initialize sensor\n");
		return ret;
	}

	ret = devm_request_threaded_irq(dev, irq, uniphier_tm_alarm_irq,
					uniphier_tm_alarm_irq_thread,
					0, "thermal", tdev);
	if (ret)
		return ret;

	platform_set_drvdata(pdev, tdev);

	tdev->tz_dev = devm_thermal_zone_of_sensor_register(dev, 0, tdev,
						&uniphier_of_thermal_ops);
	if (IS_ERR(tdev->tz_dev)) {
		dev_err(dev, "failed to register sensor device\n");
		return PTR_ERR(tdev->tz_dev);
	}

	/* get trip points */
	trips = of_thermal_get_trip_points(tdev->tz_dev);
	ntrips = of_thermal_get_ntrips(tdev->tz_dev);
	if (ntrips > ALERT_CH_NUM) {
		dev_err(dev, "thermal zone has too many trips\n");
		return -E2BIG;
	}

	/* set alert temperatures */
	for (i = 0; i < ntrips; i++) {
		if (trips[i].type == THERMAL_TRIP_CRITICAL &&
		    trips[i].temperature < crit_temp)
			crit_temp = trips[i].temperature;
		uniphier_tm_set_alert(tdev, i, trips[i].temperature);
		tdev->alert_en[i] = true;
	}
	if (crit_temp > CRITICAL_TEMP_LIMIT) {
		dev_err(dev, "critical trip is over limit(>%d), or not set\n",
			CRITICAL_TEMP_LIMIT);
		return -EINVAL;
	}

	uniphier_tm_enable_sensor(tdev);

	return 0;
}
Exemplo n.º 26
0
static int zx_tdm_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct of_phandle_args out_args;
	unsigned int dma_reg_offset;
	struct zx_tdm_info *zx_tdm;
	unsigned int dma_mask;
	struct resource *res;
	struct regmap *regmap_sysctrl;
	int ret;

	zx_tdm = devm_kzalloc(&pdev->dev, sizeof(*zx_tdm), GFP_KERNEL);
	if (!zx_tdm)
		return -ENOMEM;

	zx_tdm->dev = dev;

	zx_tdm->dai_wclk = devm_clk_get(&pdev->dev, "wclk");
	if (IS_ERR(zx_tdm->dai_wclk)) {
		dev_err(&pdev->dev, "Fail to get wclk\n");
		return PTR_ERR(zx_tdm->dai_wclk);
	}

	zx_tdm->dai_pclk = devm_clk_get(&pdev->dev, "pclk");
	if (IS_ERR(zx_tdm->dai_pclk)) {
		dev_err(&pdev->dev, "Fail to get pclk\n");
		return PTR_ERR(zx_tdm->dai_pclk);
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	zx_tdm->phy_addr = res->start;
	zx_tdm->regbase = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(zx_tdm->regbase))
		return PTR_ERR(zx_tdm->regbase);

	ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
				"zte,tdm-dma-sysctrl", 2, 0, &out_args);
	if (ret) {
		dev_err(&pdev->dev, "Fail to get zte,tdm-dma-sysctrl\n");
		return ret;
	}

	dma_reg_offset = out_args.args[0];
	dma_mask = out_args.args[1];
	regmap_sysctrl = syscon_node_to_regmap(out_args.np);
	if (IS_ERR(regmap_sysctrl)) {
		of_node_put(out_args.np);
		return PTR_ERR(regmap_sysctrl);
	}

	regmap_update_bits(regmap_sysctrl, dma_reg_offset, dma_mask, dma_mask);
	of_node_put(out_args.np);

	zx_tdm_init_state(zx_tdm);
	platform_set_drvdata(pdev, zx_tdm);

	ret = devm_snd_soc_register_component(&pdev->dev, &zx_tdm_component,
						&zx_tdm_dai, 1);
	if (ret) {
		dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
		return ret;
	}

	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
	if (ret)
		dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);

	return ret;
}
Exemplo n.º 27
0
static int __init meson_mx_socinfo_init(void)
{
	struct soc_device_attribute *soc_dev_attr;
	struct soc_device *soc_dev;
	struct device_node *np;
	struct regmap *assist_regmap, *bootrom_regmap, *analog_top_regmap;
	unsigned int major_ver, misc_ver, metal_rev = 0;
	int ret;

	assist_regmap =
		syscon_regmap_lookup_by_compatible("amlogic,meson-mx-assist");
	if (IS_ERR(assist_regmap))
		return PTR_ERR(assist_regmap);

	bootrom_regmap =
		syscon_regmap_lookup_by_compatible("amlogic,meson-mx-bootrom");
	if (IS_ERR(bootrom_regmap))
		return PTR_ERR(bootrom_regmap);

	np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids);
	if (np) {
		analog_top_regmap = syscon_node_to_regmap(np);
		if (IS_ERR(analog_top_regmap))
			return PTR_ERR(analog_top_regmap);

		ret = regmap_read(analog_top_regmap,
				  MESON_MX_ANALOG_TOP_METAL_REVISION,
				  &metal_rev);
		if (ret)
			return ret;
	}

	ret = regmap_read(assist_regmap, MESON_MX_ASSIST_HW_REV, &major_ver);
	if (ret < 0)
		return ret;

	ret = regmap_read(bootrom_regmap, MESON_MX_BOOTROM_MISC_VER,
			  &misc_ver);
	if (ret < 0)
		return ret;

	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
	if (!soc_dev_attr)
		return -ENODEV;

	soc_dev_attr->family = "Amlogic Meson";

	np = of_find_node_by_path("/");
	of_property_read_string(np, "model", &soc_dev_attr->machine);
	of_node_put(np);

	soc_dev_attr->revision = meson_mx_socinfo_revision(major_ver, misc_ver,
							   metal_rev);
	soc_dev_attr->soc_id = meson_mx_socinfo_soc_id(major_ver, metal_rev);

	soc_dev = soc_device_register(soc_dev_attr);
	if (IS_ERR(soc_dev)) {
		kfree_const(soc_dev_attr->revision);
		kfree_const(soc_dev_attr->soc_id);
		kfree(soc_dev_attr);
		return PTR_ERR(soc_dev);
	}

	dev_info(soc_device_to_device(soc_dev), "Amlogic %s %s detected\n",
		 soc_dev_attr->soc_id, soc_dev_attr->revision);

	return 0;
}
Exemplo n.º 28
0
static void __init at91sam9rl_pmc_setup(struct device_node *np)
{
	const char *slck_name, *mainxtal_name;
	struct pmc_data *at91sam9rl_pmc;
	const char *parent_names[6];
	struct regmap *regmap;
	struct clk_hw *hw;
	int i;

	i = of_property_match_string(np, "clock-names", "slow_clk");
	if (i < 0)
		return;

	slck_name = of_clk_get_parent_name(np, i);

	i = of_property_match_string(np, "clock-names", "main_xtal");
	if (i < 0)
		return;
	mainxtal_name = of_clk_get_parent_name(np, i);

	regmap = syscon_node_to_regmap(np);
	if (IS_ERR(regmap))
		return;

	at91sam9rl_pmc = pmc_data_allocate(PMC_MAIN + 1,
					   nck(at91sam9rl_systemck),
					   nck(at91sam9rl_periphck), 0);
	if (!at91sam9rl_pmc)
		return;

	hw = at91_clk_register_rm9200_main(regmap, "mainck", mainxtal_name);
	if (IS_ERR(hw))
		goto err_free;

	at91sam9rl_pmc->chws[PMC_MAIN] = hw;

	hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
				   &at91rm9200_pll_layout,
				   &sam9rl_plla_characteristics);
	if (IS_ERR(hw))
		goto err_free;

	hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
	if (IS_ERR(hw))
		goto err_free;

	at91sam9rl_pmc->chws[PMC_UTMI] = hw;

	parent_names[0] = slck_name;
	parent_names[1] = "mainck";
	parent_names[2] = "pllack";
	parent_names[3] = "utmick";
	hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
				      &at91rm9200_master_layout,
				      &sam9rl_mck_characteristics);
	if (IS_ERR(hw))
		goto err_free;

	at91sam9rl_pmc->chws[PMC_MCK] = hw;

	parent_names[0] = slck_name;
	parent_names[1] = "mainck";
	parent_names[2] = "pllack";
	parent_names[3] = "utmick";
	parent_names[4] = "masterck";
	for (i = 0; i < 2; i++) {
		char name[6];

		snprintf(name, sizeof(name), "prog%d", i);

		hw = at91_clk_register_programmable(regmap, name,
						    parent_names, 5, i,
						    &at91rm9200_programmable_layout);
		if (IS_ERR(hw))
			goto err_free;
	}

	for (i = 0; i < ARRAY_SIZE(at91sam9rl_systemck); i++) {
		hw = at91_clk_register_system(regmap, at91sam9rl_systemck[i].n,
					      at91sam9rl_systemck[i].p,
					      at91sam9rl_systemck[i].id);
		if (IS_ERR(hw))
			goto err_free;

		at91sam9rl_pmc->shws[at91sam9rl_systemck[i].id] = hw;
	}

	for (i = 0; i < ARRAY_SIZE(at91sam9rl_periphck); i++) {
		hw = at91_clk_register_peripheral(regmap,
						  at91sam9rl_periphck[i].n,
						  "masterck",
						  at91sam9rl_periphck[i].id);
		if (IS_ERR(hw))
			goto err_free;

		at91sam9rl_pmc->phws[at91sam9rl_periphck[i].id] = hw;
	}

	of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9rl_pmc);

	return;

err_free:
	pmc_data_free(at91sam9rl_pmc);
}
Exemplo n.º 29
0
static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
				      struct device_node *node)
{
	const struct rockchip_domain_info *pd_info;
	struct rockchip_pm_domain *pd;
	struct device_node *qos_node;
	int i, j;
	u32 id;
	int error;

	error = of_property_read_u32(node, "reg", &id);
	if (error) {
		dev_err(pmu->dev,
			"%s: failed to retrieve domain id (reg): %d\n",
			node->name, error);
		return -EINVAL;
	}

	if (id >= pmu->info->num_domains) {
		dev_err(pmu->dev, "%s: invalid domain id %d\n",
			node->name, id);
		return -EINVAL;
	}

	pd_info = &pmu->info->domain_info[id];
	if (!pd_info) {
		dev_err(pmu->dev, "%s: undefined domain id %d\n",
			node->name, id);
		return -EINVAL;
	}

	pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);
	if (!pd)
		return -ENOMEM;

	pd->info = pd_info;
	pd->pmu = pmu;

	pd->num_clks = of_clk_get_parent_count(node);
	if (pd->num_clks > 0) {
		pd->clks = devm_kcalloc(pmu->dev, pd->num_clks,
					sizeof(*pd->clks), GFP_KERNEL);
		if (!pd->clks)
			return -ENOMEM;
	} else {
		dev_dbg(pmu->dev, "%s: doesn't have clocks: %d\n",
			node->name, pd->num_clks);
		pd->num_clks = 0;
	}

	for (i = 0; i < pd->num_clks; i++) {
		pd->clks[i].clk = of_clk_get(node, i);
		if (IS_ERR(pd->clks[i].clk)) {
			error = PTR_ERR(pd->clks[i].clk);
			dev_err(pmu->dev,
				"%s: failed to get clk at index %d: %d\n",
				node->name, i, error);
			return error;
		}
	}

	error = clk_bulk_prepare(pd->num_clks, pd->clks);
	if (error)
		goto err_put_clocks;

	pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
						 NULL);

	if (pd->num_qos > 0) {
		pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos,
					      sizeof(*pd->qos_regmap),
					      GFP_KERNEL);
		if (!pd->qos_regmap) {
			error = -ENOMEM;
			goto err_unprepare_clocks;
		}

		for (j = 0; j < MAX_QOS_REGS_NUM; j++) {
			pd->qos_save_regs[j] = devm_kcalloc(pmu->dev,
							    pd->num_qos,
							    sizeof(u32),
							    GFP_KERNEL);
			if (!pd->qos_save_regs[j]) {
				error = -ENOMEM;
				goto err_unprepare_clocks;
			}
		}

		for (j = 0; j < pd->num_qos; j++) {
			qos_node = of_parse_phandle(node, "pm_qos", j);
			if (!qos_node) {
				error = -ENODEV;
				goto err_unprepare_clocks;
			}
			pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);
			if (IS_ERR(pd->qos_regmap[j])) {
				error = -ENODEV;
				of_node_put(qos_node);
				goto err_unprepare_clocks;
			}
			of_node_put(qos_node);
		}
	}

	error = rockchip_pd_power(pd, true);
	if (error) {
		dev_err(pmu->dev,
			"failed to power on domain '%s': %d\n",
			node->name, error);
		goto err_unprepare_clocks;
	}

	pd->genpd.name = node->name;
	pd->genpd.power_off = rockchip_pd_power_off;
	pd->genpd.power_on = rockchip_pd_power_on;
	pd->genpd.attach_dev = rockchip_pd_attach_dev;
	pd->genpd.detach_dev = rockchip_pd_detach_dev;
	pd->genpd.flags = GENPD_FLAG_PM_CLK;
	if (pd_info->active_wakeup)
		pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
	pm_genpd_init(&pd->genpd, NULL, false);

	pmu->genpd_data.domains[id] = &pd->genpd;
	return 0;

err_unprepare_clocks:
	clk_bulk_unprepare(pd->num_clks, pd->clks);
err_put_clocks:
	clk_bulk_put(pd->num_clks, pd->clks);
	return error;
}
Exemplo n.º 30
0
static int hip04_mac_probe(struct platform_device *pdev)
{
    struct device *d = &pdev->dev;
    struct device_node *node = d->of_node;
    struct of_phandle_args arg;
    struct net_device *ndev;
    struct hip04_priv *priv;
    struct resource *res;
    int irq;
    int ret;

    ndev = alloc_etherdev(sizeof(struct hip04_priv));
    if (!ndev)
        return -ENOMEM;

    priv = netdev_priv(ndev);
    priv->ndev = ndev;
    platform_set_drvdata(pdev, ndev);

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    priv->base = devm_ioremap_resource(d, res);
    if (IS_ERR(priv->base)) {
        ret = PTR_ERR(priv->base);
        goto init_fail;
    }

    ret = of_parse_phandle_with_fixed_args(node, "port-handle", 2, 0, &arg);
    if (ret < 0) {
        dev_warn(d, "no port-handle\n");
        goto init_fail;
    }

    priv->port = arg.args[0];
    priv->chan = arg.args[1] * RX_DESC_NUM;

    hrtimer_init(&priv->tx_coalesce_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);

    /* BQL will try to keep the TX queue as short as possible, but it can't
     * be faster than tx_coalesce_usecs, so we need a fast timeout here,
     * but also long enough to gather up enough frames to ensure we don't
     * get more interrupts than necessary.
     * 200us is enough for 16 frames of 1500 bytes at gigabit ethernet rate
     */
    priv->tx_coalesce_frames = TX_DESC_NUM * 3 / 4;
    priv->tx_coalesce_usecs = 200;
    priv->tx_coalesce_timer.function = tx_done;

    priv->map = syscon_node_to_regmap(arg.np);
    if (IS_ERR(priv->map)) {
        dev_warn(d, "no syscon hisilicon,hip04-ppe\n");
        ret = PTR_ERR(priv->map);
        goto init_fail;
    }

    priv->phy_mode = of_get_phy_mode(node);
    if (priv->phy_mode < 0) {
        dev_warn(d, "not find phy-mode\n");
        ret = -EINVAL;
        goto init_fail;
    }

    irq = platform_get_irq(pdev, 0);
    if (irq <= 0) {
        ret = -EINVAL;
        goto init_fail;
    }

    ret = devm_request_irq(d, irq, hip04_mac_interrupt,
                           0, pdev->name, ndev);
    if (ret) {
        netdev_err(ndev, "devm_request_irq failed\n");
        goto init_fail;
    }

    priv->phy_node = of_parse_phandle(node, "phy-handle", 0);
    if (priv->phy_node) {
        priv->phy = of_phy_connect(ndev, priv->phy_node,
                                   &hip04_adjust_link,
                                   0, priv->phy_mode);
        if (!priv->phy) {
            ret = -EPROBE_DEFER;
            goto init_fail;
        }
    }

    INIT_WORK(&priv->tx_timeout_task, hip04_tx_timeout_task);

    ether_setup(ndev);
    ndev->netdev_ops = &hip04_netdev_ops;
    ndev->ethtool_ops = &hip04_ethtool_ops;
    ndev->watchdog_timeo = TX_TIMEOUT;
    ndev->priv_flags |= IFF_UNICAST_FLT;
    ndev->irq = irq;
    netif_napi_add(ndev, &priv->napi, hip04_rx_poll, NAPI_POLL_WEIGHT);
    SET_NETDEV_DEV(ndev, &pdev->dev);

    hip04_reset_ppe(priv);
    if (priv->phy_mode == PHY_INTERFACE_MODE_MII)
        hip04_config_port(ndev, SPEED_100, DUPLEX_FULL);

    hip04_config_fifo(priv);
    random_ether_addr(ndev->dev_addr);
    hip04_update_mac_address(ndev);

    ret = hip04_alloc_ring(ndev, d);
    if (ret) {
        netdev_err(ndev, "alloc ring fail\n");
        goto alloc_fail;
    }

    ret = register_netdev(ndev);
    if (ret) {
        free_netdev(ndev);
        goto alloc_fail;
    }

    return 0;

alloc_fail:
    hip04_free_ring(ndev, d);
init_fail:
    of_node_put(priv->phy_node);
    free_netdev(ndev);
    return ret;
}