diff options
-rw-r--r-- | drivers/phy/broadcom/phy-brcm-usb.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index 8ffd0f14f809..195b98139e5f 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -27,6 +27,8 @@ #include "phy-brcm-usb-init.h" +static DEFINE_MUTEX(sysfs_lock); + enum brcm_usb_phy_id { BRCM_USB_PHY_2_0 = 0, BRCM_USB_PHY_3_0, @@ -45,6 +47,12 @@ static struct value_to_name_map brcm_dr_mode_to_name[] = { { USB_CTLR_MODE_TYPEC_PD, "typec-pd" } }; +static struct value_to_name_map brcm_dual_mode_to_name[] = { + { 0, "host" }, + { 1, "device" }, + { 2, "auto" }, +}; + struct brcm_usb_phy { struct phy *phy; unsigned int id; @@ -161,6 +169,73 @@ static int name_to_value(struct value_to_name_map *table, int count, return -EINVAL; } +static const char *value_to_name(struct value_to_name_map *table, int count, + int value) +{ + if (value >= count) + return "unknown"; + return table[value].name; +} + +static ssize_t dr_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct brcm_usb_phy_data *priv = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", + value_to_name(&brcm_dr_mode_to_name[0], + ARRAY_SIZE(brcm_dr_mode_to_name), + priv->ini.mode)); +} +static DEVICE_ATTR_RO(dr_mode); + +static ssize_t dual_select_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct brcm_usb_phy_data *priv = dev_get_drvdata(dev); + int value; + int res; + + mutex_lock(&sysfs_lock); + res = name_to_value(&brcm_dual_mode_to_name[0], + ARRAY_SIZE(brcm_dual_mode_to_name), buf, &value); + if (!res) { + brcm_usb_init_set_dual_select(&priv->ini, value); + res = len; + } + mutex_unlock(&sysfs_lock); + return res; +} + +static ssize_t dual_select_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct brcm_usb_phy_data *priv = dev_get_drvdata(dev); + int value; + + mutex_lock(&sysfs_lock); + value = brcm_usb_init_get_dual_select(&priv->ini); + mutex_unlock(&sysfs_lock); + return sprintf(buf, "%s\n", + value_to_name(&brcm_dual_mode_to_name[0], + ARRAY_SIZE(brcm_dual_mode_to_name), + value)); +} +static DEVICE_ATTR_RW(dual_select); + +static struct attribute *brcm_usb_phy_attrs[] = { + &dev_attr_dr_mode.attr, + &dev_attr_dual_select.attr, + NULL +}; + +static const struct attribute_group brcm_usb_phy_group = { + .attrs = brcm_usb_phy_attrs, +}; + static int brcm_usb_phy_dvr_init(struct device *dev, struct brcm_usb_phy_data *priv, struct device_node *dn) @@ -277,6 +352,16 @@ static int brcm_usb_phy_probe(struct platform_device *pdev) /* make sure invert settings are correct */ brcm_usb_init_ipp(&priv->ini); + /* + * Create sysfs entries for mode. + * Remove "dual_select" attribute if not in dual mode + */ + if (priv->ini.mode != USB_CTLR_MODE_DRD) + brcm_usb_phy_attrs[1] = NULL; + err = sysfs_create_group(&dev->kobj, &brcm_usb_phy_group); + if (err) + dev_warn(dev, "Error creating sysfs attributes\n"); + /* start with everything off */ if (priv->has_xhci) brcm_usb_uninit_xhci(&priv->ini); |