Message ID | 20180204101934.27842-2-noltari@gmail.com |
---|---|
State | Superseded, archived |
Headers | show |
Series | bmips: add support for bcm6368 usbh phy | expand |
On 04.02.2018 11:19, Álvaro Fernández Rojas wrote: > Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com> > --- > drivers/phy/Kconfig | 6 ++ > drivers/phy/Makefile | 1 + > drivers/phy/bcm6368-usbh-phy.c | 203 +++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 210 insertions(+) > create mode 100644 drivers/phy/bcm6368-usbh-phy.c > Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> nits below > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig > index 43fb4c9bfd..d3fa9ded2a 100644 > --- a/drivers/phy/Kconfig > +++ b/drivers/phy/Kconfig > @@ -71,6 +71,12 @@ config BCM6358_USBH_PHY > help > Support for the Broadcom MIPS BCM6358 USBH PHY. > > +config BCM6368_USBH_PHY > + bool "BCM6368 USBH PHY support" > + depends on PHY && ARCH_BMIPS > + help > + Support for the Broadcom MIPS BCM6368 USBH PHY. > + > config PIPE3_PHY > bool "Support omap's PIPE3 PHY" > depends on PHY && ARCH_OMAP2PLUS > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile > index 04843fd49b..d8239854a3 100644 > --- a/drivers/phy/Makefile > +++ b/drivers/phy/Makefile > @@ -9,6 +9,7 @@ obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o > obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o > obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o > obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o > +obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o > obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o > obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o > obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o > diff --git a/drivers/phy/bcm6368-usbh-phy.c b/drivers/phy/bcm6368-usbh-phy.c > new file mode 100644 > index 0000000000..93577b30ba > --- /dev/null > +++ b/drivers/phy/bcm6368-usbh-phy.c > @@ -0,0 +1,203 @@ > +/* > + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com> > + * > + * Derived from linux/arch/mips/bcm63xx/usb-common.c: > + * Copyright 2008 Maxime Bizon <mbizon@freebox.fr> > + * Copyright 2013 Florian Fainelli <florian@openwrt.org> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <clk.h> > +#include <dm.h> > +#include <generic-phy.h> > +#include <power-domain.h> > +#include <reset.h> > +#include <asm/io.h> > +#include <dm/device.h> > + > +/* USBH PLL Control register */ > +#define USBH_PLL_REG 0x18 > +#define USBH_PLL_IDDQ_PWRDN BIT(9) > +#define USBH_PLL_PWRDN_DELAY BIT(10) > + > +/* USBH Swap Control register */ > +#define USBH_SWAP_REG 0x1c > +#define USBH_SWAP_OHCI_DATA BIT(0) > +#define USBH_SWAP_OHCI_ENDIAN BIT(1) > +#define USBH_SWAP_EHCI_DATA BIT(3) > +#define USBH_SWAP_EHCI_ENDIAN BIT(4) > + > +/* USBH Setup register */ > +#define USBH_SETUP_REG 0x28 > +#define USBH_SETUP_IOC BIT(4) > +#define USBH_SETUP_IPP BIT(5) > + > +struct bcm6368_usbh_hw { > + uint32_t setup_clr; > + uint32_t setup_set; > + uint32_t pll_clr; > +}; > + > +struct bcm6368_usbh_priv { > + const struct bcm6368_usbh_hw *hw; > + void __iomem *regs; > +}; > + > +static int bcm6368_usbh_init(struct phy *phy) > +{ > + struct bcm6368_usbh_priv *priv = dev_get_priv(phy->dev); > + const struct bcm6368_usbh_hw *hw = priv->hw; > + > + /* configure to work in native cpu endian */ > + clrsetbits_be32(priv->regs + USBH_SWAP_REG, > + USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN, > + USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA); > + > + /* setup config */ > + if (hw->setup_clr) > + clrbits_be32(priv->regs + USBH_SETUP_REG, > + hw->setup_clr); > + > + setbits_be32(priv->regs + USBH_SETUP_REG, hw->setup_set); > + > + /* enable pll control */ > + if (hw->pll_clr) > + clrbits_be32(priv->regs + USBH_PLL_REG, > + hw->pll_clr); > + > + return 0; > +} > + > +static struct phy_ops bcm6368_usbh_ops = { > + .init = bcm6368_usbh_init, > +}; > + > +static const struct bcm6368_usbh_hw bcm6328_hw = { > + .pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY, > + .setup_clr = 0, > + .setup_set = USBH_SETUP_IOC, > +}; > + > +static const struct bcm6368_usbh_hw bcm6362_hw = { > + .pll_clr = 0, > + .setup_clr = 0, > + .setup_set = USBH_SETUP_IOC, > +}; > + > +static const struct bcm6368_usbh_hw bcm6368_hw = { > + .pll_clr = 0, > + .setup_clr = 0, > + .setup_set = USBH_SETUP_IOC, > +}; > + > +static const struct bcm6368_usbh_hw bcm63268_hw = { > + .pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY, > + .setup_clr = USBH_SETUP_IPP, > + .setup_set = USBH_SETUP_IOC, > +}; > + > +static const struct udevice_id bcm6368_usbh_ids[] = { > + { > + .compatible = "brcm,bcm6328-usbh", > + .data = (ulong)&bcm6328_hw, > + }, { > + .compatible = "brcm,bcm6362-usbh", > + .data = (ulong)&bcm6362_hw, > + }, { > + .compatible = "brcm,bcm6368-usbh", > + .data = (ulong)&bcm6368_hw, > + }, { > + .compatible = "brcm,bcm63268-usbh", > + .data = (ulong)&bcm63268_hw, > + }, { /* sentinel */ } > +}; > + > +static int bcm6368_usbh_probe(struct udevice *dev) > +{ > + struct bcm6368_usbh_priv *priv = dev_get_priv(dev); > + const struct bcm6368_usbh_hw *hw = > + (const struct bcm6368_usbh_hw *)dev_get_driver_data(dev); > +#if defined(CONFIG_POWER_DOMAIN) > + struct power_domain pwr_dom; > +#endif would the driver work without CONFIG_POWER_DOMAIN or would this be always needed? I'm asking because in the USB PHY driver for BCM6318 you do a "select POWER_DOMAIN". > + struct reset_ctl rst_ctl; > + struct clk clk; > + fdt_addr_t addr; > + fdt_size_t size; > + int ret; > + > + addr = devfdt_get_addr_size_index(dev, 0, &size); > + if (addr == FDT_ADDR_T_NONE) > + return -EINVAL; > + > + priv->regs = ioremap(addr, size); > + priv->hw = hw; > + > + /* enable usbh clock */ > + ret = clk_get_by_name(dev, "usbh", &clk); > + if (ret < 0) > + return ret; > + > + ret = clk_enable(&clk); > + if (ret < 0) > + return ret; > + > + ret = clk_free(&clk); > + if (ret < 0) > + return ret; > + > +#if defined(CONFIG_POWER_DOMAIN) > + /* enable power domain */ > + ret = power_domain_get(dev, &pwr_dom); > + if (ret < 0) > + return ret; > + > + ret = power_domain_on(&pwr_dom); > + if (ret < 0) > + return ret; > + > + ret = power_domain_free(&pwr_dom); > + if (ret < 0) > + return ret; > +#endif > + > + /* perform reset */ > + ret = reset_get_by_index(dev, 0, &rst_ctl); > + if (ret < 0) > + return ret; > + > + ret = reset_deassert(&rst_ctl); > + if (ret < 0) > + return ret; > + > + ret = reset_free(&rst_ctl); > + if (ret < 0) > + return ret; > + > + /* enable usb_ref clock */ > + ret = clk_get_by_name(dev, "usb_ref", &clk); > + if (!ret) { > + ret = clk_enable(&clk); > + if (ret < 0) > + return ret; > + > + ret = clk_free(&clk); > + if (ret < 0) > + return ret; > + } > + > + mdelay(100); > + > + return 0; > +} > + > +U_BOOT_DRIVER(bcm6368_usbh) = { > + .name = "bcm6368-usbh", > + .id = UCLASS_PHY, > + .of_match = bcm6368_usbh_ids, > + .ops = &bcm6368_usbh_ops, > + .priv_auto_alloc_size = sizeof(struct bcm6368_usbh_priv), > + .probe = bcm6368_usbh_probe, > +}; >
Hi Daniel, El 04/02/2018 a las 19:32, Daniel Schwierzeck escribió: > > On 04.02.2018 11:19, Álvaro Fernández Rojas wrote: >> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com> >> --- >> drivers/phy/Kconfig | 6 ++ >> drivers/phy/Makefile | 1 + >> drivers/phy/bcm6368-usbh-phy.c | 203 +++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 210 insertions(+) >> create mode 100644 drivers/phy/bcm6368-usbh-phy.c >> > Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> > > nits below > >> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig >> index 43fb4c9bfd..d3fa9ded2a 100644 >> --- a/drivers/phy/Kconfig >> +++ b/drivers/phy/Kconfig >> @@ -71,6 +71,12 @@ config BCM6358_USBH_PHY >> help >> Support for the Broadcom MIPS BCM6358 USBH PHY. >> >> +config BCM6368_USBH_PHY >> + bool "BCM6368 USBH PHY support" >> + depends on PHY && ARCH_BMIPS >> + help >> + Support for the Broadcom MIPS BCM6368 USBH PHY. >> + >> config PIPE3_PHY >> bool "Support omap's PIPE3 PHY" >> depends on PHY && ARCH_OMAP2PLUS >> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile >> index 04843fd49b..d8239854a3 100644 >> --- a/drivers/phy/Makefile >> +++ b/drivers/phy/Makefile >> @@ -9,6 +9,7 @@ obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o >> obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o >> obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o >> obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o >> +obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o >> obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o >> obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o >> obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o >> diff --git a/drivers/phy/bcm6368-usbh-phy.c b/drivers/phy/bcm6368-usbh-phy.c >> new file mode 100644 >> index 0000000000..93577b30ba >> --- /dev/null >> +++ b/drivers/phy/bcm6368-usbh-phy.c >> @@ -0,0 +1,203 @@ >> +/* >> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com> >> + * >> + * Derived from linux/arch/mips/bcm63xx/usb-common.c: >> + * Copyright 2008 Maxime Bizon <mbizon@freebox.fr> >> + * Copyright 2013 Florian Fainelli <florian@openwrt.org> >> + * >> + * SPDX-License-Identifier: GPL-2.0+ >> + */ >> + >> +#include <common.h> >> +#include <clk.h> >> +#include <dm.h> >> +#include <generic-phy.h> >> +#include <power-domain.h> >> +#include <reset.h> >> +#include <asm/io.h> >> +#include <dm/device.h> >> + >> +/* USBH PLL Control register */ >> +#define USBH_PLL_REG 0x18 >> +#define USBH_PLL_IDDQ_PWRDN BIT(9) >> +#define USBH_PLL_PWRDN_DELAY BIT(10) >> + >> +/* USBH Swap Control register */ >> +#define USBH_SWAP_REG 0x1c >> +#define USBH_SWAP_OHCI_DATA BIT(0) >> +#define USBH_SWAP_OHCI_ENDIAN BIT(1) >> +#define USBH_SWAP_EHCI_DATA BIT(3) >> +#define USBH_SWAP_EHCI_ENDIAN BIT(4) >> + >> +/* USBH Setup register */ >> +#define USBH_SETUP_REG 0x28 >> +#define USBH_SETUP_IOC BIT(4) >> +#define USBH_SETUP_IPP BIT(5) >> + >> +struct bcm6368_usbh_hw { >> + uint32_t setup_clr; >> + uint32_t setup_set; >> + uint32_t pll_clr; >> +}; >> + >> +struct bcm6368_usbh_priv { >> + const struct bcm6368_usbh_hw *hw; >> + void __iomem *regs; >> +}; >> + >> +static int bcm6368_usbh_init(struct phy *phy) >> +{ >> + struct bcm6368_usbh_priv *priv = dev_get_priv(phy->dev); >> + const struct bcm6368_usbh_hw *hw = priv->hw; >> + >> + /* configure to work in native cpu endian */ >> + clrsetbits_be32(priv->regs + USBH_SWAP_REG, >> + USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN, >> + USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA); >> + >> + /* setup config */ >> + if (hw->setup_clr) >> + clrbits_be32(priv->regs + USBH_SETUP_REG, >> + hw->setup_clr); >> + >> + setbits_be32(priv->regs + USBH_SETUP_REG, hw->setup_set); >> + >> + /* enable pll control */ >> + if (hw->pll_clr) >> + clrbits_be32(priv->regs + USBH_PLL_REG, >> + hw->pll_clr); >> + >> + return 0; >> +} >> + >> +static struct phy_ops bcm6368_usbh_ops = { >> + .init = bcm6368_usbh_init, >> +}; >> + >> +static const struct bcm6368_usbh_hw bcm6328_hw = { >> + .pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY, >> + .setup_clr = 0, >> + .setup_set = USBH_SETUP_IOC, >> +}; >> + >> +static const struct bcm6368_usbh_hw bcm6362_hw = { >> + .pll_clr = 0, >> + .setup_clr = 0, >> + .setup_set = USBH_SETUP_IOC, >> +}; >> + >> +static const struct bcm6368_usbh_hw bcm6368_hw = { >> + .pll_clr = 0, >> + .setup_clr = 0, >> + .setup_set = USBH_SETUP_IOC, >> +}; >> + >> +static const struct bcm6368_usbh_hw bcm63268_hw = { >> + .pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY, >> + .setup_clr = USBH_SETUP_IPP, >> + .setup_set = USBH_SETUP_IOC, >> +}; >> + >> +static const struct udevice_id bcm6368_usbh_ids[] = { >> + { >> + .compatible = "brcm,bcm6328-usbh", >> + .data = (ulong)&bcm6328_hw, >> + }, { >> + .compatible = "brcm,bcm6362-usbh", >> + .data = (ulong)&bcm6362_hw, >> + }, { >> + .compatible = "brcm,bcm6368-usbh", >> + .data = (ulong)&bcm6368_hw, >> + }, { >> + .compatible = "brcm,bcm63268-usbh", >> + .data = (ulong)&bcm63268_hw, >> + }, { /* sentinel */ } >> +}; >> + >> +static int bcm6368_usbh_probe(struct udevice *dev) >> +{ >> + struct bcm6368_usbh_priv *priv = dev_get_priv(dev); >> + const struct bcm6368_usbh_hw *hw = >> + (const struct bcm6368_usbh_hw *)dev_get_driver_data(dev); >> +#if defined(CONFIG_POWER_DOMAIN) >> + struct power_domain pwr_dom; >> +#endif > would the driver work without CONFIG_POWER_DOMAIN or would this be > always needed? I'm asking because in the USB PHY driver for BCM6318 you > do a "select POWER_DOMAIN". Only 6328, 6362 and 63268 have a power domain controller. However, the 6368 doesn't have it. > >> + struct reset_ctl rst_ctl; >> + struct clk clk; >> + fdt_addr_t addr; >> + fdt_size_t size; >> + int ret; >> + >> + addr = devfdt_get_addr_size_index(dev, 0, &size); >> + if (addr == FDT_ADDR_T_NONE) >> + return -EINVAL; >> + >> + priv->regs = ioremap(addr, size); >> + priv->hw = hw; >> + >> + /* enable usbh clock */ >> + ret = clk_get_by_name(dev, "usbh", &clk); >> + if (ret < 0) >> + return ret; >> + >> + ret = clk_enable(&clk); >> + if (ret < 0) >> + return ret; >> + >> + ret = clk_free(&clk); >> + if (ret < 0) >> + return ret; >> + >> +#if defined(CONFIG_POWER_DOMAIN) >> + /* enable power domain */ >> + ret = power_domain_get(dev, &pwr_dom); >> + if (ret < 0) >> + return ret; >> + >> + ret = power_domain_on(&pwr_dom); >> + if (ret < 0) >> + return ret; >> + >> + ret = power_domain_free(&pwr_dom); >> + if (ret < 0) >> + return ret; >> +#endif >> + >> + /* perform reset */ >> + ret = reset_get_by_index(dev, 0, &rst_ctl); >> + if (ret < 0) >> + return ret; >> + >> + ret = reset_deassert(&rst_ctl); >> + if (ret < 0) >> + return ret; >> + >> + ret = reset_free(&rst_ctl); >> + if (ret < 0) >> + return ret; >> + >> + /* enable usb_ref clock */ >> + ret = clk_get_by_name(dev, "usb_ref", &clk); >> + if (!ret) { >> + ret = clk_enable(&clk); >> + if (ret < 0) >> + return ret; >> + >> + ret = clk_free(&clk); >> + if (ret < 0) >> + return ret; >> + } >> + >> + mdelay(100); >> + >> + return 0; >> +} >> + >> +U_BOOT_DRIVER(bcm6368_usbh) = { >> + .name = "bcm6368-usbh", >> + .id = UCLASS_PHY, >> + .of_match = bcm6368_usbh_ids, >> + .ops = &bcm6368_usbh_ops, >> + .priv_auto_alloc_size = sizeof(struct bcm6368_usbh_priv), >> + .probe = bcm6368_usbh_probe, >> +}; >>
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 43fb4c9bfd..d3fa9ded2a 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -71,6 +71,12 @@ config BCM6358_USBH_PHY help Support for the Broadcom MIPS BCM6358 USBH PHY. +config BCM6368_USBH_PHY + bool "BCM6368 USBH PHY support" + depends on PHY && ARCH_BMIPS + help + Support for the Broadcom MIPS BCM6368 USBH PHY. + config PIPE3_PHY bool "Support omap's PIPE3 PHY" depends on PHY && ARCH_OMAP2PLUS diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 04843fd49b..d8239854a3 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o +obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o diff --git a/drivers/phy/bcm6368-usbh-phy.c b/drivers/phy/bcm6368-usbh-phy.c new file mode 100644 index 0000000000..93577b30ba --- /dev/null +++ b/drivers/phy/bcm6368-usbh-phy.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com> + * + * Derived from linux/arch/mips/bcm63xx/usb-common.c: + * Copyright 2008 Maxime Bizon <mbizon@freebox.fr> + * Copyright 2013 Florian Fainelli <florian@openwrt.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <generic-phy.h> +#include <power-domain.h> +#include <reset.h> +#include <asm/io.h> +#include <dm/device.h> + +/* USBH PLL Control register */ +#define USBH_PLL_REG 0x18 +#define USBH_PLL_IDDQ_PWRDN BIT(9) +#define USBH_PLL_PWRDN_DELAY BIT(10) + +/* USBH Swap Control register */ +#define USBH_SWAP_REG 0x1c +#define USBH_SWAP_OHCI_DATA BIT(0) +#define USBH_SWAP_OHCI_ENDIAN BIT(1) +#define USBH_SWAP_EHCI_DATA BIT(3) +#define USBH_SWAP_EHCI_ENDIAN BIT(4) + +/* USBH Setup register */ +#define USBH_SETUP_REG 0x28 +#define USBH_SETUP_IOC BIT(4) +#define USBH_SETUP_IPP BIT(5) + +struct bcm6368_usbh_hw { + uint32_t setup_clr; + uint32_t setup_set; + uint32_t pll_clr; +}; + +struct bcm6368_usbh_priv { + const struct bcm6368_usbh_hw *hw; + void __iomem *regs; +}; + +static int bcm6368_usbh_init(struct phy *phy) +{ + struct bcm6368_usbh_priv *priv = dev_get_priv(phy->dev); + const struct bcm6368_usbh_hw *hw = priv->hw; + + /* configure to work in native cpu endian */ + clrsetbits_be32(priv->regs + USBH_SWAP_REG, + USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN, + USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA); + + /* setup config */ + if (hw->setup_clr) + clrbits_be32(priv->regs + USBH_SETUP_REG, + hw->setup_clr); + + setbits_be32(priv->regs + USBH_SETUP_REG, hw->setup_set); + + /* enable pll control */ + if (hw->pll_clr) + clrbits_be32(priv->regs + USBH_PLL_REG, + hw->pll_clr); + + return 0; +} + +static struct phy_ops bcm6368_usbh_ops = { + .init = bcm6368_usbh_init, +}; + +static const struct bcm6368_usbh_hw bcm6328_hw = { + .pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY, + .setup_clr = 0, + .setup_set = USBH_SETUP_IOC, +}; + +static const struct bcm6368_usbh_hw bcm6362_hw = { + .pll_clr = 0, + .setup_clr = 0, + .setup_set = USBH_SETUP_IOC, +}; + +static const struct bcm6368_usbh_hw bcm6368_hw = { + .pll_clr = 0, + .setup_clr = 0, + .setup_set = USBH_SETUP_IOC, +}; + +static const struct bcm6368_usbh_hw bcm63268_hw = { + .pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY, + .setup_clr = USBH_SETUP_IPP, + .setup_set = USBH_SETUP_IOC, +}; + +static const struct udevice_id bcm6368_usbh_ids[] = { + { + .compatible = "brcm,bcm6328-usbh", + .data = (ulong)&bcm6328_hw, + }, { + .compatible = "brcm,bcm6362-usbh", + .data = (ulong)&bcm6362_hw, + }, { + .compatible = "brcm,bcm6368-usbh", + .data = (ulong)&bcm6368_hw, + }, { + .compatible = "brcm,bcm63268-usbh", + .data = (ulong)&bcm63268_hw, + }, { /* sentinel */ } +}; + +static int bcm6368_usbh_probe(struct udevice *dev) +{ + struct bcm6368_usbh_priv *priv = dev_get_priv(dev); + const struct bcm6368_usbh_hw *hw = + (const struct bcm6368_usbh_hw *)dev_get_driver_data(dev); +#if defined(CONFIG_POWER_DOMAIN) + struct power_domain pwr_dom; +#endif + struct reset_ctl rst_ctl; + struct clk clk; + fdt_addr_t addr; + fdt_size_t size; + int ret; + + addr = devfdt_get_addr_size_index(dev, 0, &size); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->regs = ioremap(addr, size); + priv->hw = hw; + + /* enable usbh clock */ + ret = clk_get_by_name(dev, "usbh", &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + if (ret < 0) + return ret; + + ret = clk_free(&clk); + if (ret < 0) + return ret; + +#if defined(CONFIG_POWER_DOMAIN) + /* enable power domain */ + ret = power_domain_get(dev, &pwr_dom); + if (ret < 0) + return ret; + + ret = power_domain_on(&pwr_dom); + if (ret < 0) + return ret; + + ret = power_domain_free(&pwr_dom); + if (ret < 0) + return ret; +#endif + + /* perform reset */ + ret = reset_get_by_index(dev, 0, &rst_ctl); + if (ret < 0) + return ret; + + ret = reset_deassert(&rst_ctl); + if (ret < 0) + return ret; + + ret = reset_free(&rst_ctl); + if (ret < 0) + return ret; + + /* enable usb_ref clock */ + ret = clk_get_by_name(dev, "usb_ref", &clk); + if (!ret) { + ret = clk_enable(&clk); + if (ret < 0) + return ret; + + ret = clk_free(&clk); + if (ret < 0) + return ret; + } + + mdelay(100); + + return 0; +} + +U_BOOT_DRIVER(bcm6368_usbh) = { + .name = "bcm6368-usbh", + .id = UCLASS_PHY, + .of_match = bcm6368_usbh_ids, + .ops = &bcm6368_usbh_ops, + .priv_auto_alloc_size = sizeof(struct bcm6368_usbh_priv), + .probe = bcm6368_usbh_probe, +};
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com> --- drivers/phy/Kconfig | 6 ++ drivers/phy/Makefile | 1 + drivers/phy/bcm6368-usbh-phy.c | 203 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 drivers/phy/bcm6368-usbh-phy.c