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]

 



Hi Balbi,



> 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.
> 
thanks, I can a try. Here I can remove this print.

>> +    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.
> 
OK, I will.

> -- 
> balbi
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

  Powered by Linux