18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Renesas USB driver RZ/A2 initialization and power control
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2019 Chris Brandt
68c2ecf20Sopenharmony_ci * Copyright (C) 2019 Renesas Electronics Corporation
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/of_device.h>
128c2ecf20Sopenharmony_ci#include <linux/phy/phy.h>
138c2ecf20Sopenharmony_ci#include "common.h"
148c2ecf20Sopenharmony_ci#include "rza.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic int usbhs_rza2_hardware_init(struct platform_device *pdev)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
198c2ecf20Sopenharmony_ci	struct phy *phy = phy_get(&pdev->dev, "usb");
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	if (IS_ERR(phy))
228c2ecf20Sopenharmony_ci		return PTR_ERR(phy);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	priv->phy = phy;
258c2ecf20Sopenharmony_ci	return 0;
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic int usbhs_rza2_hardware_exit(struct platform_device *pdev)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	phy_put(&pdev->dev, priv->phy);
338c2ecf20Sopenharmony_ci	priv->phy = NULL;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	return 0;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic int usbhs_rza2_power_ctrl(struct platform_device *pdev,
398c2ecf20Sopenharmony_ci				void __iomem *base, int enable)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
428c2ecf20Sopenharmony_ci	int retval = 0;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (!priv->phy)
458c2ecf20Sopenharmony_ci		return -ENODEV;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (enable) {
488c2ecf20Sopenharmony_ci		retval = phy_init(priv->phy);
498c2ecf20Sopenharmony_ci		usbhs_bset(priv, SUSPMODE, SUSPM, SUSPM);
508c2ecf20Sopenharmony_ci		udelay(100);	/* Wait for PLL to become stable */
518c2ecf20Sopenharmony_ci		if (!retval)
528c2ecf20Sopenharmony_ci			retval = phy_power_on(priv->phy);
538c2ecf20Sopenharmony_ci	} else {
548c2ecf20Sopenharmony_ci		usbhs_bset(priv, SUSPMODE, SUSPM, 0);
558c2ecf20Sopenharmony_ci		phy_power_off(priv->phy);
568c2ecf20Sopenharmony_ci		phy_exit(priv->phy);
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	return retval;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ciconst struct renesas_usbhs_platform_info usbhs_rza2_plat_info = {
638c2ecf20Sopenharmony_ci	.platform_callback = {
648c2ecf20Sopenharmony_ci		.hardware_init = usbhs_rza2_hardware_init,
658c2ecf20Sopenharmony_ci		.hardware_exit = usbhs_rza2_hardware_exit,
668c2ecf20Sopenharmony_ci		.power_ctrl = usbhs_rza2_power_ctrl,
678c2ecf20Sopenharmony_ci		.get_id = usbhs_get_id_as_gadget,
688c2ecf20Sopenharmony_ci	},
698c2ecf20Sopenharmony_ci	.driver_param = {
708c2ecf20Sopenharmony_ci		.has_cnen = 1,
718c2ecf20Sopenharmony_ci		.cfifo_byte_addr = 1,
728c2ecf20Sopenharmony_ci		.has_new_pipe_configs = 1,
738c2ecf20Sopenharmony_ci	},
748c2ecf20Sopenharmony_ci};
75