[PATCH] phy: add inno-usb2-phy driver for hi3798cv200 SoC

Kishon Vijay Abraham I kishon at ti.com
Wed Oct 18 05:38:01 PDT 2017


Hi,

On Sunday 15 October 2017 08:19 PM, Shawn Guo wrote:
> From: Pengcheng Li <lpc.li at hisilicon.com>
> 
> It adds inno-usb2-phy driver for hi3798cv200 SoC USB 2.0 support.  One
> inno-usb2-phy device can support up to two PHY ports.  While there is
> device level reference clock and power reset to be controlled, each PHY
> port has its own utmi reset that needs to assert/de-assert as needed.
> 
> Hi3798cv200 needs to access PHY port0 register via particular peripheral
> syscon controller register to control PHY, like turning on PHY clock.
> 
> Signed-off-by: Pengcheng Li <lpc.li at hisilicon.com>
> Signed-off-by: Jiancheng Xue <xuejiancheng at hisilicon.com>
> Signed-off-by: Shawn Guo <shawn.guo at linaro.org>
> ---
>  .../devicetree/bindings/phy/phy-hisi-inno-usb2.txt |  31 +++
>  drivers/phy/hisilicon/Kconfig                      |  10 +
>  drivers/phy/hisilicon/Makefile                     |   1 +
>  drivers/phy/hisilicon/phy-hisi-inno-usb2.c         | 223 +++++++++++++++++++++
>  4 files changed, 265 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt
>  create mode 100644 drivers/phy/hisilicon/phy-hisi-inno-usb2.c
> 
> diff --git a/Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt
> new file mode 100644
> index 000000000000..4ef7af24a703
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt
> @@ -0,0 +1,31 @@
> +HiSilicon INNO USB2 PHY
> +
> +Required properties:
> +- compatible: Should be one of the following strings:
> +	"hisilicon,inno-usb2-phy",
> +	"hisilicon,hi3798cv200-usb2-phy".
> +- #phy-cells: Should be 1. The specifier is the index of the PHY port to
> +  reference.
> +- hisilicon,peripheral-syscon: The phandle of syscon used to control PHY,
> +  followed by a integer cell which defines the syscon register offset used
> +  to talk to PHY.
> +- clocks: The phandle and clock specifier pair for reference clock utmi_refclk.
> +- resets: The list of phandle and reset specifier pairs for each reset signal
> +  in reset-names.
> +- reset-names: Should contain "power_on", "utmi0" and "utmi1". The "utmi1"
> +  should exist only if the device has two PHY port.
> +
> +Refer to phy/phy-bindings.txt for the generic PHY binding properties
> +
> +Example:
> +
> +	usb2_phy1: usb2-phy1 {
> +		compatible = "hisilicon,hi3798cv200-usb2-phy";
> +		#phy-cells = <1>;
> +		hisilicon,peripheral-syscon = <&peri_ctrl 0x120>;
> +		clocks = <&crg HISTB_USB2_PHY1_REF_CLK>;
> +		resets = <&crg 0xbc 4>,
> +			 <&crg 0xbc 8>,
> +			 <&crg 0xbc 9>;
> +		reset-names = "power_on", "utmi0", "utmi1";
> +	};

please send the devicetree binding documentation as a separate patch.
> diff --git a/drivers/phy/hisilicon/Kconfig b/drivers/phy/hisilicon/Kconfig
> index 6164c4cd0f65..c21470eb7fba 100644
> --- a/drivers/phy/hisilicon/Kconfig
> +++ b/drivers/phy/hisilicon/Kconfig
> @@ -11,6 +11,16 @@ config PHY_HI6220_USB
>  
>  	  To compile this driver as a module, choose M here.
>  
> +config PHY_HISI_INNO_USB2
> +       tristate "HiSilicon INNO USB2 PHY support"
> +       depends on (ARCH_HISI && ARM64) || COMPILE_TEST
> +       select GENERIC_PHY
> +       select MFD_SYSCON
> +       help
> +         Support for INNO USB2 PHY on HiSilicon SoCs. This Phy supports
> +         USB 1.5Mb/s, USB 12Mb/s, USB 480Mb/s speeds. It supports one
> +         USB host port to accept one USB device.
> +
>  config PHY_HIX5HD2_SATA
>  	tristate "HIX5HD2 SATA PHY Driver"
>  	depends on ARCH_HIX5HD2 && OF && HAS_IOMEM
> diff --git a/drivers/phy/hisilicon/Makefile b/drivers/phy/hisilicon/Makefile
> index 541b348187a8..e6c979458d3b 100644
> --- a/drivers/phy/hisilicon/Makefile
> +++ b/drivers/phy/hisilicon/Makefile
> @@ -1,2 +1,3 @@
>  obj-$(CONFIG_PHY_HI6220_USB)		+= phy-hi6220-usb.o
> +obj-$(CONFIG_PHY_HISI_INNO_USB2)	+= phy-hisi-inno-usb2.o
>  obj-$(CONFIG_PHY_HIX5HD2_SATA)		+= phy-hix5hd2-sata.o
> diff --git a/drivers/phy/hisilicon/phy-hisi-inno-usb2.c b/drivers/phy/hisilicon/phy-hisi-inno-usb2.c
> new file mode 100644
> index 000000000000..3772aef23539
> --- /dev/null
> +++ b/drivers/phy/hisilicon/phy-hisi-inno-usb2.c
> @@ -0,0 +1,223 @@
> +/*
> + * HiSilicon INNO USB2 PHY Driver.
> + *
> + * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/phy/phy.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#define INNO_PHY_PORT_NUM	2
> +#define REF_CLK_STABLE_TIME	100	/* unit:us */
> +#define UTMI_CLK_STABLE_TIME	200	/* unit:us */
> +#define TEST_CLK_STABLE_TIME	2	/* unit:ms */
> +#define PHY_CLK_STABLE_TIME	2	/* unit:ms */
> +#define UTMI_RST_COMPLETE_TIME	2	/* unit:ms */
> +#define POR_RST_COMPLETE_TIME	300	/* unit:us */
> +#define PHY_TEST_DATA		GENMASK(7, 0)
> +#define PHY_TEST_ADDR		GENMASK(15, 8)
> +#define PHY_TEST_PORT		GENMASK(18, 16)
> +#define PHY_TEST_WREN		BIT(21)
> +#define PHY_TEST_CLK		BIT(22)	/* rising edge active */
> +#define PHY_TEST_RST		BIT(23)	/* low active */
> +#define PHY_CLK_ENABLE		BIT(2)
> +
> +struct hisi_inno_phy_port {
> +	struct phy *phy;
> +	struct device *dev;
> +	struct reset_control *utmi_rst;
> +};
> +
> +struct hisi_inno_phy_priv {
> +	struct regmap *syscon;
> +	u32 syscon_reg;
> +	struct clk *ref_clk;
> +	struct reset_control *por_rst;
> +	struct hisi_inno_phy_port ports[INNO_PHY_PORT_NUM];
> +	u32 port_num;
> +};
> +
> +static void hisi_inno_phy_write_reg(struct regmap *syscon, u32 reg,
> +				    u8 port, u32 addr, u32 data)
> +{
> +	u32 value;
> +
> +	value = (data & PHY_TEST_DATA)
> +		| ((addr << 8) & PHY_TEST_ADDR)
> +		| ((port << 16) & PHY_TEST_PORT)
> +		| PHY_TEST_WREN | PHY_TEST_RST;
> +	regmap_write(syscon, reg, value);
> +	value |= PHY_TEST_CLK;
> +	regmap_write(syscon, reg, value);
> +	value &= ~PHY_TEST_CLK;
> +	regmap_write(syscon, reg, value);
> +}
> +
> +static void hisi_inno_phy_setup(struct hisi_inno_phy_priv *priv)
> +{
> +	/* The phy clk is controlled by the port0 register 0x06. */
> +	hisi_inno_phy_write_reg(priv->syscon, priv->syscon_reg, 0, 0x06,
> +				PHY_CLK_ENABLE);
> +	msleep(PHY_CLK_STABLE_TIME);
> +}
> +
> +static int hisi_inno_phy_start(struct phy *phy)
> +{
> +	struct hisi_inno_phy_port *port = phy_get_drvdata(phy);
> +	struct hisi_inno_phy_priv *priv = dev_get_drvdata(port->dev);
> +	int ret;
> +
> +	ret = clk_prepare_enable(priv->ref_clk);
> +	if (ret)
> +		return ret;
> +	udelay(REF_CLK_STABLE_TIME);
> +
> +	reset_control_deassert(priv->por_rst);
> +	udelay(POR_RST_COMPLETE_TIME);
> +
> +	/* Set up phy registers via peripheral syscon controller */
> +	hisi_inno_phy_setup(priv);
> +
> +	reset_control_deassert(port->utmi_rst);
> +	udelay(UTMI_RST_COMPLETE_TIME);
> +
> +	return 0;
> +}
> +
> +static int hisi_inno_phy_exit(struct phy *phy)
> +{
> +	struct hisi_inno_phy_port *port = phy_get_drvdata(phy);
> +	struct hisi_inno_phy_priv *priv = dev_get_drvdata(port->dev);
> +
> +	reset_control_assert(port->utmi_rst);
> +	reset_control_assert(priv->por_rst);
> +	clk_disable_unprepare(priv->ref_clk);
> +
> +	return 0;
> +}
> +
> +static const struct phy_ops hisi_inno_phy_ops = {
> +	.init = hisi_inno_phy_start,

in order to make it identical you can just end it with *_init().

Thanks
Kishon



More information about the linux-arm-kernel mailing list