Re: [PATCH v2] usb: phy: mv_u3d: Add usb phy driver for mv_u3d

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 09, 2012 at 08:04:44PM +0800, Yu Xu wrote:
> The driver supports phy_init and phy_shutdown functions to
> enable and disable phy for Marvell USB 3.0 controller.
> 
> Signed-off-by: Yu Xu <yuxu@xxxxxxxxxxx>
> ---
>  drivers/usb/phy/Kconfig      |    8 +
>  drivers/usb/phy/Makefile     |    1 +
>  drivers/usb/phy/mv_u3d_phy.c |  354 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/phy/mv_u3d_phy.h |  105 +++++++++++++
>  4 files changed, 468 insertions(+)
>  create mode 100644 drivers/usb/phy/mv_u3d_phy.c
>  create mode 100644 drivers/usb/phy/mv_u3d_phy.h
> 
> diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
> index e7cf84f..2838adb 100644
> --- a/drivers/usb/phy/Kconfig
> +++ b/drivers/usb/phy/Kconfig
> @@ -15,3 +15,11 @@ config USB_ISP1301
>  
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called isp1301.
> +
> +config MV_U3D_PHY
> +	bool "Marvell USB 3.0 PHY controller Driver"
> +	depends on USB_MV_U3D
> +	select USB_OTG_UTILS
> +	help
> +	  Enable this to support Marvell USB 3.0 phy controller for Marvell
> +	  SoC.
> diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
> index eca095b..cf38f08 100644
> --- a/drivers/usb/phy/Makefile
> +++ b/drivers/usb/phy/Makefile
> @@ -5,3 +5,4 @@
>  ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
>  
>  obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
> +obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
> diff --git a/drivers/usb/phy/mv_u3d_phy.c b/drivers/usb/phy/mv_u3d_phy.c
> new file mode 100644
> index 0000000..99312e4
> --- /dev/null
> +++ b/drivers/usb/phy/mv_u3d_phy.c
> @@ -0,0 +1,354 @@
> +/*
> + * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/usb/otg.h>
> +#include <linux/platform_data/mv_usb.h>
> +
> +#include "mv_u3d_phy.h"
> +
> +/*
> + * struct mv_u3d_phy - transceiver driver state
> + * @phy: transceiver structure
> + * @dev: The parent device supplied to the probe function
> + * @clk: usb phy clock
> + * @base: usb phy register memory base
> + */
> +struct mv_u3d_phy {
> +	struct usb_phy	phy;
> +	struct mv_usb_platform_data *plat;
> +	struct device	*dev;
> +	struct clk	*clk;
> +	void __iomem	*base;
> +};
> +
> +static u32 mv_u3d_phy_read(void __iomem *base, u32 reg)
> +{
> +	void __iomem *addr, *data;
> +
> +	addr = base;
> +	data = base + 0x4;
> +
> +	writel_relaxed(reg, addr);
> +	return readl_relaxed(data);
> +}
> +
> +static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value)
> +{
> +	void __iomem *addr, *data;
> +	u32 tmp;
> +
> +	addr = base;
> +	data = base + 0x4;
> +
> +	writel_relaxed(reg, addr);
> +	tmp = readl_relaxed(data);
> +	tmp |= value;
> +	writel_relaxed(tmp, data);
> +}
> +
> +static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value)
> +{
> +	void __iomem *addr, *data;
> +	u32 tmp;
> +
> +	addr = base;
> +	data = base + 0x4;
> +
> +	writel_relaxed(reg, addr);
> +	tmp = readl_relaxed(data);
> +	tmp &= ~value;
> +	writel_relaxed(tmp, data);
> +}
> +
> +static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value)
> +{
> +	void __iomem *addr, *data;
> +
> +	addr = base;
> +	data = base + 0x4;
> +
> +	writel_relaxed(reg, addr);
> +	writel_relaxed(value, data);
> +}
> +
> +static void mv_u3d_phy_reg_print(void __iomem *base, u32 reg)
> +{
> +	u32 data;
> +	data = mv_u3d_phy_read(base, reg);
> +	pr_debug("phy reg 0x%x: phy data 0x%x\n", reg, data);
> +}
> +
> +void mv_u3d_phy_shutdown(struct usb_phy *phy)
> +{
> +	struct mv_u3d_phy *mv_u3d_phy;
> +	void __iomem *base;
> +	u32 val;
> +
> +	mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy);
> +	base = mv_u3d_phy->base;
> +
> +	/* Power down Reference Analog current, bit 15
> +	 * Power down PLL, bit 14
> +	 * Power down Receiver, bit 13
> +	 * Power down Transmitter, bit 12
> +	 * of USB3_POWER_PLL_CONTROL register
> +	 */
> +	val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
> +	val &= ~(USB3_POWER_PLL_CONTROL_PU);
> +	mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
> +
> +	if (mv_u3d_phy->clk)
> +		clk_disable(mv_u3d_phy->clk);
> +}
> +
> +static int mv_u3d_phy_init(struct usb_phy *phy)
> +{
> +	struct mv_u3d_phy *mv_u3d_phy;
> +	void __iomem *base;
> +	u32 val, count;
> +
> +	/* enable usb3 phy */
> +	mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy);
> +
> +	if (mv_u3d_phy->clk)
> +		clk_enable(mv_u3d_phy->clk);
> +
> +	base = mv_u3d_phy->base;
> +
> +	val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
> +	val &= ~(USB3_POWER_PLL_CONTROL_PU_MASK);
> +	val |= 0xF << USB3_POWER_PLL_CONTROL_PU_SHIFT;
> +	mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
> +	udelay(100);
> +
> +	mv_u3d_phy_write(base, USB3_RESET_CONTROL,
> +			USB3_RESET_CONTROL_RESET_PIPE);
> +	udelay(100);
> +
> +	mv_u3d_phy_write(base, USB3_RESET_CONTROL,
> +			USB3_RESET_CONTROL_RESET_PIPE
> +			| USB3_RESET_CONTROL_RESET_PHY);
> +	udelay(100);
> +
> +	val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
> +	val &= ~(USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK
> +		| USB3_POWER_PLL_CONTROL_PHY_MODE_MASK);
> +	val |=  (USB3_PLL_25MHZ << USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT)
> +		| (0x5 << USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT);
> +	mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
> +	udelay(100);
> +
> +	mv_u3d_phy_clear(base, USB3_KVCO_CALI_CONTROL,
> +		USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK);
> +	udelay(100);
> +
> +	val = mv_u3d_phy_read(base, USB3_SQUELCH_FFE);
> +	val &= ~(USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK
> +		| USB3_SQUELCH_FFE_FFE_RES_SEL_MASK
> +		| USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK);
> +	val |= ((0xD << USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT)
> +		| (0x7 << USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT)
> +		| (0x8 << USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT));
> +	mv_u3d_phy_write(base, USB3_SQUELCH_FFE, val);
> +	udelay(100);
> +
> +	val = mv_u3d_phy_read(base, USB3_GEN1_SET0);
> +	val &= ~USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK;
> +	val |= 1 << USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT;
> +	mv_u3d_phy_write(base, USB3_GEN1_SET0, val);
> +	udelay(100);
> +
> +	val = mv_u3d_phy_read(base, USB3_GEN2_SET0);
> +	val &= ~(USB3_GEN2_SET0_G2_TX_AMP_MASK
> +		| USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK
> +		| USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK);
> +	val |= ((0x14 << USB3_GEN2_SET0_G2_TX_AMP_SHIFT)
> +		| (1 << USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT)
> +		| (0xA << USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT)
> +		| (1 << USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT));
> +	mv_u3d_phy_write(base, USB3_GEN2_SET0, val);
> +	udelay(100);
> +
> +	mv_u3d_phy_read(base, USB3_TX_EMPPH);
> +	val &= ~(USB3_TX_EMPPH_AMP_MASK
> +		| USB3_TX_EMPPH_EN_MASK
> +		| USB3_TX_EMPPH_AMP_FORCE_MASK
> +		| USB3_TX_EMPPH_PAR1_MASK
> +		| USB3_TX_EMPPH_PAR2_MASK);
> +	val |= ((0xB << USB3_TX_EMPPH_AMP_SHIFT)
> +		| (1 << USB3_TX_EMPPH_EN_SHIFT)
> +		| (1 << USB3_TX_EMPPH_AMP_FORCE_SHIFT)
> +		| (0x1C << USB3_TX_EMPPH_PAR1_SHIFT)
> +		| (1 << USB3_TX_EMPPH_PAR2_SHIFT));
> +
> +	mv_u3d_phy_write(base, USB3_TX_EMPPH, val);
> +	udelay(100);
> +
> +	val = mv_u3d_phy_read(base, USB3_GEN2_SET1);
> +	val &= ~(USB3_GEN2_SET1_G2_RX_SELMUPI_MASK
> +		| USB3_GEN2_SET1_G2_RX_SELMUPF_MASK
> +		| USB3_GEN2_SET1_G2_RX_SELMUFI_MASK
> +		| USB3_GEN2_SET1_G2_RX_SELMUFF_MASK);
> +	val |= ((1 << USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT)
> +		| (1 << USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT)
> +		| (1 << USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT)
> +		| (1 << USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT));
> +	mv_u3d_phy_write(base, USB3_GEN2_SET1, val);
> +	udelay(100);
> +
> +	val = mv_u3d_phy_read(base, USB3_DIGITAL_LOOPBACK_EN);
> +	val &= ~USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK;
> +	val |= 1 << USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT;
> +	mv_u3d_phy_write(base, USB3_DIGITAL_LOOPBACK_EN, val);
> +	udelay(100);
> +
> +	val = mv_u3d_phy_read(base, USB3_IMPEDANCE_TX_SSC);
> +	val &= ~USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK;
> +	val |= 0xC << USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT;
> +	mv_u3d_phy_write(base, USB3_IMPEDANCE_TX_SSC, val);
> +	udelay(100);
> +
> +	val = mv_u3d_phy_read(base, USB3_IMPEDANCE_CALI_CTRL);
> +	val &= ~USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK;
> +	val |= 0x4 << USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT;
> +	mv_u3d_phy_write(base, USB3_IMPEDANCE_CALI_CTRL, val);
> +	udelay(100);
> +
> +	val = mv_u3d_phy_read(base, USB3_PHY_ISOLATION_MODE);
> +	val &= ~(USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK
> +		| USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK
> +		| USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK);
> +	val |= ((1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT)
> +		| (1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT));
> +	mv_u3d_phy_write(base, USB3_PHY_ISOLATION_MODE, val);
> +	udelay(100);
> +
> +	val = mv_u3d_phy_read(base, USB3_TXDETRX);
> +	val &= ~(USB3_TXDETRX_VTHSEL_MASK);
> +	val |= 0x1 << USB3_TXDETRX_VTHSEL_SHIFT;
> +	mv_u3d_phy_write(base, USB3_TXDETRX, val);
> +	udelay(100);
> +
> +	mv_u3d_phy_reg_print(base, USB3_KVCO_CALI_CONTROL);

I'm not sure you really want this constantly on your driver, because it
introduces quite some overhead when you always need to readback the
register before printing. Couldn't you just move this out of the driver
and use perf for that kind of thing ? You could try something like:

# perf probe --add mv_u3d_phy_write addr data
# perf probe --add mv_u3d_phy_read addr data
# perf record -gaR sleep 10 # it will record for 10 seconds
# perf report

I didn't test that, but I think it could work and it wouldn't cause
a lot of overhead in your driver.

> +	pr_debug("%s: start calibration", __func__);

drop all pr_* and convert them in to dev_* you have your dev pointer
saved on your mv_u3d_phy structure.

-- 
balbi

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux