extcon: gpio-states: Add support for provide cable state without gpios
Laxman Dewangan [Fri, 5 Feb 2016 13:02:43 +0000 (18:02 +0530)]
Add support to provide cable connection states via extcon
framework even if there is no gpios property is provided.

On this case, it will read the initial cable state property
from DT and set the cable state. The cable state can be change
by extcon sysfs.

This helps in case where dynamic detection of cable is not
available and user still want to use multiple type of
cable on port. On this case, user can connect cable and
then cable state via sysfs.

bug 1671524

Change-Id: I79a2ca117d07c432440ed2f328a8a61919e22218
Reviewed-on: http://git-master/r/1008915
(cherry picked from commit 7b192eb4849cf1303b446188e91994ccc900c6c5)
Signed-off-by: Venkat Reddy Talla <vreddytalla@nvidia.com>
Reviewed-on: http://git-master/r/1011844
GVS: Gerrit_Virtual_Submit
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>

Documentation/devicetree/bindings/extcon/extcon-gpio-states.txt
drivers/extcon/extcon-gpio-states.c

index 10f43b4..e4184e2 100644 (file)
@@ -14,6 +14,18 @@ Optional Properties:
  - extcon-gpio,cable-states: GPIO states and ther corresponding output cable
        state. This is array of the data for table as
                gpio-state <-> output cable-state
+- cable-connected-on-boot: Cable connected on boot. It should be cable index
+       in the output cable names. The number start from 0. Absence of this
+       property will be assume as there is no cable connected. This property
+       will be valid if there is no gpios provided for cable states.
+
+
+This driver also supports the extcon interface for different cable without
+gpios. On this case, if property cable-connected-on-boot provided then
+it will be consider this as the default cable otherwise it will assume
+that there is no cable connected. Later on, through extcon sysfs, the
+state can be chnaged.
+
 extcon-gpio {
        compatible = "extcon-gpio-states";
                gpio = <&gpio 20 0 &gpio 30 0>;
index 1f46622..faf9421 100644 (file)
@@ -57,6 +57,7 @@ struct gpio_extcon_platform_data {
        struct gpio_extcon_cables *cable_states;
        int n_cable_states;
        int cable_detect_delay;
+       int init_state;
 };
 
 struct gpio_extcon_info {
@@ -144,14 +145,17 @@ static struct gpio_extcon_platform_data *of_get_platform_data(
        if (!pdata)
                return ERR_PTR(-ENOMEM);
 
-       of_property_read_string(np, "extcon-gpio,name", &pdata->name);
+       of_property_read_string(np, "label", &pdata->name);
+       if (!pdata->name)
+               of_property_read_string(np, "extcon-gpio,name", &pdata->name);
        if (!pdata->name)
                pdata->name = np->name;
 
        n_gpio = of_gpio_named_count(np, "gpios");
        if (n_gpio < 1) {
-               dev_err(&pdev->dev, "Not sufficient gpios\n");
-               return ERR_PTR(-EINVAL);
+               ret = of_property_read_u32(np, "cable-connected-on-boot", &pval);
+               pdata->init_state = (!ret) ? pval : -1;
+               goto parse_cable_names;
        }
 
        pdata->n_gpio = n_gpio;
@@ -192,23 +196,6 @@ static struct gpio_extcon_platform_data *of_get_platform_data(
                pdata->wait_for_gpio_scan = 100;
 
 
-       pdata->n_out_cables = of_property_count_strings(np,
-                                       "extcon-gpio,out-cable-names");
-       if (pdata->n_out_cables <= 0) {
-               dev_err(&pdev->dev, "not found out cable names\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       pdata->out_cable_name = devm_kzalloc(&pdev->dev,
-                               (pdata->n_out_cables + 1) *
-                               sizeof(*pdata->out_cable_name), GFP_KERNEL);
-       if (!pdata->out_cable_name)
-               return ERR_PTR(-ENOMEM);
-       count = 0;
-       of_property_for_each_string(np, "extcon-gpio,out-cable-names",
-                                               prop, names)
-               pdata->out_cable_name[count++] = names;
-       pdata->out_cable_name[count] = NULL;
 
        pdata->n_cable_states = of_property_count_u32(np,
                                                "extcon-gpio,cable-states");
@@ -234,6 +221,25 @@ static struct gpio_extcon_platform_data *of_get_platform_data(
                        pdata->cable_states[count].cstate = pval;
        }
 
+parse_cable_names:
+       pdata->n_out_cables = of_property_count_strings(np,
+                                       "extcon-gpio,out-cable-names");
+       if (pdata->n_out_cables <= 0) {
+               dev_err(&pdev->dev, "not found out cable names\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       pdata->out_cable_name = devm_kzalloc(&pdev->dev,
+                               (pdata->n_out_cables + 1) *
+                               sizeof(*pdata->out_cable_name), GFP_KERNEL);
+       if (!pdata->out_cable_name)
+               return ERR_PTR(-ENOMEM);
+       count = 0;
+       of_property_for_each_string(np, "extcon-gpio,out-cable-names",
+                                               prop, names)
+               pdata->out_cable_name[count++] = names;
+       pdata->out_cable_name[count] = NULL;
+
        return pdata;
 }
 
@@ -252,7 +258,7 @@ static int gpio_extcon_probe(struct platform_device *pdev)
        if (!pdata)
                return -EINVAL;
 
-       if (!pdata->irq_flags) {
+       if (!pdata->irq_flags && pdata->n_gpio) {
                dev_err(&pdev->dev, "IRQ flag is not specified.\n");
                return -EINVAL;
        }
@@ -320,7 +326,19 @@ static int gpio_extcon_probe(struct platform_device *pdev)
        device_wakeup_enable(gpex->dev);
 
        /* Perform initial detection */
-       gpio_extcon_scan_work(&gpex->work.work);
+       if (gpex->pdata->n_gpio) {
+               gpio_extcon_scan_work(&gpex->work.work);
+       } else {
+               if (pdata->init_state < 0) {
+                       dev_info(gpex->dev, "No Cable connected on boot\n");
+                       extcon_set_state(&gpex->edev, 0);
+               } else {
+                       dev_info(gpex->dev, "Cable %s connected on boot\n",
+                               pdata->out_cable_name[pdata->init_state]);
+                       extcon_set_state(&gpex->edev, BIT(pdata->init_state));
+               }
+       }
+
        return 0;
 
 err: