Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ddaa00ee authored by Sebastian Reichel's avatar Sebastian Reichel
Browse files

Merge remote-tracking branch 'chanwoo-extcon/ib-extcon-4.12' into psy-next

parents 61489b0f 815429b3
Loading
Loading
Loading
Loading
+61 −0
Original line number Diff line number Diff line
@@ -50,6 +50,13 @@ static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res)
	extcon_unregister_notifier(this->edev, this->id, this->nb);
}

static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res)
{
	struct extcon_dev_notifier_devres *this = res;

	extcon_unregister_notifier_all(this->edev, this->nb);
}

/**
 * devm_extcon_dev_allocate - Allocate managed extcon device
 * @dev:		device owning the extcon device being created
@@ -214,3 +221,57 @@ void devm_extcon_unregister_notifier(struct device *dev,
			       devm_extcon_dev_match, edev));
}
EXPORT_SYMBOL(devm_extcon_unregister_notifier);

/**
 * devm_extcon_register_notifier_all()
 *		- Resource-managed extcon_register_notifier_all()
 * @dev:	device to allocate extcon device
 * @edev:	the extcon device that has the external connecotr.
 * @nb:		a notifier block to be registered.
 *
 * This function manages automatically the notifier of extcon device using
 * device resource management and simplify the control of unregistering
 * the notifier of extcon device. To get more information, refer that function.
 *
 * Returns 0 if success or negaive error number if failure.
 */
int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev,
				struct notifier_block *nb)
{
	struct extcon_dev_notifier_devres *ptr;
	int ret;

	ptr = devres_alloc(devm_extcon_dev_notifier_all_unreg, sizeof(*ptr),
				GFP_KERNEL);
	if (!ptr)
		return -ENOMEM;

	ret = extcon_register_notifier_all(edev, nb);
	if (ret) {
		devres_free(ptr);
		return ret;
	}

	ptr->edev = edev;
	ptr->nb = nb;
	devres_add(dev, ptr);

	return 0;
}
EXPORT_SYMBOL(devm_extcon_register_notifier_all);

/**
 * devm_extcon_unregister_notifier_all()
 *		- Resource-managed extcon_unregister_notifier_all()
 * @dev:	device to allocate extcon device
 * @edev:	the extcon device that has the external connecotr.
 * @nb:		a notifier block to be registered.
 */
void devm_extcon_unregister_notifier_all(struct device *dev,
				struct extcon_dev *edev,
				struct notifier_block *nb)
{
	WARN_ON(devres_release(dev, devm_extcon_dev_notifier_all_unreg,
			       devm_extcon_dev_match, edev));
}
EXPORT_SYMBOL(devm_extcon_unregister_notifier_all);
+66 −0
Original line number Diff line number Diff line
@@ -448,8 +448,19 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id)
	spin_lock_irqsave(&edev->lock, flags);

	state = !!(edev->state & BIT(index));

	/*
	 * Call functions in a raw notifier chain for the specific one
	 * external connector.
	 */
	raw_notifier_call_chain(&edev->nh[index], state, edev);

	/*
	 * Call functions in a raw notifier chain for the all supported
	 * external connectors.
	 */
	raw_notifier_call_chain(&edev->nh_all, state, edev);

	/* This could be in interrupt handler */
	prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
	if (!prop_buf) {
@@ -954,6 +965,59 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
}
EXPORT_SYMBOL_GPL(extcon_unregister_notifier);

/**
 * extcon_register_notifier_all() - Register a notifier block for all connectors
 * @edev:	the extcon device that has the external connecotr.
 * @nb:		a notifier block to be registered.
 *
 * This fucntion registers a notifier block in order to receive the state
 * change of all supported external connectors from extcon device.
 * And The second parameter given to the callback of nb (val) is
 * the current state and third parameter is the edev pointer.
 *
 * Returns 0 if success or error number if fail
 */
int extcon_register_notifier_all(struct extcon_dev *edev,
				struct notifier_block *nb)
{
	unsigned long flags;
	int ret;

	if (!edev || !nb)
		return -EINVAL;

	spin_lock_irqsave(&edev->lock, flags);
	ret = raw_notifier_chain_register(&edev->nh_all, nb);
	spin_unlock_irqrestore(&edev->lock, flags);

	return ret;
}
EXPORT_SYMBOL_GPL(extcon_register_notifier_all);

/**
 * extcon_unregister_notifier_all() - Unregister a notifier block from extcon.
 * @edev:	the extcon device that has the external connecotr.
 * @nb:		a notifier block to be registered.
 *
 * Returns 0 if success or error number if fail
 */
int extcon_unregister_notifier_all(struct extcon_dev *edev,
				struct notifier_block *nb)
{
	unsigned long flags;
	int ret;

	if (!edev || !nb)
		return -EINVAL;

	spin_lock_irqsave(&edev->lock, flags);
	ret = raw_notifier_chain_unregister(&edev->nh_all, nb);
	spin_unlock_irqrestore(&edev->lock, flags);

	return ret;
}
EXPORT_SYMBOL_GPL(extcon_unregister_notifier_all);

static struct attribute *extcon_attrs[] = {
	&dev_attr_state.attr,
	&dev_attr_name.attr,
@@ -1212,6 +1276,8 @@ int extcon_dev_register(struct extcon_dev *edev)
	for (index = 0; index < edev->max_supported; index++)
		RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]);

	RAW_INIT_NOTIFIER_HEAD(&edev->nh_all);

	dev_set_drvdata(&edev->dev, edev);
	edev->state = 0;

+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@
 * @dev:		Device of this extcon.
 * @state:		Attach/detach state of this extcon. Do not provide at
 *			register-time.
 * @nh_all:		Notifier for the state change events for all supported
 *			external connectors from this extcon.
 * @nh:			Notifier for the state change events from this extcon
 * @entry:		To support list of extcon devices so that users can
 *			search for extcon devices based on the extcon name.
@@ -43,6 +45,7 @@ struct extcon_dev {

	/* Internal data. Please do not set. */
	struct device dev;
	struct raw_notifier_head nh_all;
	struct raw_notifier_head *nh;
	struct list_head entry;
	int max_supported;
+16 −5
Original line number Diff line number Diff line
@@ -236,11 +236,11 @@ extern int extcon_set_property_capability(struct extcon_dev *edev,
				unsigned int id, unsigned int prop);

/*
 * Following APIs are to monitor every action of a notifier.
 * Registrar gets notified for every external port of a connection device.
 * Probably this could be used to debug an action of notifier; however,
 * we do not recommend to use this for normal 'notifiee' device drivers who
 * want to be notified by a specific external port of the notifier.
 * Following APIs are to monitor the status change of the external connectors.
 * extcon_register_notifier(*edev, id, *nb) : Register a notifier block
 *			for specific external connector of the extcon.
 * extcon_register_notifier_all(*edev, *nb) : Register a notifier block
 *			for all supported external connectors of the extcon.
 */
extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
				    struct notifier_block *nb);
@@ -253,6 +253,17 @@ extern void devm_extcon_unregister_notifier(struct device *dev,
				struct extcon_dev *edev, unsigned int id,
				struct notifier_block *nb);

extern int extcon_register_notifier_all(struct extcon_dev *edev,
				struct notifier_block *nb);
extern int extcon_unregister_notifier_all(struct extcon_dev *edev,
				struct notifier_block *nb);
extern int devm_extcon_register_notifier_all(struct device *dev,
				struct extcon_dev *edev,
				struct notifier_block *nb);
extern void devm_extcon_unregister_notifier_all(struct device *dev,
				struct extcon_dev *edev,
				struct notifier_block *nb);

/*
 * Following API get the extcon device from devicetree.
 * This function use phandle of devicetree to get extcon device directly.