extcon: Add the support for the capability of each property
authorChanwoo Choi <cw00.choi@samsung.com>
Mon, 25 Jul 2016 12:15:19 +0000 (21:15 +0900)
committerKishon Vijay Abraham I <kishon@ti.com>
Sat, 10 Sep 2016 11:18:52 +0000 (16:48 +0530)
This patch adds the support of the property capability setting. This function
decides the supported properties of each external connector on extcon provider
driver.

Ths list of new extcon APIs to get/set the capability of property as following:
- int extcon_get_property_capability(struct extcon_dev *edev,
unsigned int id, unsigned int prop);
- int extcon_set_property_capability(struct extcon_dev *edev,
unsigned int id, unsigned int prop);

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>
drivers/extcon/extcon.c
include/linux/extcon.h

index 37fa4b51c5a1e5c4768c2e32c404ae9877b7769f..599fc377a9658f3929e5509d80946564b6a90de7 100644 (file)
@@ -201,6 +201,11 @@ struct extcon_cable {
        union extcon_property_value chg_propval[EXTCON_PROP_CHG_CNT];
        union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT];
        union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT];
+
+       unsigned long usb_bits[BITS_TO_LONGS(EXTCON_PROP_USB_CNT)];
+       unsigned long chg_bits[BITS_TO_LONGS(EXTCON_PROP_CHG_CNT)];
+       unsigned long jack_bits[BITS_TO_LONGS(EXTCON_PROP_JACK_CNT)];
+       unsigned long disp_bits[BITS_TO_LONGS(EXTCON_PROP_DISP_CNT)];
 };
 
 static struct class *extcon_class;
@@ -297,6 +302,39 @@ static bool is_extcon_property_supported(unsigned int id, unsigned int prop)
        return !!(extcon_info[id].type & type);
 }
 
+static int is_extcon_property_capability(struct extcon_dev *edev,
+                               unsigned int id, int index,unsigned int prop)
+{
+       struct extcon_cable *cable;
+       int type, ret;
+
+       /* Check whether the property is supported or not. */
+       type = get_extcon_type(prop);
+       if (type < 0)
+               return type;
+
+       cable = &edev->cables[index];
+
+       switch (type) {
+       case EXTCON_TYPE_USB:
+               ret = test_bit(prop - EXTCON_PROP_USB_MIN, cable->usb_bits);
+               break;
+       case EXTCON_TYPE_CHG:
+               ret = test_bit(prop - EXTCON_PROP_CHG_MIN, cable->chg_bits);
+               break;
+       case EXTCON_TYPE_JACK:
+               ret = test_bit(prop - EXTCON_PROP_JACK_MIN, cable->jack_bits);
+               break;
+       case EXTCON_TYPE_DISP:
+               ret = test_bit(prop - EXTCON_PROP_DISP_MIN, cable->disp_bits);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
 static void init_property(struct extcon_dev *edev, unsigned int id, int index)
 {
        unsigned int type = extcon_info[id].type;
@@ -554,6 +592,12 @@ int extcon_get_property(struct extcon_dev *edev, unsigned int id,
 
        spin_lock_irqsave(&edev->lock, flags);
 
+       /* Check whether the property is available or not. */
+       if (!is_extcon_property_capability(edev, id, index, prop)) {
+               spin_unlock_irqrestore(&edev->lock, flags);
+               return -EPERM;
+       }
+
        /*
         * Check whether the external connector is attached.
         * If external connector is detached, the user can not
@@ -626,6 +670,12 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id,
 
        spin_lock_irqsave(&edev->lock, flags);
 
+       /* Check whether the property is available or not. */
+       if (!is_extcon_property_capability(edev, id, index, prop)) {
+               spin_unlock_irqrestore(&edev->lock, flags);
+               return -EPERM;
+       }
+
        cable = &edev->cables[index];
 
        /* Set the property value according to extcon type */
@@ -653,6 +703,96 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id,
 }
 EXPORT_SYMBOL_GPL(extcon_set_property);
 
+/**
+ * extcon_get_property_capability() - Get the capability of property
+ *                     of an external connector.
+ * @edev:              the extcon device that has the cable.
+ * @id:                        the unique id of each external connector
+ *                     in extcon enumeration.
+ * @prop:              the property id among enum extcon_property.
+ *
+ * Returns 1 if the property is available or 0 if not available.
+ */
+int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id,
+                                       unsigned int prop)
+{
+       int index;
+
+       if (!edev)
+               return -EINVAL;
+
+       /* Check whether the property is supported or not */
+       if (!is_extcon_property_supported(id, prop))
+               return -EINVAL;
+
+       /* Find the cable index of external connector by using id */
+       index = find_cable_index_by_id(edev, id);
+       if (index < 0)
+               return index;
+
+       return is_extcon_property_capability(edev, id, index, prop);
+}
+EXPORT_SYMBOL_GPL(extcon_get_property_capability);
+
+/**
+ * extcon_set_property_capability() - Set the capability of a property
+ *                     of an external connector.
+ * @edev:              the extcon device that has the cable.
+ * @id:                        the unique id of each external connector
+ *                     in extcon enumeration.
+ * @prop:              the property id among enum extcon_property.
+ *
+ * This function set the capability of a property for an external connector
+ * to mark the bit in capability bitmap which mean the available state of
+ * a property.
+ *
+ * Returns 0 if success or error number if fail
+ */
+int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id,
+                                       unsigned int prop)
+{
+       struct extcon_cable *cable;
+       int index, type, ret = 0;
+
+       if (!edev)
+               return -EINVAL;
+
+       /* Check whether the property is supported or not. */
+       if (!is_extcon_property_supported(id, prop))
+               return -EINVAL;
+
+       /* Find the cable index of external connector by using id. */
+       index = find_cable_index_by_id(edev, id);
+       if (index < 0)
+               return index;
+
+       type = get_extcon_type(prop);
+       if (type < 0)
+               return type;
+
+       cable = &edev->cables[index];
+
+       switch (type) {
+       case EXTCON_TYPE_USB:
+               __set_bit(prop - EXTCON_PROP_USB_MIN, cable->usb_bits);
+               break;
+       case EXTCON_TYPE_CHG:
+               __set_bit(prop - EXTCON_PROP_CHG_MIN, cable->chg_bits);
+               break;
+       case EXTCON_TYPE_JACK:
+               __set_bit(prop - EXTCON_PROP_JACK_MIN, cable->jack_bits);
+               break;
+       case EXTCON_TYPE_DISP:
+               __set_bit(prop - EXTCON_PROP_DISP_MIN, cable->disp_bits);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(extcon_set_property_capability);
+
 /**
  * extcon_get_extcon_dev() - Get the extcon device instance from the name
  * @extcon_name:       The extcon name provided with extcon_dev_register()
index f9d4a44e86d3df6242b37de0f7556cb922e1c323..f08469089f7442316a9c165c5b6dd5137d3afb5c 100644 (file)
@@ -234,6 +234,16 @@ extern int extcon_set_property(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
+ * external connector. They are used to set the capability of the property
+ * of each external connector based on the id and property.
+ */
+extern int extcon_get_property_capability(struct extcon_dev *edev,
+                               unsigned int id, unsigned int prop);
+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.
@@ -320,6 +330,18 @@ static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
        return 0;
 }
 
+static inline int extcon_get_property_capability(struct extcon_dev *edev,
+                                       unsigned int id, unsigned int prop)
+{
+       return 0;
+}
+
+static inline int extcon_set_property_capability(struct extcon_dev *edev,
+                                       unsigned int id, unsigned int prop)
+{
+       return 0;
+}
+
 static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
 {
        return NULL;