aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/typec/tcpm/fusb302.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/typec/tcpm/fusb302.c')
-rw-r--r--drivers/usb/typec/tcpm/fusb302.c101
1 files changed, 43 insertions, 58 deletions
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index c524088246ee..ed8655c6af8c 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/usb.h>
#include <linux/usb/typec.h>
#include <linux/usb/tcpm.h>
#include <linux/usb/pd.h>
@@ -75,7 +76,6 @@ struct fusb302_chip {
struct i2c_client *i2c_client;
struct tcpm_port *tcpm_port;
struct tcpc_dev tcpc_dev;
- struct tcpc_config tcpc_config;
struct regulator *vbus;
@@ -207,23 +207,19 @@ static int fusb302_debug_show(struct seq_file *s, void *v)
}
DEFINE_SHOW_ATTRIBUTE(fusb302_debug);
-static struct dentry *rootdir;
-
static void fusb302_debugfs_init(struct fusb302_chip *chip)
{
- mutex_init(&chip->logbuffer_lock);
- if (!rootdir)
- rootdir = debugfs_create_dir("fusb302", NULL);
+ char name[NAME_MAX];
- chip->dentry = debugfs_create_file(dev_name(chip->dev),
- S_IFREG | 0444, rootdir,
+ mutex_init(&chip->logbuffer_lock);
+ snprintf(name, NAME_MAX, "fusb302-%s", dev_name(chip->dev));
+ chip->dentry = debugfs_create_file(name, S_IFREG | 0444, usb_debug_root,
chip, &fusb302_debug_fops);
}
static void fusb302_debugfs_exit(struct fusb302_chip *chip)
{
debugfs_remove(chip->dentry);
- debugfs_remove(rootdir);
}
#else
@@ -1110,23 +1106,6 @@ done:
mutex_unlock(&chip->lock);
}
-#define PDO_FIXED_FLAGS \
- (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP | PDO_FIXED_USB_COMM)
-
-static const u32 src_pdo[] = {
- PDO_FIXED(5000, 400, PDO_FIXED_FLAGS),
-};
-
-static const struct tcpc_config fusb302_tcpc_config = {
- .src_pdo = src_pdo,
- .nr_src_pdo = ARRAY_SIZE(src_pdo),
- .operating_snk_mw = 2500,
- .type = TYPEC_PORT_DRP,
- .data = TYPEC_PORT_DRD,
- .default_role = TYPEC_SINK,
- .alt_modes = NULL,
-};
-
static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev)
{
fusb302_tcpc_dev->init = tcpm_init;
@@ -1670,27 +1649,36 @@ static int init_gpio(struct fusb302_chip *chip)
return 0;
}
-static int fusb302_composite_snk_pdo_array(struct fusb302_chip *chip)
-{
- struct device *dev = chip->dev;
- u32 max_uv, max_ua;
+#define PDO_FIXED_FLAGS \
+ (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP | PDO_FIXED_USB_COMM)
- chip->snk_pdo[0] = PDO_FIXED(5000, 400, PDO_FIXED_FLAGS);
+static const u32 src_pdo[] = {
+ PDO_FIXED(5000, 400, PDO_FIXED_FLAGS)
+};
- /*
- * As max_snk_ma/mv/mw is not needed for tcpc_config,
- * those settings should be passed in via sink PDO, so
- * "fcs, max-sink-*" properties will be deprecated, to
- * perserve compatibility with existing users of them,
- * we read those properties to convert them to be a var
- * PDO.
- */
- if (device_property_read_u32(dev, "fcs,max-sink-microvolt", &max_uv) ||
- device_property_read_u32(dev, "fcs,max-sink-microamp", &max_ua))
- return 1;
+static const u32 snk_pdo[] = {
+ PDO_FIXED(5000, 400, PDO_FIXED_FLAGS)
+};
+
+static const struct property_entry port_props[] = {
+ PROPERTY_ENTRY_STRING("data-role", "dual"),
+ PROPERTY_ENTRY_STRING("power-role", "dual"),
+ PROPERTY_ENTRY_STRING("try-power-role", "sink"),
+ PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo),
+ PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo),
+ PROPERTY_ENTRY_U32("op-sink-microwatt", 2500),
+ { }
+};
- chip->snk_pdo[1] = PDO_VAR(5000, max_uv / 1000, max_ua / 1000);
- return 2;
+static struct fwnode_handle *fusb302_fwnode_get(struct device *dev)
+{
+ struct fwnode_handle *fwnode;
+
+ fwnode = device_get_named_child_node(dev, "connector");
+ if (!fwnode)
+ fwnode = fwnode_create_software_node(port_props, NULL);
+
+ return fwnode;
}
static int fusb302_probe(struct i2c_client *client,
@@ -1701,7 +1689,6 @@ static int fusb302_probe(struct i2c_client *client,
struct device *dev = &client->dev;
const char *name;
int ret = 0;
- u32 v;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
dev_err(&client->dev,
@@ -1714,20 +1701,8 @@ static int fusb302_probe(struct i2c_client *client,
chip->i2c_client = client;
chip->dev = &client->dev;
- chip->tcpc_config = fusb302_tcpc_config;
- chip->tcpc_dev.config = &chip->tcpc_config;
mutex_init(&chip->lock);
- chip->tcpc_dev.fwnode =
- device_get_named_child_node(dev, "connector");
-
- if (!device_property_read_u32(dev, "fcs,operating-sink-microwatt", &v))
- chip->tcpc_config.operating_snk_mw = v / 1000;
-
- /* Composite sink PDO */
- chip->tcpc_config.nr_snk_pdo = fusb302_composite_snk_pdo_array(chip);
- chip->tcpc_config.snk_pdo = chip->snk_pdo;
-
/*
* Devicetree platforms should get extcon via phandle (not yet
* supported). On ACPI platforms, we get the name from a device prop.
@@ -1753,6 +1728,7 @@ static int fusb302_probe(struct i2c_client *client,
INIT_WORK(&chip->irq_work, fusb302_irq_work);
INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work);
init_tcpc_dev(&chip->tcpc_dev);
+ fusb302_debugfs_init(chip);
if (client->irq) {
chip->gpio_int_n_irq = client->irq;
@@ -1762,8 +1738,15 @@ static int fusb302_probe(struct i2c_client *client,
goto destroy_workqueue;
}
+ chip->tcpc_dev.fwnode = fusb302_fwnode_get(dev);
+ if (IS_ERR(chip->tcpc_dev.fwnode)) {
+ ret = PTR_ERR(chip->tcpc_dev.fwnode);
+ goto destroy_workqueue;
+ }
+
chip->tcpm_port = tcpm_register_port(&client->dev, &chip->tcpc_dev);
if (IS_ERR(chip->tcpm_port)) {
+ fwnode_handle_put(chip->tcpc_dev.fwnode);
ret = PTR_ERR(chip->tcpm_port);
if (ret != -EPROBE_DEFER)
dev_err(dev, "cannot register tcpm port, ret=%d", ret);
@@ -1778,14 +1761,15 @@ static int fusb302_probe(struct i2c_client *client,
goto tcpm_unregister_port;
}
enable_irq_wake(chip->gpio_int_n_irq);
- fusb302_debugfs_init(chip);
i2c_set_clientdata(client, chip);
return ret;
tcpm_unregister_port:
tcpm_unregister_port(chip->tcpm_port);
+ fwnode_handle_put(chip->tcpc_dev.fwnode);
destroy_workqueue:
+ fusb302_debugfs_exit(chip);
destroy_workqueue(chip->wq);
return ret;
@@ -1800,6 +1784,7 @@ static int fusb302_remove(struct i2c_client *client)
cancel_work_sync(&chip->irq_work);
cancel_delayed_work_sync(&chip->bc_lvl_handler);
tcpm_unregister_port(chip->tcpm_port);
+ fwnode_handle_put(chip->tcpc_dev.fwnode);
destroy_workqueue(chip->wq);
fusb302_debugfs_exit(chip);