aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2021-03-12 17:08:31 +0900
committerChanwoo Choi <cw00.choi@samsung.com>2022-06-06 15:03:46 +0900
commitf0ddda961c6b76730445f886748eb069bdba8edf (patch)
treeadcff01798e9add107cb4414039fe580d7b43f7a
parentf2906aa863381afb0015a9eb7fefad885d4e5a56 (diff)
downloadextcon-testing.tar.gz
extcon: Add support of multiple external connector on a deviceextcon-testing
TODO Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
-rw-r--r--drivers/extcon/extcon.c14
-rw-r--r--drivers/extcon/extcon.h5
-rw-r--r--include/linux/extcon-provider.h61
-rw-r--r--include/linux/extcon.h74
4 files changed, 152 insertions, 2 deletions
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
index d3a32b8064994..b03ccd7ee3992 100644
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -192,6 +192,8 @@ static const struct __extcon_info {
* struct extcon_cable - An internal data for an external connector.
* @edev: the extcon device
* @cable_index: the index of this cable in the edev
+ * @devnum: the devnum of this cable among the same connector type
+ * in the edev
* @attr_g: the attribute group for the cable
* @attr_name: "name" sysfs entry
* @attr_state: "state" sysfs entry
@@ -200,6 +202,7 @@ static const struct __extcon_info {
struct extcon_cable {
struct extcon_dev *edev;
int cable_index;
+ int devnum;
struct attribute_group attr_g;
struct device_attribute attr_name;
@@ -1075,7 +1078,7 @@ EXPORT_SYMBOL_GPL(extcon_dev_free);
*/
int extcon_dev_register(struct extcon_dev *edev)
{
- int ret, index = 0;
+ int ret, id, index = 0;
static atomic_t edev_no = ATOMIC_INIT(-1);
if (!extcon_class) {
@@ -1087,7 +1090,11 @@ int extcon_dev_register(struct extcon_dev *edev)
if (!edev || !edev->supported_cable)
return -EINVAL;
- for (; edev->supported_cable[index] != EXTCON_NONE; index++);
+ for (; edev->supported_cable[index] != EXTCON_NONE; index++) {
+ id = edev->supported_cable[index];
+ if (id < 0 || id >= EXTCON_NUM || extcon_info[id].type == EXTCON_NONE)
+ return -EINVAL;
+ }
edev->max_supported = index;
if (index > SUPPORTED_CABLE_MAX) {
@@ -1120,7 +1127,10 @@ int extcon_dev_register(struct extcon_dev *edev)
goto err_sysfs_alloc;
}
for (index = 0; index < edev->max_supported; index++) {
+ id = edev->supported_cable[index];
+
cable = &edev->cables[index];
+ cable->devnum = edev->max_supported_type[id]++;
str = kasprintf(GFP_KERNEL, "cable.%d", index);
if (!str) {
diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h
index 93b5e0306966d..385aed3726321 100644
--- a/drivers/extcon/extcon.h
+++ b/drivers/extcon/extcon.h
@@ -24,11 +24,14 @@
* register-time.
* @nh_all: Notifier for the state change events for all supported
* external connectors from this extcon.
+ * @nh_type: Notifier for the state change events for specific type
+ * among 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.
* @lock:
* @max_supported: Internal value to store the number of cables.
+ * @max_supported_type: Internal value to store the number of cable types.
* @extcon_dev_type: Device_type struct to provide attribute_groups
* customized for each extcon device.
* @cables: Sysfs subdirectories. Each represents one cable.
@@ -47,9 +50,11 @@ struct extcon_dev {
/* Internal data. Please do not set. */
struct device dev;
struct raw_notifier_head nh_all;
+ struct raw_notifier_head *nh_type;
struct raw_notifier_head *nh;
struct list_head entry;
int max_supported;
+ int max_supported_type[EXTCON_NUM];
spinlock_t lock; /* could be called by irq handler */
u32 state;
diff --git a/include/linux/extcon-provider.h b/include/linux/extcon-provider.h
index fa70945f4e6b8..d548d232ab6c7 100644
--- a/include/linux/extcon-provider.h
+++ b/include/linux/extcon-provider.h
@@ -33,6 +33,8 @@ void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
/* Synchronize the state and property value for each external connector. */
int extcon_sync(struct extcon_dev *edev, unsigned int id);
+int extcon_sync_with_devnum(struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum);
/*
* Following APIs set the connected state of each external connector.
@@ -42,6 +44,10 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id,
bool state);
int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
bool state);
+int extcon_set_state_with_devnum(struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum, bool state);
+int extcon_set_state_sync_devnum(struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum, bool state);
/*
* Following APIs set the property of each external connector.
@@ -60,6 +66,17 @@ int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
union extcon_property_value prop_val);
int extcon_set_property_capability(struct extcon_dev *edev,
unsigned int id, unsigned int prop);
+int extcon_set_property_with_devnum(struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum,
+ unsigned int prop,
+ union extcon_property_value prop_val);
+int extcon_set_property_sync_devnum(struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum,
+ unsigned int prop,
+ union extcon_property_value prop_val);
+int extcon_set_property_capability_devnum(struct extcon_dev *edev,
+ unsigned int devnum,
+ unsigned int id, unsigned int prop);
#else /* CONFIG_EXTCON */
static inline int extcon_dev_register(struct extcon_dev *edev)
@@ -106,11 +123,31 @@ static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id
return 0;
}
+static inline int extcon_set_state_with_devnum(struct extcon_dev *edev,
+ unsigned int id, unsigned int devnum,
+ bool state)
+{
+ return 0;
+}
+
+static inline int extcon_set_state_sync_devnum(struct extcon_dev *edev,
+ unsigned int id, unsigned int devnum,
+ bool state)
+{
+ return 0;
+}
+
static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
{
return 0;
}
+static inline int extcon_sync_with_devnum(struct extcon_dev *edev,
+ unsigned int id, unsigned int devnum)
+{
+ return 0;
+}
+
static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
unsigned int prop,
union extcon_property_value prop_val)
@@ -130,5 +167,29 @@ static inline int extcon_set_property_capability(struct extcon_dev *edev,
{
return 0;
}
+
+static inline int extcon_set_property_with_devnum(struct extcon_dev *edev,
+ unsigned int id, unsigned int devnum,
+ unsigned int prop,
+ union extcon_property_value prop_val)
+{
+ return 0;
+}
+
+static inline int extcon_set_property_sync_devnum(struct extcon_dev *edev,
+ unsigned int id, unsigned int devnum,
+ unsigned int prop,
+ union extcon_property_value prop_val)
+{
+ return 0;
+}
+
+static inline int extcon_set_property_capability_devnum(struct extcon_dev *edev,
+ unsigned int id, unsigned int devnum,
+ unsigned int prop)
+{
+ return 0;
+}
+
#endif /* CONFIG_EXTCON */
#endif /* __LINUX_EXTCON_PROVIDER_H__ */
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
index 685401d94d398..ddfcfc8c80ced 100644
--- a/include/linux/extcon.h
+++ b/include/linux/extcon.h
@@ -171,6 +171,8 @@ struct extcon_dev;
* The 'id' argument indicates the defined external connector.
*/
int extcon_get_state(struct extcon_dev *edev, unsigned int id);
+int extcon_get_state_with_devnum(struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum);
/*
* Following APIs get the property of each external connector.
@@ -186,6 +188,17 @@ int extcon_get_property(struct extcon_dev *edev, unsigned int id,
union extcon_property_value *prop_val);
int extcon_get_property_capability(struct extcon_dev *edev,
unsigned int id, unsigned int prop);
+int extcon_get_property_with_devnum(struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum,
+ unsigned int prop,
+ union extcon_property_value *prop_val);
+int extcon_get_property_capability_with_devnum(struct extcon_dev *edev,
+ unsigned int devnum,
+ unsigned int id, unsigned int prop);
+
+/* TODO */
+int extcon_is_supported(struct extcon_dev *edev, unsigned int id);
+int extcon_get_dev_count(struct extcon_dev *edev, unsigned int id);
/*
* Following APIs register the notifier block in order to detect
@@ -206,6 +219,22 @@ int devm_extcon_register_notifier(struct device *dev,
void devm_extcon_unregister_notifier(struct device *dev,
struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb);
+int extcon_register_notifier_with_devnum(struct extcon_dev *edev,
+ unsigned int id,
+ unsigned int devnum,
+ struct notifier_block *nb);
+int extcon_unregister_notifier_with_devnum(struct extcon_dev *edev,
+ unsigned int id,
+ unsigned int devnum,
+ struct notifier_block *nb);
+int devm_extcon_register_notifier_with_devnum(struct device *dev,
+ struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum,
+ struct notifier_block *nb);
+void devm_extcon_unregister_notifier_with_devnum(struct device *dev,
+ struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum,
+ struct notifier_block *nb);
int extcon_register_notifier_all(struct extcon_dev *edev,
struct notifier_block *nb);
@@ -235,6 +264,13 @@ static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id)
return 0;
}
+static inline int extcon_get_state_with_devnum(struct extcon_dev *edev,
+ unsigned int id,
+ unsigned int devnum)
+{
+ return 0;
+}
+
static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id,
unsigned int prop,
union extcon_property_value *prop_val)
@@ -248,6 +284,24 @@ static inline int extcon_get_property_capability(struct extcon_dev *edev,
return 0;
}
+static inline int extcon_get_property_with_devnum(struct extcon_dev *edev,
+ unsigned int id,
+ unsigned int devnum,
+ unsigned int prop,
+ union extcon_property_value *prop_val)
+{
+ return 0;
+}
+
+static inline int extcon_get_property_capability_with_devnum(
+ struct extcon_dev *edev,
+ unsigned int devnum,
+ unsigned int id,
+ unsigned int prop)
+{
+ return 0;
+}
+
static inline int extcon_register_notifier(struct extcon_dev *edev,
unsigned int id, struct notifier_block *nb)
{
@@ -271,6 +325,26 @@ static inline void devm_extcon_unregister_notifier(struct device *dev,
struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb) { }
+static inline int extcon_register_notifier_with_devnum(struct extcon_dev *edev,
+ unsigned int id,
+ unsigned int devnum,
+ struct notifier_block *nb) { return 0; }
+
+static inline int extcon_unregister_notifier_with_devnum(struct extcon_dev *edev,
+ unsigned int id,
+ unsigned int devnum,
+ struct notifier_block *nb) { return 0; }
+
+static inline int devm_extcon_register_notifier_with_devnum(struct device *dev,
+ struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum,
+ struct notifier_block *nb) { return 0; }
+
+static inline void devm_extcon_unregister_notifier_with_devnum(struct device *dev,
+ struct extcon_dev *edev, unsigned int id,
+ unsigned int devnum,
+ struct notifier_block *nb) { }
+
static inline int extcon_register_notifier_all(struct extcon_dev *edev,
struct notifier_block *nb)
{