Commit e727efee authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'extcon-next-for-5.19' of...

Merge tag 'extcon-next-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon into char-misc-next

Chanwoo writes:

Update extcon next for v5.19

Detailed description for this pull request:
1. update extcon core driver
- extcon_get_extcon_dev() has been almost used to get the extcon device
on booting time. If extcon provider driver is probed at late time,
the extcon consumer driver get the -EPROBE_DEFER return value.
It requires the inefficient handling code of -EPROBE_DEFER.
Instead, extcon_get_extcon_dev() will return -EPROBE_DEFER
if the required extcon device is none. It makes the extcon consumer driver
to be simplified when getting extcon device.
- Register device after dev_set_drvdata because of accessing
the sysfs attributes at timing of between drv_set_data and device_register.
- Fix some kernel-doc comments of extcon functions.

2. update extcon provider driver
- Update extcon-intel-int3496.c
: Add support for controlling vbus power via regulator and support
to the extcon-intel-int3496.c driver to bind to devices without
an ACPi companion. And fix the minor clean-up.
- Use struct_size() helper on extcon-usbc-cros-ec.c
- Remove the disable irq operation in system sleep for using vbus/id
gpio as the wakeup source on extcon-usb-gpio.c
- Add support of SM5703 device by using existing extcon-sm5502.c
and rename i2c_devic_id from sm5703 to sm5703-muic to reduce confusion
between SM5703 MFD device and extcon device.
- Add usb role class support and add queue work sync before driver release
on extcon-ptn5150.c

* tag 'extcon-next-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon:
  extcon: Modify extcon device to be created after driver data is set
  extcon: sm5502: Clarify SM5703's i2c device ID
  extcon: ptn5150: Add usb role class support
  extcon: ptn5150: Add queue work sync before driver release
  extcon: sm5502: Add support for SM5703
  dt-bindings: extcon: bindings for SM5703
  extcon: usb-gpio: Remove disable irq operation in system sleep
  extcon: Fix some kernel-doc comments
  extcon: usbc-cros-ec: Use struct_size() helper in kzalloc()
  extcon: int3496: Add support for controlling Vbus through a regulator
  extcon: int3496: Add support for binding to plain platform devices
  extcon: int3496: Request non-exclusive access to the ID GPIO
  extcon: int3496: Make the driver a bit less verbose
  extcon: Fix extcon_get_extcon_dev() error handling
parents fa5602c6 5dcc2afe
......@@ -20,11 +20,12 @@ properties:
enum:
- siliconmitus,sm5502-muic
- siliconmitus,sm5504-muic
- siliconmitus,sm5703-muic
reg:
maxItems: 1
description: I2C slave address of the device. Usually 0x25 for SM5502,
0x14 for SM5504.
description: I2C slave address of the device. Usually 0x25 for SM5502
and SM5703, 0x14 for SM5504.
interrupts:
maxItems: 1
......
......@@ -131,6 +131,7 @@ config EXTCON_PALMAS
config EXTCON_PTN5150
tristate "NXP PTN5150 CC LOGIC USB EXTCON support"
depends on I2C && (GPIOLIB || COMPILE_TEST)
depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH
select REGMAP_I2C
help
Say Y here to enable support for USB peripheral and USB host
......@@ -156,7 +157,7 @@ config EXTCON_RT8973A
from abnormal high input voltage (up to 28V).
config EXTCON_SM5502
tristate "Silicon Mitus SM5502/SM5504 EXTCON support"
tristate "Silicon Mitus SM5502/SM5504/SM5703 EXTCON support"
depends on I2C
select IRQ_DOMAIN
select REGMAP_I2C
......
......@@ -394,8 +394,8 @@ static int axp288_extcon_probe(struct platform_device *pdev)
if (adev) {
info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev));
put_device(&adev->dev);
if (!info->id_extcon)
return -EPROBE_DEFER;
if (IS_ERR(info->id_extcon))
return PTR_ERR(info->id_extcon);
dev_info(dev, "controlling USB role\n");
} else {
......
......@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#define INT3496_GPIO_USB_ID 0
#define INT3496_GPIO_VBUS_EN 1
......@@ -30,7 +31,9 @@ struct int3496_data {
struct gpio_desc *gpio_usb_id;
struct gpio_desc *gpio_vbus_en;
struct gpio_desc *gpio_usb_mux;
struct regulator *vbus_boost;
int usb_id_irq;
bool vbus_boost_enabled;
};
static const unsigned int int3496_cable[] = {
......@@ -53,6 +56,27 @@ static const struct acpi_gpio_mapping acpi_int3496_default_gpios[] = {
{ },
};
static void int3496_set_vbus_boost(struct int3496_data *data, bool enable)
{
int ret;
if (IS_ERR_OR_NULL(data->vbus_boost))
return;
if (data->vbus_boost_enabled == enable)
return;
if (enable)
ret = regulator_enable(data->vbus_boost);
else
ret = regulator_disable(data->vbus_boost);
if (ret == 0)
data->vbus_boost_enabled = enable;
else
dev_err(data->dev, "Error updating Vbus boost regulator: %d\n", ret);
}
static void int3496_do_usb_id(struct work_struct *work)
{
struct int3496_data *data =
......@@ -71,6 +95,8 @@ static void int3496_do_usb_id(struct work_struct *work)
if (!IS_ERR(data->gpio_vbus_en))
gpiod_direction_output(data->gpio_vbus_en, !id);
else
int3496_set_vbus_boost(data, !id);
extcon_set_state_sync(data->edev, EXTCON_USB_HOST, !id);
}
......@@ -91,10 +117,12 @@ static int int3496_probe(struct platform_device *pdev)
struct int3496_data *data;
int ret;
ret = devm_acpi_dev_add_driver_gpios(dev, acpi_int3496_default_gpios);
if (ret) {
dev_err(dev, "can't add GPIO ACPI mapping\n");
return ret;
if (has_acpi_companion(dev)) {
ret = devm_acpi_dev_add_driver_gpios(dev, acpi_int3496_default_gpios);
if (ret) {
dev_err(dev, "can't add GPIO ACPI mapping\n");
return ret;
}
}
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
......@@ -106,7 +134,8 @@ static int int3496_probe(struct platform_device *pdev)
if (ret)
return ret;
data->gpio_usb_id = devm_gpiod_get(dev, "id", GPIOD_IN);
data->gpio_usb_id =
devm_gpiod_get(dev, "id", GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
if (IS_ERR(data->gpio_usb_id)) {
ret = PTR_ERR(data->gpio_usb_id);
dev_err(dev, "can't request USB ID GPIO: %d\n", ret);
......@@ -120,12 +149,14 @@ static int int3496_probe(struct platform_device *pdev)
}
data->gpio_vbus_en = devm_gpiod_get(dev, "vbus", GPIOD_ASIS);
if (IS_ERR(data->gpio_vbus_en))
dev_info(dev, "can't request VBUS EN GPIO\n");
if (IS_ERR(data->gpio_vbus_en)) {
dev_dbg(dev, "can't request VBUS EN GPIO\n");
data->vbus_boost = devm_regulator_get_optional(dev, "vbus");
}
data->gpio_usb_mux = devm_gpiod_get(dev, "mux", GPIOD_ASIS);
if (IS_ERR(data->gpio_usb_mux))
dev_info(dev, "can't request USB MUX GPIO\n");
dev_dbg(dev, "can't request USB MUX GPIO\n");
/* register extcon device */
data->edev = devm_extcon_dev_allocate(dev, int3496_cable);
......@@ -164,12 +195,19 @@ static const struct acpi_device_id int3496_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, int3496_acpi_match);
static const struct platform_device_id int3496_ids[] = {
{ .name = "intel-int3496" },
{},
};
MODULE_DEVICE_TABLE(platform, int3496_ids);
static struct platform_driver int3496_driver = {
.driver = {
.name = "intel-int3496",
.acpi_match_table = int3496_acpi_match,
},
.probe = int3496_probe,
.id_table = int3496_ids,
};
module_platform_driver(int3496_driver);
......
......@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/extcon-provider.h>
#include <linux/gpio/consumer.h>
#include <linux/usb/role.h>
/* PTN5150 registers */
#define PTN5150_REG_DEVICE_ID 0x01
......@@ -52,6 +53,7 @@ struct ptn5150_info {
int irq;
struct work_struct irq_work;
struct mutex mutex;
struct usb_role_switch *role_sw;
};
/* List of detectable cables */
......@@ -70,6 +72,7 @@ static const struct regmap_config ptn5150_regmap_config = {
static void ptn5150_check_state(struct ptn5150_info *info)
{
unsigned int port_status, reg_data, vbus;
enum usb_role usb_role = USB_ROLE_NONE;
int ret;
ret = regmap_read(info->regmap, PTN5150_REG_CC_STATUS, &reg_data);
......@@ -85,6 +88,7 @@ static void ptn5150_check_state(struct ptn5150_info *info)
extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false);
gpiod_set_value_cansleep(info->vbus_gpiod, 0);
extcon_set_state_sync(info->edev, EXTCON_USB, true);
usb_role = USB_ROLE_DEVICE;
break;
case PTN5150_UFP_ATTACHED:
extcon_set_state_sync(info->edev, EXTCON_USB, false);
......@@ -95,10 +99,18 @@ static void ptn5150_check_state(struct ptn5150_info *info)
gpiod_set_value_cansleep(info->vbus_gpiod, 1);
extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true);
usb_role = USB_ROLE_HOST;
break;
default:
break;
}
if (usb_role) {
ret = usb_role_switch_set_role(info->role_sw, usb_role);
if (ret)
dev_err(info->dev, "failed to set %s role: %d\n",
usb_role_string(usb_role), ret);
}
}
static void ptn5150_irq_work(struct work_struct *work)
......@@ -133,6 +145,13 @@ static void ptn5150_irq_work(struct work_struct *work)
extcon_set_state_sync(info->edev,
EXTCON_USB, false);
gpiod_set_value_cansleep(info->vbus_gpiod, 0);
ret = usb_role_switch_set_role(info->role_sw,
USB_ROLE_NONE);
if (ret)
dev_err(info->dev,
"failed to set none role: %d\n",
ret);
}
}
......@@ -194,6 +213,14 @@ static int ptn5150_init_dev_type(struct ptn5150_info *info)
return 0;
}
static void ptn5150_work_sync_and_put(void *data)
{
struct ptn5150_info *info = data;
cancel_work_sync(&info->irq_work);
usb_role_switch_put(info->role_sw);
}
static int ptn5150_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
......@@ -284,6 +311,15 @@ static int ptn5150_i2c_probe(struct i2c_client *i2c)
if (ret)
return -EINVAL;
info->role_sw = usb_role_switch_get(info->dev);
if (IS_ERR(info->role_sw))
return dev_err_probe(info->dev, PTR_ERR(info->role_sw),
"failed to get role switch\n");
ret = devm_add_action_or_reset(dev, ptn5150_work_sync_and_put, info);
if (ret)
return ret;
/*
* Update current extcon state if for example OTG connection was there
* before the probe
......
......@@ -798,6 +798,7 @@ static const struct sm5502_type sm5504_data = {
static const struct of_device_id sm5502_dt_match[] = {
{ .compatible = "siliconmitus,sm5502-muic", .data = &sm5502_data },
{ .compatible = "siliconmitus,sm5504-muic", .data = &sm5504_data },
{ .compatible = "siliconmitus,sm5703-muic", .data = &sm5502_data },
{ },
};
MODULE_DEVICE_TABLE(of, sm5502_dt_match);
......@@ -830,6 +831,7 @@ static SIMPLE_DEV_PM_OPS(sm5502_muic_pm_ops,
static const struct i2c_device_id sm5502_i2c_id[] = {
{ "sm5502", (kernel_ulong_t)&sm5502_data },
{ "sm5504", (kernel_ulong_t)&sm5504_data },
{ "sm5703-muic", (kernel_ulong_t)&sm5502_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, sm5502_i2c_id);
......
......@@ -226,16 +226,6 @@ static int usb_extcon_suspend(struct device *dev)
}
}
/*
* We don't want to process any IRQs after this point
* as GPIOs used behind I2C subsystem might not be
* accessible until resume completes. So disable IRQ.
*/
if (info->id_gpiod)
disable_irq(info->id_irq);
if (info->vbus_gpiod)
disable_irq(info->vbus_irq);
if (!device_may_wakeup(dev))
pinctrl_pm_select_sleep_state(dev);
......@@ -267,11 +257,6 @@ static int usb_extcon_resume(struct device *dev)
}
}
if (info->id_gpiod)
enable_irq(info->id_irq);
if (info->vbus_gpiod)
enable_irq(info->vbus_irq);
queue_delayed_work(system_power_efficient_wq,
&info->wq_detcable, 0);
......
......@@ -68,7 +68,7 @@ static int cros_ec_pd_command(struct cros_ec_extcon_info *info,
struct cros_ec_command *msg;
int ret;
msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL);
msg = kzalloc(struct_size(msg, data, max(outsize, insize)), GFP_KERNEL);
if (!msg)
return -ENOMEM;
......
......@@ -399,6 +399,7 @@ static ssize_t cable_state_show(struct device *dev,
/**
* extcon_sync() - Synchronize the state for an external connector.
* @edev: the extcon device
* @id: the unique id indicating an external connector
*
* Note that this function send a notification in order to synchronize
* the state and property of an external connector.
......@@ -736,6 +737,9 @@ EXPORT_SYMBOL_GPL(extcon_set_property);
/**
* extcon_set_property_sync() - Set property of an external connector with sync.
* @edev: the extcon device
* @id: the unique id indicating an external connector
* @prop: the property id indicating an extcon property
* @prop_val: the pointer including the new value of extcon property
*
* Note that when setting the property value of external connector,
......@@ -851,6 +855,8 @@ EXPORT_SYMBOL_GPL(extcon_set_property_capability);
* @extcon_name: the extcon name provided with extcon_dev_register()
*
* Return the pointer of extcon device if success or ERR_PTR(err) if fail.
* NOTE: This function returns -EPROBE_DEFER so it may only be called from
* probe() functions.
*/
struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
{
......@@ -864,7 +870,7 @@ struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
if (!strcmp(sd->name, extcon_name))
goto out;
}
sd = NULL;
sd = ERR_PTR(-EPROBE_DEFER);
out:
mutex_unlock(&extcon_dev_list_lock);
return sd;
......@@ -1218,19 +1224,14 @@ int extcon_dev_register(struct extcon_dev *edev)
edev->dev.type = &edev->extcon_dev_type;
}
ret = device_register(&edev->dev);
if (ret) {
put_device(&edev->dev);
goto err_dev;
}
spin_lock_init(&edev->lock);
edev->nh = devm_kcalloc(&edev->dev, edev->max_supported,
sizeof(*edev->nh), GFP_KERNEL);
if (!edev->nh) {
ret = -ENOMEM;
device_unregister(&edev->dev);
goto err_dev;
if (edev->max_supported) {
edev->nh = kcalloc(edev->max_supported, sizeof(*edev->nh),
GFP_KERNEL);
if (!edev->nh) {
ret = -ENOMEM;
goto err_alloc_nh;
}
}
for (index = 0; index < edev->max_supported; index++)
......@@ -1241,6 +1242,12 @@ int extcon_dev_register(struct extcon_dev *edev)
dev_set_drvdata(&edev->dev, edev);
edev->state = 0;
ret = device_register(&edev->dev);
if (ret) {
put_device(&edev->dev);
goto err_dev;
}
mutex_lock(&extcon_dev_list_lock);
list_add(&edev->entry, &extcon_dev_list);
mutex_unlock(&extcon_dev_list_lock);
......@@ -1248,6 +1255,9 @@ int extcon_dev_register(struct extcon_dev *edev)
return 0;
err_dev:
if (edev->max_supported)
kfree(edev->nh);
err_alloc_nh:
if (edev->max_supported)
kfree(edev->extcon_dev_type.groups);
err_alloc_groups:
......@@ -1308,6 +1318,7 @@ void extcon_dev_unregister(struct extcon_dev *edev)
if (edev->max_supported) {
kfree(edev->extcon_dev_type.groups);
kfree(edev->cables);
kfree(edev->nh);
}
put_device(&edev->dev);
......
......@@ -865,17 +865,20 @@ static int axp288_charger_probe(struct platform_device *pdev)
info->regmap_irqc = axp20x->regmap_irqc;
info->cable.edev = extcon_get_extcon_dev(AXP288_EXTCON_DEV_NAME);
if (info->cable.edev == NULL) {
dev_dbg(dev, "%s is not ready, probe deferred\n",
AXP288_EXTCON_DEV_NAME);
return -EPROBE_DEFER;
if (IS_ERR(info->cable.edev)) {
dev_err_probe(dev, PTR_ERR(info->cable.edev),
"extcon_get_extcon_dev(%s) failed\n",
AXP288_EXTCON_DEV_NAME);
return PTR_ERR(info->cable.edev);
}
if (acpi_dev_present(USB_HOST_EXTCON_HID, NULL, -1)) {
info->otg.cable = extcon_get_extcon_dev(USB_HOST_EXTCON_NAME);
if (info->otg.cable == NULL) {
dev_dbg(dev, "EXTCON_USB_HOST is not ready, probe deferred\n");
return -EPROBE_DEFER;
if (IS_ERR(info->otg.cable)) {
dev_err_probe(dev, PTR_ERR(info->otg.cable),
"extcon_get_extcon_dev(%s) failed\n",
USB_HOST_EXTCON_NAME);
return PTR_ERR(info->otg.cable);
}
dev_info(dev, "Using " USB_HOST_EXTCON_HID " extcon for usb-id\n");
}
......
......@@ -985,13 +985,10 @@ static int charger_extcon_init(struct charger_manager *cm,
cable->nb.notifier_call = charger_extcon_notifier;
cable->extcon_dev = extcon_get_extcon_dev(cable->extcon_name);
if (IS_ERR_OR_NULL(cable->extcon_dev)) {
if (IS_ERR(cable->extcon_dev)) {
pr_err("Cannot find extcon_dev for %s (cable: %s)\n",
cable->extcon_name, cable->name);
if (cable->extcon_dev == NULL)
return -EPROBE_DEFER;
else
return PTR_ERR(cable->extcon_dev);
return PTR_ERR(cable->extcon_dev);
}
for (i = 0; i < ARRAY_SIZE(extcon_mapping); i++) {
......
......@@ -242,10 +242,10 @@ static int max8997_battery_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "couldn't get charger regulator\n");
}
charger->edev = extcon_get_extcon_dev("max8997-muic");
if (IS_ERR_OR_NULL(charger->edev)) {
if (!charger->edev)
return -EPROBE_DEFER;
dev_info(charger->dev, "couldn't get extcon device\n");
if (IS_ERR(charger->edev)) {
dev_err_probe(charger->dev, PTR_ERR(charger->edev),
"couldn't get extcon device: max8997-muic\n");
return PTR_ERR(charger->edev);
}
if (!IS_ERR(charger->reg) && !IS_ERR_OR_NULL(charger->edev)) {
......
......@@ -455,13 +455,8 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
* This device property is for kernel internal use only and
* is expected to be set by the glue code.
*/
if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
edev = extcon_get_extcon_dev(name);
if (!edev)
return ERR_PTR(-EPROBE_DEFER);
return edev;
}
if (device_property_read_string(dev, "linux,extcon-name", &name) == 0)
return extcon_get_extcon_dev(name);
/*
* Try to get an extcon device from the USB PHY controller's "port"
......
......@@ -95,8 +95,8 @@ static int omap_otg_probe(struct platform_device *pdev)
return -ENODEV;
extcon = extcon_get_extcon_dev(config->extcon);
if (!extcon)
return -EPROBE_DEFER;
if (IS_ERR(extcon))
return PTR_ERR(extcon);
otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL);
if (!otg_dev)
......
......@@ -1708,8 +1708,8 @@ static int fusb302_probe(struct i2c_client *client,
*/
if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
chip->extcon = extcon_get_extcon_dev(name);
if (!chip->extcon)
return -EPROBE_DEFER;
if (IS_ERR(chip->extcon))
return PTR_ERR(chip->extcon);
}
chip->vbus = devm_regulator_get(chip->dev, "vbus");
......
......@@ -296,7 +296,7 @@ static inline void devm_extcon_unregister_notifier_all(struct device *dev,
static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
{
return ERR_PTR(-ENODEV);
return NULL;
}
static inline struct extcon_dev *extcon_find_edev_by_node(struct device_node *node)
......
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