* Re: [PATCH V2 2/5] phy: phy-exynos-pcie: Add support for Exynos PCIe phy
From: Kishon Vijay Abraham I @ 2017-01-16 8:37 UTC (permalink / raw)
To: Jaehoon Chung, linux-pci
Cc: devicetree, linux-kernel, linux-samsung-soc, bhelgaas, robh+dt,
mark.rutland, kgene, krzk, jingoohan1, vivek.gautam, pankaj.dubey,
alim.akhtar, cpgs
In-Reply-To: <20170104123435.30740-3-jh80.chung@samsung.com>
Hi,
On Wednesday 04 January 2017 06:04 PM, Jaehoon Chung wrote:
> This patch supports to use Generic Phy framework for Exynos PCIe phy.
> When Exynos that supported the pcie want to use the PCIe,
> it needs to control the phy resgister.
> But it should be more complex to control in their own PCIe device drivers.
>
> Currently, there is an exynos5440 case to support the pcie.
> So this driver is based on Exynos5440 PCIe.
> In future, will support the Other exynos SoCs likes exynos5433, exynos7.
please re-write the commit message.
>
> Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
> ---
> Changelog on V2:
> - Not include the codes relevant to pci-exynos.
> - Remove the getting child node.
>
> drivers/phy/Kconfig | 9 ++
> drivers/phy/Makefile | 1 +
> drivers/phy/phy-exynos-pcie.c | 280 ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 290 insertions(+)
> create mode 100644 drivers/phy/phy-exynos-pcie.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index e8eb7f2..2dddef4 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -331,6 +331,15 @@ config PHY_EXYNOS5_USBDRD
> This driver provides PHY interface for USB 3.0 DRD controller
> present on Exynos5 SoC series.
>
> +config PHY_EXYNOS_PCIE
> + bool "Exynos PCIe PHY driver"
> + depends on ARCH_EXYNOS && OF
include COMPILE_TEST
> + depends on PCI_EXYNOS
PCI_EXYNOS should depend on PHY_EXYNOS_PCIE if at all required. Or else do away
with this dependency.
> + select GENERIC_PHY
> + help
> + Enable PCIe PHY support for Exynos SoC series.
> + This driver provides PHY interface for Exynos PCIe controller.
> +
> config PHY_PISTACHIO_USB
> tristate "IMG Pistachio USB2.0 PHY driver"
> depends on MACH_PISTACHIO
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 65eb2f4..081aeb4 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -37,6 +37,7 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o
> phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o
> phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o
> obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o
> +obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o
> obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
> obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
> obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
> diff --git a/drivers/phy/phy-exynos-pcie.c b/drivers/phy/phy-exynos-pcie.c
> new file mode 100644
> index 0000000..b57f49b
> --- /dev/null
> +++ b/drivers/phy/phy-exynos-pcie.c
> @@ -0,0 +1,280 @@
> +/*
> + * Samsung EXYNOS SoC series PCIe PHY driver
> + *
> + * Phy provider for PCIe controller on Exynos SoC series
> + *
> + * Copyright (C) 2016 Samsung Electronics Co., Ltd.
2017?
> + * Jaehoon Chung <jh80.chung@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/phy/phy.h>
> +#include <linux/regmap.h>
> +
> +/* PCIe Purple registers */
> +#define PCIE_PHY_GLOBAL_RESET 0x000
> +#define PCIE_PHY_COMMON_RESET 0x004
> +#define PCIE_PHY_CMN_REG 0x008
> +#define PCIE_PHY_MAC_RESET 0x00c
> +#define PCIE_PHY_PLL_LOCKED 0x010
> +#define PCIE_PHY_TRSVREG_RESET 0x020
> +#define PCIE_PHY_TRSV_RESET 0x024
Please use BIT() macro for bit definitions.
> +
> +/* PCIe PHY registers */
> +#define PCIE_PHY_IMPEDANCE 0x004
> +#define PCIE_PHY_PLL_DIV_0 0x008
> +#define PCIE_PHY_PLL_BIAS 0x00c
> +#define PCIE_PHY_DCC_FEEDBACK 0x014
> +#define PCIE_PHY_PLL_DIV_1 0x05c
> +#define PCIE_PHY_COMMON_POWER 0x064
> +#define PCIE_PHY_COMMON_PD_CMN BIT(3)
> +#define PCIE_PHY_TRSV0_EMP_LVL 0x084
> +#define PCIE_PHY_TRSV0_DRV_LVL 0x088
> +#define PCIE_PHY_TRSV0_RXCDR 0x0ac
> +#define PCIE_PHY_TRSV0_POWER 0x0c4
> +#define PCIE_PHY_TRSV0_PD_TSV BIT(7)
> +#define PCIE_PHY_TRSV0_LVCC 0x0dc
> +#define PCIE_PHY_TRSV1_EMP_LVL 0x144
> +#define PCIE_PHY_TRSV1_RXCDR 0x16c
> +#define PCIE_PHY_TRSV1_POWER 0x184
> +#define PCIE_PHY_TRSV1_PD_TSV BIT(7)
> +#define PCIE_PHY_TRSV1_LVCC 0x19c
> +#define PCIE_PHY_TRSV2_EMP_LVL 0x204
> +#define PCIE_PHY_TRSV2_RXCDR 0x22c
> +#define PCIE_PHY_TRSV2_POWER 0x244
> +#define PCIE_PHY_TRSV2_PD_TSV BIT(7)
> +#define PCIE_PHY_TRSV2_LVCC 0x25c
> +#define PCIE_PHY_TRSV3_EMP_LVL 0x2c4
> +#define PCIE_PHY_TRSV3_RXCDR 0x2ec
> +#define PCIE_PHY_TRSV3_POWER 0x304
> +#define PCIE_PHY_TRSV3_PD_TSV BIT(7)
> +#define PCIE_PHY_TRSV3_LVCC 0x31c
> +
> +struct exynos_pcie_phy_data {
> + struct phy_ops *ops;
> +};
> +
> +/* For Exynos pcie phy */
> +struct exynos_pcie_phy {
> + const struct exynos_pcie_phy_data *drv_data;
> + void __iomem *phy_base;
> + void __iomem *blk_base; /* For exynos5440 */
> +};
> +
> +static void exynos_pcie_phy_writel(void __iomem *base, u32 val, u32 offset)
> +{
> + writel(val, base + offset);
> +}
> +
> +static u32 exynos_pcie_phy_readl(void __iomem *base, u32 offset)
> +{
> + return readl(base + offset);
> +}
> +
> +/* For Exynos5440 specific functions */
> +static int exynos5440_pcie_phy_init(struct phy *phy)
> +{
> + struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
> +
> + /* DCC feedback control off */
> + exynos_pcie_phy_writel(ep->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
> +
> + /* set TX/RX impedance */
> + exynos_pcie_phy_writel(ep->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
> +
> + /* set 50Mhz PHY clock */
> + exynos_pcie_phy_writel(ep->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
> + exynos_pcie_phy_writel(ep->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
> +
> + /* set TX Differential output for lane 0 */
> + exynos_pcie_phy_writel(ep->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
> +
> + /* set TX Pre-emphasis Level Control for lane 0 to minimum */
> + exynos_pcie_phy_writel(ep->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
> +
> + /* set RX clock and data recovery bandwidth */
> + exynos_pcie_phy_writel(ep->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
> + exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
> + exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
> + exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
> + exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
> +
> + /* change TX Pre-emphasis Level Control for lanes */
> + exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
> + exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
> + exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
> + exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
> +
> + /* set LVCC */
> + exynos_pcie_phy_writel(ep->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
> + exynos_pcie_phy_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
> + exynos_pcie_phy_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
> + exynos_pcie_phy_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
I'm starting to dis-like all this hard-coded hw params. All this should come
from dt. Define a dt binding like this for all hw params..
phy,tx-differential = <val, reg-offset, mask>
and have one API in phy-core to do all these settings.
> +
> + /* pulse for common reset */
> + exynos_pcie_phy_writel(ep->blk_base, 1, PCIE_PHY_COMMON_RESET);
> + udelay(500);
how did you get this delay value? Adding a comment might help.
> + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_COMMON_RESET);
> +
> + return 0;
> +}
> +
> +static int exynos5440_pcie_phy_power_on(struct phy *phy)
> +{
> + struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
> + u32 val;
> +
> + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_COMMON_RESET);
> + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_CMN_REG);
> + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_TRSVREG_RESET);
> + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_TRSV_RESET);
> +
> + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
> + val &= ~PCIE_PHY_COMMON_PD_CMN;
> + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
> +
> + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
> + val &= ~PCIE_PHY_TRSV0_PD_TSV;
> + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
> +
> + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
> + val &= ~PCIE_PHY_TRSV1_PD_TSV;
> + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
> +
> + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
> + val &= ~PCIE_PHY_TRSV2_PD_TSV;
> + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
> +
> + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
> + val &= ~PCIE_PHY_TRSV3_PD_TSV;
> + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
> +
> + return 0;
> +}
> +
> +static int exynos5440_pcie_phy_power_off(struct phy *phy)
> +{
> + struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
> + u32 val;
> +
> + while (exynos_pcie_phy_readl(ep->phy_base,
> + PCIE_PHY_PLL_LOCKED) == 0) {
> + val = exynos_pcie_phy_readl(ep->blk_base,
> + PCIE_PHY_PLL_LOCKED);
> + dev_info(&phy->dev, "PLL Locked: 0x%x\n", val);
> + }
> +
> + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
> + val |= PCIE_PHY_COMMON_PD_CMN;
> + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
> +
> + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
> + val |= PCIE_PHY_TRSV0_PD_TSV;
> + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
> +
> + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
> + val |= PCIE_PHY_TRSV1_PD_TSV;
> + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
> +
> + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
> + val |= PCIE_PHY_TRSV2_PD_TSV;
> + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
> +
> + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
> + val |= PCIE_PHY_TRSV3_PD_TSV;
> + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
> +
> + return 0;
> +}
> +
> +static int exynos5440_pcie_phy_reset(struct phy *phy)
> +{
> + struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
> +
> + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_MAC_RESET);
> + exynos_pcie_phy_writel(ep->blk_base, 1, PCIE_PHY_GLOBAL_RESET);
> + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_GLOBAL_RESET);
> +
> + return 0;
> +}
> +
> +static struct phy_ops exynos5440_phy_ops = {
> + .init = exynos5440_pcie_phy_init,
> + .power_on = exynos5440_pcie_phy_power_on,
> + .power_off = exynos5440_pcie_phy_power_off,
> + .reset = exynos5440_pcie_phy_reset,
add .owner
> +};
> +
> +static const struct exynos_pcie_phy_data exynos5440_pcie_phy_data = {
> + .ops = &exynos5440_phy_ops,
why do you need a wrapper for phy_ops?
> +};
> +
> +static const struct of_device_id exynos_pcie_phy_match[] = {
> + {
> + .compatible = "samsung,exynos5440-pcie-phy",
> + .data = &exynos5440_pcie_phy_data,
> + },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, exynos_pcie_phy_match);
> +
> +static int exynos_pcie_phy_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct exynos_pcie_phy *exynos_phy;
> + struct phy *generic_phy;
> + struct phy_provider *phy_provider;
> + struct resource *res;
> + const struct exynos_pcie_phy_data *drv_data;
> +
> + drv_data = of_device_get_match_data(dev);
> + if (!drv_data)
> + return -ENODEV;
> +
> + exynos_phy = devm_kzalloc(dev, sizeof(*exynos_phy), GFP_KERNEL);
> + if (!exynos_phy)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + exynos_phy->phy_base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(exynos_phy->phy_base))
> + return PTR_ERR(exynos_phy->phy_base);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> + exynos_phy->blk_base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(exynos_phy->phy_base))
> + return PTR_ERR(exynos_phy->phy_base);
> +
> + exynos_phy->drv_data = drv_data;
> +
> + generic_phy = devm_phy_create(dev, dev->of_node, drv_data->ops);
> + if (IS_ERR(generic_phy)) {
> + dev_err(dev, "failed to create PHY\n");
> + return PTR_ERR(generic_phy);
> + }
> +
> + phy_set_drvdata(generic_phy, exynos_phy);
> + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> +
> + return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static struct platform_driver exynos_pcie_phy_driver = {
> + .probe = exynos_pcie_phy_probe,
> + .driver = {
> + .of_match_table = exynos_pcie_phy_match,
> + .name = "exynos_pcie_phy",
> + }
> +};
> +module_platform_driver(exynos_pcie_phy_driver);
>
Thanks
Kishon
^ permalink raw reply
* Re: [PATCH V7 1/4] Documentation/devicetree/bindings: b850v3_lvds_dp
From: Peter Senna Tschudin @ 2017-01-16 8:37 UTC (permalink / raw)
To: Laurent Pinchart
Cc: dri-devel, Peter Senna Tschudin, Rob Herring, Mark Rutland,
Daniel Vetter, Peter Senna Tschudin, Takashi Iwai, Yakir Yang,
Jiri Slaby, Martyn Welch, Ian Campbell, Russell King,
Javier Martinez Canillas, Thierry Reding, Guenter Roeck,
martin.donnelly, devicetree@vger.kernel.org, Pawel Moll,
Mauro Carvalho Chehab, enric.balletb
In-Reply-To: <6276161.johxDync2u@avalon>
On Tue, Jan 10, 2017 at 11:04:58PM +0200, Laurent Pinchart wrote:
> Hi Peter,
Laurent!
>
> On Saturday 07 Jan 2017 01:29:52 Peter Senna Tschudin wrote:
> > On 04 January, 2017 21:39 CET, Rob Herring wrote:
> > > On Tue, Jan 3, 2017 at 5:34 PM, Peter Senna Tschudin wrote:
> > >> On 03 January, 2017 23:51 CET, Rob Herring <robh@kernel.org> wrote:
> > >>> On Sun, Jan 01, 2017 at 09:24:29PM +0100, Peter Senna Tschudin wrote:
> > >>>> Devicetree bindings documentation for the GE B850v3 LVDS/DP++
> > >>>> display bridge.
> > >>>>
> > >>>> Cc: Martyn Welch <martyn.welch@collabora.co.uk>
> > >>>> Cc: Martin Donnelly <martin.donnelly@ge.com>
> > >>>> Cc: Javier Martinez Canillas <javier@dowhile0.org>
> > >>>> Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> > >>>> Cc: Philipp Zabel <p.zabel@pengutronix.de>
> > >>>> Cc: Rob Herring <robh@kernel.org>
> > >>>> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > >>>> Signed-off-by: Peter Senna Tschudin <peter.senna@collabora.com>
> > >>>> ---
> > >>>> There was an Acked-by from Rob Herring <robh@kernel.org> for V6, but
> > >>>> I changed the bindings to use i2c_new_secondary_device() so I
> > >>>> removed it from the commit message.
> > >>>>
> > >>>> .../devicetree/bindings/ge/b850v3-lvds-dp.txt | 39 ++++++++++++++
> > >>> Generally, bindings are not organized by vendor. Put in
> > >>> bindings/display/bridge/... instead.
> > >>
> > >> Will change that.
> > >>
> > >>>> 1 file changed, 39 insertions(+)
> > >>>> create mode 100644
> > >>>> Documentation/devicetree/bindings/ge/b850v3-lvds-dp.txt
> > >>>>
> > >>>> diff --git a/Documentation/devicetree/bindings/ge/b850v3-lvds-dp.txt
> > >>>> b/Documentation/devicetree/bindings/ge/b850v3-lvds-dp.txt new file
> > >>>> mode 100644
> > >>>> index 0000000..1bc6ebf
> > >>>> --- /dev/null
> > >>>> +++ b/Documentation/devicetree/bindings/ge/b850v3-lvds-dp.txt
> > >>>> @@ -0,0 +1,39 @@
> > >>>> +Driver for GE B850v3 LVDS/DP++ display bridge
> > >>>> +
> > >>>> +Required properties:
> > >>>> + - compatible : should be "ge,b850v3-lvds-dp".
> > >>>
> > >>> Isn't '-lvds-dp' redundant? The part# should be enough.
> > >>
> > >> b850v3 is the name of the product, this is why the proposed name. What
> > >> about, b850v3-dp2 dp2 indicating the second DP output?
> > >
> > > Humm, b850v3 is the board name? This node should be the name of the bridge
> > > chip.
> >
> > From the cover letter:
> >
> > -- // --
> > There are two physical bridges on the video signal pipeline: a STDP4028(LVDS
> > to DP) and a STDP2690(DP to DP++). The hardware and firmware made it
> > complicated for this binding to comprise two device tree nodes, as the
> > design goal is to configure both bridges based on the LVDS signal, which
> > leave the driver powerless to control the video processing pipeline. The
> > two bridges behaves as a single bridge, and the driver is only needed for
> > telling the host about EDID / HPD, and for giving the host powers to ack
> > interrupts. The video signal pipeline is as follows:
> >
> > Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
> > -- // --
>
> You forgot to prefix your patch series with [HACK] ;-)
>
> How about fixing the issues that make the two DT nodes solution difficult ?
> What are they ?
The Firmware and the hardware design. Both bridges, with stock firmware,
are fully capable of providig EDID information and handling interrupts.
But on this specific design, with this specific firmware, I need to read
EDID from one bridge, and handle interrupts on the other. Back when I
was starting the development I could not come up with a proper way to
split EDID and interrupts between two bridges in a way that would result
in a fully functional connector. Did I miss something?
>
> --
> Regards,
>
> Laurent Pinchart
>
^ permalink raw reply
* [PATCH v3 1/1] iio: adc: tlc4541: add support for TI tlc4541 adc
From: Phil Reid @ 2017-01-16 8:38 UTC (permalink / raw)
To: jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
This adds TI's tlc4541 16-bit ADC driver. Which is a single channel
ADC. Supports raw and trigger buffer access.
Also supports the tlc3541 14-bit device, which has not been tested.
Implementation of the tlc3541 is fairly straight forward thou.
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Phil Reid <preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
---
Notes:
Changes from v2:
- Fix paste error in binding document.
- Remove index from channel description. Note this break libiio.
libiio will no longer recognise that the cahnnel is buffer enabled.
- Add brackets to macro parameter bitshift
- Make tcl3541 / tcl4541 order in code consistent.
- Use spi_message_init_with_transfers
- Cleanup whitespace lines
- Add TLC3541 to kconfig description
- Add Robs Ack.
Changes from v1:
- Add tlc3541 support and chan spec.
- remove fields that where already 0 from TLC4541_V_CHAN macro
- Increase rx_buf size in tlc4541_state to avoid copy in tlc4541_trigger_handle
- Remove erroneous be16_to_cpu in tlc4541_trigger_handle
- Docs/binding: spi -> SPI & add ti,tlc3541
.../devicetree/bindings/iio/adc/ti-tlc4541.txt | 17 ++
drivers/iio/adc/Kconfig | 12 +
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/ti-tlc4541.c | 271 +++++++++++++++++++++
4 files changed, 301 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/adc/ti-tlc4541.txt
create mode 100644 drivers/iio/adc/ti-tlc4541.c
diff --git a/Documentation/devicetree/bindings/iio/adc/ti-tlc4541.txt b/Documentation/devicetree/bindings/iio/adc/ti-tlc4541.txt
new file mode 100644
index 0000000..6b26927
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ti-tlc4541.txt
@@ -0,0 +1,17 @@
+* Texas Instruments' TLC4541
+
+Required properties:
+ - compatible: Should be one of
+ * "ti,tlc4541"
+ * "ti,tlc3541"
+ - reg: SPI chip select number for the device
+ - vref-supply: The regulator supply for ADC reference voltage
+ - spi-max-frequency: Max SPI frequency to use (<= 200000)
+
+Example:
+adc@0 {
+ compatible = "ti,tlc4541";
+ reg = <0>;
+ vref-supply = <&vdd_supply>;
+ spi-max-frequency = <200000>;
+};
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 99c0514..fb9ede7 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -525,6 +525,18 @@ config TI_AM335X_ADC
To compile this driver as a module, choose M here: the module will be
called ti_am335x_adc.
+config TI_TLC4541
+ tristate "Texas Instruments TLC4541 ADC driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Texas Instruments TLC4541 / TLC3541
+ ADC chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-tlc4541.
+
config TWL4030_MADC
tristate "TWL4030 MADC (Monitoring A/D Converter)"
depends on TWL4030_CORE
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 7a40c04..9bf2377 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
+obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c
new file mode 100644
index 0000000..78d91a0
--- /dev/null
+++ b/drivers/iio/adc/ti-tlc4541.c
@@ -0,0 +1,271 @@
+/*
+ * TI tlc4541 ADC Driver
+ *
+ * Copyright (C) 2017 Phil Reid
+ *
+ * Datasheets can be found here:
+ * http://www.ti.com/lit/gpn/tlc3541
+ * http://www.ti.com/lit/gpn/tlc4541
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The tlc4541 requires 24 clock cycles to start a transfer.
+ * Conversion then takes 2.94us to complete before data is ready
+ * Data is returned MSB first.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+
+struct tlc4541_state {
+ struct spi_device *spi;
+ struct regulator *reg;
+ struct spi_transfer scan_single_xfer[3];
+ struct spi_message scan_single_msg;
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ * 2 bytes data + 6 bytes padding + 8 bytes timestamp when
+ * call iio_push_to_buffers_with_timestamp.
+ */
+ __be16 rx_buf[8] ____cacheline_aligned;
+};
+
+struct tlc4541_chip_info {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+enum tlc4541_id {
+ TLC3541,
+ TLC4541,
+};
+
+#define TLC4541_V_CHAN(bits, bitshift) { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = (bitshift), \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define DECLARE_TLC4541_CHANNELS(name, bits, bitshift) \
+const struct iio_chan_spec name ## _channels[] = { \
+ TLC4541_V_CHAN(bits, bitshift), \
+ IIO_CHAN_SOFT_TIMESTAMP(1), \
+}
+
+static DECLARE_TLC4541_CHANNELS(tlc3541, 14, 2);
+static DECLARE_TLC4541_CHANNELS(tlc4541, 16, 0);
+
+static const struct tlc4541_chip_info tlc4541_chip_info[] = {
+ [TLC3541] = {
+ .channels = tlc3541_channels,
+ .num_channels = ARRAY_SIZE(tlc3541_channels),
+ },
+ [TLC4541] = {
+ .channels = tlc4541_channels,
+ .num_channels = ARRAY_SIZE(tlc4541_channels),
+ },
+};
+
+static irqreturn_t tlc4541_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct tlc4541_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = spi_sync(st->spi, &st->scan_single_msg);
+ if (ret < 0)
+ goto done;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
+ iio_get_time_ns(indio_dev));
+
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+static int tlc4541_get_range(struct tlc4541_state *st)
+{
+ int vref;
+
+ vref = regulator_get_voltage(st->reg);
+ if (vref < 0)
+ return vref;
+
+ vref /= 1000;
+
+ return vref;
+}
+
+static int tlc4541_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long m)
+{
+ int ret = 0;
+ struct tlc4541_state *st = iio_priv(indio_dev);
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+ ret = spi_sync(st->spi, &st->scan_single_msg);
+ iio_device_release_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+ *val = be16_to_cpu(st->rx_buf[0]);
+ *val = *val >> chan->scan_type.shift;
+ *val &= GENMASK(chan->scan_type.realbits - 1, 0);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ ret = tlc4541_get_range(st);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
+ return -EINVAL;
+}
+
+static const struct iio_info tlc4541_info = {
+ .read_raw = &tlc4541_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int tlc4541_probe(struct spi_device *spi)
+{
+ struct tlc4541_state *st;
+ struct iio_dev *indio_dev;
+ const struct tlc4541_chip_info *info;
+ int ret;
+ int8_t device_init = 0;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ spi_set_drvdata(spi, indio_dev);
+
+ st->spi = spi;
+
+ info = &tlc4541_chip_info[spi_get_device_id(spi)->driver_data];
+
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = info->channels;
+ indio_dev->num_channels = info->num_channels;
+ indio_dev->info = &tlc4541_info;
+
+ /* perform reset */
+ spi_write(spi, &device_init, 1);
+
+ /* Setup default message */
+ st->scan_single_xfer[0].rx_buf = &st->rx_buf[0];
+ st->scan_single_xfer[0].len = 3;
+ st->scan_single_xfer[1].delay_usecs = 3;
+ st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
+ st->scan_single_xfer[2].len = 2;
+
+ spi_message_init_with_transfers(&st->scan_single_msg,
+ st->scan_single_xfer, 3);
+
+ st->reg = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
+
+ ret = regulator_enable(st->reg);
+ if (ret)
+ return ret;
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ &tlc4541_trigger_handler, NULL);
+ if (ret)
+ goto error_disable_reg;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_cleanup_buffer;
+
+ return 0;
+
+error_cleanup_buffer:
+ iio_triggered_buffer_cleanup(indio_dev);
+error_disable_reg:
+ regulator_disable(st->reg);
+
+ return ret;
+}
+
+static int tlc4541_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct tlc4541_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ regulator_disable(st->reg);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id tlc4541_dt_ids[] = {
+ { .compatible = "ti,tlc3541", },
+ { .compatible = "ti,tlc4541", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tlc4541_dt_ids);
+#endif
+
+static const struct spi_device_id tlc4541_id[] = {
+ {"tlc3541", TLC3541},
+ {"tlc4541", TLC4541},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, tlc4541_id);
+
+static struct spi_driver tlc4541_driver = {
+ .driver = {
+ .name = "tlc4541",
+ .of_match_table = of_match_ptr(tlc4541_dt_ids),
+ },
+ .probe = tlc4541_probe,
+ .remove = tlc4541_remove,
+ .id_table = tlc4541_id,
+};
+module_spi_driver(tlc4541_driver);
+
+MODULE_AUTHOR("Phil Reid <preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>");
+MODULE_DESCRIPTION("Texas Instruments TLC4541 ADC");
+MODULE_LICENSE("GPL v2");
--
1.8.3.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v1 2/2] arm: dts: mt2701: add nor flash node
From: Boris Brezillon @ 2017-01-16 8:40 UTC (permalink / raw)
To: Marek Vasut, Rob Herring, Mark Rutland
Cc: Matthias Brugger, Guochun Mao, David Woodhouse, Brian Norris,
Richard Weinberger, Cyrille Pitchen, Russell King,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <e7fa1542-f0e2-0e45-23b3-25d6491ae40d-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Sun, 15 Jan 2017 01:23:48 +0100
Marek Vasut <marek.vasut-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On 01/14/2017 09:29 AM, Boris Brezillon wrote:
> > On Fri, 13 Jan 2017 18:33:40 +0100
> > Marek Vasut <marek.vasut-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> >
> >> On 01/13/2017 05:56 PM, Boris Brezillon wrote:
> >>> On Fri, 13 Jan 2017 17:44:12 +0100
> >>> Marek Vasut <marek.vasut-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> >>>
> >>>> On 01/13/2017 05:28 PM, Boris Brezillon wrote:
> >>>>> On Fri, 13 Jan 2017 17:13:55 +0100
> >>>>> Marek Vasut <marek.vasut-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> >>>>>
> >>>>>> On 01/13/2017 04:12 PM, Matthias Brugger wrote:
> >>>>>>>
> >>>>>>>
> >>>>>>> On 13/01/17 15:17, Boris Brezillon wrote:
> >>>>>>>> On Fri, 13 Jan 2017 15:13:29 +0800
> >>>>>>>> Guochun Mao <guochun.mao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org> wrote:
> >>>>>>>>
> >>>>>>>>> Add Mediatek nor flash node.
> >>>>>>>>>
> >>>>>>>>> Signed-off-by: Guochun Mao <guochun.mao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> >>>>>>>>> ---
> >>>>>>>>> arch/arm/boot/dts/mt2701-evb.dts | 25 +++++++++++++++++++++++++
> >>>>>>>>> arch/arm/boot/dts/mt2701.dtsi | 12 ++++++++++++
> >>>>>>>>> 2 files changed, 37 insertions(+)
> >>>>>>>>>
> >>>>>>>>> diff --git a/arch/arm/boot/dts/mt2701-evb.dts
> >>>>>>>>> b/arch/arm/boot/dts/mt2701-evb.dts
> >>>>>>>>> index 082ca88..85e5ae8 100644
> >>>>>>>>> --- a/arch/arm/boot/dts/mt2701-evb.dts
> >>>>>>>>> +++ b/arch/arm/boot/dts/mt2701-evb.dts
> >>>>>>>>> @@ -24,6 +24,31 @@
> >>>>>>>>> };
> >>>>>>>>> };
> >>>>>>>>>
> >>>>>>>>> +&nor_flash {
> >>>>>>>>> + pinctrl-names = "default";
> >>>>>>>>> + pinctrl-0 = <&nor_pins_default>;
> >>>>>>>>> + status = "okay";
> >>>>>>>>> + flash@0 {
> >>>>>>>>> + compatible = "jedec,spi-nor";
> >>>>>>>>> + reg = <0>;
> >>>>>>>>> + };
> >>>>>>>>> +};
> >>>>>>>>> +
> >>>>>>>>> +&pio {
> >>>>>>>>> + nor_pins_default: nor {
> >>>>>>>>> + pins1 {
> >>>>>>>>> + pinmux = <MT2701_PIN_240_EXT_XCS__FUNC_EXT_XCS>,
> >>>>>>>>> + <MT2701_PIN_241_EXT_SCK__FUNC_EXT_SCK>,
> >>>>>>>>> + <MT2701_PIN_239_EXT_SDIO0__FUNC_EXT_SDIO0>,
> >>>>>>>>> + <MT2701_PIN_238_EXT_SDIO1__FUNC_EXT_SDIO1>,
> >>>>>>>>> + <MT2701_PIN_237_EXT_SDIO2__FUNC_EXT_SDIO2>,
> >>>>>>>>> + <MT2701_PIN_236_EXT_SDIO3__FUNC_EXT_SDIO3>;
> >>>>>>>>> + drive-strength = <MTK_DRIVE_4mA>;
> >>>>>>>>> + bias-pull-up;
> >>>>>>>>> + };
> >>>>>>>>> + };
> >>>>>>>>> +};
> >>>>>>>>> +
> >>>>>>>>> &uart0 {
> >>>>>>>>> status = "okay";
> >>>>>>>>> };
> >>>>>>>>> diff --git a/arch/arm/boot/dts/mt2701.dtsi
> >>>>>>>>> b/arch/arm/boot/dts/mt2701.dtsi
> >>>>>>>>> index bdf8954..1eefce4 100644
> >>>>>>>>> --- a/arch/arm/boot/dts/mt2701.dtsi
> >>>>>>>>> +++ b/arch/arm/boot/dts/mt2701.dtsi
> >>>>>>>>> @@ -227,6 +227,18 @@
> >>>>>>>>> status = "disabled";
> >>>>>>>>> };
> >>>>>>>>>
> >>>>>>>>> + nor_flash: spi@11014000 {
> >>>>>>>>> + compatible = "mediatek,mt2701-nor",
> >>>>>>>>> + "mediatek,mt8173-nor";
> >>>>>>>>
> >>>>>>>> Why define both here? Is "mediatek,mt8173-nor" really providing a
> >>>>>>>> subset of the features supported by "mediatek,mt2701-nor"?
> >>>>>>>>
> >>>>>>>
> >>>>>>> I think even if the ip block is the same, we should provide both
> >>>>>>> bindings, just in case in the future we find out that mt2701 has some
> >>>>>>> hidden bug, feature or bug-feature. This way even if we update the
> >>>>>>> driver, we stay compatible with older device tree blobs in the wild.
> >>>>>>>
> >>>>>>> We can drop the mt2701-nor in the bindings definition if you want.
> >>>>>
> >>>>> Oh, sorry, I misunderstood. What I meant is that if you want to
> >>>>> list/support all possible compatibles, maybe you should just put one
> >>>>> compatible in your DT and patch your driver (+ binding doc) to define
> >>>>> all of them.
> >>>>
> >>>> Uh, what ? I lost you here :-)
> >
> > I mean adding a new entry in the mtk_nor_of_ids table (in
> > mtk-quadspi.c) so that the mediatek,mt2701-nor compatible string can be
> > matched directly, and you won't need to define 2 compatible strings in
> > your device tree.
>
> But then you grow the table in the driver, is that what we want if we
> can avoid that ?
The space you save by not growing the mtk_nor_of_ids table is lost in
your dtbs, so I'm not sure the size argument is relevant here. Also,
note that distros are shipping a lot of dtbs, and you're likely to have
several boards based on the mt2701 SoC, so, for this specific use case,
it's better to make the in-driver of-id table grow than specifying 2
compatibles in the DT. But as I said, I'm not sure we should rely on
this argument to decide which approach to choose (we're talking about a
few bytes here).
>
> >>>>
> >>>>>> This exactly. We should have a DT compat in the form:
> >>>>>> compatible = "vendor,<soc>-block", "vendor,<oldest-compat-soc>-block";
> >>>>>> Then if we find a problem in the future, we can match on the
> >>>>>> "vendor,<soc>-block" and still support the old DTs.
> >>>>>
> >>>>> Not sure it's only in term of whose IP appeared first. My understanding
> >>>>> is that it's a way to provide inheritance. For example:
> >>>>>
> >>>>> "<soc-vendor>,<ip-version>", "<ip-vendor>,<ip-version>";
> >>>>>
> >>>>> or
> >>>>>
> >>>>> "<soc-vendor>,<full-featured-ip-version>","<soc-vendor>,<basic-feature-ip-version>";
> >>>>>
> >>>>> BTW, which one is the oldest between mt8173 and mt2701? :-)
> >>>>
> >>>> And that's another thing and I agree with you, but I don't think that's
> >>>> what we're discussing in this thread. But (!), OT, I think we should
> >>>> codify the rules in Documentation/ . This discussion came up multiple
> >>>> times recently.
> >>>>
> >>>> And my question still stands, what do we put into the DT here, IMO
> >>>> compatible = "mediatek,mt2701-nor", "mediatek,mt8173-nor";
> >>>
> >>> I'd say
> >>>
> >>> compatible = "mediatek,mt8173-nor";
> >>>
> >>> because both compatible are referring to very specific IP version. It's
> >>> not the same as
> >>
> >> But then you don't have the ability to handle a block in this particular
> >> SoC in case there's a bug found in it in the future,
> >> so IMO it should be:
> >>
> >> compatible = "mediatek,mt2701-nor", "mediatek,mt8173-nor";
> >
> > Sorry again, I meant
> >
> > compatible = "mediatek,mt2701-nor";
> >
> >>
> >>> compatible = "mediatek,mt8173-nor", "mediatek,mt81xx-nor";
> >>
> >> This doesn't look right, since here we add two new compatibles ...
> >
> > That was just an example to describe how compatible inheritance works
> > (at least that's my understanding of it), it does not apply to this
> > particular use case.
>
> Well this is OK I guess, but then you can also use "mediatek,mt8173-nor"
> as the oldest supported compatible and be done with it, no ? It looks a
> bit crappy though, I admit that ...
>
Let's stop bikeshedding and wait for DT maintainers feedback
before taking a decision ;-).
Rob, Mark, any opinion?
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 2/4] phy: qcom-qusb2: New driver for QUSB2 PHY on Qcom chips
From: Kishon Vijay Abraham I @ 2017-01-16 8:45 UTC (permalink / raw)
To: Vivek Gautam, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: mark.rutland-5wv7dgnIgG8, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
bjorn.andersson-QSEj5FYQhm4dnm+yROfE0A,
srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1484045519-19030-3-git-send-email-vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Hi,
On Tuesday 10 January 2017 04:21 PM, Vivek Gautam wrote:
> PHY transceiver driver for QUSB2 phy controller that provides
> HighSpeed functionality for DWC3 controller present on
> Qualcomm chipsets.
>
> Signed-off-by: Vivek Gautam <vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> Reviewed-by: Stephen Boyd <sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
>
> Changes since v3:
> - Added 'Reviewed-by' from Stephen.
> - Fixed debug message for qusb2_phy_set_tune2_param().
> - Replaced devm_reset_control_get() with devm_reset_control_get_by_index()
> since we are requesting only one reset.
> - Updated devm_nvmem_cell_get() with a NULL cell id.
> - Made error labels more idiomatic.
> - Refactored qusb2_setbits() and qusb2_clrbits() a little bit to accept
> base address and register offset as two separate arguments.
>
> Changes since v2:
> - Removed selecting 'RESET_CONTROLLER' config.
> - Added error handling for clk_prepare_enable paths.
> - Removed explicitly setting ref_clk rate to 19.2 MHz. Don't need to
> do that since 'xo' is modeled as parent to this clock.
> - Removed 'ref_clk_src' handling. Driver doesn't need to request and
> handle this clock.
> - Moved nvmem_cell_get() to probe function.
> - Simplified phy pll status handling.
> - Using of_device_get_match_data() to get match data.
> - Uniformly using lowercase for hex numbers.
> - Fixed sparse warnings.
> - Using shorter variable names in structure and in functions.
> - Handling various comment style shortcomings.
>
> Changes since v1:
> - removed reference to clk_enabled/pwr_enabled.
> - moved clock and regulator enable code to phy_power_on/off() callbacks.
> - fixed return on EPROBE_DEFER in qusb2_phy_probe().
> - fixed phy create and phy register ordering.
> - removed references to non-lkml links from commit message.
> - took care of other minor nits.
> - Fixed coccinelle warnings -
> 'PTR_ERR applied after initialization to constant'
> - Addressed review comment, regarding qfprom access for tune2 param value.
> This driver is now based on qfprom patch[1] that allows byte access now.
>
> drivers/phy/Kconfig | 10 +
> drivers/phy/Makefile | 1 +
> drivers/phy/phy-qcom-qusb2.c | 539 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 550 insertions(+)
> create mode 100644 drivers/phy/phy-qcom-qusb2.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index e8eb7f225a88..0ed53d018b23 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -430,6 +430,16 @@ config PHY_STIH407_USB
> Enable this support to enable the picoPHY device used by USB2
> and USB3 controllers on STMicroelectronics STiH407 SoC families.
>
> +config PHY_QCOM_QUSB2
> + tristate "Qualcomm QUSB2 PHY Driver"
> + depends on OF && (ARCH_QCOM || COMPILE_TEST)
> + select GENERIC_PHY
> + help
> + Enable this to support the HighSpeed QUSB2 PHY transceiver for USB
> + controllers on Qualcomm chips. This driver supports the high-speed
> + PHY which is usually paired with either the ChipIdea or Synopsys DWC3
> + USB IPs on MSM SOCs.
> +
> config PHY_QCOM_UFS
> tristate "Qualcomm UFS PHY driver"
> depends on OF && ARCH_QCOM
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 65eb2f436a41..dad1682b80e3 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -49,6 +49,7 @@ obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
> obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
> obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
> obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
> +obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
> obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
> obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
> obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
> diff --git a/drivers/phy/phy-qcom-qusb2.c b/drivers/phy/phy-qcom-qusb2.c
> new file mode 100644
> index 000000000000..c69118610164
> --- /dev/null
> +++ b/drivers/phy/phy-qcom-qusb2.c
> @@ -0,0 +1,539 @@
> +/*
> + * Copyright (c) 2016, The Linux Foundation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +
> +#define QUSB2PHY_PLL_TEST 0x04
> +#define CLK_REF_SEL BIT(7)
> +
> +#define QUSB2PHY_PLL_TUNE 0x08
> +#define QUSB2PHY_PLL_USER_CTL1 0x0c
> +#define QUSB2PHY_PLL_USER_CTL2 0x10
> +#define QUSB2PHY_PLL_AUTOPGM_CTL1 0x1c
> +#define QUSB2PHY_PLL_PWR_CTRL 0x18
> +
> +#define QUSB2PHY_PLL_STATUS 0x38
> +#define PLL_LOCKED BIT(5)
> +
> +#define QUSB2PHY_PORT_TUNE1 0x80
> +#define QUSB2PHY_PORT_TUNE2 0x84
> +#define QUSB2PHY_PORT_TUNE3 0x88
> +#define QUSB2PHY_PORT_TUNE4 0x8c
> +#define QUSB2PHY_PORT_TUNE5 0x90
> +#define QUSB2PHY_PORT_TEST2 0x9c
> +
> +#define QUSB2PHY_PORT_POWERDOWN 0xb4
> +#define CLAMP_N_EN BIT(5)
> +#define FREEZIO_N BIT(1)
> +#define POWER_DOWN BIT(0)
> +
> +#define QUSB2PHY_REFCLK_ENABLE BIT(0)
> +
> +#define PHY_CLK_SCHEME_SEL BIT(0)
> +
> +struct qusb2_phy_init_tbl {
> + unsigned int offset;
> + unsigned int val;
> +};
> +#define QUSB2_PHY_INIT_CFG(o, v) \
> + { \
> + .offset = o, \
> + .val = v, \
> + }
> +
> +static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
> + QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE1, 0xf8),
> + QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE2, 0xb3),
> + QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE3, 0x83),
> + QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE4, 0xc0),
> + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
> + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
> + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
> + QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TEST2, 0x14),
> + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
> + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
> +};
I wish all this data comes from device tree and one API in phy-core can do all
these settings. Your other driver qcom-qmp also seems to have a bunch of
similar settings.
The problem is every vnedor driver adds a bunch of code to perform the same
thing again and again when all of these settings can be done by a single phy API.
Thanks
Kishon
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 3/4] dt-bindings: phy: Add support for QMP phy
From: Kishon Vijay Abraham I @ 2017-01-16 8:49 UTC (permalink / raw)
To: Vivek Gautam, robh+dt, linux-kernel, devicetree
Cc: mark.rutland, sboyd, bjorn.andersson, srinivas.kandagatla,
linux-arm-msm
In-Reply-To: <1484045519-19030-4-git-send-email-vivek.gautam@codeaurora.org>
Hi,
On Tuesday 10 January 2017 04:21 PM, Vivek Gautam wrote:
> Qualcomm chipsets have QMP phy controller that provides
> support to a number of controller, viz. PCIe, UFS, and USB.
> Adding dt binding information for the same.
>
> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
> Acked-by: Rob Herring <robh@kernel.org>
> ---
>
> Changes since v3:
> - Added #clock-cells = <1>, indicating that phy is a clock provider.
>
> Changes since v2:
> - Removed binding for "ref_clk_src" since we don't request this
> clock in the driver.
> - Addressed s/ref_clk/ref. Don't need to add '_clk' suffix to clock names.
> - Using 'phy' for the node name.
>
> Changes since v1:
> - New patch, forked out of the original driver patch:
> "phy: qcom-qmp: new qmp phy driver for qcom-chipsets"
> - Added 'Acked-by' from Rob.
> - Updated bindings to include mem resource as a list of
> offset - length pair for serdes block and for each lane.
> - Added a new binding for 'lane-offsets' that contains offsets
> to tx, rx and pcs blocks from each lane base address.
>
> .../devicetree/bindings/phy/qcom-qmp-phy.txt | 76 ++++++++++++++++++++++
> 1 file changed, 76 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
>
> diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
> new file mode 100644
> index 000000000000..6f510fe48f46
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
> @@ -0,0 +1,76 @@
> +Qualcomm QMP PHY controller
> +===========================
> +
> +QMP phy controller supports physical layer functionality for a number of
> +controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
> +
> +Required properties:
> + - compatible: compatible list, contains:
> + "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
> + "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996.
> + - reg: list of offset and length pair of the PHY register sets.
> + at index 0: offset and length of register set for PHY common
> + serdes block.
> + from index 1 - N: offset and length of register set for each lane,
> + for N number of phy lanes (ports).
> + - lane-offsets: array of offsets to tx, rx and pcs blocks for phy lanes.
> + - #phy-cells: must be 1
> + - Cell after phy phandle should be the port (lane) number.
> + - #clock-cells: must be 1
> + - Phy pll outputs a bunch of clocks for Tx, Rx and Pipe
> + interface (for pipe based PHYs). These clock are then gate-controlled
> + by gcc.
> + - clocks: a list of phandles and clock-specifier pairs,
> + one for each entry in clock-names.
> + - clock-names: must be "cfg_ahb" for phy config clock,
> + "aux" for phy aux clock,
> + "ref" for 19.2 MHz ref clk,
> + "pipe<port-number>" for pipe clock specific to
> + each port/lane (Optional).
> + - resets: a list of phandles and reset controller specifier pairs,
> + one for each entry in reset-names.
> + - reset-names: must be "phy" for reset of phy block,
> + "common" for phy common block reset,
> + "cfg" for phy's ahb cfg block reset (Optional).
> + "port<port-number>" for reset specific to
> + each port/lane (Optional).
> + - vdda-phy-supply: Phandle to a regulator supply to PHY core block.
> + - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
> +
> +Optional properties:
> + - vddp-ref-clk-supply: Phandle to a regulator supply to any specific refclk
> + pll block.
> +
> +Example:
> + pcie_phy: phy@34000 {
> + compatible = "qcom,msm8996-qmp-pcie-phy";
> + reg = <0x034000 0x48f>,
> + <0x035000 0x5bf>,
> + <0x036000 0x5bf>,
> + <0x037000 0x5bf>;
> + /* tx, rx, pcs */
> + lane-offsets = <0x0 0x200 0x400>;
> + #phy-cells = <1>;
> + #clock-cells = <1>;
> +
> + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>,
> + <&gcc GCC_PCIE_PHY_CFG_AHB_CLK>,
> + <&gcc GCC_PCIE_CLKREF_CLK>,
> + <&gcc GCC_PCIE_0_PIPE_CLK>,
> + <&gcc GCC_PCIE_1_PIPE_CLK>,
> + <&gcc GCC_PCIE_2_PIPE_CLK>;
> + clock-names = "aux", "cfg_ahb", "ref",
> + "pipe0", "pipe1", "pipe2";
> +
> + vdda-phy-supply = <&pm8994_l28>;
> + vdda-pll-supply = <&pm8994_l12>;
> +
> + resets = <&gcc GCC_PCIE_PHY_BCR>,
> + <&gcc GCC_PCIE_PHY_COM_BCR>,
> + <&gcc GCC_PCIE_PHY_COM_NOCSR_BCR>,
> + <&gcc GCC_PCIE_0_PHY_BCR>,
> + <&gcc GCC_PCIE_1_PHY_BCR>,
> + <&gcc GCC_PCIE_2_PHY_BCR>;
> + reset-names = "phy", "common", "cfg",
> + "lane0", "lane1", "lane2";
Each lane has a separate clock, separate reset.. why not create sub-nodes for
each lane?
Thanks
Kishon
^ permalink raw reply
* RE: [PATCH v3 2/3] USB3/DWC3: Add property "snps, incr-burst-type-adjustment" for INCR burst type
From: Felipe Balbi @ 2017-01-16 8:50 UTC (permalink / raw)
To: Jerry Huang, Rob Herring
Cc: mark.rutland@arm.com, catalin.marinas@arm.com,
will.deacon@arm.com, linux@armlinux.org.uk,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <DB5PR0401MB18132BB4CDE32EEA8F479E55FE7D0@DB5PR0401MB1813.eurprd04.prod.outlook.com>
[-- Attachment #1: Type: text/plain, Size: 4776 bytes --]
Hi,
Jerry Huang <jerry.huang@nxp.com> writes:
>> > On Thu, Dec 22, 2016 at 8:52 PM, Jerry Huang <jerry.huang@nxp.com>
>> wrote:
>> > > Hi, Rob,
>> > >> -----Original Message-----
>> > >> From: Rob Herring [mailto:robh@kernel.org]
>> > >> Sent: Friday, December 23, 2016 2:45 AM
>> > >> To: Jerry Huang <jerry.huang@nxp.com>
>> > >> Cc: balbi@kernel.org; mark.rutland@arm.com;
>> > >> catalin.marinas@arm.com; will.deacon@arm.com;
>> > >> linux@armlinux.org.uk; devicetree@vger.kernel.org;
>> > >> linux-usb@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-
>> > >> kernel@lists.infradead.org
>> > >> Subject: Re: [PATCH v3 2/3] USB3/DWC3: Add property "snps,
>> > >> incr-burst- type-adjustment" for INCR burst type
>> > >>
>> > >> On Mon, Dec 19, 2016 at 05:25:53PM +0800, Changming Huang wrote:
>> > >> > New property "snps,incr-burst-type-adjustment = <x>, <y>" for
>> > >> > USB3.0
>> > >> DWC3.
>> > >> > Field "x": 1/0 - undefined length INCR burst type enable or not;
>> > >> > Field
>> > >> > "y": INCR4/INCR8/INCR16/INCR32/INCR64/INCR128/INCR256 burst
>> type.
>> > >> >
>> > >> > While enabling undefined length INCR burst type and INCR16 burst
>> > >> > type, get better write performance on NXP Layerscape platform:
>> > >> > around 3% improvement (from 364MB/s to 375MB/s).
>> > >> >
>> > >> > Signed-off-by: Changming Huang <jerry.huang@nxp.com>
>> > >> > ---
>> > >> > Changes in v3:
>> > >> > - add new property for INCR burst in usb node.
>> > >> >
>> > >> > Documentation/devicetree/bindings/usb/dwc3.txt | 5 +++++
>> > >> > arch/arm/boot/dts/ls1021a.dtsi | 1 +
>> > >> > arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++
>> > >> > arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 2 ++
>> > >> > 4 files changed, 11 insertions(+)
>> > >> >
>> > >> > diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt
>> > >> > b/Documentation/devicetree/bindings/usb/dwc3.txt
>> > >> > index e3e6983..8c405a3 100644
>> > >> > --- a/Documentation/devicetree/bindings/usb/dwc3.txt
>> > >> > +++ b/Documentation/devicetree/bindings/usb/dwc3.txt
>> > >> > @@ -55,6 +55,10 @@ Optional properties:
>> > >> > fladj_30mhz_sdbnd signal is invalid or incorrect.
>> > >> >
>> > >> > - <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to
>> > >> > be
>> > >> reallocated.
>> > >> > + - snps,incr-burst-type-adjustment: Value for INCR burst type of
>> > >> GSBUSCFG0
>> > >> > + register, undefined length INCR burst type enable and INCRx type.
>> > >> > + First field is for undefined length INCR burst type enable or not.
>> > >> > + Second field is for largest INCRx type enabled.
>> > >>
>> > >> Why do you need the first field? Is the 2nd field used if the 1st is 0?
>> > >> If not, then just use the presence of the property to enable or not.
>> > > The first field is one switch.
>> > > When it is 1, means undefined length INCR burst type enabled, we can
>> > > use
>> > any length less than or equal to the largest-enabled burst length of
>> > INCR4/8/16/32/64/128/256.
>> > > When it is zero, means INCRx burst mode enabled, we can use one
>> > > fixed
>> > burst length of 1/4/8/16/32/64/128/256 byte.
>> > > So, the 2nd field is used if the 1st is 0, we need to select one
>> > > largest burst
>> > length the USB controller can support.
>> > > If we don't want to change the value of this register (use the
>> > > default value),
>> > we don't need to add this property to usb node.
>> >
>> > Just make this a single value with 0 meaning INCR and 4/8/16/etc being
>> INCRx.
>> Maybe, I didn't describe it clearly.
>> According to DWC3 spec, the value "0" of field INCRBrstEna means INCRx
>> burst mode, 1 means INCR burst mode.
>> Regardless of the value of INCRBrstEna [bit0], we need to modify the other
>> field bit[1,2,3,4,5,6,7] to one INCR burst type for the platform supported.
>> Ad you mentioned, if we just use a single value with 0 meaning INCR and
>> 4/8/16/etc being INCRx.
>> I understand totally that when it is none-zero, we can use it for INCR burst
>> mode.
>> Then, when it is 0, how to select the INCRx value?
>>
>> So, I think we still need two vaue to specify INCRBrstEna and INCRx burst
>> type.
> Hi, Balbi,
> It seems there is no feedback for my comment, so these patches can be accepted?
probably not, we need to really understand what information we need so
it can be described properly. The last thing we want is unnecessary DT
properties.
It seems to me that we can extrapolate INCRBrstEna based on which burst
modes are enabled. If only 0 is passed, then that bit should be 1, if 0
and any other size is passed, then that bit should be 0, no?
--
balbi
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply
* Re: [v2 2/3] ARM: dts: STM32 Add USB FS host mode support
From: Alexandre Torgue @ 2017-01-16 8:57 UTC (permalink / raw)
To: Bruno Herrera, Rob Herring, Mark Rutland, Maxime Coquelin
Cc: devicetree, Russell King, linux-arm-kernel, linux-kernel
In-Reply-To: <20170116020958.62767-2-bruherrera@gmail.com>
Hi Bruno,
On 01/16/2017 03:09 AM, Bruno Herrera wrote:
> This patch adds the USB pins and nodes for USB HS/FS cores working at FS speed,
> using embedded PHY.
>
> Signed-off-by: Bruno Herrera <bruherrera@gmail.com>
Sorry, but what is patch 1 & pacth 3 status ?
For this one, can split it in 3 patches (one patch for SOC and one for
each board) please.
> ---
> arch/arm/boot/dts/stm32f429-disco.dts | 30 ++++++++++++++++++++++++++++++
> arch/arm/boot/dts/stm32f429.dtsi | 35 ++++++++++++++++++++++++++++++++++-
> arch/arm/boot/dts/stm32f469-disco.dts | 30 ++++++++++++++++++++++++++++++
> 3 files changed, 94 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
> index 7d0415e..374c5ed 100644
> --- a/arch/arm/boot/dts/stm32f429-disco.dts
> +++ b/arch/arm/boot/dts/stm32f429-disco.dts
> @@ -88,6 +88,16 @@
> gpios = <&gpioa 0 0>;
> };
> };
> +
> + /* This turns on vbus for otg for host mode (dwc2) */
> + vcc5v_otg: vcc5v-otg-regulator {
> + compatible = "regulator-fixed";
> + gpio = <&gpioc 4 0>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&usbotg_pwren_h>;
> + regulator-name = "vcc5_host1";
> + regulator-always-on;
> + };
> };
>
> &clk_hse {
> @@ -99,3 +109,23 @@
> pinctrl-names = "default";
> status = "okay";
> };
> +
> +&usbotg_hs {
> + compatible = "st,stm32-fsotg", "snps,dwc2";
> + dr_mode = "host";
> + pinctrl-0 = <&usbotg_fs_pins_b>;
> + pinctrl-names = "default";
> + status = "okay";
> +};
> +
> +&pinctrl {
> + usb-host {
> + usbotg_pwren_h: usbotg-pwren-h {
> + pins {
> + pinmux = <STM32F429_PC4_FUNC_GPIO>;
> + bias-disable;
> + drive-push-pull;
> + };
> + };
> + };
> +};
Pinctrl muxing has to be defined/declared in stm32f429.dtsi
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index e4dae0e..bc07aa8 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -206,7 +206,7 @@
> reg = <0x40007000 0x400>;
> };
>
> - pin-controller {
> + pinctrl: pin-controller {
> #address-cells = <1>;
> #size-cells = <1>;
> compatible = "st,stm32f429-pinctrl";
> @@ -316,6 +316,30 @@
> };
> };
>
> + usbotg_fs_pins_a: usbotg_fs@0 {
> + pins {
> + pinmux = <STM32F429_PA10_FUNC_OTG_FS_ID>,
> + <STM32F429_PA11_FUNC_OTG_FS_DM>,
> + <STM32F429_PA12_FUNC_OTG_FS_DP>;
> + bias-disable;
> + drive-push-pull;
> + slew-rate = <2>;
> + };
> + };
> +
> + usbotg_fs_pins_b: usbotg_fs@1 {
> + pins {
> + pinmux = <STM32F429_PB12_FUNC_OTG_HS_ID>,
> + <STM32F429_PB14_FUNC_OTG_HS_DM>,
> + <STM32F429_PB15_FUNC_OTG_HS_DP>;
> + bias-disable;
> + drive-push-pull;
> + slew-rate = <2>;
> + };
> + };
> +
> +
> +
> usbotg_hs_pins_a: usbotg_hs@0 {
> pins {
> pinmux = <STM32F429_PH4_FUNC_OTG_HS_ULPI_NXT>,
> @@ -420,6 +444,15 @@
> status = "disabled";
> };
>
> + usbotg_fs: usb@50000000 {
> + compatible = "st,stm32f4xx-fsotg", "snps,dwc2";
> + reg = <0x50000000 0x40000>;
> + interrupts = <67>;
> + clocks = <&rcc 0 39>;
> + clock-names = "otg";
> + status = "disabled";
> + };
> +
> rng: rng@50060800 {
> compatible = "st,stm32-rng";
> reg = <0x50060800 0x400>;
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8877c00..8ae6763 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -68,6 +68,17 @@
> soc {
> dma-ranges = <0xc0000000 0x0 0x10000000>;
> };
> +
> + /* This turns on vbus for otg for host mode (dwc2) */
> + vcc5v_otg: vcc5v-otg-regulator {
> + compatible = "regulator-fixed";
> + enable-active-high;
> + gpio = <&gpiob 2 0>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&usbotg_pwren_h>;
> + regulator-name = "vcc5_host1";
> + regulator-always-on;
> + };
> };
>
> &rcc {
> @@ -81,3 +92,22 @@
> &usart3 {
> status = "okay";
> };
> +
> +&usbotg_fs {
> + dr_mode = "host";
> + pinctrl-0 = <&usbotg_fs_pins_a>;
> + pinctrl-names = "default";
> + status = "okay";
> +};
> +
> +&pinctrl {
> + usb-host {
> + usbotg_pwren_h: usbotg-pwren-h {
> + pins {
> + pinmux = <STM32F429_PB2_FUNC_GPIO>;
> + bias-disable;
> + drive-push-pull;
> + };
> + };
> + };
> +};
Same. Note that if you have 2 configuration for one feature (like it is
here for "usbotg_pwren_h"), you could index it. Not that I'm adding a
dedidacted pinctroller for stm32f469.
Br
Alex
>
^ permalink raw reply
* [PATCH] rtc: stm32: use 0 instead of ~PWR_CR_DBP in regmap_update_bits
From: Amelie Delaunay @ 2017-01-16 8:57 UTC (permalink / raw)
To: Alessandro Zummo, Alexandre Belloni, Rob Herring, Mark Rutland,
Maxime Coquelin, Alexandre Torgue, Russell King
Cc: rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Gabriel Fernandez,
Amelie Delaunay
Using the ~ operator on a BIT() constant results in a large 'unsigned long'
constant that won't fit into an 'unsigned int' function argument on 64-bit
architectures, resulting in a harmless build warning in x86 allmodconfig:
drivers/rtc/rtc-stm32.c: In function 'stm32_rtc_probe':
drivers/rtc/rtc-stm32.c:651:51: error: large integer implicitly truncated to unsigned type [-Werror=overflow]
regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
As PWR_CR_DBP mask prevents other bits to be cleared, replace all
~PWR_CR_DBP by 0.
Fixes: 4e64350f42e2 ("rtc: add STM32 RTC driver")
Signed-off-by: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>
Signed-off-by: Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>
---
drivers/rtc/rtc-stm32.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index 8c599f5..03c97c1 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -648,7 +648,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
err:
clk_disable_unprepare(rtc->ck_rtc);
- regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+ regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
device_init_wakeup(&pdev->dev, false);
@@ -670,7 +670,7 @@ static int stm32_rtc_remove(struct platform_device *pdev)
clk_disable_unprepare(rtc->ck_rtc);
/* Enable backup domain write protection */
- regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+ regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
device_init_wakeup(&pdev->dev, false);
--
1.9.1
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply related
* Re: [PATCH v1 1/3] dt: bindings: add documentation for zx2967 family watchdog controller
From: Shawn Guo @ 2017-01-16 9:04 UTC (permalink / raw)
To: Baoyou Xie
Cc: jun.nie-QSEj5FYQhm4dnm+yROfE0A, wim-IQzOog9fTRqzQB+pC5nmwQ,
linux-0h96xk9xTtrk1uMJSBkQmQ, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
xie.baoyou-Th6q7B73Y6EnDS1+zs4M5A,
chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
wang.qiang01-Th6q7B73Y6EnDS1+zs4M5A
In-Reply-To: <1484540395-3335-1-git-send-email-baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On Mon, Jan 16, 2017 at 12:19:53PM +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zx2967 family
> watchdog controller.
>
> Signed-off-by: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> .../bindings/watchdog/zte,zx2967-wdt.txt | 29 ++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
>
> diff --git a/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
> new file mode 100644
> index 0000000..0fe0d40
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
> @@ -0,0 +1,29 @@
> +ZTE zx2967 Watchdog timer
> +
> +Required properties:
> +
> +- compatible : should be one of the following.
> + * zte,zx296718-wdt
> +- reg : Specifies base physical address and size of the registers.
> +- clocks : Pairs of phandle and specifier referencing the controller's clocks.
> +- clock-names: "wdtclk" for the watchdog clock.
clock-names only makes sense when there are multiple clock phandles in
'clocks' property. When clock-names is not present, the driver code
calls devm_clk_get() with the second parameter being NULL.
> +- resets : Reference to the reset controller controlling the watchdog
> + controller.
> +- reset-names : Must include the following entries:
> + * wdtrst
Same as clock-names.
> +
> +Optional properties:
> +
> +- reset-mask-config : Mask and configuare value that be wrote to aon-sysctrl.
First of all, for vendor specific properties, we should have a vendor
prefix, something like "zte,reset-mask-config".
Secondly, we should really have more comments to explain why this
property is optional, i.e. in which cases it should be present, and in
which cases it can be missing. Also, the relationship between this
reset and 'resets = <&toprst 35>' should be explained a bit as well.
Shawn
> +
> +Example:
> +
> +wdt_ares: watchdog@1465000 {
> + compatible = "zte,zx296718-wdt";
> + reg = <0x1465000 0x1000>;
> + clocks = <&topcrm WDT_WCLK>;
> + clock-names = "wdtclk";
> + resets = <&toprst 35>;
> + reset-names = "wdtrst";
> + reset-mask-config = <1 0x115>;
> +};
> --
> 2.7.4
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/4] phy: sun4i-usb: add support for V3s USB PHY
From: Kishon Vijay Abraham I @ 2017-01-16 9:06 UTC (permalink / raw)
To: Maxime Ripard, Icenowy Zheng
Cc: Chen-Yu Tsai, Bin Liu, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170106135624.kbjdvb3wtytfj6ob@lukather>
On Friday 06 January 2017 07:26 PM, Maxime Ripard wrote:
> On Tue, Jan 03, 2017 at 11:25:31PM +0800, Icenowy Zheng wrote:
>> Allwinner V3s come with a USB PHY controller slightly different to other
>> SoCs, with only one PHY.
>>
>> Add support for it.
>>
>> Signed-off-by: Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org>
>
> Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
merged, thanks!
-Kishon
>
> Thanks,
> Maxime
>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 0/6] USB support for Broadcom NSP SoC
From: Kishon Vijay Abraham I @ 2017-01-16 9:17 UTC (permalink / raw)
To: Florian Fainelli, Yendapally Reddy Dhananjaya Reddy, Rob Herring,
Mark Rutland, Russell King, Ray Jui, Scott Branden, Jon Mason
Cc: netdev, bcm-kernel-feedback-list, linux-kernel, linux-arm-kernel,
devicetree
In-Reply-To: <79483fc3-5e91-a1f0-1dbf-1987682373e6@gmail.com>
On Tuesday 13 December 2016 07:50 AM, Florian Fainelli wrote:
> On 11/09/2016 01:33 AM, Yendapally Reddy Dhananjaya Reddy wrote:
>> This patch set contains the usb support for Broadcom NSP SoC.
>> The usb phy is connected through mdio interface. The mdio interface
>> can be used to access either internal phys or external phys using a
>> multiplexer.
>>
>> The first patch provides the documentation details for mdio-mux and
>> second patch provides the documentation details for usb3 phy. The third
>> patch contains the mdio-mux support and fourth patch contains the
>> changes to the mdio bus driver.
>>
>> The fifth patch provides the phy driver and sixth patch provides the
>> enable method for usb.
>>
>> This patch series has been tested on NSP bcm958625HR board.
>> This patch series is based on v4.9.0-rc1 and is available from github-
>> repo: https://github.com/Broadcom/cygnus-linux.git
>> branch:nsp-usb-v1
>
> Can you resubmit this patch series with the feedback from Andrew, Rob
> and Scott addressed?
can the phy patches be re-submitted based on latest mainline and addressing
those feedbacks?
Thanks
Kishon
^ permalink raw reply
* Re: [PATCH 2/3] Broadcom USB DRD Phy driver for Northstar2
From: Kishon Vijay Abraham I @ 2017-01-16 9:22 UTC (permalink / raw)
To: Raviteja Garimella, Rob Herring, Mark Rutland, Ray Jui,
Scott Branden, Jon Mason, Catalin Marinas, Will Deacon
Cc: devicetree, bcm-kernel-feedback-list, linux-kernel,
linux-arm-kernel
In-Reply-To: <1480485338-23451-3-git-send-email-raviteja.garimella@broadcom.com>
Hi,
On Wednesday 30 November 2016 11:25 AM, Raviteja Garimella wrote:
> This is driver for USB DRD Phy used in Broadcom's Northstar2
> SoC. The phy can be configured to be in Device mode or Host
> mode based on the type of cable connected to the port. The
> driver registers to extcon framework to get appropriate
> connect events for Host/Device cables connect/disconnect
> states based on VBUS and ID interrupts.
>
> Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
> ---
> drivers/phy/Kconfig | 13 +
> drivers/phy/Makefile | 1 +
> drivers/phy/phy-bcm-ns2-usbdrd.c | 587 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 601 insertions(+)
> create mode 100644 drivers/phy/phy-bcm-ns2-usbdrd.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index fe00f91..b3b6a73 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -479,6 +479,19 @@ config PHY_CYGNUS_PCIE
> Enable this to support the Broadcom Cygnus PCIe PHY.
> If unsure, say N.
>
> +config PHY_NS2_USB_DRD
> + tristate "Broadcom Northstar2 USB DRD PHY support"
> + depends on OF && (ARCH_BCM_IPROC || COMPILE_TEST)
> + select GENERIC_PHY
> + select EXTCON
> + default ARCH_BCM_IPROC
> + help
> + Enable this to support the Broadcom Northstar2 USB DRD PHY.
> + This driver initializes the PHY in either HOST or DEVICE mode.
> + The host or device configuration is read from device tree.
> +
> + If unsure, say N.
> +
> source "drivers/phy/tegra/Kconfig"
>
> config PHY_NS2_PCIE
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index a534cf5..b733ba2 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -58,5 +58,6 @@ obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
> obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
> obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
> obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
> +obj-$(CONFIG_PHY_NS2_USB_DRD) += phy-bcm-ns2-usbdrd.o
> obj-$(CONFIG_ARCH_TEGRA) += tegra/
> obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
> diff --git a/drivers/phy/phy-bcm-ns2-usbdrd.c b/drivers/phy/phy-bcm-ns2-usbdrd.c
> new file mode 100644
> index 0000000..460040d
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-ns2-usbdrd.c
> @@ -0,0 +1,587 @@
> +/*
> + * Copyright (C) 2016 Broadcom
> + *
> + * 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 version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/extcon.h>
> +#include <linux/gpio.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +
> +#define ICFG_DRD_AFE 0x0
> +#define ICFG_MISC_STAT 0x18
> +#define ICFG_DRD_P0CTL 0x1C
> +#define ICFG_STRAP_CTRL 0x20
> +#define ICFG_FSM_CTRL 0x24
> +
> +#define IDM_RST_BIT BIT(0)
> +#define AFE_CORERDY_VDDC BIT(18)
> +#define PHY_PLL_RESETB BIT(15)
> +#define PHY_RESETB BIT(14)
> +#define PHY_PLL_LOCK BIT(0)
> +
> +#define DRD_DEV_MODE BIT(20)
> +#define OHCI_OVRCUR_POL BIT(11)
> +#define ICFG_OFF_MODE BIT(6)
> +#define PLL_LOCK_RETRY 1000
> +
> +#define EVT_DEVICE 0
> +#define EVT_HOST 1
> +#define EVT_IDLE 2
> +
> +#define DRD_HOST_MODE (BIT(2) | BIT(3))
> +#define DRD_DEVICE_MODE (BIT(4) | BIT(5))
> +#define DRD_HOST_VAL 0x803
> +#define DRD_DEV_VAL 0x807
> +#define GPIO_DELAY 20
> +#define PHY_WQ_DELAY msecs_to_jiffies(600)
> +
> +struct ns2_phy_data;
> +struct ns2_phy_driver {
> + void __iomem *icfgdrd_regs;
> + void __iomem *idmdrd_rst_ctrl;
> + void __iomem *crmu_usb2_ctrl;
> + void __iomem *usb2h_strap_reg;
> + spinlock_t lock; /* spin lock for phy driver */
> + bool host_mode;
> + struct ns2_phy_data *data;
> + struct extcon_specific_cable_nb extcon_dev;
> + struct extcon_specific_cable_nb extcon_host;
> + struct notifier_block host_nb;
> + struct notifier_block dev_nb;
> + struct delayed_work conn_work;
> + struct extcon_dev *edev;
> + struct gpio_desc *vbus_gpiod;
> + struct gpio_desc *id_gpiod;
> + int id_irq;
> + int vbus_irq;
> + unsigned long debounce_jiffies;
> + struct delayed_work wq_extcon;
> +};
> +
> +struct ns2_phy_data {
> + struct ns2_phy_driver *driver;
> + struct phy *phy;
> + int new_state;
> + bool poweron;
> +};
> +
> +static const unsigned int usb_extcon_cable[] = {
> + EXTCON_USB,
> + EXTCON_USB_HOST,
> + EXTCON_NONE,
> +};
> +
> +static inline int pll_lock_stat(u32 usb_reg, int reg_mask,
> + struct ns2_phy_driver *driver)
> +{
> + int retry = PLL_LOCK_RETRY;
> + u32 val;
> +
> + do {
> + udelay(1);
> + val = readl(driver->icfgdrd_regs + usb_reg);
> + if (val & reg_mask)
> + return 0;
> + } while (--retry > 0);
> +
> + return -EBUSY;
> +}
> +
> +static int ns2_drd_phy_init(struct phy *phy)
> +{
> + struct ns2_phy_data *data = phy_get_drvdata(phy);
> + struct ns2_phy_driver *driver = data->driver;
> + unsigned long flags;
> + u32 val;
> +
> + spin_lock_irqsave(&driver->lock, flags);
> +
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + if (data->new_state == EVT_HOST) {
> + val &= ~DRD_DEVICE_MODE;
> + val |= DRD_HOST_MODE;
> + } else {
> + val &= ~DRD_HOST_MODE;
> + val |= DRD_DEVICE_MODE;
> + }
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + spin_unlock_irqrestore(&driver->lock, flags);
> + return 0;
> +}
> +
> +static int ns2_drd_phy_shutdown(struct phy *phy)
> +{
> + struct ns2_phy_data *data = phy_get_drvdata(phy);
> + struct ns2_phy_driver *driver = data->driver;
> + unsigned long flags;
> + u32 val;
> +
> + spin_lock_irqsave(&driver->lock, flags);
> + if (!data->poweron)
> + goto exit;
> +
> + val = readl(driver->crmu_usb2_ctrl);
> + val &= ~AFE_CORERDY_VDDC;
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + driver->host_mode = 0;
> + val = readl(driver->crmu_usb2_ctrl);
> + val &= ~DRD_DEV_MODE;
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + /* Disable Host and Device Mode */
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> + val &= ~(DRD_HOST_MODE | DRD_DEVICE_MODE | ICFG_OFF_MODE);
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + data->poweron = 0;
> +exit:
> + spin_unlock_irqrestore(&driver->lock, flags);
> + return 0;
> +}
> +
> +static int ns2_drd_phy_poweron(struct phy *phy)
> +{
> + struct ns2_phy_data *data = phy_get_drvdata(phy);
> + struct ns2_phy_driver *driver = data->driver;
> + u32 extcon_event = data->new_state;
> + unsigned long flags;
> + int ret;
> + u32 val;
> +
> + spin_lock_irqsave(&driver->lock, flags);
> + if (extcon_event == EVT_DEVICE) {
> + if (data->poweron)
> + goto exit;
> +
> + writel(DRD_DEV_VAL, driver->icfgdrd_regs + ICFG_DRD_P0CTL);
> +
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> + val &= ~(DRD_HOST_MODE | ICFG_OFF_MODE);
> + val |= DRD_DEVICE_MODE;
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + val = readl(driver->idmdrd_rst_ctrl);
> + val &= ~IDM_RST_BIT;
> + writel(val, driver->idmdrd_rst_ctrl);
> +
> + val = readl(driver->crmu_usb2_ctrl);
> + val |= (AFE_CORERDY_VDDC | DRD_DEV_MODE);
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + /* Bring PHY and PHY_PLL out of Reset */
> + val = readl(driver->crmu_usb2_ctrl);
> + val |= (PHY_PLL_RESETB | PHY_RESETB);
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + ret = pll_lock_stat(ICFG_MISC_STAT, PHY_PLL_LOCK, driver);
> + if (ret < 0) {
> + dev_err(&phy->dev, "Phy PLL lock failed\n");
> + goto err_shutdown;
> + }
> + } else {
> + if (data->poweron && driver->host_mode)
> + goto exit;
> +
> + writel(DRD_HOST_VAL, driver->icfgdrd_regs + ICFG_DRD_P0CTL);
> +
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> + val &= ~(DRD_DEVICE_MODE | ICFG_OFF_MODE);
> + val |= DRD_HOST_MODE;
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + val = readl(driver->crmu_usb2_ctrl);
> + val |= AFE_CORERDY_VDDC;
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + ret = pll_lock_stat(ICFG_MISC_STAT, PHY_PLL_LOCK, driver);
> + if (ret < 0) {
> + dev_err(&phy->dev, "Phy PLL lock failed\n");
> + goto err_shutdown;
> + }
> +
> + val = readl(driver->idmdrd_rst_ctrl);
> + val &= ~IDM_RST_BIT;
> + writel(val, driver->idmdrd_rst_ctrl);
> +
> + /* port over current Polarity */
> + val = readl(driver->usb2h_strap_reg);
> + val |= OHCI_OVRCUR_POL;
> + writel(val, driver->usb2h_strap_reg);
> +
> + driver->host_mode = 1;
> + }
> +
> + data->poweron = 1;
> +exit:
> + spin_unlock_irqrestore(&driver->lock, flags);
> + return 0;
> +
> +err_shutdown:
> + data->poweron = 1;
> + spin_unlock_irqrestore(&driver->lock, flags);
> + ns2_drd_phy_shutdown(phy);
> + return ret;
> +}
> +
> +static void connect_work(struct work_struct *work)
> +{
> + struct ns2_phy_driver *driver;
> + struct ns2_phy_data *data;
> + u32 extcon_event;
> +
> + driver = container_of(to_delayed_work(work),
> + struct ns2_phy_driver, conn_work);
> + data = driver->data;
> + extcon_event = data->new_state;
> +
> + if (extcon_event == EVT_DEVICE || extcon_event == EVT_HOST) {
> + ns2_drd_phy_init(data->phy);
> + ns2_drd_phy_poweron(data->phy);
> + } else if (extcon_event == EVT_IDLE) {
> + ns2_drd_phy_shutdown(data->phy);
> + }
> +}
> +
> +static int drd_device_notify(struct notifier_block *self,
> + unsigned long event, void *ptr)
> +{
> + struct ns2_phy_driver *driver = container_of(self,
> + struct ns2_phy_driver, dev_nb);
> +
> + if (event) {
> + pr_debug("Device connected\n");
> + driver->data->new_state = EVT_DEVICE;
> + schedule_delayed_work(&driver->conn_work, 0);
> + } else {
> + pr_debug("Device disconnected\n");
> + driver->data->new_state = EVT_IDLE;
> + schedule_delayed_work(&driver->conn_work, PHY_WQ_DELAY);
> + }
> +
> + return NOTIFY_DONE;
> +}
> +
> +static int drd_host_notify(struct notifier_block *self,
> + unsigned long event, void *ptr)
> +{
> + struct ns2_phy_driver *driver = container_of(self,
> + struct ns2_phy_driver, host_nb);
> +
> + if (event) {
> + pr_debug("Host connected\n");
> + driver->data->new_state = EVT_HOST;
> + schedule_delayed_work(&driver->conn_work, 0);
> + } else {
> + pr_debug("Host disconnected\n");
> + driver->data->new_state = EVT_IDLE;
> + schedule_delayed_work(&driver->conn_work, PHY_WQ_DELAY);
> + }
> +
> + return NOTIFY_DONE;
> +}
> +
> +static void extcon_work(struct work_struct *work)
> +{
> + struct ns2_phy_driver *driver;
> + int vbus;
> + int id;
> +
> + driver = container_of(to_delayed_work(work),
> + struct ns2_phy_driver, wq_extcon);
> +
> + id = gpiod_get_value_cansleep(driver->id_gpiod);
> + vbus = gpiod_get_value_cansleep(driver->vbus_gpiod);
> +
> + if (!id && vbus) {
> + extcon_set_cable_state_(driver->edev, EXTCON_USB_HOST, true);
> + } else if (id && !vbus) {
> + extcon_set_cable_state_(driver->edev, EXTCON_USB_HOST, false);
> + extcon_set_cable_state_(driver->edev, EXTCON_USB, false);
> + } else if (id && vbus) {
> + extcon_set_cable_state_(driver->edev, EXTCON_USB, true);
> + }
> +}
> +
> +static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
> +{
> + struct ns2_phy_driver *driver = dev_id;
> +
> + queue_delayed_work(system_power_efficient_wq, &driver->wq_extcon,
> + driver->debounce_jiffies);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int register_extcon_notifier(struct ns2_phy_driver *phy_driver,
> + struct device *dev)
> +{
> + struct extcon_dev *edev;
> + int ret;
> +
> + phy_driver->host_nb.notifier_call = drd_host_notify;
> + phy_driver->dev_nb.notifier_call = drd_device_notify;
> +
> + edev = phy_driver->edev;
> +
> + /* Register for device change notification */
> + ret = extcon_register_notifier(edev, EXTCON_USB,
> + &phy_driver->dev_nb);
> + if (ret < 0) {
> + dev_err(dev, "can't register extcon_dev for %s\n", edev->name);
> + return ret;
> + }
> +
> + /* Register for host change notification */
> + ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
> + &phy_driver->host_nb);
> + if (ret < 0) {
> + dev_err(dev, "can't register extcon_dev for %s\n", edev->name);
> + goto err_dev;
> + }
> +
> + /* Check the device cable connect state */
> + ret = extcon_get_cable_state_(edev, EXTCON_USB);
> + if (ret < 0) {
> + dev_err(dev, "can't get extcon_dev state for %s\n", edev->name);
> + goto err_host;
> + } else if (ret) {
> + phy_driver->data->new_state = EVT_DEVICE;
> + }
> +
> + /* Check the host cable connect state */
> + ret = extcon_get_cable_state_(edev, EXTCON_USB_HOST);
> + if (ret < 0) {
> + dev_err(dev, "can't get extcon_dev state for %s\n", edev->name);
> + goto err_host;
> + } else if (ret) {
> + phy_driver->data->new_state = EVT_HOST;
> + }
> +
> + return 0;
> +
> +err_host:
> + ret = extcon_unregister_notifier(edev, EXTCON_USB_HOST,
> + &phy_driver->host_nb);
> +err_dev:
> + ret = extcon_unregister_notifier(edev, EXTCON_USB,
> + &phy_driver->dev_nb);
> + return ret;
> +}
> +
> +static struct phy_ops ops = {
> + .init = ns2_drd_phy_init,
Is this really being used by any controller driver? Can you point me to the
controller driver that is using this driver?
> + .power_on = ns2_drd_phy_poweron,
> + .power_off = ns2_drd_phy_shutdown,
missing .owner.
Thanks
Kishon
^ permalink raw reply
* Re: [PATCH] pcie: ti: Provide patch to force GEN1 PCIe operation
From: Lukasz Majewski @ 2017-01-16 9:31 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: Bjorn Helgaas, Rob Herring, Mark Rutland, Jingoo Han, Joao Pinto,
linux-omap, linux-pci, devicetree, linux-kernel
In-Reply-To: <587C8088.80905@ti.com>
Hi Kishon,
> Hi Łukasz,
>
> On Monday 16 January 2017 12:19 PM, Lukasz Majewski wrote:
> > Hi Kishon,
> >
> >> Hi,
> >>
> >> On Sunday 15 January 2017 06:49 PM, Lukasz Majewski wrote:
> >>> Some devices (due to e.g. bad PCIe signal integrity) require to
> >>> run with forced GEN1 speed on PCIe bus.
> >>>
> >>> This patch changes the speed explicitly on dra7 based devices when
> >>> proper device tree attribute is defined for the PCIe controller.
> >>>
> >>> Signed-off-by: Lukasz Majewski <lukma@denx.de>
> >>
> >> Bjorn has already queued a patch to do the same thing
> >> https://git.kernel.org/cgit/linux/kernel/git/helgaas/pci.git/log/?h=pci/host-dra7xx
> >
> > It seems like Bjorn only modifies CAP registers.
>
> The patch also modifies the LNKCTL2 register.
> >
> > He also needs to change register with 0x080C offset to actually
> > ( PCIECTRL_PL_WIDTH_SPEED_CTL )
>
> This bit is used to initiate speed change (after the link is
> initialized in GEN1). Resetting the bit (like what you have done
> here) prevents speed change.
This is strange, but e2e advised me to do things as I did in the patch
to _force_ GEN1 operation on PCIe2 port [1] (AM5728)
Link:
[1] https://e2e.ti.com/support/arm/sitara_arm/f/791/t/566421
Both patches modify 0x5180 007C register to set GEN1 capability
(PCI_EXP_LNKCAP_SLS_2_5GB)
The problem is with second register (in your patch):
>From SPRUHZ6G TRM:
PCIECTRL_EP_DBICS_LNK_CAS_2 (0x5180 00A0)
- TRGT_LINK_SPEED (Reset 0x1) - "Target Link Speed" - no more
description in TRM
It is set to PCI_EXP_LNKCAP_SLS_2_5GB = 0x1, which is the same as
default /reset value.
Could you clarify which way to _force_ PCIe GEN1 operation is correct?
Mine shows differences in lspci output (as posted in [1]).
>
> IMO the better way is to set the LNKCTL2 to GEN1 instead of hacking
> the IP register.
>From the original patch description:
"Add support to force Root Complex to work in GEN1 mode if so desired,
but don't force GEN1 mode on any board just yet."
Are there any (floating around) patches allowing forcing GEN1 operation
on any board (I would like to reuse/port them to my current solution)?
Thanks in advance,
Łukasz Majewski
>
> Thanks
> Kishon
>
> >
> > Best regards,
> > Łukasz
> >
> >>
> >> Thanks
> >> Kishon
> >>
> >>> ---
> >>>
> >>> Patch applies on newest origin/master
> >>> SHA1: f4d3935e4f4884ba80561db5549394afb8eef8f7
> >>>
> >>> Tested at AM5728
> >>>
> >>> ---
> >>> Documentation/devicetree/bindings/pci/ti-pci.txt | 1 +
> >>> drivers/pci/host/pci-dra7xx.c | 23
> >>> +++++++++++++++++++++++
> >>> drivers/pci/host/pcie-designware.h | 1 + 3 files
> >>> changed, 25 insertions(+)
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/pci/ti-pci.txt
> >>> b/Documentation/devicetree/bindings/pci/ti-pci.txt index
> >>> 60e2516..9f97409 100644 ---
> >>> a/Documentation/devicetree/bindings/pci/ti-pci.txt +++
> >>> b/Documentation/devicetree/bindings/pci/ti-pci.txt @@ -25,6 +25,7
> >>> @@ PCIe Designware Controller
> >>> Optional Property:
> >>> - gpios : Should be added if a gpio line is required to drive
> >>> PERST# line
> >>> + - to,pcie-is-gen1: Indicates that forced gen1 port operation is
> >>> needed.
> >>> Example:
> >>> axi {
> >>> diff --git a/drivers/pci/host/pci-dra7xx.c
> >>> b/drivers/pci/host/pci-dra7xx.c index 9595fad..eec5fae 100644
> >>> --- a/drivers/pci/host/pci-dra7xx.c
> >>> +++
> >>> b/drivers/pci/host/pci-https://git.kernel.org/cgit/linux/kernel/git/helgaas/pci.git/log/?h=pci/host-dra7xxdra7xx.c
> >>> @@ -63,6 +63,13 @@ #define
> >>> LINK_UP BIT(16)
> >>> #define
> >>> DRA7XX_CPU_TO_BUS_ADDR 0x0FFFFFFF
> >>> +#define PCIECTRL_EP_DBICS_LNK_CAP
> >>> 0x007C +#define
> >>> MAX_LINK_SPEEDS_MASK GENMASK(3, 0)
> >>> +#define MAX_LINK_SPEEDS_GEN1
> >>> BIT(0) + +#define
> >>> PCIECTRL_PL_WIDTH_SPEED_CTL 0x080C
> >>> +#define CFG_DIRECTED_SPEED_CHANGE
> >>> BIT(17) + struct dra7xx_pcie { struct pcie_port pp;
> >>> void __iomem *base; /* DT
> >>> ti_conf */ @@ -270,6 +277,7 @@ static int __init
> >>> dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, struct pcie_port
> >>> *pp = &dra7xx->pp; struct device *dev = pp->dev;
> >>> struct resource *res;
> >>> + u32 val;
> >>>
> >>> pp->irq = platform_get_irq(pdev, 1);
> >>> if (pp->irq < 0) {
> >>> @@ -296,6 +304,18 @@ static int __init dra7xx_add_pcie_port(struct
> >>> dra7xx_pcie *dra7xx, if (!pp->dbi_base)
> >>> return -ENOMEM;
> >>>
> >>> + if (pp->is_gen1) {
> >>> + dev_info(dev, "GEN1 forced\n");
> >>> +
> >>> + val = readl(pp->dbi_base +
> >>> PCIECTRL_EP_DBICS_LNK_CAP);
> >>> + set_mask_bits(&val, MAX_LINK_SPEEDS_MASK,
> >>> MAX_LINK_SPEEDS_GEN1);
> >>> + writel(val, pp->dbi_base +
> >>> PCIECTRL_EP_DBICS_LNK_CAP); +
> >>> + val = readl(pp->dbi_base +
> >>> PCIECTRL_PL_WIDTH_SPEED_CTL);
> >>> + val &= ~CFG_DIRECTED_SPEED_CHANGE;
> >>> + writel(val, pp->dbi_base +
> >>> PCIECTRL_PL_WIDTH_SPEED_CTL);
> >>> + }
> >>> +
> >>> ret = dw_pcie_host_init(pp);
> >>> if (ret) {
> >>> dev_err(dev, "failed to initialize host\n");
> >>> @@ -404,6 +424,9 @@ static int __init dra7xx_pcie_probe(struct
> >>> platform_device *pdev) goto err_gpio;
> >>> }
> >>>
> >>> + if (of_property_read_bool(np, "ti,pcie-is-gen1"))
> >>> + pp->is_gen1 = true;
> >>> +
> >>> reg = dra7xx_pcie_readl(dra7xx,
> >>> PCIECTRL_DRA7XX_CONF_DEVICE_CMD); reg &= ~LTSSM_EN;
> >>> dra7xx_pcie_writel(dra7xx,
> >>> PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); diff --git
> >>> a/drivers/pci/host/pcie-designware.h
> >>> b/drivers/pci/host/pcie-designware.h index a567ea2..2fb0b18 100644
> >>> --- a/drivers/pci/host/pcie-designware.h +++
> >>> b/drivers/pci/host/pcie-designware.h @@ -50,6 +50,7 @@ struct
> >>> pcie_port { struct irq_domain *irq_domain;
> >>> unsigned long msi_data;
> >>> u8 iatu_unroll_enabled;
> >>> + u8 is_gen1;
> >>> DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
> >>> };
> >>>
> >>>
> >
> >
> >
> >
> > Best regards,
> >
> > Lukasz Majewski
> >
> > --
> >
> > DENX Software Engineering GmbH, Managing Director: Wolfgang
> > Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell,
> > Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email:
> > wd@denx.de
> >
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
^ permalink raw reply
* Re: [PATCH v2 0/3] Adding DT support for TI HECC module
From: Yegor Yefremov @ 2017-01-16 9:34 UTC (permalink / raw)
To: Tony Lindgren
Cc: linux-can@vger.kernel.org, linux-omap@vger.kernel.org, devicetree,
robh+dt, Andrey Skvortsov, hs, Marc Kleine-Budde
In-Reply-To: <20170112154155.GA2630@atomide.com>
On Thu, Jan 12, 2017 at 4:41 PM, Tony Lindgren <tony@atomide.com> wrote:
> * Yegor Yefremov <yegorslists@googlemail.com> [170112 00:00]:
>> On Thu, Jan 12, 2017 at 1:47 AM, Tony Lindgren <tony@atomide.com> wrote:
>> > * Yegor Yefremov <yegorslists@googlemail.com> [170111 13:52]:
>> >> On Wed, Jan 11, 2017 at 3:05 PM, <yegorslists@googlemail.com> wrote:
>> >> > From: Yegor Yefremov <yegorslists@googlemail.com>
>> >> >
>> >> > This is an attempt to revive DT support for TI HECC that was started in 2015.
>> >> >
>> >> > I haven't changed much because not all questions could be fully answered:
>> >> >
>> >> > * Should HECC use "am3505" as compatible?
>> >>
>> >> I mean "ti,am3505-hecc"
>> >
>> > Yeah it should use the device name for the driver.
>> >
>> >> > * What should be done to the offsets (ti,scc-ram-offset, ti,hecc-ram-offset, ti,mbx-offset)?
>> >
>> > The devicetree maintainers need to ack the binding doc. Maybe
>> > send that as a first patch?
>>
>> The question is whether to place these settings into dtsi (as it was
>> done in the original patch) or in the driver itself.
>
> Well where are they on the SoC? Each driver should only access registers
> that belong to the driver module.
>
> If the ti,scc-ram-offset and ti,hecc-ram-offset are not within the ECC
> driver module, probably you should use a separate driver for them
> such as drivers/misc/sram.c.
>
> Also, sounds like the ti,mbx-offset should just be using the mailbox
> framework like remoteproc is doing with include/linux/omap-mailbox.h?
AFAIK all offsets are in RAM and belong to ioremapped space:
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "No mem resources\n");
goto probe_exit;
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "No irq resource\n");
goto probe_exit;
}
if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
dev_err(&pdev->dev, "HECC region already claimed\n");
err = -EBUSY;
goto probe_exit;
}
addr = ioremap(mem->start, resource_size(mem));
if (!addr) {
dev_err(&pdev->dev, "ioremap failed\n");
err = -ENOMEM;
goto probe_exit_free_region;
}
hecc_ram_offset usage:
static inline void hecc_write_lam(struct ti_hecc_priv *priv, u32 mbxno, u32 val)
{
__raw_writel(val, priv->base + priv->hecc_ram_offset + mbxno * 4);
}
mbx_offset usage:
static inline void hecc_write_mbx(struct ti_hecc_priv *priv, u32 mbxno,
u32 reg, u32 val)
{
__raw_writel(val, priv->base + priv->mbx_offset + mbxno * 0x10 +
reg);
}
static inline u32 hecc_read_mbx(struct ti_hecc_priv *priv, u32 mbxno, u32 reg)
{
return __raw_readl(priv->base + priv->mbx_offset + mbxno * 0x10 +
reg);
}
scc_ram_offset won't be used at all. CAN controller will be used in
HECC mode only:
/* SCC compat mode NOT supported (and not needed too) */
hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_SCM);
@Marc is mailbox infra applicable here?
Yegor
^ permalink raw reply
* Re: [PATCH 2/5] phy: meson: add USB2 and USB3 PHY support for Meson GXL
From: Kishon Vijay Abraham I @ 2017-01-16 9:41 UTC (permalink / raw)
To: Martin Blumenstingl, linux-amlogic, linux-arm-kernel, devicetree,
khilman, carlo, mark.rutland, robh+dt
Cc: catalin.marinas, will.deacon, narmstrong
In-Reply-To: <20161126145635.24488-3-martin.blumenstingl@googlemail.com>
Hi,
On Saturday 26 November 2016 08:26 PM, Martin Blumenstingl wrote:
> This adds two new USB PHY drivers found on Meson GXL and GXM SoCs.
Please send them as separate drivers.
>
> The registers for the USB2 PHY block handle a maximum of 4 ports (newer
> SoCs may allow more ports, the driver handles this as long as the
> register length is adjusted in the .dts). The PHY block theoretically
> allows powering down each PHY port separately (by putting it into
> "reset" state). Unfortunately this does not work (my board has 2 USB
> ports, connected to port 1 and 2 of the dwc3's internal hub. When
> leaving the third USB PHY disabled then the hub sees that a device is
> plugged in, but it does not work: "usb usb1-port2: connect-debounce
> failed").
> The USB3 PHY will take care of enabling/disabling all available ports,
> because the USB3 PHY also manages the mode of the USB2 PHYs.
>
> The USB3 PHY actually has three purposes:
> - it provides the USB3 PHY
> - it handles the OTG device/host mode detection interrupt
> - it notifies the corresponding USB2 PHYs of the OTG mode changes
> On GXL and GXM SoCs one references all available USB2 PHY ports in the
> USB3 PHY because all are connected to the same USB controller (thus the
> mode will always match). This behavior is configurable via devicetree,
> by passing (or not passing) a list of other ("child") PHYs which should
> be configured by the USB3 PHY.
>
> Unfortunately there are no datasheets available for any of these PHYs.
> Both drivers were written by reading the reference drivers provided by
> Amlogic and analyzing the registers on the kernel that was shipped with
> my board.
>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
> drivers/phy/Kconfig | 13 ++
> drivers/phy/Makefile | 2 +
> drivers/phy/phy-meson-gxl-usb2.c | 374 ++++++++++++++++++++++++++++++++++++++
> drivers/phy/phy-meson-gxl-usb3.c | 377 +++++++++++++++++++++++++++++++++++++++
> 4 files changed, 766 insertions(+)
> create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
> create mode 100644 drivers/phy/phy-meson-gxl-usb3.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 728e03f..ea74843 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -502,4 +502,17 @@ config PHY_MESON8B_USB2
> and GXBB SoCs.
> If unsure, say N.
>
> +config PHY_MESON_GXL_USB
> + tristate "Meson GXL USB2 and USB3 PHY drivers"
> + default ARCH_MESON
> + depends on OF && (ARCH_MESON || COMPILE_TEST)
> + depends on USB_SUPPORT
> + select USB_COMMON
> + select GENERIC_PHY
> + select REGMAP_MMIO
> + help
> + Enable this to support the Meson USB2 and USB3 PHYs found in
> + Meson GXL SoCs.
> + If unsure, say N.
> +
> endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 0c7fdae..960a96e 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -61,3 +61,5 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
> obj-$(CONFIG_ARCH_TEGRA) += tegra/
> obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
> obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb3.o
> diff --git a/drivers/phy/phy-meson-gxl-usb2.c b/drivers/phy/phy-meson-gxl-usb2.c
> new file mode 100644
> index 0000000..c081ce3
> --- /dev/null
> +++ b/drivers/phy/phy-meson-gxl-usb2.c
> @@ -0,0 +1,374 @@
> +/*
> + * Meson GXL USB2 PHY driver
> + *
> + * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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/io.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/usb/of.h>
> +
> +/* bits [31:27] are read-only */
> +#define U2P_R0 0x0
> + #define U2P_R0_BYPASS_SEL BIT(0)
> + #define U2P_R0_BYPASS_DM_EN BIT(1)
> + #define U2P_R0_BYPASS_DP_EN BIT(2)
> + #define U2P_R0_TXBITSTUFF_ENH BIT(3)
> + #define U2P_R0_TXBITSTUFF_EN BIT(4)
> + #define U2P_R0_DM_PULLDOWN BIT(5)
> + #define U2P_R0_DP_PULLDOWN BIT(6)
> + #define U2P_R0_DP_VBUS_VLD_EXT_SEL BIT(7)
> + #define U2P_R0_DP_VBUS_VLD_EXT BIT(8)
> + #define U2P_R0_ADP_PRB_EN BIT(9)
> + #define U2P_R0_ADP_DISCHARGE BIT(10)
> + #define U2P_R0_ADP_CHARGE BIT(11)
> + #define U2P_R0_DRV_VBUS BIT(12)
> + #define U2P_R0_ID_PULLUP BIT(13)
> + #define U2P_R0_LOOPBACK_EN_B BIT(14)
> + #define U2P_R0_OTG_DISABLE BIT(15)
> + #define U2P_R0_COMMON_ONN BIT(16)
> + #define U2P_R0_FSEL_SHIFT 17
> + #define U2P_R0_FSEL_MASK GENMASK(19, 17)
> + #define U2P_R0_REF_CLK_SEL_SHIFT 20
> + #define U2P_R0_REF_CLK_SEL_MASK GENMASK(21, 20)
> + #define U2P_R0_POWER_ON_RESET BIT(22)
> + #define U2P_R0_V_ATE_TEST_EN_B_SHIFT 23
> + #define U2P_R0_V_ATE_TEST_EN_B_MASK GENMASK(24, 23)
> + #define U2P_R0_ID_SET_ID_DQ BIT(25)
> + #define U2P_R0_ATE_RESET BIT(26)
> + #define U2P_R0_FSV_MINUS BIT(27)
> + #define U2P_R0_FSV_PLUS BIT(28)
> + #define U2P_R0_BYPASS_DM_DATA BIT(29)
> + #define U2P_R0_BYPASS_DP_DATA BIT(30)
> +
> +#define U2P_R1 0x4
> + #define U2P_R1_BURN_IN_TEST BIT(0)
> + #define U2P_R1_ACA_ENABLE BIT(1)
> + #define U2P_R1_DCD_ENABLE BIT(2)
> + #define U2P_R1_VDAT_SRC_EN_B BIT(3)
> + #define U2P_R1_VDAT_DET_EN_B BIT(4)
> + #define U2P_R1_CHARGES_SEL BIT(5)
> + #define U2P_R1_TX_PREEMP_PULSE_TUNE BIT(6)
> + #define U2P_R1_TX_PREEMP_AMP_TUNE_SHIFT 7
> + #define U2P_R1_TX_PREEMP_AMP_TUNE_MASK GENMASK(8, 7)
> + #define U2P_R1_TX_RES_TUNE_SHIFT 9
> + #define U2P_R1_TX_RES_TUNE_MASK GENMASK(10, 9)
> + #define U2P_R1_TX_RISE_TUNE_SHIFT 11
> + #define U2P_R1_TX_RISE_TUNE_MASK GENMASK(12, 11)
> + #define U2P_R1_TX_VREF_TUNE_SHIFT 13
> + #define U2P_R1_TX_VREF_TUNE_MASK GENMASK(16, 13)
> + #define U2P_R1_TX_FSLS_TUNE_SHIFT 17
> + #define U2P_R1_TX_FSLS_TUNE_MASK GENMASK(20, 17)
> + #define U2P_R1_TX_HSXV_TUNE_SHIFT 21
> + #define U2P_R1_TX_HSXV_TUNE_MASK GENMASK(22, 21)
> + #define U2P_R1_OTG_TUNE_SHIFT 23
> + #define U2P_R1_OTG_TUNE_MASK GENMASK(25, 23)
> + #define U2P_R1_SQRX_TUNE_SHIFT 26
> + #define U2P_R1_SQRX_TUNE_MASK GENMASK(28, 26)
> + #define U2P_R1_COMP_DIS_TUNE_SHIFT 29
> + #define U2P_R1_COMP_DIS_TUNE_MASK GENMASK(31, 29)
> +
> +/* bits [31:14] are read-only */
> +#define U2P_R2 0x8
> + #define U2P_R2_DATA_IN_SHIFT 0
> + #define U2P_R2_DATA_IN_MASK GENMASK(3, 0)
> + #define U2P_R2_DATA_IN_EN_SHIFT 4
> + #define U2P_R2_DATA_IN_EN_MASK GENMASK(7, 4)
> + #define U2P_R2_ADDR_SHIFT 8
> + #define U2P_R2_ADDR_MASK GENMASK(11, 8)
> + #define U2P_R2_DATA_OUT_SEL BIT(12)
> + #define U2P_R2_CLK BIT(13)
> + #define U2P_R2_DATA_OUT_SHIFT 14
> + #define U2P_R2_DATA_OUT_MASK GENMASK(17, 14)
> + #define U2P_R2_ACA_PIN_RANGE_C BIT(18)
> + #define U2P_R2_ACA_PIN_RANGE_B BIT(19)
> + #define U2P_R2_ACA_PIN_RANGE_A BIT(20)
> + #define U2P_R2_ACA_PIN_GND BIT(21)
> + #define U2P_R2_ACA_PIN_FLOAT BIT(22)
> + #define U2P_R2_CHARGE_DETECT BIT(23)
> + #define U2P_R2_DEVICE_SESSION_VALID BIT(24)
> + #define U2P_R2_ADP_PROBE BIT(25)
> + #define U2P_R2_ADP_SENSE BIT(26)
> + #define U2P_R2_SESSION_END BIT(27)
> + #define U2P_R2_VBUS_VALID BIT(28)
> + #define U2P_R2_B_VALID BIT(29)
> + #define U2P_R2_A_VALID BIT(30)
> + #define U2P_R2_ID_DIG BIT(31)
> +
> +#define U2P_R3 0xc
> +
> +#define PHY_PORT_RESOURCE_SIZE 0x20
> +
> +#define RESET_COMPLETE_TIME 500
> +
> +struct phy_meson_gxl_usb2_priv {
> + struct regmap *regmap;
> + enum phy_mode mode;
> +};
> +
> +struct phy_meson_gxl_usb2_drv {
> + void __iomem *base;
> + int num_ports;
> + struct phy **ports;
> + struct clk *clk_usb;
> + struct clk *clk_usb_ddr;
> +};
> +
> +static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = U2P_R3,
> +};
> +
> +static int phy_meson_gxl_usb2_set_mode(struct phy *phy, enum phy_mode mode)
> +{
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> + switch (mode) {
> + case PHY_MODE_USB_HOST:
> + case PHY_MODE_USB_OTG:
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
> + U2P_R0_DM_PULLDOWN);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
> + U2P_R0_DP_PULLDOWN);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP, 0);
> + break;
> +
> + case PHY_MODE_USB_DEVICE:
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
> + 0);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
> + 0);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP,
> + U2P_R0_ID_PULLUP);
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + /* reset the PHY and wait until settings are stabilized */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> + U2P_R0_POWER_ON_RESET);
> + udelay(RESET_COMPLETE_TIME);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
> + udelay(RESET_COMPLETE_TIME);
> +
> + priv->mode = mode;
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_power_off(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb2_drv *drv_priv =
> + dev_get_drvdata(phy->dev.parent);
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> + /* power off the PHY by putting it into reset mode */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> + U2P_R0_POWER_ON_RESET);
> +
> + clk_disable_unprepare(drv_priv->clk_usb_ddr);
> + clk_disable_unprepare(drv_priv->clk_usb);
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_power_on(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb2_drv *drv_priv =
> + dev_get_drvdata(phy->dev.parent);
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> + int ret;
> +
> + ret = clk_prepare_enable(drv_priv->clk_usb);
> + if (ret) {
> + dev_err(&phy->dev, "Failed to enable USB clock\n");
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(drv_priv->clk_usb_ddr);
> + if (ret) {
> + clk_disable_unprepare(drv_priv->clk_usb);
> +
> + dev_err(&phy->dev, "Failed to enable USB DDR clock\n");
> + return ret;
> + }
> +
> + /* power on the PHY by taking it out of reset mode */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
> +
> + ret = phy_meson_gxl_usb2_set_mode(phy, priv->mode);
> + if (ret) {
> + phy_meson_gxl_usb2_power_off(phy);
> +
> + dev_err(&phy->dev, "Failed to initialize PHY with mode %d\n",
> + priv->mode);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct phy_ops phy_meson_gxl_usb2_ops = {
> + .power_on = phy_meson_gxl_usb2_power_on,
> + .power_off = phy_meson_gxl_usb2_power_off,
> + .set_mode = phy_meson_gxl_usb2_set_mode,
> + .owner = THIS_MODULE,
> +};
> +
> +static struct phy *phy_meson_gxl_usb2_of_xlate(struct device *dev,
> + struct of_phandle_args *args)
> +{
> + struct phy_meson_gxl_usb2_drv *priv = dev_get_drvdata(dev);
> + int port;
> +
> + if (args->args_count != 1) {
> + dev_err(dev, "Invalid number of cells in 'phy' property\n");
> + return ERR_PTR(-ENODEV);
> + }
> +
> + port = args->args[0];
> + if (WARN_ON(port >= priv->num_ports))
> + return ERR_PTR(-ENODEV);
> +
> + return priv->ports[port];
> +}
Please model every port as a sub-node and get rid of custom xlate implementation.
> +
> +static int phy_meson_gxl_usb2_probe_port(struct device *dev, int port)
> +{
> + struct phy_meson_gxl_usb2_drv *drv_priv = dev_get_drvdata(dev);
> + struct phy_meson_gxl_usb2_priv *phy_priv;
> + struct phy *phy;
> + void __iomem *port_base;
> +
> + phy_priv = devm_kzalloc(dev, sizeof(*phy_priv), GFP_KERNEL);
> + if (!phy_priv)
> + return -ENOMEM;
> +
> + switch (of_usb_get_dr_mode_by_phy(dev->of_node, port)) {
> + case USB_DR_MODE_PERIPHERAL:
> + phy_priv->mode = PHY_MODE_USB_DEVICE;
> + break;
> + case USB_DR_MODE_OTG:
> + phy_priv->mode = PHY_MODE_USB_OTG;
> + break;
> + case USB_DR_MODE_HOST:
> + default:
> + phy_priv->mode = PHY_MODE_USB_HOST;
> + break;
> + }
> +
> + phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops);
> + if (IS_ERR(phy)) {
> + dev_err(dev, "failed to create PHY port %d\n", port);
> + return PTR_ERR(phy);
> + }
> +
> + port_base = drv_priv->base + (port * PHY_PORT_RESOURCE_SIZE);
> + phy_priv->regmap = devm_regmap_init_mmio(&phy->dev, port_base,
> + &phy_meson_gxl_usb2_regmap_conf);
> + if (IS_ERR(phy_priv->regmap))
> + return PTR_ERR(phy_priv->regmap);
> +
> + phy_set_drvdata(phy, phy_priv);
> +
> + drv_priv->ports[port] = phy;
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct phy_meson_gxl_usb2_drv *priv;
> + struct phy_provider *phy_provider;
> + struct resource *res;
> + int i, ret;
> +
> + ret = device_reset(dev);
> + if (ret) {
> + dev_err(dev, "failed to reset device\n");
> + return ret;
> + }
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, priv);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + priv->base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(priv->base))
> + return PTR_ERR(priv->base);
> +
> + priv->num_ports = resource_size(res) / PHY_PORT_RESOURCE_SIZE;
> + if (priv->num_ports < 1) {
> + dev_err(dev, "specified memory range is too small\n");
> + return -EINVAL;
> + }
> +
> + priv->ports = devm_kcalloc(dev, priv->num_ports, sizeof(*priv->ports),
> + GFP_KERNEL);
> + if (!priv->ports)
> + return -ENOMEM;
> +
> + priv->clk_usb = devm_clk_get(dev, "usb");
> + if (IS_ERR(priv->clk_usb)) {
> + dev_err(dev, "failed to get USB clock\n");
> + return PTR_ERR(priv->clk_usb);
> + }
> +
> + priv->clk_usb_ddr = devm_clk_get(dev, "usb_ddr");
> + if (IS_ERR(priv->clk_usb_ddr)) {
> + dev_err(dev, "failed to get USB DDR clock\n");
> + return PTR_ERR(priv->clk_usb_ddr);
> + }
> +
> + for (i = 0; i < priv->num_ports; i++) {
> + ret = phy_meson_gxl_usb2_probe_port(dev, i);
> + if (ret)
> + return ret;
> + }
> +
> + phy_provider = devm_of_phy_provider_register(dev,
> + phy_meson_gxl_usb2_of_xlate);
> +
> + return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static const struct of_device_id phy_meson_gxl_usb2_of_match[] = {
> + { .compatible = "amlogic,meson-gxl-usb2-phy", },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb2_of_match);
> +
> +static struct platform_driver phy_meson_gxl_usb2_driver = {
> + .probe = phy_meson_gxl_usb2_probe,
> + .driver = {
> + .name = "phy-meson-gxl-usb2",
> + .of_match_table = phy_meson_gxl_usb2_of_match,
> + },
> +};
> +module_platform_driver(phy_meson_gxl_usb2_driver);
> +
> +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
> +MODULE_DESCRIPTION("Meson GXL USB2 PHY driver");
> +MODULE_LICENSE("GPL");
GPL v2 to match with the file header.
> diff --git a/drivers/phy/phy-meson-gxl-usb3.c b/drivers/phy/phy-meson-gxl-usb3.c
> new file mode 100644
> index 0000000..90a4028
> --- /dev/null
> +++ b/drivers/phy/phy-meson-gxl-usb3.c
> @@ -0,0 +1,377 @@
> +/*
> + * Meson GXL USB3 PHY driver
> + *
> + * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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/io.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/reset.h>
> +#include <linux/regmap.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/usb/of.h>
> +#include <linux/workqueue.h>
> +
> +#define USB_R0 0x00
> + #define USB_R0_P30_FSEL_SHIFT 0
> + #define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
> + #define USB_R0_P30_PHY_RESET BIT(6)
> + #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
> + #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
> + #define USB_R0_P30_ACJT_LEVEL_SHIFT 9
> + #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
> + #define USB_R0_P30_TX_BOOST_LEVEL_SHIFT 14
> + #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
> + #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
> + #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
> + #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_SHIFT 19
> + #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
> + #define USB_R0_U2D_SS_SCALEDOWN_MODE_SHIFT 29
> + #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
> + #define USB_R0_U2D_ACT BIT(31)
> +
> +#define USB_R1 0x04
> + #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
> + #define USB_R1_U3H_PME_ENABLE BIT(1)
> + #define USB_R1_U3H_HUB_PORT_OVERCURRENT_SHIFT 2
> + #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
> + #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_SHIFT 7
> + #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
> + #define USB_R1_U3H_HOST_U2_PORT_DISABLE_SHIFT 12
> + #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
> + #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
> + #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
> + #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
> + #define USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT 19
> + #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
> + #define USB_R1_P30_PCS_TX_SWING_FULL_SHIFT 25
> + #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
> +
> +#define USB_R2 0x08
> + #define USB_R2_P30_CR_DATA_IN_SHIFT 0
> + #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
> + #define USB_R2_P30_CR_READ BIT(16)
> + #define USB_R2_P30_CR_WRITE BIT(17)
> + #define USB_R2_P30_CR_CAP_ADDR BIT(18)
> + #define USB_R2_P30_CR_CAP_DATA BIT(19)
> + #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT 20
> + #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
> + #define USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT 26
> + #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
> +
> +#define USB_R3 0x0c
> + #define USB_R3_P30_SSC_ENABLE BIT(0)
> + #define USB_R3_P30_SSC_RANGE_SHIFT 1
> + #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
> + #define USB_R3_P30_SSC_REF_CLK_SEL_SHIFT 4
> + #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
> + #define USB_R3_P30_REF_SSP_EN BIT(13)
> + #define USB_R3_P30_LOS_BIAS_SHIFT 16
> + #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
> + #define USB_R3_P30_LOS_LEVEL_SHIFT 19
> + #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
> + #define USB_R3_P30_MPLL_MULTIPLIER_SHIFT 24
> + #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
> +
> +#define USB_R4 0x10
> + #define USB_R4_P21_PORT_RESET_0 BIT(0)
> + #define USB_R4_P21_SLEEP_M0 BIT(1)
> + #define USB_R4_MEM_PD_SHIFT 2
> + #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
> + #define USB_R4_P21_ONLY BIT(4)
> +
> +#define USB_R5 0x14
> + #define USB_R5_ID_DIG_SYNC BIT(0)
> + #define USB_R5_ID_DIG_REG BIT(1)
> + #define USB_R5_ID_DIG_CFG_SHIFT 2
> + #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
> + #define USB_R5_ID_DIG_EN_0 BIT(4)
> + #define USB_R5_ID_DIG_EN_1 BIT(5)
> + #define USB_R5_ID_DIG_CURR BIT(6)
> + #define USB_R5_ID_DIG_IRQ BIT(7)
> + #define USB_R5_ID_DIG_TH_SHIFT 8
> + #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
> + #define USB_R5_ID_DIG_CNT_SHIFT 16
> + #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
> +
> +/* read-only register */
> +#define USB_R6 0x18
> + #define USB_R6_P30_CR_DATA_OUT_SHIFT 0
> + #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
> + #define USB_R6_P30_CR_ACK BIT(16)
> +
> +#define RESET_COMPLETE_TIME 500
> +
> +struct phy_meson_gxl_usb3_priv {
> + struct regmap *regmap;
> + struct delayed_work otg_work;
> + struct phy *this_phy;
> + int num_usb2_phys;
> + struct phy **usb2_phys;
> +};
> +
> +static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = USB_R6,
> +};
> +
> +static int phy_meson_gxl_usb3_update_mode(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + u32 val;
> + enum phy_mode mode;
> + int i, ret;
> +
> + ret = regmap_read(priv->regmap, USB_R5, &val);
> + if (ret)
> + return ret;
> +
> + if (val & USB_R5_ID_DIG_CURR) {
> + mode = PHY_MODE_USB_DEVICE;
> +
> + regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT,
> + USB_R0_U2D_ACT);
> + regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
> + USB_R4_P21_SLEEP_M0);
> + } else {
> + mode = PHY_MODE_USB_HOST;
> +
> + regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT, 0);
> + regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
> + 0);
> + }
> +
> + /* inform the USB2 PHY that we have changed the mode */
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_set_mode(priv->usb2_phys[i], mode);
I'm finding it difficult to understand this. Why should the mode of one phy be
set from another phy? Maybe this part should be implemented using extcon?
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to update usb2-phy #%d mode to %d\n",
> + i, mode);
> + return ret;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static void phy_meson_gxl_usb3_work(struct work_struct *data)
> +{
> + struct phy_meson_gxl_usb3_priv *priv =
> + container_of(data, struct phy_meson_gxl_usb3_priv,
> + otg_work.work);
> +
> + phy_meson_gxl_usb3_update_mode(priv->this_phy);
> +
> + /* unmask IRQs which may have arrived in the meantime */
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
> +}
> +
> +static int phy_meson_gxl_usb3_init(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_init(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to initialize related usb2-phy #%d\n",
> + i);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb3_exit(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_exit(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to exit related usb2-phy #%d\n", i);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb3_power_on(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_power_on(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to power on related usb2-phy #%d\n",
> + i);
> + return ret;
> + }
> + }
> +
> + regmap_update_bits(priv->regmap, USB_R1,
> + USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
> + 0x20 << USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT);
> +
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
> + USB_R5_ID_DIG_EN_0);
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1,
> + USB_R5_ID_DIG_EN_1);
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_TH_MASK,
> + 0xff << USB_R5_ID_DIG_TH_SHIFT);
> +
> + return phy_meson_gxl_usb3_update_mode(phy);
> +}
> +
> +static int phy_meson_gxl_usb3_power_off(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_power_off(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to power off related usb2-phy #%d\n",
> + i);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static irqreturn_t phy_meson_gxl_usb3_irq(int irq, void *data)
> +{
> + u32 val;
> + struct phy_meson_gxl_usb3_priv *priv = data;
> +
> + regmap_read(priv->regmap, USB_R5, &val);
> + if (!(val & USB_R5_ID_DIG_IRQ)) {
> + dev_err(&priv->this_phy->dev, "spurious interrupt\n");
> + return IRQ_NONE;
> + }
> +
> + schedule_delayed_work(&priv->otg_work, msecs_to_jiffies(10));
> +
> + /* acknowledge the IRQ */
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static const struct phy_ops phy_meson_gxl_usb3_ops = {
> + .init = phy_meson_gxl_usb3_init,
> + .exit = phy_meson_gxl_usb3_exit,
> + .power_on = phy_meson_gxl_usb3_power_on,
> + .power_off = phy_meson_gxl_usb3_power_off,
> + .owner = THIS_MODULE,
> +};
> +
> +static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
> + struct phy_meson_gxl_usb3_priv *priv;
> + struct resource *res;
> + struct phy *phy;
> + struct phy_provider *phy_provider;
> + void __iomem *base;
> + int i, irq;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + priv->regmap = devm_regmap_init_mmio(dev, base,
> + &phy_meson_gxl_usb3_regmap_conf);
> + if (IS_ERR(priv->regmap))
> + return PTR_ERR(priv->regmap);
> +
> + irq = platform_get_irq(pdev, 0);
> + if (irq >= 0) {
> + INIT_DELAYED_WORK(&priv->otg_work, phy_meson_gxl_usb3_work);
> +
> + irq = devm_request_irq(dev, irq, phy_meson_gxl_usb3_irq,
> + IRQF_SHARED, dev_name(dev),
> + priv);
> + if (irq < 0) {
> + dev_err(dev, "could not register IRQ handler (%d)\n",
> + irq);
> + return -EINVAL;
> + }
> + }
> +
> + priv->num_usb2_phys = of_count_phandle_with_args(np, "phys",
> + "#phy-cells");
> +
> + priv->usb2_phys = devm_kcalloc(dev, priv->num_usb2_phys,
> + sizeof(*priv->usb2_phys), GFP_KERNEL);
> + if (!priv->usb2_phys)
> + return -ENOMEM;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + priv->usb2_phys[i] = devm_of_phy_get_by_index(dev, np, i);
I'm not sure if referencing usb2_phy from here is the right approach.
Thanks
Kishon
^ permalink raw reply
* Re: [PATCH 3/4] ARM64: dts: meson-gx-p23x-q20x: enable the Bluetooth module
From: Martin Blumenstingl @ 2017-01-16 9:44 UTC (permalink / raw)
To: Andreas Färber
Cc: linux-serial-u79uwXL29TY76Z2rM5mHXA,
linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
jslaby-IBi9RG/b67k, gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <042e2824-0772-cf27-ffa5-4c3b2af7c92b-l3A5Bk7waGM@public.gmane.org>
On Mon, Jan 16, 2017 at 1:47 AM, Andreas Färber <afaerber-l3A5Bk7waGM@public.gmane.org> wrote:
> Am 15.01.2017 um 23:32 schrieb Martin Blumenstingl:
>> This takes the Bluetooth module out of reset (the reset line is
>> connected to GPIOX_17) and enables uart_A which is used to configure the
>> module.
>> This is identical for all boards which inherit meson-gx-p23x-q20x:
>> - GXL S905D P230
>> - GXL S905D P231
>> - GXM S912 Q200
>> - GXM S912 Q201
>>
>> To get the HCI interface up one has to install bluez-utils and run:
>> hciattach -s115200 /dev/ttyAML1 bcm43xx 2000000 flow -
>>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
>> ---
>> arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 12 +++++++++++-
>> 1 file changed, 11 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
>> index 7a078bef04cd..7db779048091 100644
>> --- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
>> +++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
>> @@ -48,6 +48,7 @@
>> / {
>> aliases {
>> serial0 = &uart_AO;
>> + serial1 = &uart_A;
>> };
>>
>> chosen {
>> @@ -94,12 +95,21 @@
>>
>> sdio_pwrseq: sdio-pwrseq {
>> compatible = "mmc-pwrseq-simple";
>> - reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
>> + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>,
>> + <&gpio GPIOX_17 GPIO_ACTIVE_LOW>;
>> clocks = <&wifi32k>;
>> clock-names = "ext_clock";
>> };
>> };
>>
>> +/* This is connected to the Bluetooth module of the wifi/BT combo chip: */
>> +&uart_A {
>> + status = "okay";
>> + pinctrl-0 = <&uart_a_pins &uart_a_cts_rts_pins>;
>
> Nit: <&uart_a_pins>, <&uart_a_cts_rts_pins> please, like you've done for
> reset-gpios above.
indeed, not sure why I mixed it up. should I also send an update for
the pinctrl-documentation (as it seems to use the same pattern): [0]?
> Regards,
> Andreas
>
>> + pinctrl-names = "default";
>> + uart-has-rtscts;
>> +};
>> +
>> /* This UART is brought out to the DB9 connector */
>> &uart_AO {
>> status = "okay";
>>
>
>
> --
> SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Felix Imendörffer, Jane Smithard, Graham Norton
> HRB 21284 (AG Nürnberg)
[0] http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt?v=4.9#L74
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] fbdev: ssd1307fb: allow reset-gpios is missing
From: Icenowy Zheng @ 2017-01-16 9:50 UTC (permalink / raw)
To: Maxime Ripard
Cc: David Airlie, linux-fbdev, Rob Herring, linux-kernel, devicetree
2017年1月16日 16:02于 Maxime Ripard <maxime.ripard@free-electrons.com>写道:
>
> On Sun, Jan 15, 2017 at 07:21:46PM +0800, Icenowy Zheng wrote:
> > Currently some SSD1306 OLED modules are sold without a reset pin (only
> > VCC, GND, SCK, SDA four pins).
> >
> > Add support for missing reset-gpios property.
> >
> > Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
>
> Unfortunately, a similar patch has been sent a couple of times
> already:
> https://www.spinics.net/lists/devicetree/msg158330.html
Why is it never merged?
There are really boards that needs this function.
>
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
^ permalink raw reply
* Re: [PATCH v1 1/3] dt: bindings: add documentation for zx2967 family reset controller
From: Philipp Zabel @ 2017-01-16 9:57 UTC (permalink / raw)
To: Baoyou Xie
Cc: jun.nie-QSEj5FYQhm4dnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
shawnguo-DgEjT+Ai2ygdnm+yROfE0A,
xie.baoyou-Th6q7B73Y6EnDS1+zs4M5A,
chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
wang.qiang01-Th6q7B73Y6EnDS1+zs4M5A
In-Reply-To: <1484377530-30635-1-git-send-email-baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Hi,
On Sat, 2017-01-14 at 15:05 +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zx2967 family
> reset controller.
>
> Signed-off-by: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> .../devicetree/bindings/reset/zte,zx2967-reset.txt | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
>
> diff --git a/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt b/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
> new file mode 100644
> index 0000000..22d590e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
> @@ -0,0 +1,20 @@
> +ZTE zx2967 SoCs Reset Controller
> +=======================================
> +
> +Please also refer to reset.txt in this directory for common reset
> +controller binding usage.
> +
> +Required properties:
> +- compatible: should be one of the following.
> + * zte,zx296718-reset
> +- reg: physical base address of the controller and length of memory mapped
> + region.
> +- #reset-cells: must be 1.
> +
> +example:
> +
> + toprst: reset@1461060 {
That node should be named reset-controller.
> + compatible = "zte,zx296718-reset";
> + reg = <0x01461060 0x8>;
> + #reset-cells = <1>;
> + };
regards
Philipp
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v1 3/3] reset: zx2967: add reset controller driver for ZTE's zx2967 family
From: Philipp Zabel @ 2017-01-16 9:58 UTC (permalink / raw)
To: Baoyou Xie
Cc: jun.nie, robh+dt, mark.rutland, linux-arm-kernel, devicetree,
linux-kernel, shawnguo, xie.baoyou, chen.chaokai, wang.qiang01
In-Reply-To: <1484377530-30635-3-git-send-email-baoyou.xie@linaro.org>
On Sat, 2017-01-14 at 15:05 +0800, Baoyou Xie wrote:
> This patch adds reset controller driver for ZTE's zx2967 family.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
> drivers/reset/Kconfig | 6 ++
> drivers/reset/Makefile | 1 +
> drivers/reset/reset-zx2967.c | 136 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 143 insertions(+)
> create mode 100644 drivers/reset/reset-zx2967.c
>
> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
> index 172dc96..972d077 100644
> --- a/drivers/reset/Kconfig
> +++ b/drivers/reset/Kconfig
> @@ -92,6 +92,12 @@ config RESET_ZYNQ
> help
> This enables the reset controller driver for Xilinx Zynq SoCs.
>
> +config RESET_ZX2967
> + bool "ZX2967 Reset Driver"
> + depends on ARCH_ZX || COMPILE_TEST
> + help
> + This enables the reset controller driver for ZTE zx2967 family.
> +
> source "drivers/reset/sti/Kconfig"
> source "drivers/reset/hisilicon/Kconfig"
> source "drivers/reset/tegra/Kconfig"
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 13b346e..807b77b 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -14,3 +14,4 @@ obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
> obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
> obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
> obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
> +obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o
> diff --git a/drivers/reset/reset-zx2967.c b/drivers/reset/reset-zx2967.c
> new file mode 100644
> index 0000000..63f9c41
> --- /dev/null
> +++ b/drivers/reset/reset-zx2967.c
> @@ -0,0 +1,136 @@
> +/*
> + * ZTE's zx2967 family thermal sensor driver
This description is incorrect.
> + *
> + * Copyright (C) 2017 ZTE Ltd.
> + *
> + * Author: Baoyou Xie <baoyou.xie@linaro.org>
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +
> +struct zx2967_reset {
> + void __iomem *reg_base;
> + spinlock_t lock;
> + struct reset_controller_dev rcdev;
> +};
> +
> +static int zx2967_reset_assert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct zx2967_reset *reset = NULL;
> + int bank = id / 32;
> + int offset = id % 32;
> + unsigned int reg;
> + unsigned long flags;
> +
> + reset = container_of(rcdev, struct zx2967_reset, rcdev);
> +
> + spin_lock_irqsave(&reset->lock, flags);
> +
> + reg = readl(reset->reg_base + (bank * 4));
> + writel(reg & ~BIT(offset), reset->reg_base + (bank * 4));
> + reg = readl(reset->reg_base + (bank * 4));
> +
> + spin_unlock_irqrestore(&reset->lock, flags);
> +
> + return 0;
> +}
> +
> +static int zx2967_reset_deassert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct zx2967_reset *reset = NULL;
> + int bank = id / 32;
> + int offset = id % 32;
> + unsigned int reg;
> + unsigned long flags;
> +
> + reset = container_of(rcdev, struct zx2967_reset, rcdev);
> +
> + spin_lock_irqsave(&reset->lock, flags);
> +
> + reg = readl(reset->reg_base + (bank * 4));
> + writel(reg | BIT(offset), reset->reg_base + (bank * 4));
> + reg = readl(reset->reg_base + (bank * 4));
> +
> + spin_unlock_irqrestore(&reset->lock, flags);
> +
> + return 0;
> +}
> +
> +static struct reset_control_ops zx2967_reset_ops = {
> + .assert = zx2967_reset_assert,
> + .deassert = zx2967_reset_deassert,
> +};
> +
> +static int zx2967_reset_probe(struct platform_device *pdev)
> +{
> + struct zx2967_reset *reset;
> + struct resource *res;
> +
> + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
> + if (!reset)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + reset->reg_base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(reset->reg_base))
> + return PTR_ERR(reset->reg_base);
> +
> + spin_lock_init(&reset->lock);
> +
> + reset->rcdev.owner = THIS_MODULE;
> + reset->rcdev.nr_resets = resource_size(res) * 8;
> + reset->rcdev.ops = &zx2967_reset_ops;
> + reset->rcdev.of_node = pdev->dev.of_node;
> +
> + dev_info(&pdev->dev, "reset controller cnt:%d",
> + reset->rcdev.nr_resets);
> +
> + return reset_controller_register(&reset->rcdev);
As Shawn suggested, use the devm_ variant here. It allows you to drop
the remove function below.
> +}
> +
> +static int zx2967_reset_remove(struct platform_device *pdev)
> +{
> + struct zx2967_reset *reset = platform_get_drvdata(pdev);
> +
> + reset_controller_unregister(&reset->rcdev);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id zx2967_reset_dt_ids[] = {
> + { .compatible = "zte,zx296718-reset", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, zx2967_reset_dt_ids);
> +
> +static struct platform_driver zx2967_reset_driver = {
> + .probe = zx2967_reset_probe,
> + .remove = zx2967_reset_remove,
> + .driver = {
> + .name = "zx2967-reset",
> + .of_match_table = zx2967_reset_dt_ids,
> + },
> +};
> +
> +static int __init zx2967_reset_init(void)
> +{
> + return platform_driver_register(&zx2967_reset_driver);
> +}
> +arch_initcall(zx2967_reset_init);
> +
> +static void __exit zx2967_reset_exit(void)
> +{
> + platform_driver_unregister(&zx2967_reset_driver);
> +}
> +module_exit(zx2967_reset_exit);
> +
> +MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
> +MODULE_DESCRIPTION("ZTE zx2967 Reset Controller Driver");
> +MODULE_LICENSE("GPL");
regards
Philipp
^ permalink raw reply
* Re: [PATCH 09/10] ARM: dts: da850: add the SATA node
From: Bartosz Golaszewski @ 2017-01-16 10:03 UTC (permalink / raw)
To: David Lechner
Cc: Kevin Hilman, Sekhar Nori, Patrick Titiano, Michael Turquette,
Tejun Heo, Rob Herring, Mark Rutland, Russell King,
linux-ide-u79uwXL29TY76Z2rM5mHXA, linux-devicetree, LKML, arm-soc
In-Reply-To: <4eb4ada8-1d2d-2fa1-7961-21da56ea0082-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>
2017-01-13 20:36 GMT+01:00 David Lechner <david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>:
> On 01/13/2017 06:38 AM, Bartosz Golaszewski wrote:
>>
>> Add the SATA node to the da850 device tree.
>>
>> Signed-off-by: Bartosz Golaszewski <bgolaszewski-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
>> ---
>> arch/arm/boot/dts/da850.dtsi | 6 ++++++
>> 1 file changed, 6 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
>> index 1f6a47d..f5086b1 100644
>> --- a/arch/arm/boot/dts/da850.dtsi
>> +++ b/arch/arm/boot/dts/da850.dtsi
>> @@ -427,6 +427,12 @@
>> phy-names = "usb-phy";
>> status = "disabled";
>> };
>> + sata: ahci@0x218000 {
>
>
> 0x needs to be omitted.
>
> sata: ahci@218000 {
>
Will fix in v2.
Thanks,
Bartosz Golaszewski
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 0/11] Rockchip dw-mipi-dsi driver
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
linux-arm-kernel
Hi all
This patch serial is for RK3399 MIPI DSI. The MIPI DSI controller of
RK3399 is almost the same as RK3288, except a little bit of difference
in phy clock controlling and port id selection register.
And these patches also fixes some driver bugs; add the power domain
support.
they have been tested on rk3399 and rk3288 evb board.
Chris Zhong (7):
dt-bindings: add rk3399 support for dw-mipi-rockchip
drm/rockchip/dsi: dw-mipi: support RK3399 mipi dsi
drm/rockchip/dsi: remove mode_valid function
dt-bindings: add power domain node for dw-mipi-rockchip
drm/rockchip/dsi: add dw-mipi power domain support
drm/rockchip/dsi: fix phy clk lane stop state timeout
drm/rockchip/dsi: fix insufficient bandwidth of some panel
Mark Yao (2):
drm/rockchip/dsi: return probe defer if attach panel failed
drm/rockchip/dsi: fix mipi display can't found at init time
xubilv (2):
drm/rockchip/dsi: fix the issue can not send commands
drm/rockchip/dsi: decrease the value of Ths-prepare
.../display/rockchip/dw_mipi_dsi_rockchip.txt | 7 +-
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 254 +++++++++++++--------
2 files changed, 163 insertions(+), 98 deletions(-)
--
2.6.3
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* [PATCH v2 01/11] dt-bindings: add rk3399 support for dw-mipi-rockchip
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
The dw-mipi-dsi of rk3399 is almost the same as rk3288, the rk3399 has
additional phy config clock.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---
.../devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
index 1753f0c..0f82568 100644
--- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
@@ -5,10 +5,12 @@ Required properties:
- #address-cells: Should be <1>.
- #size-cells: Should be <0>.
- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi".
+ "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi".
- reg: Represent the physical address range of the controller.
- interrupts: Represent the controller's interrupt to the CPU(s).
- clocks, clock-names: Phandles to the controller's pll reference
- clock(ref) and APB clock(pclk), as described in [1].
+ clock(ref) and APB clock(pclk). For RK3399, a phy config clock
+ (phy_cfg) is additional required. As described in [1].
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
- ports: contain a port node with endpoint definitions as defined in [2].
For vopb,set the reg = <0> and set the reg = <1> for vopl.
--
2.6.3
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v2 02/11] drm/rockchip/dsi: dw-mipi: support RK3399 mipi dsi
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
The vopb/vopl switch register of RK3399 mipi is different from RK3288,
the default setting for mipi dsi mode is different too, so add a
of_device_id structure to distinguish them, and make sure set the
correct mode before mipi phy init.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 101 ++++++++++++++++++++++++---------
1 file changed, 74 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index d9aa382..04fd595 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -28,9 +28,17 @@
#define DRIVER_NAME "dw-mipi-dsi"
-#define GRF_SOC_CON6 0x025c
-#define DSI0_SEL_VOP_LIT (1 << 6)
-#define DSI1_SEL_VOP_LIT (1 << 9)
+#define RK3288_GRF_SOC_CON6 0x025c
+#define RK3288_DSI0_SEL_VOP_LIT BIT(6)
+#define RK3288_DSI1_SEL_VOP_LIT BIT(9)
+
+#define RK3399_GRF_SOC_CON19 0x6250
+#define RK3399_DSI0_SEL_VOP_LIT BIT(0)
+#define RK3399_DSI1_SEL_VOP_LIT BIT(4)
+
+/* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
+#define RK3399_GRF_SOC_CON22 0x6258
+#define RK3399_GRF_DSI_MODE 0xffff0000
#define DSI_VERSION 0x00
#define DSI_PWR_UP 0x04
@@ -147,7 +155,6 @@
#define LPRX_TO_CNT(p) ((p) & 0xffff)
#define DSI_BTA_TO_CNT 0x8c
-
#define DSI_LPCLK_CTRL 0x94
#define AUTO_CLKLANE_CTRL BIT(1)
#define PHY_TXREQUESTCLKHS BIT(0)
@@ -213,11 +220,11 @@
#define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
-#define INPUT_DIVIDER(val) ((val - 1) & 0x7f)
+#define INPUT_DIVIDER(val) (((val) - 1) & 0x7f)
#define LOW_PROGRAM_EN 0
#define HIGH_PROGRAM_EN BIT(7)
-#define LOOP_DIV_LOW_SEL(val) ((val - 1) & 0x1f)
-#define LOOP_DIV_HIGH_SEL(val) (((val - 1) >> 5) & 0x1f)
+#define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f)
+#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0x1f)
#define PLL_LOOP_DIV_EN BIT(5)
#define PLL_INPUT_DIV_EN BIT(4)
@@ -263,6 +270,11 @@ enum {
};
struct dw_mipi_dsi_plat_data {
+ u32 dsi0_en_bit;
+ u32 dsi1_en_bit;
+ u32 grf_switch_reg;
+ u32 grf_dsi0_mode;
+ u32 grf_dsi0_mode_reg;
unsigned int max_data_lanes;
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
@@ -279,6 +291,7 @@ struct dw_mipi_dsi {
struct clk *pllref_clk;
struct clk *pclk;
+ struct clk *phy_cfg_clk;
unsigned int lane_mbps; /* per lane */
u32 channel;
@@ -353,6 +366,7 @@ static inline struct dw_mipi_dsi *encoder_to_dsi(struct drm_encoder *encoder)
{
return container_of(encoder, struct dw_mipi_dsi, encoder);
}
+
static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val)
{
writel(val, dsi->base + reg);
@@ -364,7 +378,7 @@ static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg)
}
static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi *dsi, u8 test_code,
- u8 test_data)
+ u8 test_data)
{
/*
* With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
@@ -400,6 +414,14 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
dsi_write(dsi, DSI_PWR_UP, POWERUP);
+ if (!IS_ERR(dsi->phy_cfg_clk)) {
+ ret = clk_prepare_enable(dsi->phy_cfg_clk);
+ if (ret) {
+ dev_err(dsi->dev, "Failed to enable phy_cfg_clk\n");
+ return ret;
+ }
+ }
+
dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
VCO_RANGE_CON_SEL(vco) |
VCO_IN_CAP_CON_LOW |
@@ -439,22 +461,23 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
-
ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS,
val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US);
if (ret < 0) {
dev_err(dsi->dev, "failed to wait for phy lock state\n");
- return ret;
+ goto phy_init_end;
}
ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS,
val, val & STOP_STATE_CLK_LANE, 1000,
PHY_STATUS_TIMEOUT_US);
- if (ret < 0) {
+ if (ret < 0)
dev_err(dsi->dev,
"failed to wait for phy clk lane stop state\n");
- return ret;
- }
+
+phy_init_end:
+ if (!IS_ERR(dsi->phy_cfg_clk))
+ clk_disable_unprepare(dsi->phy_cfg_clk);
return ret;
}
@@ -512,7 +535,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
if (device->lanes > dsi->pdata->max_data_lanes) {
dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
- device->lanes);
+ device->lanes);
return -EINVAL;
}
@@ -815,8 +838,8 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
}
static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
int ret;
@@ -878,6 +901,7 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
{
struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
+ const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
u32 val;
@@ -886,6 +910,10 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
return;
}
+ if (pdata->grf_dsi0_mode_reg)
+ regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
+ pdata->grf_dsi0_mode);
+
dw_mipi_dsi_phy_init(dsi);
dw_mipi_dsi_wait_for_two_frames(dsi);
@@ -895,11 +923,11 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
clk_disable_unprepare(dsi->pclk);
if (mux)
- val = DSI0_SEL_VOP_LIT | (DSI0_SEL_VOP_LIT << 16);
+ val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
else
- val = DSI0_SEL_VOP_LIT << 16;
+ val = pdata->dsi0_en_bit << 16;
- regmap_write(dsi->grf_regmap, GRF_SOC_CON6, val);
+ regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
}
@@ -931,7 +959,7 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
return 0;
}
-static struct drm_encoder_helper_funcs
+static const struct drm_encoder_helper_funcs
dw_mipi_dsi_encoder_helper_funcs = {
.commit = dw_mipi_dsi_encoder_commit,
.mode_set = dw_mipi_dsi_encoder_mode_set,
@@ -939,7 +967,7 @@ dw_mipi_dsi_encoder_helper_funcs = {
.atomic_check = dw_mipi_dsi_encoder_atomic_check,
};
-static struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
+static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
@@ -975,7 +1003,7 @@ static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
-static struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
+static const struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = dw_mipi_dsi_drm_connector_destroy,
@@ -985,7 +1013,7 @@ static struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
};
static int dw_mipi_dsi_register(struct drm_device *drm,
- struct dw_mipi_dsi *dsi)
+ struct dw_mipi_dsi *dsi)
{
struct drm_encoder *encoder = &dsi->encoder;
struct drm_connector *connector = &dsi->connector;
@@ -1006,14 +1034,14 @@ static int dw_mipi_dsi_register(struct drm_device *drm,
drm_encoder_helper_add(&dsi->encoder,
&dw_mipi_dsi_encoder_helper_funcs);
ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs,
- DRM_MODE_ENCODER_DSI, NULL);
+ DRM_MODE_ENCODER_DSI, NULL);
if (ret) {
dev_err(dev, "Failed to initialize encoder with drm\n");
return ret;
}
drm_connector_helper_add(connector,
- &dw_mipi_dsi_connector_helper_funcs);
+ &dw_mipi_dsi_connector_helper_funcs);
drm_connector_init(drm, &dsi->connector,
&dw_mipi_dsi_atomic_connector_funcs,
@@ -1059,21 +1087,36 @@ static enum drm_mode_status rk3288_mipi_dsi_mode_valid(
}
static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
+ .dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT,
+ .dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT,
+ .grf_switch_reg = RK3288_GRF_SOC_CON6,
.max_data_lanes = 4,
.mode_valid = rk3288_mipi_dsi_mode_valid,
};
+static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
+ .dsi0_en_bit = RK3399_DSI0_SEL_VOP_LIT,
+ .dsi1_en_bit = RK3399_DSI1_SEL_VOP_LIT,
+ .grf_switch_reg = RK3399_GRF_SOC_CON19,
+ .grf_dsi0_mode = RK3399_GRF_DSI_MODE,
+ .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
+ .max_data_lanes = 4,
+};
+
static const struct of_device_id dw_mipi_dsi_dt_ids[] = {
{
.compatible = "rockchip,rk3288-mipi-dsi",
.data = &rk3288_mipi_dsi_drv_data,
+ }, {
+ .compatible = "rockchip,rk3399-mipi-dsi",
+ .data = &rk3399_mipi_dsi_drv_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
- void *data)
+ void *data)
{
const struct of_device_id *of_id =
of_match_device(dw_mipi_dsi_dt_ids, dev);
@@ -1117,6 +1160,10 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
return ret;
}
+ dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
+ if (IS_ERR(dsi->phy_cfg_clk))
+ dev_dbg(dev, "have not phy_cfg_clk\n");
+
ret = clk_prepare_enable(dsi->pllref_clk);
if (ret) {
dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
@@ -1141,7 +1188,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
}
static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
- void *data)
+ void *data)
{
struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
--
2.6.3
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v2 03/11] drm/rockchip/dsi: remove mode_valid function
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
The MIPI DSI do not need check the validity of resolution, the max
resolution should depend VOP. Hence, remove rk3288_mipi_dsi_mode_valid
here.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 39 ----------------------------------
1 file changed, 39 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 04fd595..8f8d48a 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -276,8 +276,6 @@ struct dw_mipi_dsi_plat_data {
u32 grf_dsi0_mode;
u32 grf_dsi0_mode_reg;
unsigned int max_data_lanes;
- enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
- struct drm_display_mode *mode);
};
struct dw_mipi_dsi {
@@ -978,23 +976,8 @@ static int dw_mipi_dsi_connector_get_modes(struct drm_connector *connector)
return drm_panel_get_modes(dsi->panel);
}
-static enum drm_mode_status dw_mipi_dsi_mode_valid(
- struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- struct dw_mipi_dsi *dsi = con_to_dsi(connector);
-
- enum drm_mode_status mode_status = MODE_OK;
-
- if (dsi->pdata->mode_valid)
- mode_status = dsi->pdata->mode_valid(connector, mode);
-
- return mode_status;
-}
-
static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = {
.get_modes = dw_mipi_dsi_connector_get_modes,
- .mode_valid = dw_mipi_dsi_mode_valid,
};
static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
@@ -1065,33 +1048,11 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
return 0;
}
-static enum drm_mode_status rk3288_mipi_dsi_mode_valid(
- struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- /*
- * The VID_PKT_SIZE field in the DSI_VID_PKT_CFG
- * register is 11-bit.
- */
- if (mode->hdisplay > 0x7ff)
- return MODE_BAD_HVALUE;
-
- /*
- * The V_ACTIVE_LINES field in the DSI_VTIMING_CFG
- * register is 11-bit.
- */
- if (mode->vdisplay > 0x7ff)
- return MODE_BAD_VVALUE;
-
- return MODE_OK;
-}
-
static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
.dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT,
.dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT,
.grf_switch_reg = RK3288_GRF_SOC_CON6,
.max_data_lanes = 4,
- .mode_valid = rk3288_mipi_dsi_mode_valid,
};
static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
--
2.6.3
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox