uboot/drivers/phy/sti_usb_phy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
   4 * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics.
   5 */
   6
   7#include <common.h>
   8#include <log.h>
   9#include <asm/io.h>
  10#include <bitfield.h>
  11#include <dm.h>
  12#include <errno.h>
  13#include <fdtdec.h>
  14#include <generic-phy.h>
  15#include <linux/libfdt.h>
  16#include <regmap.h>
  17#include <reset-uclass.h>
  18#include <syscon.h>
  19#include <wait_bit.h>
  20
  21#include <linux/bitops.h>
  22#include <linux/compat.h>
  23
  24DECLARE_GLOBAL_DATA_PTR;
  25
  26/* Default PHY_SEL and REFCLKSEL configuration */
  27#define STIH407_USB_PICOPHY_CTRL_PORT_CONF      0x6
  28
  29/* ports parameters overriding */
  30#define STIH407_USB_PICOPHY_PARAM_DEF           0x39a4dc
  31
  32#define PHYPARAM_REG    1
  33#define PHYCTRL_REG     2
  34#define PHYPARAM_NB     3
  35
  36struct sti_usb_phy {
  37        struct regmap *regmap;
  38        struct reset_ctl global_ctl;
  39        struct reset_ctl port_ctl;
  40        int param;
  41        int ctrl;
  42};
  43
  44static int sti_usb_phy_deassert(struct sti_usb_phy *phy)
  45{
  46        int ret;
  47
  48        ret = reset_deassert(&phy->global_ctl);
  49        if (ret < 0) {
  50                pr_err("PHY global deassert failed: %d", ret);
  51                return ret;
  52        }
  53
  54        ret = reset_deassert(&phy->port_ctl);
  55        if (ret < 0)
  56                pr_err("PHY port deassert failed: %d", ret);
  57
  58        return ret;
  59}
  60
  61static int sti_usb_phy_init(struct phy *usb_phy)
  62{
  63        struct udevice *dev = usb_phy->dev;
  64        struct sti_usb_phy *phy = dev_get_priv(dev);
  65        void __iomem *reg;
  66
  67        /* set ctrl picophy value */
  68        reg = (void __iomem *)phy->regmap->ranges[0].start + phy->ctrl;
  69        /* CTRL_PORT mask is 0x1f */
  70        clrsetbits_le32(reg, 0x1f, STIH407_USB_PICOPHY_CTRL_PORT_CONF);
  71
  72        /* set ports parameters overriding */
  73        reg = (void __iomem *)phy->regmap->ranges[0].start + phy->param;
  74        /* PARAM_DEF mask is 0xffffffff */
  75        clrsetbits_le32(reg, 0xffffffff, STIH407_USB_PICOPHY_PARAM_DEF);
  76
  77        return sti_usb_phy_deassert(phy);
  78}
  79
  80static int sti_usb_phy_exit(struct phy *usb_phy)
  81{
  82        struct udevice *dev = usb_phy->dev;
  83        struct sti_usb_phy *phy = dev_get_priv(dev);
  84        int ret;
  85
  86        ret = reset_assert(&phy->port_ctl);
  87        if (ret < 0) {
  88                pr_err("PHY port assert failed: %d", ret);
  89                return ret;
  90        }
  91
  92        ret = reset_assert(&phy->global_ctl);
  93        if (ret < 0)
  94                pr_err("PHY global assert failed: %d", ret);
  95
  96        return ret;
  97}
  98
  99struct phy_ops sti_usb_phy_ops = {
 100        .init = sti_usb_phy_init,
 101        .exit = sti_usb_phy_exit,
 102};
 103
 104int sti_usb_phy_probe(struct udevice *dev)
 105{
 106        struct sti_usb_phy *priv = dev_get_priv(dev);
 107        struct udevice *syscon;
 108        struct ofnode_phandle_args syscfg_phandle;
 109        u32 cells[PHYPARAM_NB];
 110        int ret, count;
 111
 112        /* get corresponding syscon phandle */
 113        ret = dev_read_phandle_with_args(dev, "st,syscfg", NULL, 0, 0,
 114                                         &syscfg_phandle);
 115
 116        if (ret < 0) {
 117                pr_err("Can't get syscfg phandle: %d\n", ret);
 118                return ret;
 119        }
 120
 121        ret = uclass_get_device_by_ofnode(UCLASS_SYSCON, syscfg_phandle.node,
 122                                          &syscon);
 123        if (ret) {
 124                pr_err("unable to find syscon device (%d)\n", ret);
 125                return ret;
 126        }
 127
 128        priv->regmap = syscon_get_regmap(syscon);
 129        if (!priv->regmap) {
 130                pr_err("unable to find regmap\n");
 131                return -ENODEV;
 132        }
 133
 134        /* get phy param offset */
 135        count = fdtdec_get_int_array_count(gd->fdt_blob, dev_of_offset(dev),
 136                                           "st,syscfg", cells,
 137                                           ARRAY_SIZE(cells));
 138
 139        if (count < 0) {
 140                pr_err("Bad PHY st,syscfg property %d\n", count);
 141                return -EINVAL;
 142        }
 143
 144        if (count > PHYPARAM_NB) {
 145                pr_err("Unsupported PHY param count %d\n", count);
 146                return -EINVAL;
 147        }
 148
 149        priv->param = cells[PHYPARAM_REG];
 150        priv->ctrl = cells[PHYCTRL_REG];
 151
 152        /* get global reset control */
 153        ret = reset_get_by_name(dev, "global", &priv->global_ctl);
 154        if (ret) {
 155                pr_err("can't get global reset for %s (%d)", dev->name, ret);
 156                return ret;
 157        }
 158
 159        /* get port reset control */
 160        ret = reset_get_by_name(dev, "port", &priv->port_ctl);
 161        if (ret) {
 162                pr_err("can't get port reset for %s (%d)", dev->name, ret);
 163                return ret;
 164        }
 165
 166        return 0;
 167}
 168
 169static const struct udevice_id sti_usb_phy_ids[] = {
 170        { .compatible = "st,stih407-usb2-phy" },
 171        { }
 172};
 173
 174U_BOOT_DRIVER(sti_usb_phy) = {
 175        .name = "sti_usb_phy",
 176        .id = UCLASS_PHY,
 177        .of_match = sti_usb_phy_ids,
 178        .probe = sti_usb_phy_probe,
 179        .ops = &sti_usb_phy_ops,
 180        .priv_auto_alloc_size = sizeof(struct sti_usb_phy),
 181};
 182