Re: [PATCH v2 2/3] usb: typec: tipd: Factor out i2c specifics
Heikki Krogerus <[email protected]> Wed, 5 Aug 2026 13:47:38 +0200
| Newsgroups | org.kernel.vger.linux-usb,dev.linux.lists.asahi,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Hi, Sorry to keep you waiting. On Mon, Jul 27, 2026 at 06:09:29PM +0200, Sasha Finkelstein wrote: > From: Alyssa Milburn <[email protected]> > > Make the core driver more bus-agnostic to prepare for SPMI variants of > the tipd chip > > Signed-off-by: Alyssa Milburn <[email protected]> > Signed-off-by: Sasha Finkelstein <[email protected]> > --- > drivers/usb/typec/tipd/Kconfig | 8 ++++-- > drivers/usb/typec/tipd/Makefile | 11 ++++--- > drivers/usb/typec/tipd/core.c | 224 ++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------- > drivers/usb/typec/tipd/i2c.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > drivers/usb/typec/tipd/tps6598x.h | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 265 insertions(+), 196 deletions(-) > > diff --git a/drivers/usb/typec/tipd/Kconfig b/drivers/usb/typec/tipd/Kconfig > index b82715293072..c87cbe6109ca 100644 > --- a/drivers/usb/typec/tipd/Kconfig > +++ b/drivers/usb/typec/tipd/Kconfig > @@ -1,9 +1,13 @@ > +config TYPEC_TPS6598X_CORE > + tristate > + select USB_ROLE_SWITCH > + select POWER_SUPPLY > + > config TYPEC_TPS6598X > tristate "TI TPS6598x USB Power Delivery controller driver" > depends on I2C > - select POWER_SUPPLY > select REGMAP_I2C > - select USB_ROLE_SWITCH > + select TYPEC_TPS6598X_CORE > help > Say Y or M here if your system has TI TPS65982 or TPS65983 USB Power > Delivery controller. Looks better now. > diff --git a/drivers/usb/typec/tipd/Makefile b/drivers/usb/typec/tipd/Makefile > index aa439f80a889..c741bf44f52f 100644 > --- a/drivers/usb/typec/tipd/Makefile > +++ b/drivers/usb/typec/tipd/Makefile > @@ -1,6 +1,9 @@ > # SPDX-License-Identifier: GPL-2.0 > -CFLAGS_trace.o := -I$(src) > +CFLAGS_trace.o := -I$(src) > > -obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o > -tps6598x-y := core.o > -tps6598x-$(CONFIG_TRACING) += trace.o > +obj-$(CONFIG_TYPEC_TPS6598X_CORE) += tps6598x-core.o > +tps6598x-core-y := core.o > +tps6598x-core-$(CONFIG_TRACING) += trace.o > + > +obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o > +tps6598x-y := i2c.o > diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c > index d5ee0af9058b..aadadfdc6ed1 100644 > --- a/drivers/usb/typec/tipd/core.c > +++ b/drivers/usb/typec/tipd/core.c > @@ -9,7 +9,6 @@ > #include <linux/i2c.h> > #include <linux/acpi.h> > #include <linux/gpio/consumer.h> > -#include <linux/module.h> > #include <linux/of.h> > #include <linux/power_supply.h> > #include <linux/regmap.h> > @@ -92,31 +91,6 @@ struct tps6598x_rx_identity_reg { > struct usb_pd_identity identity; > } __packed; > > -/* TPS_REG_USB4_STATUS */ > -struct tps6598x_usb4_status_reg { > - u8 mode_status; > - __le32 eudo; > - __le32 unknown; > -} __packed; > - > -/* TPS_REG_DP_SID_STATUS */ > -struct tps6598x_dp_sid_status_reg { > - u8 mode_status; > - __le32 status_tx; > - __le32 status_rx; > - __le32 configure; > - __le32 mode_data; > -} __packed; > - > -/* TPS_REG_INTEL_VID_STATUS */ > -struct tps6598x_intel_vid_status_reg { > - u8 mode_status; > - __le32 attention_vdo; > - __le16 enter_vdo; > - __le16 device_mode; > - __le16 cable_mode; > -} __packed; > - > /* Standard Task return codes */ > #define TPS_TASK_TIMEOUT 1 > #define TPS_TASK_REJECTED 3 > @@ -143,81 +117,6 @@ static const char *const modes[] = { > /* Unrecognized commands will be replaced with "!CMD" */ > #define INVALID_CMD(_cmd_) (_cmd_ == 0x444d4321) > > -struct tps6598x; > - > -struct tipd_data { > - irq_handler_t irq_handler; > - u64 irq_mask1; > - size_t tps_struct_size; > - void (*remove)(struct tps6598x *tps); > - int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node); > - void (*unregister_port)(struct tps6598x *tps); > - void (*trace_data_status)(u32 status); > - void (*trace_power_status)(u16 status); > - void (*trace_status)(u32 status); > - int (*apply_patch)(struct tps6598x *tps); > - int (*init)(struct tps6598x *tps); > - int (*switch_power_state)(struct tps6598x *tps, u8 target_state); > - bool (*read_data_status)(struct tps6598x *tps); > - int (*reset)(struct tps6598x *tps); > - int (*connect)(struct tps6598x *tps, u32 status); > -}; > - > -struct tps6598x { > - struct device *dev; > - struct regmap *regmap; > - struct mutex lock; /* device lock */ > - u8 i2c_protocol:1; > - > - struct gpio_desc *reset; > - struct typec_port *port; > - struct typec_partner *partner; > - struct usb_pd_identity partner_identity; > - struct usb_role_switch *role_sw; > - struct typec_capability typec_cap; > - > - struct power_supply *psy; > - struct power_supply_desc psy_desc; > - enum power_supply_usb_type usb_type; > - > - int wakeup; > - u32 status; /* status reg */ > - u32 data_status; > - u16 pwr_status; > - struct delayed_work wq_poll; > - > - const struct tipd_data *data; > -}; > - > -struct cd321x_status { > - u32 status; > - u32 pwr_status; > - u32 data_status; > - u32 status_changed; > - struct usb_pd_identity partner_identity; > - struct tps6598x_dp_sid_status_reg dp_sid_status; > - struct tps6598x_intel_vid_status_reg intel_vid_status; > - struct tps6598x_usb4_status_reg usb4_status; > -}; > - > -struct cd321x { > - struct tps6598x tps; > - > - struct tps6598x_dp_sid_status_reg dp_sid_status; > - struct tps6598x_intel_vid_status_reg intel_vid_status; > - struct tps6598x_usb4_status_reg usb4_status; > - > - struct typec_altmode *port_altmode_dp; > - struct typec_altmode *port_altmode_tbt; > - > - struct typec_mux *mux; > - struct typec_mux_state state; > - > - struct cd321x_status update_status; > - struct delayed_work update_work; > - struct usb_pd_identity cur_partner_identity; > -}; > - > static enum power_supply_property tps6598x_psy_props[] = { > POWER_SUPPLY_PROP_USB_TYPE, > POWER_SUPPLY_PROP_ONLINE, > @@ -1087,11 +986,12 @@ static int tps6598x_check_mode(struct tps6598x *tps) > return -ENODEV; > } > > -static const struct regmap_config tps6598x_regmap_config = { > +const struct regmap_config tps6598x_regmap_config = { > .reg_bits = 8, > .val_bits = 8, > .max_register = 0x7F, > }; > +EXPORT_SYMBOL_GPL(tps6598x_regmap_config); Don't export that. Just move it to i2c.c > static int tps6598x_psy_get_online(struct tps6598x *tps, > union power_supply_propval *val) > @@ -1738,27 +1638,13 @@ static void cd321x_remove(struct tps6598x *tps) > cancel_delayed_work_sync(&cd321x->update_work); > } > > -static int tps6598x_probe(struct i2c_client *client) > +int tipd_init(struct tps6598x *tps) > { > - const struct tipd_data *data; > - struct tps6598x *tps; > struct fwnode_handle *fwnode; > u32 status; > u32 vid; > int ret; > > - data = i2c_get_match_data(client); > - if (!data) > - return -EINVAL; > - > - tps = devm_kzalloc(&client->dev, data->tps_struct_size, GFP_KERNEL); > - if (!tps) > - return -ENOMEM; > - > - mutex_init(&tps->lock); > - tps->dev = &client->dev; > - tps->data = data; > - > tps->reset = devm_gpiod_get_optional(tps->dev, "reset", GPIOD_OUT_LOW); > if (IS_ERR(tps->reset)) > return dev_err_probe(tps->dev, PTR_ERR(tps->reset), > @@ -1766,23 +1652,12 @@ static int tps6598x_probe(struct i2c_client *client) > if (tps->reset) > msleep(TPS_SETUP_MS); > > - tps->regmap = devm_regmap_init_i2c(client, &tps6598x_regmap_config); > - if (IS_ERR(tps->regmap)) > - return PTR_ERR(tps->regmap); > - > if (!device_is_compatible(tps->dev, "ti,tps25750")) { > ret = tps6598x_read32(tps, TPS_REG_VID, &vid); > if (ret < 0 || !vid) > return -ENODEV; > } > > - /* > - * Checking can the adapter handle SMBus protocol. If it can not, the > - * driver needs to take care of block reads separately. > - */ > - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) > - tps->i2c_protocol = true; > - > if (tps->data->switch_power_state) { > ret = tps->data->switch_power_state(tps, TPS_SYSTEM_POWER_STATE_S0); > if (ret) > @@ -1816,7 +1691,7 @@ static int tps6598x_probe(struct i2c_client *client) > * with existing DT files, we work around this by deleting any > * fwnode_links to/from this fwnode. > */ > - fwnode = device_get_named_child_node(&client->dev, "connector"); > + fwnode = device_get_named_child_node(tps->dev, "connector"); > if (fwnode) > fw_devlink_purge_absent_suppliers(fwnode); > > @@ -1842,14 +1717,14 @@ static int tps6598x_probe(struct i2c_client *client) > goto err_unregister_port; > ret = tps->data->connect(tps, status); > if (ret) > - dev_err(&client->dev, "failed to register partner\n"); > + dev_err(tps->dev, "failed to register partner\n"); > } > > - if (client->irq) { > - ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, > + if (tps->irq) { > + ret = devm_request_threaded_irq(tps->dev, tps->irq, NULL, > tps->data->irq_handler, > IRQF_SHARED | IRQF_ONESHOT, > - dev_name(&client->dev), tps); > + dev_name(tps->dev), tps); > } else { > dev_warn(tps->dev, "Unable to find the interrupt, switching to polling\n"); > INIT_DELAYED_WORK(&tps->wq_poll, tps6598x_poll_work); > @@ -1860,13 +1735,12 @@ static int tps6598x_probe(struct i2c_client *client) > if (ret) > goto err_disconnect; > > - i2c_set_clientdata(client, tps); > fwnode_handle_put(fwnode); > > tps->wakeup = device_property_read_bool(tps->dev, "wakeup-source"); > - if (tps->wakeup && client->irq) { > - devm_device_init_wakeup(&client->dev); > - enable_irq_wake(client->irq); > + if (tps->wakeup && tps->irq) { > + devm_device_init_wakeup(tps->dev); > + enable_irq_wake(tps->irq); > } > > return 0; > @@ -1887,15 +1761,14 @@ static int tps6598x_probe(struct i2c_client *client) > > return ret; > } > +EXPORT_SYMBOL_GPL(tipd_init); > > -static void tps6598x_remove(struct i2c_client *client) > +void tipd_remove(struct tps6598x *tps) > { > - struct tps6598x *tps = i2c_get_clientdata(client); > - > - if (!client->irq) > + if (!tps->irq) > cancel_delayed_work_sync(&tps->wq_poll); > else > - devm_free_irq(tps->dev, client->irq, tps); > + devm_free_irq(tps->dev, tps->irq, tps); > > if (tps->data->remove) > tps->data->remove(tps); > @@ -1910,29 +1783,26 @@ static void tps6598x_remove(struct i2c_client *client) > if (tps->reset) > gpiod_set_value_cansleep(tps->reset, 1); > } > +EXPORT_SYMBOL_GPL(tipd_remove); > > -static int __maybe_unused tps6598x_suspend(struct device *dev) > +int tipd_suspend(struct tps6598x *tps) > { > - struct i2c_client *client = to_i2c_client(dev); > - struct tps6598x *tps = i2c_get_clientdata(client); > - > if (tps->wakeup) { > - disable_irq(client->irq); > - enable_irq_wake(client->irq); > + disable_irq(tps->irq); > + enable_irq_wake(tps->irq); > } else if (tps->reset) { > gpiod_set_value_cansleep(tps->reset, 1); > } > > - if (!client->irq) > + if (!tps->irq) > cancel_delayed_work_sync(&tps->wq_poll); > > return 0; > } > +EXPORT_SYMBOL_GPL(tipd_suspend); > > -static int __maybe_unused tps6598x_resume(struct device *dev) > +int tipd_resume(struct tps6598x *tps) > { > - struct i2c_client *client = to_i2c_client(dev); > - struct tps6598x *tps = i2c_get_clientdata(client); > int ret; > > ret = tps6598x_check_mode(tps); > @@ -1946,25 +1816,22 @@ static int __maybe_unused tps6598x_resume(struct device *dev) > } > > if (tps->wakeup) { > - disable_irq_wake(client->irq); > - enable_irq(client->irq); > + disable_irq_wake(tps->irq); > + enable_irq(tps->irq); > } else if (tps->reset) { > gpiod_set_value_cansleep(tps->reset, 0); > msleep(TPS_SETUP_MS); > } > > - if (!client->irq) > + if (!tps->irq) > queue_delayed_work(system_power_efficient_wq, &tps->wq_poll, > msecs_to_jiffies(POLL_INTERVAL)); > > return 0; > } > +EXPORT_SYMBOL_GPL(tipd_resume); > > -static const struct dev_pm_ops tps6598x_pm_ops = { > - SET_SYSTEM_SLEEP_PM_OPS(tps6598x_suspend, tps6598x_resume) > -}; > - > -static const struct tipd_data cd321x_data = { > +const struct tipd_data tipd_cd321x_data = { > .irq_handler = cd321x_interrupt, > .irq_mask1 = APPLE_CD_REG_INT_POWER_STATUS_UPDATE | > APPLE_CD_REG_INT_DATA_STATUS_UPDATE | > @@ -1982,8 +1849,9 @@ static const struct tipd_data cd321x_data = { > .switch_power_state = cd321x_switch_power_state, > .connect = cd321x_connect, > }; > +EXPORT_SYMBOL_GPL(tipd_cd321x_data); There shouldn't be need to export these either. You can add a variant flag member to struct tps6598x for now, and pick the correct data for example from a lookup table. Ideally IMO each variant would be handled in its own file. But that would require a bit more refactoring of course. > -static const struct tipd_data tps6598x_data = { > +const struct tipd_data tipd_tps6598x_data = { > .irq_handler = tps6598x_interrupt, > .irq_mask1 = TPS_REG_INT_POWER_STATUS_UPDATE | > TPS_REG_INT_DATA_STATUS_UPDATE | > @@ -2000,8 +1868,9 @@ static const struct tipd_data tps6598x_data = { > .reset = tps6598x_reset, > .connect = tps6598x_connect, > }; > +EXPORT_SYMBOL_GPL(tipd_tps6598x_data); > > -static const struct tipd_data tps25750_data = { > +const struct tipd_data tipd_tps25750_data = { > .irq_handler = tps25750_interrupt, > .irq_mask1 = TPS_REG_INT_POWER_STATUS_UPDATE | > TPS_REG_INT_DATA_STATUS_UPDATE | > @@ -2018,33 +1887,8 @@ static const struct tipd_data tps25750_data = { > .reset = tps25750_reset, > .connect = tps6598x_connect, > }; > - > -static const struct of_device_id tps6598x_of_match[] = { > - { .compatible = "ti,tps6598x", &tps6598x_data}, > - { .compatible = "apple,cd321x", &cd321x_data}, > - { .compatible = "ti,tps25750", &tps25750_data}, > - {} > -}; > -MODULE_DEVICE_TABLE(of, tps6598x_of_match); > - > -static const struct i2c_device_id tps6598x_id[] = { > - { .name = "tps6598x", .driver_data = (kernel_ulong_t)&tps6598x_data }, > - { } > -}; > -MODULE_DEVICE_TABLE(i2c, tps6598x_id); > - > -static struct i2c_driver tps6598x_i2c_driver = { > - .driver = { > - .name = "tps6598x", > - .pm = &tps6598x_pm_ops, > - .of_match_table = tps6598x_of_match, > - }, > - .probe = tps6598x_probe, > - .remove = tps6598x_remove, > - .id_table = tps6598x_id, > -}; > -module_i2c_driver(tps6598x_i2c_driver); > +EXPORT_SYMBOL_GPL(tipd_tps25750_data); > > MODULE_AUTHOR("Heikki Krogerus <[email protected]>"); > -MODULE_LICENSE("GPL v2"); > -MODULE_DESCRIPTION("TI TPS6598x USB Power Delivery Controller Driver"); > +MODULE_LICENSE("GPL"); > +MODULE_DESCRIPTION("TI TPS6598x USB Power Delivery Controller Core Functions"); Thanks, -- heikki