From: Kishon Vijay Abraham I <kishon@ti.com>
To: <gregkh@linuxfoundation.org>
Cc: <kishon@ti.com>, <linux-kernel@vger.kernel.org>
Subject: [PATCH 32/51] extcon: Add the synchronization extcon APIs to support the notification
Date: Wed, 14 Sep 2016 13:14:13 +0530 [thread overview]
Message-ID: <1473839072-5673-33-git-send-email-kishon@ti.com> (raw)
In-Reply-To: <1473839072-5673-1-git-send-email-kishon@ti.com>
From: Chanwoo Choi <cw00.choi@samsung.com>
This patch adds the synchronization extcon APIs to support the notifications
for both state and property. When extcon_*_sync() functions is called,
the extcon informs the information from extcon provider to extcon client.
The extcon driver may need to change the both state and multiple properties
at the same time. After setting the data of a external connector,
the extcon send the notification to client driver with the extcon_*_sync().
The list of new extcon APIs as following:
- extcon_sync() : Send the notification for each external connector to
synchronize the information between extcon provider driver
and extcon client driver.
- extcon_set_state_sync() : Set the state of external connector with noti.
- extcon_set_property_sync() : Set the property of external connector with noti.
For example,
case 1, change the state of external connector and synchronized the data.
extcon_set_state_sync(edev, EXTCON_USB, 1);
case 2, change both the state and property of external connector
and synchronized the data.
extcon_set_state(edev, EXTCON_USB, 1);
extcon_set_property(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS 1);
extcon_sync(edev, EXTCON_USB);
case 3, change the property of external connector and synchronized the data.
extcon_set_property(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS, 0);
extcon_sync(edev, EXTCON_USB);
case 4, change the property of external connector and synchronized the data.
extcon_set_property_sync(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS, 0);
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Tested-by: Chris Zhong <zyw@rock-chips.com>
Tested-by: Guenter Roeck <groeck@chromium.org>
Reviewed-by: Guenter Roeck <groeck@chromium.org>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
drivers/extcon/extcon.c | 210 ++++++++++++++++++++++++++++++-----------------
include/linux/extcon.h | 30 ++++++-
2 files changed, 164 insertions(+), 76 deletions(-)
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
index d66adfd..8fde4be 100644
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -279,14 +279,11 @@ static bool is_extcon_attached(struct extcon_dev *edev, unsigned int index)
return !!(edev->state & BIT(index));
}
-static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached)
+static bool is_extcon_changed(struct extcon_dev *edev, int index,
+ bool new_state)
{
- if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) {
- *attached = ((new >> idx) & 0x1) ? true : false;
- return true;
- }
-
- return false;
+ int state = !!(edev->state & BIT(index));
+ return (state != new_state);
}
static bool is_extcon_property_supported(unsigned int id, unsigned int prop)
@@ -402,21 +399,13 @@ static ssize_t cable_state_show(struct device *dev,
}
/**
- * extcon_update_state() - Update the cable attach states of the extcon device
- * only for the masked bits.
- * @edev: the extcon device
- * @mask: the bit mask to designate updated bits.
- * @state: new cable attach status for @edev
- *
- * Changing the state sends uevent with environment variable containing
- * the name of extcon device (envp[0]) and the state output (envp[1]).
- * Tizen uses this format for extcon device to get events from ports.
- * Android uses this format as well.
+ * extcon_sync() - Synchronize the states for both the attached/detached
+ * @edev: the extcon device that has the cable.
*
- * Note that the notifier provides which bits are changed in the state
- * variable with the val parameter (second) to the callback.
+ * This function send a notification to synchronize the all states of a
+ * specific external connector
*/
-static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
+int extcon_sync(struct extcon_dev *edev, unsigned int id)
{
char name_buf[120];
char state_buf[120];
@@ -425,73 +414,58 @@ static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
int env_offset = 0;
int length;
int index;
+ int state;
unsigned long flags;
- bool attached;
if (!edev)
return -EINVAL;
+ index = find_cable_index_by_id(edev, id);
+ if (index < 0)
+ return index;
+
spin_lock_irqsave(&edev->lock, flags);
- if (edev->state != ((edev->state & ~mask) | (state & mask))) {
- u32 old_state;
+ state = !!(edev->state & BIT(index));
+ raw_notifier_call_chain(&edev->nh[index], state, edev);
- if (check_mutually_exclusive(edev, (edev->state & ~mask) |
- (state & mask))) {
- spin_unlock_irqrestore(&edev->lock, flags);
- return -EPERM;
- }
+ /* This could be in interrupt handler */
+ prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
+ if (!prop_buf) {
+ /* Unlock early before uevent */
+ spin_unlock_irqrestore(&edev->lock, flags);
- old_state = edev->state;
- edev->state &= ~mask;
- edev->state |= state & mask;
+ dev_err(&edev->dev, "out of memory in extcon_set_state\n");
+ kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE);
- for (index = 0; index < edev->max_supported; index++) {
- if (is_extcon_changed(old_state, edev->state, index,
- &attached))
- raw_notifier_call_chain(&edev->nh[index],
- attached, edev);
- }
-
- /* This could be in interrupt handler */
- prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
- if (prop_buf) {
- length = name_show(&edev->dev, NULL, prop_buf);
- if (length > 0) {
- if (prop_buf[length - 1] == '\n')
- prop_buf[length - 1] = 0;
- snprintf(name_buf, sizeof(name_buf),
- "NAME=%s", prop_buf);
- envp[env_offset++] = name_buf;
- }
- length = state_show(&edev->dev, NULL, prop_buf);
- if (length > 0) {
- if (prop_buf[length - 1] == '\n')
- prop_buf[length - 1] = 0;
- snprintf(state_buf, sizeof(state_buf),
- "STATE=%s", prop_buf);
- envp[env_offset++] = state_buf;
- }
- envp[env_offset] = NULL;
- /* Unlock early before uevent */
- spin_unlock_irqrestore(&edev->lock, flags);
+ return 0;
+ }
- kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp);
- free_page((unsigned long)prop_buf);
- } else {
- /* Unlock early before uevent */
- spin_unlock_irqrestore(&edev->lock, flags);
+ length = name_show(&edev->dev, NULL, prop_buf);
+ if (length > 0) {
+ if (prop_buf[length - 1] == '\n')
+ prop_buf[length - 1] = 0;
+ snprintf(name_buf, sizeof(name_buf), "NAME=%s", prop_buf);
+ envp[env_offset++] = name_buf;
+ }
- dev_err(&edev->dev, "out of memory in extcon_set_state\n");
- kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE);
- }
- } else {
- /* No changes */
- spin_unlock_irqrestore(&edev->lock, flags);
+ length = state_show(&edev->dev, NULL, prop_buf);
+ if (length > 0) {
+ if (prop_buf[length - 1] == '\n')
+ prop_buf[length - 1] = 0;
+ snprintf(state_buf, sizeof(state_buf), "STATE=%s", prop_buf);
+ envp[env_offset++] = state_buf;
}
+ envp[env_offset] = NULL;
+
+ /* Unlock early before uevent */
+ spin_unlock_irqrestore(&edev->lock, flags);
+ kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp);
+ free_page((unsigned long)prop_buf);
return 0;
}
+EXPORT_SYMBOL_GPL(extcon_sync);
/**
* extcon_get_state() - Get the state of a external connector.
@@ -520,17 +494,22 @@ EXPORT_SYMBOL_GPL(extcon_get_state);
/**
* extcon_set_state() - Set the state of a external connector.
+ * without a notification.
* @edev: the extcon device that has the cable.
* @id: the unique id of each external connector
* in extcon enumeration.
* @state: the new cable status. The default semantics is
* true: attached / false: detached.
+ *
+ * This function only set the state of a external connector without
+ * a notification. To synchronize the data of a external connector,
+ * use extcon_set_state_sync() and extcon_sync().
*/
int extcon_set_state(struct extcon_dev *edev, unsigned int id,
bool cable_state)
{
- u32 state;
- int index;
+ unsigned long flags;
+ int index, ret = 0;
if (!edev)
return -EINVAL;
@@ -539,6 +518,18 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id,
if (index < 0)
return index;
+ spin_lock_irqsave(&edev->lock, flags);
+
+ /* Check whether the external connector's state is changed. */
+ if (!is_extcon_changed(edev, index, cable_state))
+ goto out;
+
+ if (check_mutually_exclusive(edev,
+ (edev->state & ~BIT(index)) | (cable_state & BIT(index)))) {
+ ret = -EPERM;
+ goto out;
+ }
+
/*
* Initialize the value of extcon property before setting
* the detached state for an external connector.
@@ -546,12 +537,56 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id,
if (!cable_state)
init_property(edev, id, index);
- state = cable_state ? (1 << index) : 0;
- return extcon_update_state(edev, 1 << index, state);
+ /* Update the state for a external connector. */
+ if (cable_state)
+ edev->state |= BIT(index);
+ else
+ edev->state &= ~(BIT(index));
+out:
+ spin_unlock_irqrestore(&edev->lock, flags);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(extcon_set_state);
/**
+ * extcon_set_state_sync() - Set the state of a external connector
+ * with a notification.
+ * @edev: the extcon device that has the cable.
+ * @id: the unique id of each external connector
+ * in extcon enumeration.
+ * @state: the new cable status. The default semantics is
+ * true: attached / false: detached.
+ *
+ * This function set the state of external connector and synchronize the data
+ * by usning a notification.
+ */
+int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
+ bool cable_state)
+{
+ int ret, index;
+ unsigned long flags;
+
+ index = find_cable_index_by_id(edev, id);
+ if (index < 0)
+ return index;
+
+ /* Check whether the external connector's state is changed. */
+ spin_lock_irqsave(&edev->lock, flags);
+ ret = is_extcon_changed(edev, index, cable_state);
+ spin_unlock_irqrestore(&edev->lock, flags);
+ if (!ret)
+ return 0;
+
+ ret = extcon_set_state(edev, id, cable_state);
+ if (ret < 0)
+ return ret;
+
+ return extcon_sync(edev, id);
+}
+EXPORT_SYMBOL_GPL(extcon_set_state_sync);
+
+/**
* extcon_get_property() - Get the property value of a specific cable.
* @edev: the extcon device that has the cable.
* @id: the unique id of each external connector
@@ -702,6 +737,31 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id,
EXPORT_SYMBOL_GPL(extcon_set_property);
/**
+ * extcon_set_property_sync() - Set the property value of a specific cable
+ with a notification.
+ * @prop_val: the pointer including the new value of property.
+ *
+ * When setting the property value of external connector, the external connector
+ * should be attached. The each property should be included in the list of
+ * supported properties according to the type of external connectors.
+ *
+ * Returns 0 if success or error number if fail
+ */
+int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
+ unsigned int prop,
+ union extcon_property_value prop_val)
+{
+ int ret;
+
+ ret = extcon_set_property(edev, id, prop, prop_val);
+ if (ret < 0)
+ return ret;
+
+ return extcon_sync(edev, id);
+}
+EXPORT_SYMBOL_GPL(extcon_set_property_sync);
+
+/**
* extcon_get_property_capability() - Get the capability of property
* of an external connector.
* @edev: the extcon device that has the cable.
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
index 4fa3738..162c46a 100644
--- a/include/linux/extcon.h
+++ b/include/linux/extcon.h
@@ -222,6 +222,13 @@ extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
extern int extcon_get_state(struct extcon_dev *edev, unsigned int id);
extern int extcon_set_state(struct extcon_dev *edev, unsigned int id,
bool cable_state);
+extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
+ bool cable_state);
+
+/*
+ * Synchronize the state and property data for a specific external connector.
+ */
+extern int extcon_sync(struct extcon_dev *edev, unsigned int id);
/*
* get/set_property access the property value of each external connector.
@@ -233,6 +240,9 @@ extern int extcon_get_property(struct extcon_dev *edev, unsigned int id,
extern int extcon_set_property(struct extcon_dev *edev, unsigned int id,
unsigned int prop,
union extcon_property_value prop_val);
+extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
+ unsigned int prop,
+ union extcon_property_value prop_val);
/*
* get/set_property_capability set the capability of the property for each
@@ -317,6 +327,17 @@ static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id,
return 0;
}
+static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
+ bool cable_state)
+{
+ return 0;
+}
+
+static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
+{
+ return 0;
+}
+
static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id,
unsigned int prop,
union extcon_property_value *prop_val)
@@ -330,6 +351,13 @@ static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
return 0;
}
+static inline int extcon_set_property_sync(struct extcon_dev *edev,
+ unsigned int id, unsigned int prop,
+ union extcon_property_value prop_val)
+{
+ return 0;
+}
+
static inline int extcon_get_property_capability(struct extcon_dev *edev,
unsigned int id, unsigned int prop)
{
@@ -411,6 +439,6 @@ static inline int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int
static inline int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id,
bool cable_state)
{
- return extcon_set_state(edev, id, cable_state);
+ return extcon_set_state_sync(edev, id, cable_state);
}
#endif /* __LINUX_EXTCON_H__ */
--
1.7.9.5
next prev parent reply other threads:[~2016-09-14 7:45 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-14 7:43 [GIT PULL] phy: for 4.9 Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 01/51] phy: exynos5-usbdrd: Remove "static" from local variable Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 02/51] dt: bindings: add bindings for Allwinner A64 usb phy Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 03/51] phy: sun4i: add support for " Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 04/51] phy: bcm-ns-usb3: new driver for USB 3.0 PHY on Northstar Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 05/51] phy: qcom-ufs: use of_property_read_bool Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 06/51] Documentation: bindings: add DT documentation for Rockchip USB2PHY Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 07/51] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 08/51] Documentation: bindings: add dt documentation for Rockchip PCIe PHY Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 09/51] phy: add a driver for the Rockchip SoC internal " Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 10/51] phy: tegra: add missing header dependencies Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 11/51] phy: tegra: mark tegra_xusb_lane_lookup_function() static Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 12/51] phy: bcm-ns2-pcie: Get rid of struct ns2_pci_phy Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 13/51] phy: bcm-ns2-pcie: Set missing .owner field in ns2_pci_phy_ops Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 14/51] phy: rcar-gen3-usb2: revise the example of device tree doc Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 15/51] phy: rcar-gen3-usb2: Add a compatible string for r8a7796 Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 16/51] phy: omap-usb2: support suspend/resume Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 17/51] dt-bindings: phy: ti: add documentation for ti,dra7x-usb2 Kishon Vijay Abraham I
2016-09-14 7:43 ` [PATCH 18/51] phy: rockchip-inno-usb2: add COMMON_CLK dependency Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 19/51] extcon: adc-jack: update cable state during boot Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 20/51] extcon: Move extcon_get_edev_by_phandle() errors to dbg level Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 21/51] extcon: arizona: Remove unneeded semi-colon Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 22/51] extcon: arizona: Remove the usage of extcon_update_state() Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 23/51] extcon: adc-jack: Remove the usage of extcon_set_state() Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 24/51] extcon: gpio: " Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 25/51] extcon: Remove the state_store() to prevent the wrong access Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 26/51] extcon: Block the bit masking operation for cable state except for extcon core Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 27/51] extcon: Fix compile time warning Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 28/51] extcon: Add the extcon_type to gather each connector into five category Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 29/51] extcon: Add the support for extcon property according to extcon type Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 30/51] extcon: Add the support for the capability of each property Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 31/51] extcon: Rename the extcon_set/get_state() to maintain the function naming pattern Kishon Vijay Abraham I
2016-09-14 7:44 ` Kishon Vijay Abraham I [this message]
2016-09-14 7:44 ` [PATCH 33/51] extcon: Add EXTCON_DISP_DP and the property for USB Type-C Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 34/51] extcon: Add new EXTCON_DISP_HMD for Head-mounted Display device Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 35/51] extcon: Add new EXTCON_CHG_WPT for Wireless Power Transfer device Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 36/51] extcon: Introduce EXTCON_PROP_USB_SS property for SuperSpeed mode Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 37/51] phy: da8xx-usb: Fix syscon device name Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 38/51] phy: Add USB Type-C PHY driver for rk3399 Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 39/51] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 40/51] usb: phy: add USB_SUPPORT dependency Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 41/51] phy: rockchip-typec: add pm runtime support Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 42/51] phy-sun4i-usb: Use bool where appropriate Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 43/51] phy-sun4i-usb: Refactor forced session ending Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 44/51] phy-sun4i-usb: Simplify missing dr_mode handling Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 45/51] phy-sun4i-usb: Add support for phy_set_mode Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 46/51] phy-sun4i-usb: Warn when external vbus is detected Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 47/51] phy: Add reset callback Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 48/51] phy: rockchip-usb: use rockchip_usb_phy_reset to reset phy during wakeup Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 49/51] phy: sun4i-usb: Use spinlock to guard phyctl register access Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 50/51] phy-twl4030-usb: better handle musb_mailbox() failure Kishon Vijay Abraham I
2016-09-14 7:44 ` [PATCH 51/51] phy-twl4030-usb: initialize charging-related stuff via pm_runtime Kishon Vijay Abraham I
2016-09-15 8:38 ` [GIT PULL] phy: for 4.9 Greg KH
2016-09-15 10:22 ` Kishon Vijay Abraham I
2016-09-15 10:36 ` Greg KH
2016-09-15 10:56 ` Kishon Vijay Abraham I
2016-09-15 11:13 ` Kishon Vijay Abraham I
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1473839072-5673-33-git-send-email-kishon@ti.com \
--to=kishon@ti.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox