pinctrl: core: Remove broken remove_last group and pinmux functions
[linux-block.git] / drivers / pinctrl / pinctrl-single.c
index 9c3c00515aa0fe20619fa7d2832d28ccee62c0db..42d7e76baccf5bc7739633daea72c640e889abaf 100644 (file)
@@ -712,8 +712,8 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs)
        }
 
        dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins);
-       pcs->pins.pa = devm_kzalloc(pcs->dev,
-                               sizeof(*pcs->pins.pa) * nr_pins,
+       pcs->pins.pa = devm_kcalloc(pcs->dev,
+                               nr_pins, sizeof(*pcs->pins.pa),
                                GFP_KERNEL);
        if (!pcs->pins.pa)
                return -ENOMEM;
@@ -747,38 +747,44 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs)
 /**
  * pcs_add_function() - adds a new function to the function list
  * @pcs: pcs driver instance
- * @np: device node of the mux entry
+ * @fcn: new function allocated
  * @name: name of the function
  * @vals: array of mux register value pairs used by the function
  * @nvals: number of mux register value pairs
  * @pgnames: array of pingroup names for the function
  * @npgnames: number of pingroup names
+ *
+ * Caller must take care of locking.
  */
-static struct pcs_function *pcs_add_function(struct pcs_device *pcs,
-                                       struct device_node *np,
-                                       const char *name,
-                                       struct pcs_func_vals *vals,
-                                       unsigned nvals,
-                                       const char **pgnames,
-                                       unsigned npgnames)
+static int pcs_add_function(struct pcs_device *pcs,
+                           struct pcs_function **fcn,
+                           const char *name,
+                           struct pcs_func_vals *vals,
+                           unsigned int nvals,
+                           const char **pgnames,
+                           unsigned int npgnames)
 {
        struct pcs_function *function;
-       int res;
+       int selector;
 
        function = devm_kzalloc(pcs->dev, sizeof(*function), GFP_KERNEL);
        if (!function)
-               return NULL;
+               return -ENOMEM;
 
        function->vals = vals;
        function->nvals = nvals;
 
-       res = pinmux_generic_add_function(pcs->pctl, name,
-                                         pgnames, npgnames,
-                                         function);
-       if (res)
-               return NULL;
+       selector = pinmux_generic_add_function(pcs->pctl, name,
+                                              pgnames, npgnames,
+                                              function);
+       if (selector < 0) {
+               devm_kfree(pcs->dev, function);
+               *fcn = NULL;
+       } else {
+               *fcn = function;
+       }
 
-       return function;
+       return selector;
 }
 
 /**
@@ -924,15 +930,15 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
        if (!nconfs)
                return 0;
 
-       func->conf = devm_kzalloc(pcs->dev,
-                                 sizeof(struct pcs_conf_vals) * nconfs,
+       func->conf = devm_kcalloc(pcs->dev,
+                                 nconfs, sizeof(struct pcs_conf_vals),
                                  GFP_KERNEL);
        if (!func->conf)
                return -ENOMEM;
        func->nconfs = nconfs;
        conf = &(func->conf[0]);
        m++;
-       settings = devm_kzalloc(pcs->dev, sizeof(unsigned long) * nconfs,
+       settings = devm_kcalloc(pcs->dev, nconfs, sizeof(unsigned long),
                                GFP_KERNEL);
        if (!settings)
                return -ENOMEM;
@@ -979,8 +985,8 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
 {
        const char *name = "pinctrl-single,pins";
        struct pcs_func_vals *vals;
-       int rows, *pins, found = 0, res = -ENOMEM, i;
-       struct pcs_function *function;
+       int rows, *pins, found = 0, res = -ENOMEM, i, fsel, gsel;
+       struct pcs_function *function = NULL;
 
        rows = pinctrl_count_index_with_args(np, name);
        if (rows <= 0) {
@@ -988,11 +994,11 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
                return -EINVAL;
        }
 
-       vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL);
+       vals = devm_kcalloc(pcs->dev, rows, sizeof(*vals), GFP_KERNEL);
        if (!vals)
                return -ENOMEM;
 
-       pins = devm_kzalloc(pcs->dev, sizeof(*pins) * rows, GFP_KERNEL);
+       pins = devm_kcalloc(pcs->dev, rows, sizeof(*pins), GFP_KERNEL);
        if (!pins)
                goto free_vals;
 
@@ -1030,21 +1036,25 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
        }
 
        pgnames[0] = np->name;
-       function = pcs_add_function(pcs, np, np->name, vals, found, pgnames, 1);
-       if (!function) {
-               res = -ENOMEM;
+       mutex_lock(&pcs->mutex);
+       fsel = pcs_add_function(pcs, &function, np->name, vals, found,
+                               pgnames, 1);
+       if (fsel < 0) {
+               res = fsel;
                goto free_pins;
        }
 
-       res = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
-       if (res < 0)
+       gsel = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
+       if (gsel < 0) {
+               res = gsel;
                goto free_function;
+       }
 
        (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
        (*map)->data.mux.group = np->name;
        (*map)->data.mux.function = np->name;
 
-       if (PCS_HAS_PINCONF) {
+       if (PCS_HAS_PINCONF && function) {
                res = pcs_parse_pinconf(pcs, np, function, map);
                if (res)
                        goto free_pingroups;
@@ -1052,14 +1062,16 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
        } else {
                *num_maps = 1;
        }
+       mutex_unlock(&pcs->mutex);
+
        return 0;
 
 free_pingroups:
-       pinctrl_generic_remove_last_group(pcs->pctl);
+       pinctrl_generic_remove_group(pcs->pctl, gsel);
        *num_maps = 1;
 free_function:
-       pinmux_generic_remove_last_function(pcs->pctl);
-
+       pinmux_generic_remove_function(pcs->pctl, fsel);
+       mutex_unlock(&pcs->mutex);
 free_pins:
        devm_kfree(pcs->dev, pins);
 
@@ -1077,9 +1089,9 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
 {
        const char *name = "pinctrl-single,bits";
        struct pcs_func_vals *vals;
-       int rows, *pins, found = 0, res = -ENOMEM, i;
+       int rows, *pins, found = 0, res = -ENOMEM, i, fsel, gsel;
        int npins_in_row;
-       struct pcs_function *function;
+       struct pcs_function *function = NULL;
 
        rows = pinctrl_count_index_with_args(np, name);
        if (rows <= 0) {
@@ -1089,13 +1101,15 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
 
        npins_in_row = pcs->width / pcs->bits_per_pin;
 
-       vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows * npins_in_row,
-                       GFP_KERNEL);
+       vals = devm_kzalloc(pcs->dev,
+                           array3_size(rows, npins_in_row, sizeof(*vals)),
+                           GFP_KERNEL);
        if (!vals)
                return -ENOMEM;
 
-       pins = devm_kzalloc(pcs->dev, sizeof(*pins) * rows * npins_in_row,
-                       GFP_KERNEL);
+       pins = devm_kzalloc(pcs->dev,
+                           array3_size(rows, npins_in_row, sizeof(*pins)),
+                           GFP_KERNEL);
        if (!pins)
                goto free_vals;
 
@@ -1164,15 +1178,19 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
        }
 
        pgnames[0] = np->name;
-       function = pcs_add_function(pcs, np, np->name, vals, found, pgnames, 1);
-       if (!function) {
-               res = -ENOMEM;
+       mutex_lock(&pcs->mutex);
+       fsel = pcs_add_function(pcs, &function, np->name, vals, found,
+                               pgnames, 1);
+       if (fsel < 0) {
+               res = fsel;
                goto free_pins;
        }
 
-       res = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
-       if (res < 0)
+       gsel = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
+       if (gsel < 0) {
+               res = gsel;
                goto free_function;
+       }
 
        (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
        (*map)->data.mux.group = np->name;
@@ -1184,13 +1202,16 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
        }
 
        *num_maps = 1;
+       mutex_unlock(&pcs->mutex);
+
        return 0;
 
 free_pingroups:
-       pinctrl_generic_remove_last_group(pcs->pctl);
+       pinctrl_generic_remove_group(pcs->pctl, gsel);
        *num_maps = 1;
 free_function:
-       pinmux_generic_remove_last_function(pcs->pctl);
+       pinmux_generic_remove_function(pcs->pctl, fsel);
+       mutex_unlock(&pcs->mutex);
 free_pins:
        devm_kfree(pcs->dev, pins);
 
@@ -1217,7 +1238,7 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
        pcs = pinctrl_dev_get_drvdata(pctldev);
 
        /* create 2 maps. One is for pinmux, and the other is for pinconf. */
-       *map = devm_kzalloc(pcs->dev, sizeof(**map) * 2, GFP_KERNEL);
+       *map = devm_kcalloc(pcs->dev, 2, sizeof(**map), GFP_KERNEL);
        if (!*map)
                return -ENOMEM;
 
@@ -1593,19 +1614,19 @@ static int pcs_save_context(struct pcs_device *pcs)
 
        switch (pcs->width) {
        case 64:
-               regsl = (u64 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       regsl[i] = pcs->read(pcs->base + i * mux_bytes);
+               regsl = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       *regsl++ = pcs->read(pcs->base + i);
                break;
        case 32:
-               regsw = (u32 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       regsw[i] = pcs->read(pcs->base + i * mux_bytes);
+               regsw = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       *regsw++ = pcs->read(pcs->base + i);
                break;
        case 16:
-               regshw = (u16 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       regshw[i] = pcs->read(pcs->base + i * mux_bytes);
+               regshw = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       *regshw++ = pcs->read(pcs->base + i);
                break;
        }
 
@@ -1623,19 +1644,19 @@ static void pcs_restore_context(struct pcs_device *pcs)
 
        switch (pcs->width) {
        case 64:
-               regsl = (u64 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       pcs->write(regsl[i], pcs->base + i * mux_bytes);
+               regsl = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       pcs->write(*regsl++, pcs->base + i);
                break;
        case 32:
-               regsw = (u32 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       pcs->write(regsw[i], pcs->base + i * mux_bytes);
+               regsw = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       pcs->write(*regsw++, pcs->base + i);
                break;
        case 16:
-               regshw = (u16 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       pcs->write(regshw[i], pcs->base + i * mux_bytes);
+               regshw = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       pcs->write(*regshw++, pcs->base + i);
                break;
        }
 }