|
@@ -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);
|