Commit 0415052d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'devprop-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull device properties framework updates from Rafael Wysocki:
 "These add helpers for counting items in a property array and extend
  the "software nodes" support to be more convenient for representing
  device properties supplied by drivers and make the intel_cht_int33fe
  driver use that.

  Specifics:

   - Add helpers to count items in a property array (Andy Shevchenko).

   - Extend "software nodes" support to be more convenient for
     representing device properties supplied by drivers (Heikki
     Krogerus).

   - Add device_find_child_by_name() helper to the driver core (Heikki
     Krogerus).

   - Extend device connection code to also look for references provided
     via fwnode pointers (Heikki Krogerus).

   - Start to register proper struct device objects for USB Type-C muxes
     and orientation switches (Heikki Krogerus).

   - Update the intel_cht_int33fe driver to describe devices in a more
     general way with the help of "software nodes" (Heikki Krogerus)"

* tag 'devprop-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  device property: Add helpers to count items in an array
  platform/x86: intel_cht_int33fe: Replacing the old connections with references
  platform/x86: intel_cht_int33fe: Supply fwnodes for the external dependencies
  platform/x86: intel_cht_int33fe: Provide fwnode for the USB connector
  platform/x86: intel_cht_int33fe: Provide software nodes for the devices
  platform/x86: intel_cht_int33fe: Remove unused fusb302 device property
  platform/x86: intel_cht_int33fe: Register max17047 in its own function
  usb: typec: Registering real device entries for the muxes
  device connection: Find connections also by checking the references
  device property: Introduce fwnode_find_reference()
  ACPI / property: Don't limit named child node matching to data nodes
  driver core: Add helper device_find_child_by_name()
  software node: Add software_node_get_reference_args()
  software node: Use kobject name when finding child nodes by name
  software node: Add support for static node descriptors
  software node: Simplify software_node_release() function
  software node: Allow node creation without properties
parents 4b470452 33ee09cd
...@@ -600,15 +600,29 @@ static struct fwnode_handle * ...@@ -600,15 +600,29 @@ static struct fwnode_handle *
acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode, acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode,
const char *childname) const char *childname)
{ {
char name[ACPI_PATH_SEGMENT_LENGTH];
struct fwnode_handle *child; struct fwnode_handle *child;
struct acpi_buffer path;
acpi_status status;
/* path.length = sizeof(name);
* Find first matching named child node of this fwnode. path.pointer = name;
* For ACPI this will be a data only sub-node.
*/ fwnode_for_each_child_node(fwnode, child) {
fwnode_for_each_child_node(fwnode, child) if (is_acpi_data_node(child)) {
if (acpi_data_node_match(child, childname)) if (acpi_data_node_match(child, childname))
return child; return child;
continue;
}
status = acpi_get_name(ACPI_HANDLE_FWNODE(child),
ACPI_SINGLE_NAME, &path);
if (ACPI_FAILURE(status))
break;
if (!strncmp(name, childname, ACPI_NAMESEG_SIZE))
return child;
}
return NULL; return NULL;
} }
......
...@@ -2474,6 +2474,34 @@ struct device *device_find_child(struct device *parent, void *data, ...@@ -2474,6 +2474,34 @@ struct device *device_find_child(struct device *parent, void *data,
} }
EXPORT_SYMBOL_GPL(device_find_child); EXPORT_SYMBOL_GPL(device_find_child);
/**
* device_find_child_by_name - device iterator for locating a child device.
* @parent: parent struct device
* @name: name of the child device
*
* This is similar to the device_find_child() function above, but it
* returns a reference to a device that has the name @name.
*
* NOTE: you will need to drop the reference with put_device() after use.
*/
struct device *device_find_child_by_name(struct device *parent,
const char *name)
{
struct klist_iter i;
struct device *child;
if (!parent)
return NULL;
klist_iter_init(&parent->p->klist_children, &i);
while ((child = next_device(&i)))
if (!strcmp(dev_name(child), name) && get_device(child))
break;
klist_iter_exit(&i);
return child;
}
EXPORT_SYMBOL_GPL(device_find_child_by_name);
int __init devices_init(void) int __init devices_init(void)
{ {
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
......
...@@ -38,6 +38,28 @@ fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id, ...@@ -38,6 +38,28 @@ fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
return NULL; return NULL;
} }
static void *
fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
void *data, devcon_match_fn_t match)
{
struct device_connection con = { };
void *ret;
int i;
for (i = 0; ; i++) {
con.fwnode = fwnode_find_reference(fwnode, con_id, i);
if (IS_ERR(con.fwnode))
break;
ret = match(&con, -1, data);
fwnode_handle_put(con.fwnode);
if (ret)
return ret;
}
return NULL;
}
/** /**
* device_connection_find_match - Find physical connection to a device * device_connection_find_match - Find physical connection to a device
* @dev: Device with the connection * @dev: Device with the connection
...@@ -65,6 +87,10 @@ void *device_connection_find_match(struct device *dev, const char *con_id, ...@@ -65,6 +87,10 @@ void *device_connection_find_match(struct device *dev, const char *con_id,
ret = fwnode_graph_devcon_match(fwnode, con_id, data, match); ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
if (ret) if (ret)
return ret; return ret;
ret = fwnode_devcon_match(fwnode, con_id, data, match);
if (ret)
return ret;
} }
mutex_lock(&devcon_lock); mutex_lock(&devcon_lock);
......
...@@ -484,6 +484,30 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode, ...@@ -484,6 +484,30 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,
} }
EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
/**
* fwnode_find_reference - Find named reference to a fwnode_handle
* @fwnode: Firmware node where to look for the reference
* @name: The name of the reference
* @index: Index of the reference
*
* @index can be used when the named reference holds a table of references.
*
* Returns pointer to the reference fwnode, or ERR_PTR. Caller is responsible to
* call fwnode_handle_put() on the returned fwnode pointer.
*/
struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
const char *name,
unsigned int index)
{
struct fwnode_reference_args args;
int ret;
ret = fwnode_property_get_reference_args(fwnode, name, NULL, 0, index,
&args);
return ret ? ERR_PTR(ret) : args.fwnode;
}
EXPORT_SYMBOL_GPL(fwnode_find_reference);
/** /**
* device_remove_properties - Remove properties from a device object. * device_remove_properties - Remove properties from a device object.
* @dev: Device whose properties to remove. * @dev: Device whose properties to remove.
......
This diff is collapsed.
This diff is collapsed.
...@@ -101,7 +101,7 @@ static void *usb_role_switch_match(struct device_connection *con, int ep, ...@@ -101,7 +101,7 @@ static void *usb_role_switch_match(struct device_connection *con, int ep,
struct device *dev; struct device *dev;
if (con->fwnode) { if (con->fwnode) {
if (!fwnode_property_present(con->fwnode, con->id)) if (con->id && !fwnode_property_present(con->fwnode, con->id))
return NULL; return NULL;
dev = class_find_device(role_class, NULL, con->fwnode, dev = class_find_device(role_class, NULL, con->fwnode,
......
...@@ -35,4 +35,19 @@ extern const struct device_type typec_port_dev_type; ...@@ -35,4 +35,19 @@ extern const struct device_type typec_port_dev_type;
#define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type) #define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type)
#define is_typec_port(_dev_) (_dev_->type == &typec_port_dev_type) #define is_typec_port(_dev_) (_dev_->type == &typec_port_dev_type)
extern struct class typec_mux_class;
struct typec_switch {
struct device dev;
typec_switch_set_fn_t set;
};
struct typec_mux {
struct device dev;
typec_mux_set_fn_t set;
};
#define to_typec_switch(_dev_) container_of(_dev_, struct typec_switch, dev)
#define to_typec_mux(_dev_) container_of(_dev_, struct typec_mux, dev)
#endif /* __USB_TYPEC_ALTMODE_H__ */ #endif /* __USB_TYPEC_ALTMODE_H__ */
...@@ -1646,13 +1646,25 @@ static int __init typec_init(void) ...@@ -1646,13 +1646,25 @@ static int __init typec_init(void)
if (ret) if (ret)
return ret; return ret;
ret = class_register(&typec_mux_class);
if (ret)
goto err_unregister_bus;
typec_class = class_create(THIS_MODULE, "typec"); typec_class = class_create(THIS_MODULE, "typec");
if (IS_ERR(typec_class)) { if (IS_ERR(typec_class)) {
bus_unregister(&typec_bus); ret = PTR_ERR(typec_class);
return PTR_ERR(typec_class); goto err_unregister_mux_class;
} }
return 0; return 0;
err_unregister_mux_class:
class_unregister(&typec_mux_class);
err_unregister_bus:
bus_unregister(&typec_bus);
return ret;
} }
subsys_initcall(typec_init); subsys_initcall(typec_init);
...@@ -1661,6 +1673,7 @@ static void __exit typec_exit(void) ...@@ -1661,6 +1673,7 @@ static void __exit typec_exit(void)
class_destroy(typec_class); class_destroy(typec_class);
ida_destroy(&typec_index_ida); ida_destroy(&typec_index_ida);
bus_unregister(&typec_bus); bus_unregister(&typec_bus);
class_unregister(&typec_mux_class);
} }
module_exit(typec_exit); module_exit(typec_exit);
......
...@@ -15,35 +15,47 @@ ...@@ -15,35 +15,47 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb/typec_mux.h> #include <linux/usb/typec_mux.h>
static DEFINE_MUTEX(switch_lock); #include "bus.h"
static DEFINE_MUTEX(mux_lock);
static LIST_HEAD(switch_list); static int name_match(struct device *dev, const void *name)
static LIST_HEAD(mux_list); {
return !strcmp((const char *)name, dev_name(dev));
}
static bool dev_name_ends_with(struct device *dev, const char *suffix)
{
const char *name = dev_name(dev);
const int name_len = strlen(name);
const int suffix_len = strlen(suffix);
if (suffix_len > name_len)
return false;
return strcmp(name + (name_len - suffix_len), suffix) == 0;
}
static int switch_fwnode_match(struct device *dev, const void *fwnode)
{
return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-switch");
}
static void *typec_switch_match(struct device_connection *con, int ep, static void *typec_switch_match(struct device_connection *con, int ep,
void *data) void *data)
{ {
struct typec_switch *sw; struct device *dev;
if (!con->fwnode) { if (con->fwnode) {
list_for_each_entry(sw, &switch_list, entry)
if (!strcmp(con->endpoint[ep], dev_name(sw->dev)))
return sw;
return ERR_PTR(-EPROBE_DEFER);
}
/*
* With OF graph the mux node must have a boolean device property named
* "orientation-switch".
*/
if (con->id && !fwnode_property_present(con->fwnode, con->id)) if (con->id && !fwnode_property_present(con->fwnode, con->id))
return NULL; return NULL;
list_for_each_entry(sw, &switch_list, entry) dev = class_find_device(&typec_mux_class, NULL, con->fwnode,
if (dev_fwnode(sw->dev) == con->fwnode) switch_fwnode_match);
return sw; } else {
dev = class_find_device(&typec_mux_class, NULL,
con->endpoint[ep], name_match);
}
return con->id ? ERR_PTR(-EPROBE_DEFER) : NULL; return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
} }
/** /**
...@@ -59,14 +71,10 @@ struct typec_switch *typec_switch_get(struct device *dev) ...@@ -59,14 +71,10 @@ struct typec_switch *typec_switch_get(struct device *dev)
{ {
struct typec_switch *sw; struct typec_switch *sw;
mutex_lock(&switch_lock);
sw = device_connection_find_match(dev, "orientation-switch", NULL, sw = device_connection_find_match(dev, "orientation-switch", NULL,
typec_switch_match); typec_switch_match);
if (!IS_ERR_OR_NULL(sw)) { if (!IS_ERR_OR_NULL(sw))
WARN_ON(!try_module_get(sw->dev->driver->owner)); WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
get_device(sw->dev);
}
mutex_unlock(&switch_lock);
return sw; return sw;
} }
...@@ -81,28 +89,64 @@ EXPORT_SYMBOL_GPL(typec_switch_get); ...@@ -81,28 +89,64 @@ EXPORT_SYMBOL_GPL(typec_switch_get);
void typec_switch_put(struct typec_switch *sw) void typec_switch_put(struct typec_switch *sw)
{ {
if (!IS_ERR_OR_NULL(sw)) { if (!IS_ERR_OR_NULL(sw)) {
module_put(sw->dev->driver->owner); module_put(sw->dev.parent->driver->owner);
put_device(sw->dev); put_device(&sw->dev);
} }
} }
EXPORT_SYMBOL_GPL(typec_switch_put); EXPORT_SYMBOL_GPL(typec_switch_put);
static void typec_switch_release(struct device *dev)
{
kfree(to_typec_switch(dev));
}
static const struct device_type typec_switch_dev_type = {
.name = "orientation_switch",
.release = typec_switch_release,
};
/** /**
* typec_switch_register - Register USB Type-C orientation switch * typec_switch_register - Register USB Type-C orientation switch
* @sw: USB Type-C orientation switch * @parent: Parent device
* @desc: Orientation switch description
* *
* This function registers a switch that can be used for routing the correct * This function registers a switch that can be used for routing the correct
* data pairs depending on the cable plug orientation from the USB Type-C * data pairs depending on the cable plug orientation from the USB Type-C
* connector to the USB controllers. USB Type-C plugs can be inserted * connector to the USB controllers. USB Type-C plugs can be inserted
* right-side-up or upside-down. * right-side-up or upside-down.
*/ */
int typec_switch_register(struct typec_switch *sw) struct typec_switch *
typec_switch_register(struct device *parent,
const struct typec_switch_desc *desc)
{ {
mutex_lock(&switch_lock); struct typec_switch *sw;
list_add_tail(&sw->entry, &switch_list); int ret;
mutex_unlock(&switch_lock);
if (!desc || !desc->set)
return ERR_PTR(-EINVAL);
sw = kzalloc(sizeof(*sw), GFP_KERNEL);
if (!sw)
return ERR_PTR(-ENOMEM);
return 0; sw->set = desc->set;
device_initialize(&sw->dev);
sw->dev.parent = parent;
sw->dev.fwnode = desc->fwnode;
sw->dev.class = &typec_mux_class;
sw->dev.type = &typec_switch_dev_type;
sw->dev.driver_data = desc->drvdata;
dev_set_name(&sw->dev, "%s-switch", dev_name(parent));
ret = device_add(&sw->dev);
if (ret) {
dev_err(parent, "failed to register switch (%d)\n", ret);
put_device(&sw->dev);
return ERR_PTR(ret);
}
return sw;
} }
EXPORT_SYMBOL_GPL(typec_switch_register); EXPORT_SYMBOL_GPL(typec_switch_register);
...@@ -114,28 +158,44 @@ EXPORT_SYMBOL_GPL(typec_switch_register); ...@@ -114,28 +158,44 @@ EXPORT_SYMBOL_GPL(typec_switch_register);
*/ */
void typec_switch_unregister(struct typec_switch *sw) void typec_switch_unregister(struct typec_switch *sw)
{ {
mutex_lock(&switch_lock); if (!IS_ERR_OR_NULL(sw))
list_del(&sw->entry); device_unregister(&sw->dev);
mutex_unlock(&switch_lock);
} }
EXPORT_SYMBOL_GPL(typec_switch_unregister); EXPORT_SYMBOL_GPL(typec_switch_unregister);
void typec_switch_set_drvdata(struct typec_switch *sw, void *data)
{
dev_set_drvdata(&sw->dev, data);
}
EXPORT_SYMBOL_GPL(typec_switch_set_drvdata);
void *typec_switch_get_drvdata(struct typec_switch *sw)
{
return dev_get_drvdata(&sw->dev);
}
EXPORT_SYMBOL_GPL(typec_switch_get_drvdata);
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
static int mux_fwnode_match(struct device *dev, const void *fwnode)
{
return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-mux");
}
static void *typec_mux_match(struct device_connection *con, int ep, void *data) static void *typec_mux_match(struct device_connection *con, int ep, void *data)
{ {
const struct typec_altmode_desc *desc = data; const struct typec_altmode_desc *desc = data;
struct typec_mux *mux; struct device *dev;
int nval;
bool match; bool match;
int nval;
u16 *val; u16 *val;
int i; int i;
if (!con->fwnode) { if (!con->fwnode) {
list_for_each_entry(mux, &mux_list, entry) dev = class_find_device(&typec_mux_class, NULL,
if (!strcmp(con->endpoint[ep], dev_name(mux->dev))) con->endpoint[ep], name_match);
return mux;
return ERR_PTR(-EPROBE_DEFER); return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
} }
/* /*
...@@ -180,11 +240,10 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data) ...@@ -180,11 +240,10 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data)
return NULL; return NULL;
find_mux: find_mux:
list_for_each_entry(mux, &mux_list, entry) dev = class_find_device(&typec_mux_class, NULL, con->fwnode,
if (dev_fwnode(mux->dev) == con->fwnode) mux_fwnode_match);
return mux;
return ERR_PTR(-EPROBE_DEFER); return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
} }
/** /**
...@@ -202,14 +261,10 @@ struct typec_mux *typec_mux_get(struct device *dev, ...@@ -202,14 +261,10 @@ struct typec_mux *typec_mux_get(struct device *dev,
{ {
struct typec_mux *mux; struct typec_mux *mux;
mutex_lock(&mux_lock);
mux = device_connection_find_match(dev, "mode-switch", (void *)desc, mux = device_connection_find_match(dev, "mode-switch", (void *)desc,
typec_mux_match); typec_mux_match);
if (!IS_ERR_OR_NULL(mux)) { if (!IS_ERR_OR_NULL(mux))
WARN_ON(!try_module_get(mux->dev->driver->owner)); WARN_ON(!try_module_get(mux->dev.parent->driver->owner));
get_device(mux->dev);
}
mutex_unlock(&mux_lock);
return mux; return mux;
} }
...@@ -224,28 +279,63 @@ EXPORT_SYMBOL_GPL(typec_mux_get); ...@@ -224,28 +279,63 @@ EXPORT_SYMBOL_GPL(typec_mux_get);
void typec_mux_put(struct typec_mux *mux) void typec_mux_put(struct typec_mux *mux)
{ {
if (!IS_ERR_OR_NULL(mux)) { if (!IS_ERR_OR_NULL(mux)) {
module_put(mux->dev->driver->owner); module_put(mux->dev.parent->driver->owner);
put_device(mux->dev); put_device(&mux->dev);
} }
} }
EXPORT_SYMBOL_GPL(typec_mux_put); EXPORT_SYMBOL_GPL(typec_mux_put);
static void typec_mux_release(struct device *dev)
{
kfree(to_typec_mux(dev));
}
static const struct device_type typec_mux_dev_type = {
.name = "mode_switch",
.release = typec_mux_release,
};
/** /**
* typec_mux_register - Register Multiplexer routing USB Type-C pins * typec_mux_register - Register Multiplexer routing USB Type-C pins
* @mux: USB Type-C Connector Multiplexer/DeMultiplexer * @parent: Parent device
* @desc: Multiplexer description
* *
* USB Type-C connectors can be used for alternate modes of operation besides * USB Type-C connectors can be used for alternate modes of operation besides
* USB when Accessory/Alternate Modes are supported. With some of those modes, * USB when Accessory/Alternate Modes are supported. With some of those modes,
* the pins on the connector need to be reconfigured. This function registers * the pins on the connector need to be reconfigured. This function registers
* multiplexer switches routing the pins on the connector. * multiplexer switches routing the pins on the connector.
*/ */
int typec_mux_register(struct typec_mux *mux) struct typec_mux *
typec_mux_register(struct device *parent, const struct typec_mux_desc *desc)
{ {
mutex_lock(&mux_lock); struct typec_mux *mux;
list_add_tail(&mux->entry, &mux_list); int ret;
mutex_unlock(&mux_lock);
if (!desc || !desc->set)
return ERR_PTR(-EINVAL);
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
return ERR_PTR(-ENOMEM);
mux->set = desc->set;
device_initialize(&mux->dev);
mux->dev.parent = parent;
mux->dev.fwnode = desc->fwnode;
mux->dev.class = &typec_mux_class;
mux->dev.type = &typec_mux_dev_type;
mux->dev.driver_data = desc->drvdata;
dev_set_name(&mux->dev, "%s-mux", dev_name(parent));
ret = device_add(&mux->dev);
if (ret) {
dev_err(parent, "failed to register mux (%d)\n", ret);
put_device(&mux->dev);
return ERR_PTR(ret);
}
return 0; return mux;
} }
EXPORT_SYMBOL_GPL(typec_mux_register); EXPORT_SYMBOL_GPL(typec_mux_register);
...@@ -257,8 +347,24 @@ EXPORT_SYMBOL_GPL(typec_mux_register); ...@@ -257,8 +347,24 @@ EXPORT_SYMBOL_GPL(typec_mux_register);
*/ */
void typec_mux_unregister(struct typec_mux *mux) void typec_mux_unregister(struct typec_mux *mux)
{ {
mutex_lock(&mux_lock); if (!IS_ERR_OR_NULL(mux))
list_del(&mux->entry); device_unregister(&mux->dev);
mutex_unlock(&mux_lock);
} }
EXPORT_SYMBOL_GPL(typec_mux_unregister); EXPORT_SYMBOL_GPL(typec_mux_unregister);
void typec_mux_set_drvdata(struct typec_mux *mux, void *data)
{
dev_set_drvdata(&mux->dev, data);
}
EXPORT_SYMBOL_GPL(typec_mux_set_drvdata);
void *typec_mux_get_drvdata(struct typec_mux *mux)
{
return dev_get_drvdata(&mux->dev);
}
EXPORT_SYMBOL_GPL(typec_mux_get_drvdata);
struct class typec_mux_class = {
.name = "typec_mux",
.owner = THIS_MODULE,
};
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
struct pi3usb30532 { struct pi3usb30532 {
struct i2c_client *client; struct i2c_client *client;
struct mutex lock; /* protects the cached conf register */ struct mutex lock; /* protects the cached conf register */
struct typec_switch sw; struct typec_switch *sw;
struct typec_mux mux; struct typec_mux *mux;
u8 conf; u8 conf;
}; };
...@@ -48,7 +48,7 @@ static int pi3usb30532_set_conf(struct pi3usb30532 *pi, u8 new_conf) ...@@ -48,7 +48,7 @@ static int pi3usb30532_set_conf(struct pi3usb30532 *pi, u8 new_conf)
static int pi3usb30532_sw_set(struct typec_switch *sw, static int pi3usb30532_sw_set(struct typec_switch *sw,
enum typec_orientation orientation) enum typec_orientation orientation)
{ {
struct pi3usb30532 *pi = container_of(sw, struct pi3usb30532, sw); struct pi3usb30532 *pi = typec_switch_get_drvdata(sw);
u8 new_conf; u8 new_conf;
int ret; int ret;
...@@ -75,7 +75,7 @@ static int pi3usb30532_sw_set(struct typec_switch *sw, ...@@ -75,7 +75,7 @@ static int pi3usb30532_sw_set(struct typec_switch *sw,
static int pi3usb30532_mux_set(struct typec_mux *mux, int state) static int pi3usb30532_mux_set(struct typec_mux *mux, int state)
{ {
struct pi3usb30532 *pi = container_of(mux, struct pi3usb30532, mux); struct pi3usb30532 *pi = typec_mux_get_drvdata(mux);
u8 new_conf; u8 new_conf;
int ret; int ret;
...@@ -113,6 +113,8 @@ static int pi3usb30532_mux_set(struct typec_mux *mux, int state) ...@@ -113,6 +113,8 @@ static int pi3usb30532_mux_set(struct typec_mux *mux, int state)
static int pi3usb30532_probe(struct i2c_client *client) static int pi3usb30532_probe(struct i2c_client *client)
{ {
struct device *dev = &client->dev; struct device *dev = &client->dev;
struct typec_switch_desc sw_desc;
struct typec_mux_desc mux_desc;
struct pi3usb30532 *pi; struct pi3usb30532 *pi;
int ret; int ret;
...@@ -121,10 +123,6 @@ static int pi3usb30532_probe(struct i2c_client *client) ...@@ -121,10 +123,6 @@ static int pi3usb30532_probe(struct i2c_client *client)
return -ENOMEM; return -ENOMEM;
pi->client = client; pi->client = client;
pi->sw.dev = dev;
pi->sw.set = pi3usb30532_sw_set;
pi->mux.dev = dev;
pi->mux.set = pi3usb30532_mux_set;
mutex_init(&pi->lock); mutex_init(&pi->lock);
ret = i2c_smbus_read_byte_data(client, PI3USB30532_CONF); ret = i2c_smbus_read_byte_data(client, PI3USB30532_CONF);
...@@ -134,17 +132,27 @@ static int pi3usb30532_probe(struct i2c_client *client) ...@@ -134,17 +132,27 @@ static int pi3usb30532_probe(struct i2c_client *client)
} }
pi->conf = ret; pi->conf = ret;
ret = typec_switch_register(&pi->sw); sw_desc.drvdata = pi;
if (ret) { sw_desc.fwnode = dev->fwnode;
dev_err(dev, "Error registering typec switch: %d\n", ret); sw_desc.set = pi3usb30532_sw_set;
return ret;
pi->sw = typec_switch_register(dev, &sw_desc);
if (IS_ERR(pi->sw)) {
dev_err(dev, "Error registering typec switch: %ld\n",
PTR_ERR(pi->sw));
return PTR_ERR(pi->sw);
} }
ret = typec_mux_register(&pi->mux); mux_desc.drvdata = pi;
if (ret) { mux_desc.fwnode = dev->fwnode;
typec_switch_unregister(&pi->sw); mux_desc.set = pi3usb30532_mux_set;
dev_err(dev, "Error registering typec mux: %d\n", ret);
return ret; pi->mux = typec_mux_register(dev, &mux_desc);
if (IS_ERR(pi->mux)) {
typec_switch_unregister(pi->sw);
dev_err(dev, "Error registering typec mux: %ld\n",
PTR_ERR(pi->mux));
return PTR_ERR(pi->mux);
} }
i2c_set_clientdata(client, pi); i2c_set_clientdata(client, pi);
...@@ -155,8 +163,8 @@ static int pi3usb30532_remove(struct i2c_client *client) ...@@ -155,8 +163,8 @@ static int pi3usb30532_remove(struct i2c_client *client)
{ {
struct pi3usb30532 *pi = i2c_get_clientdata(client); struct pi3usb30532 *pi = i2c_get_clientdata(client);
typec_mux_unregister(&pi->mux); typec_mux_unregister(pi->mux);
typec_switch_unregister(&pi->sw); typec_switch_unregister(pi->sw);
return 0; return 0;
} }
......
...@@ -1255,6 +1255,8 @@ extern int device_for_each_child_reverse(struct device *dev, void *data, ...@@ -1255,6 +1255,8 @@ extern int device_for_each_child_reverse(struct device *dev, void *data,
int (*fn)(struct device *dev, void *data)); int (*fn)(struct device *dev, void *data));
extern struct device *device_find_child(struct device *dev, void *data, extern struct device *device_find_child(struct device *dev, void *data,
int (*match)(struct device *dev, void *data)); int (*match)(struct device *dev, void *data));
extern struct device *device_find_child_by_name(struct device *parent,
const char *name);
extern int device_rename(struct device *dev, const char *new_name); extern int device_rename(struct device *dev, const char *new_name);
extern int device_move(struct device *dev, struct device *new_parent, extern int device_move(struct device *dev, struct device *new_parent,
enum dpm_order dpm_order); enum dpm_order dpm_order);
......
...@@ -76,6 +76,10 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode, ...@@ -76,6 +76,10 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,
unsigned int nargs, unsigned int index, unsigned int nargs, unsigned int index,
struct fwnode_reference_args *args); struct fwnode_reference_args *args);
struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
const char *name,
unsigned int index);
struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode); struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_get_next_parent( struct fwnode_handle *fwnode_get_next_parent(
struct fwnode_handle *fwnode); struct fwnode_handle *fwnode);
...@@ -141,6 +145,26 @@ static inline int device_property_read_u64(struct device *dev, ...@@ -141,6 +145,26 @@ static inline int device_property_read_u64(struct device *dev,
return device_property_read_u64_array(dev, propname, val, 1); return device_property_read_u64_array(dev, propname, val, 1);
} }
static inline int device_property_count_u8(struct device *dev, const char *propname)
{
return device_property_read_u8_array(dev, propname, NULL, 0);
}
static inline int device_property_count_u16(struct device *dev, const char *propname)
{
return device_property_read_u16_array(dev, propname, NULL, 0);
}
static inline int device_property_count_u32(struct device *dev, const char *propname)
{
return device_property_read_u32_array(dev, propname, NULL, 0);
}
static inline int device_property_count_u64(struct device *dev, const char *propname)
{
return device_property_read_u64_array(dev, propname, NULL, 0);
}
static inline bool fwnode_property_read_bool(const struct fwnode_handle *fwnode, static inline bool fwnode_property_read_bool(const struct fwnode_handle *fwnode,
const char *propname) const char *propname)
{ {
...@@ -171,6 +195,30 @@ static inline int fwnode_property_read_u64(const struct fwnode_handle *fwnode, ...@@ -171,6 +195,30 @@ static inline int fwnode_property_read_u64(const struct fwnode_handle *fwnode,
return fwnode_property_read_u64_array(fwnode, propname, val, 1); return fwnode_property_read_u64_array(fwnode, propname, val, 1);
} }
static inline int fwnode_property_count_u8(const struct fwnode_handle *fwnode,
const char *propname)
{
return fwnode_property_read_u8_array(fwnode, propname, NULL, 0);
}
static inline int fwnode_property_count_u16(const struct fwnode_handle *fwnode,
const char *propname)
{
return fwnode_property_read_u16_array(fwnode, propname, NULL, 0);
}
static inline int fwnode_property_count_u32(const struct fwnode_handle *fwnode,
const char *propname)
{
return fwnode_property_read_u32_array(fwnode, propname, NULL, 0);
}
static inline int fwnode_property_count_u64(const struct fwnode_handle *fwnode,
const char *propname)
{
return fwnode_property_read_u64_array(fwnode, propname, NULL, 0);
}
/** /**
* struct property_entry - "Built-in" device property representation. * struct property_entry - "Built-in" device property representation.
* @name: Name of the property. * @name: Name of the property.
...@@ -329,7 +377,54 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, ...@@ -329,7 +377,54 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Software fwnode support - when HW description is incomplete or missing */ /* Software fwnode support - when HW description is incomplete or missing */
struct software_node;
/**
* struct software_node_ref_args - Reference with additional arguments
* @node: Reference to a software node
* @nargs: Number of elements in @args array
* @args: Integer arguments
*/
struct software_node_ref_args {
const struct software_node *node;
unsigned int nargs;
u64 args[NR_FWNODE_REFERENCE_ARGS];
};
/**
* struct software_node_reference - Named software node reference property
* @name: Name of the property
* @nrefs: Number of elements in @refs array
* @refs: Array of references with optional arguments
*/
struct software_node_reference {
const char *name;
unsigned int nrefs;
const struct software_node_ref_args *refs;
};
/**
* struct software_node - Software node description
* @name: Name of the software node
* @parent: Parent of the software node
* @properties: Array of device properties
* @references: Array of software node reference properties
*/
struct software_node {
const char *name;
const struct software_node *parent;
const struct property_entry *properties;
const struct software_node_reference *references;
};
bool is_software_node(const struct fwnode_handle *fwnode); bool is_software_node(const struct fwnode_handle *fwnode);
const struct software_node *to_software_node(struct fwnode_handle *fwnode);
struct fwnode_handle *software_node_fwnode(const struct software_node *node);
int software_node_register_nodes(const struct software_node *nodes);
void software_node_unregister_nodes(const struct software_node *nodes);
int software_node_register(const struct software_node *node);
int software_node_notify(struct device *dev, unsigned long action); int software_node_notify(struct device *dev, unsigned long action);
......
...@@ -3,54 +3,48 @@ ...@@ -3,54 +3,48 @@
#ifndef __USB_TYPEC_MUX #ifndef __USB_TYPEC_MUX
#define __USB_TYPEC_MUX #define __USB_TYPEC_MUX
#include <linux/list.h>
#include <linux/usb/typec.h> #include <linux/usb/typec.h>
struct device; struct device;
struct typec_mux;
struct typec_switch;
struct fwnode_handle;
/** typedef int (*typec_switch_set_fn_t)(struct typec_switch *sw,
* struct typec_switch - USB Type-C cable orientation switch enum typec_orientation orientation);
* @dev: Switch device
* @entry: List entry
* @set: Callback to the driver for setting the orientation
*
* USB Type-C pin flipper switch routing the correct data pairs from the
* connector to the USB controller depending on the orientation of the cable
* plug.
*/
struct typec_switch {
struct device *dev;
struct list_head entry;
int (*set)(struct typec_switch *sw, enum typec_orientation orientation);
};
/** struct typec_switch_desc {
* struct typec_switch - USB Type-C connector pin mux struct fwnode_handle *fwnode;
* @dev: Mux device typec_switch_set_fn_t set;
* @entry: List entry void *drvdata;
* @set: Callback to the driver for setting the state of the mux
*
* Pin Multiplexer/DeMultiplexer switch routing the USB Type-C connector pins to
* different components depending on the requested mode of operation. Used with
* Accessory/Alternate modes.
*/
struct typec_mux {
struct device *dev;
struct list_head entry;
int (*set)(struct typec_mux *mux, int state);
}; };
struct typec_switch *typec_switch_get(struct device *dev); struct typec_switch *typec_switch_get(struct device *dev);
void typec_switch_put(struct typec_switch *sw); void typec_switch_put(struct typec_switch *sw);
int typec_switch_register(struct typec_switch *sw); struct typec_switch *
typec_switch_register(struct device *parent,
const struct typec_switch_desc *desc);
void typec_switch_unregister(struct typec_switch *sw); void typec_switch_unregister(struct typec_switch *sw);
void typec_switch_set_drvdata(struct typec_switch *sw, void *data);
void *typec_switch_get_drvdata(struct typec_switch *sw);
typedef int (*typec_mux_set_fn_t)(struct typec_mux *mux, int state);
struct typec_mux_desc {
struct fwnode_handle *fwnode;
typec_mux_set_fn_t set;
void *drvdata;
};
struct typec_mux * struct typec_mux *
typec_mux_get(struct device *dev, const struct typec_altmode_desc *desc); typec_mux_get(struct device *dev, const struct typec_altmode_desc *desc);
void typec_mux_put(struct typec_mux *mux); void typec_mux_put(struct typec_mux *mux);
int typec_mux_register(struct typec_mux *mux); struct typec_mux *
typec_mux_register(struct device *parent, const struct typec_mux_desc *desc);
void typec_mux_unregister(struct typec_mux *mux); void typec_mux_unregister(struct typec_mux *mux);
void typec_mux_set_drvdata(struct typec_mux *mux, void *data);
void *typec_mux_get_drvdata(struct typec_mux *mux);
#endif /* __USB_TYPEC_MUX */ #endif /* __USB_TYPEC_MUX */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment