Based function-mask and submask preoperties patch allocates and registers pins.
Patch is fixes the issue reported and discussed here:
http://www.spinics.net/lists/arm-kernel/msg235213.html
Applies on top of 3.10-rc2 of linus's tree.
Tested on da850-evm.
Manjunathappa, Prakash (3):
pinctrl: pinctrl-single: enhance to configure multiple pins of
different modules
pinctrl: pinctrl-single: pin names for pinctrl-single.bits
ARM: davinci: da850: adopt to pinctrl-single driver to configure
multiple pins
.../devicetree/bindings/pinctrl/pinctrl-single.txt | 3 +-
arch/arm/boot/dts/da850.dtsi | 2 +-
drivers/pinctrl/pinctrl-single.c | 215 ++++++++++++++++----
3 files changed, 179 insertions(+), 41 deletions(-)
--
1.7.4.1
Add support to configure multiple pins in each register, existing
implementation added by [1] does not support full fledge multiple pin
configuration in single register, reports a pin clash when different
modules configure different bits of same register. The issue reported
and discussed here
http://www.spinics.net/lists/arm-kernel/msg235213.html
With pinctrl-single,bits-per-mux property specified, use function-mask
property to find out number pins to configure. Allocate and register
pin control functions based sub mask.
Tested on da850/omap-l138 EVM.
does not support variable submask for pins.
does not support pinconf.
[1] "pinctrl: pinctrl-single: Add pinctrl-single,bits type of mux"
(9e605cb68a21d5704839a192a46ebcf387773704),
Signed-off-by: Manjunathappa, Prakash <[email protected]>
Reported-by: Lad, Prabhakar <[email protected]>
Tested-by: Lad, Prabhakar <[email protected]>
---
.../devicetree/bindings/pinctrl/pinctrl-single.txt | 3 +-
drivers/pinctrl/pinctrl-single.c | 198 ++++++++++++++++----
2 files changed, 167 insertions(+), 34 deletions(-)
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
index 08f0c3d..5a02e30 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
@@ -18,7 +18,8 @@ Optional properties:
pin functions is ignored
- pinctrl-single,bit-per-mux : boolean to indicate that one register controls
- more than one pin
+ more than one pin, for which "pinctrl-single,function-mask" property specifies
+ position mask of pin.
- pinctrl-single,drive-strength : array of value that are used to configure
drive strength in the pinmux register. They're value of drive strength
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index b9fa046..9a1ea65 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -163,6 +163,7 @@ struct pcs_name {
* @foff: value to turn mux off
* @fmax: max number of functions in fmask
* @is_pinconf: whether supports pinconf
+ * @bits_per_pin:number of bits per pin
* @names: array of register names for pins
* @pins: physical pins on the SoC
* @pgtree: pingroup index radix tree
@@ -190,6 +191,7 @@ struct pcs_device {
unsigned fmax;
bool bits_per_mux;
bool is_pinconf;
+ unsigned bits_per_pin;
struct pcs_name *names;
struct pcs_data pins;
struct radix_tree_root pgtree;
@@ -431,10 +433,11 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector,
vals = &func->vals[i];
val = pcs->read(vals->reg);
- if (!vals->mask)
- mask = pcs->fmask;
+
+ if (pcs->bits_per_mux)
+ mask = vals->mask;
else
- mask = pcs->fmask & vals->mask;
+ mask = pcs->fmask;
val &= ~mask;
val |= (vals->val & mask);
@@ -779,7 +782,13 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs)
int mux_bytes, nr_pins, i;
mux_bytes = pcs->width / BITS_PER_BYTE;
- nr_pins = pcs->size / mux_bytes;
+
+ if (pcs->bits_per_mux) {
+ pcs->bits_per_pin = fls(pcs->fmask);
+ nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin;
+ } else {
+ nr_pins = pcs->size / mux_bytes;
+ }
dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins);
pcs->pins.pa = devm_kzalloc(pcs->dev,
@@ -800,8 +809,14 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs)
for (i = 0; i < pcs->desc.npins; i++) {
unsigned offset;
int res;
+ int byte_num;
- offset = i * mux_bytes;
+ if (pcs->bits_per_mux) {
+ byte_num = (pcs->bits_per_pin * i) / BITS_PER_BYTE;
+ offset = (byte_num / mux_bytes) * mux_bytes;
+ } else {
+ offset = i * mux_bytes;
+ }
res = pcs_add_pin(pcs, offset);
if (res < 0) {
dev_err(pcs->dev, "error adding pins: %i\n", res);
@@ -919,7 +934,10 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
return -EINVAL;
}
- index = offset / (pcs->width / BITS_PER_BYTE);
+ if (pcs->bits_per_mux)
+ index = (offset * BITS_PER_BYTE) / pcs->bits_per_pin;
+ else
+ index = offset / (pcs->width / BITS_PER_BYTE);
return index;
}
@@ -1097,29 +1115,18 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
{
struct pcs_func_vals *vals;
const __be32 *mux;
- int size, params, rows, *pins, index = 0, found = 0, res = -ENOMEM;
+ int size, rows, *pins, index = 0, found = 0, res = -ENOMEM;
struct pcs_function *function;
- if (pcs->bits_per_mux) {
- params = 3;
- mux = of_get_property(np, PCS_MUX_BITS_NAME, &size);
- } else {
- params = 2;
- mux = of_get_property(np, PCS_MUX_PINS_NAME, &size);
- }
-
- if (!mux) {
- dev_err(pcs->dev, "no valid property for %s\n", np->name);
- return -EINVAL;
- }
-
- if (size < (sizeof(*mux) * params)) {
- dev_err(pcs->dev, "bad data for %s\n", np->name);
+ mux = of_get_property(np, PCS_MUX_PINS_NAME, &size);
+ if ((!mux) || (size < sizeof(*mux) * 2)) {
+ dev_err(pcs->dev, "bad data for mux %s\n",
+ np->name);
return -EINVAL;
}
size /= sizeof(*mux); /* Number of elements in array */
- rows = size / params;
+ rows = size / 2;
vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL);
if (!vals)
@@ -1137,10 +1144,6 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
val = be32_to_cpup(mux + index++);
vals[found].reg = pcs->base + offset;
vals[found].val = val;
- if (params == 3) {
- val = be32_to_cpup(mux + index++);
- vals[found].mask = val;
- }
pin = pcs_get_pin_by_offset(pcs, offset);
if (pin < 0) {
@@ -1189,6 +1192,125 @@ free_vals:
return res;
}
+
+#define PARAMS_FOR_BITS_PER_MUX 3
+
+static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned *num_maps,
+ const char **pgnames)
+{
+ struct pcs_func_vals *vals;
+ const __be32 *mux;
+ int size, rows, *pins, index = 0, found = 0, res = -ENOMEM;
+ int npins_in_row;
+ struct pcs_function *function;
+
+ mux = of_get_property(np, PCS_MUX_BITS_NAME, &size);
+
+ if (!mux) {
+ dev_err(pcs->dev, "no valid property for %s\n", np->name);
+ return -EINVAL;
+ }
+
+ if (size < (sizeof(*mux) * PARAMS_FOR_BITS_PER_MUX)) {
+ dev_err(pcs->dev, "bad data for %s\n", np->name);
+ return -EINVAL;
+ }
+
+ /* Number of elements in array */
+ size /= sizeof(*mux);
+
+ rows = size / PARAMS_FOR_BITS_PER_MUX;
+ npins_in_row = pcs->width / pcs->bits_per_pin;
+
+ vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows * npins_in_row,
+ GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ pins = devm_kzalloc(pcs->dev, sizeof(*pins) * rows * npins_in_row,
+ GFP_KERNEL);
+ if (!pins)
+ goto free_vals;
+
+ while (index < size) {
+ unsigned offset, val;
+ unsigned mask, bit_pos, val_pos, mask_pos, submask;
+ unsigned pin_num_from_lsb;
+ int pin;
+
+ offset = be32_to_cpup(mux + index++);
+ val = be32_to_cpup(mux + index++);
+ mask = be32_to_cpup(mux + index++);
+
+ /* Parse pins in each row from LSB */
+ while (mask) {
+ bit_pos = ffs(mask);
+ pin_num_from_lsb = bit_pos / pcs->bits_per_pin;
+ mask_pos = ((pcs->fmask) << (bit_pos - 1));
+ val_pos = val & mask_pos;
+ submask = mask & mask_pos;
+ mask &= ~mask_pos;
+
+ if (submask != mask_pos) {
+ dev_warn(pcs->dev,
+ "Invalid submask 0x%x for %s at 0x%x\n",
+ submask, np->name, offset);
+ continue;
+ }
+
+ vals[found].mask = submask;
+ vals[found].reg = pcs->base + offset;
+ vals[found].val = val_pos;
+
+ pin = pcs_get_pin_by_offset(pcs, offset);
+ if (pin < 0) {
+ dev_err(pcs->dev,
+ "could not add functions for %s %ux\n",
+ np->name, offset);
+ break;
+ }
+ pins[found++] = pin + pin_num_from_lsb;
+ }
+ }
+
+ pgnames[0] = np->name;
+ function = pcs_add_function(pcs, np, np->name, vals, found, pgnames, 1);
+ if (!function)
+ goto free_pins;
+
+ res = pcs_add_pingroup(pcs, np, np->name, pins, found);
+ if (res < 0)
+ goto free_function;
+
+ (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)->data.mux.group = np->name;
+ (*map)->data.mux.function = np->name;
+
+ if (pcs->is_pinconf) {
+ dev_err(pcs->dev, "pinconf not supported\n");
+ goto free_pingroups;
+ }
+
+ *num_maps = 1;
+ return 0;
+
+free_pingroups:
+ pcs_free_pingroups(pcs);
+ *num_maps = 1;
+free_function:
+ pcs_remove_function(pcs, function);
+
+free_pins:
+ devm_kfree(pcs->dev, pins);
+
+free_vals:
+ devm_kfree(pcs->dev, vals);
+
+ return res;
+}
/**
* pcs_dt_node_to_map() - allocates and parses pinctrl maps
* @pctldev: pinctrl instance
@@ -1219,12 +1341,22 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
goto free_map;
}
- ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, num_maps,
- pgnames);
- if (ret < 0) {
- dev_err(pcs->dev, "no pins entries for %s\n",
- np_config->name);
- goto free_pgnames;
+ if (pcs->bits_per_mux) {
+ ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config, map,
+ num_maps, pgnames);
+ if (ret < 0) {
+ dev_err(pcs->dev, "no pins entries for %s\n",
+ np_config->name);
+ goto free_pgnames;
+ }
+ } else {
+ ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
+ num_maps, pgnames);
+ if (ret < 0) {
+ dev_err(pcs->dev, "no pins entries for %s\n",
+ np_config->name);
+ goto free_pgnames;
+ }
}
return 0;
--
1.7.4.1
Take care to name pin names as
register-offset.bit-pos-of-pin-in-register in case configuring multiple
pins in register.
Signed-off-by: Manjunathappa, Prakash <[email protected]>
---
drivers/pinctrl/pinctrl-single.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 9a1ea65..2899c86 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -30,7 +30,7 @@
#define DRIVER_NAME "pinctrl-single"
#define PCS_MUX_PINS_NAME "pinctrl-single,pins"
#define PCS_MUX_BITS_NAME "pinctrl-single,bits"
-#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1)
+#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 3)
#define PCS_OFF_DISABLED ~0U
/**
@@ -744,7 +744,8 @@ static const struct pinconf_ops pcs_pinconf_ops = {
* @pcs: pcs driver instance
* @offset: register offset from base
*/
-static int pcs_add_pin(struct pcs_device *pcs, unsigned offset)
+static int pcs_add_pin(struct pcs_device *pcs, unsigned offset,
+ unsigned pin_pos)
{
struct pinctrl_pin_desc *pin;
struct pcs_name *pn;
@@ -759,8 +760,8 @@ static int pcs_add_pin(struct pcs_device *pcs, unsigned offset)
pin = &pcs->pins.pa[i];
pn = &pcs->names[i];
- sprintf(pn->name, "%lx",
- (unsigned long)pcs->res->start + offset);
+ sprintf(pn->name, "%lx.%d",
+ (unsigned long)pcs->res->start + offset, pin_pos);
pin->name = pn->name;
pin->number = i;
pcs->pins.cur++;
@@ -780,12 +781,14 @@ static int pcs_add_pin(struct pcs_device *pcs, unsigned offset)
static int pcs_allocate_pin_table(struct pcs_device *pcs)
{
int mux_bytes, nr_pins, i;
+ int num_pins_in_register = 0;
mux_bytes = pcs->width / BITS_PER_BYTE;
if (pcs->bits_per_mux) {
pcs->bits_per_pin = fls(pcs->fmask);
nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin;
+ num_pins_in_register = pcs->width / pcs->bits_per_pin;
} else {
nr_pins = pcs->size / mux_bytes;
}
@@ -810,14 +813,16 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs)
unsigned offset;
int res;
int byte_num;
+ int pin_pos = 0;
if (pcs->bits_per_mux) {
byte_num = (pcs->bits_per_pin * i) / BITS_PER_BYTE;
offset = (byte_num / mux_bytes) * mux_bytes;
+ pin_pos = i % num_pins_in_register;
} else {
offset = i * mux_bytes;
}
- res = pcs_add_pin(pcs, offset);
+ res = pcs_add_pin(pcs, offset, pin_pos);
if (res < 0) {
dev_err(pcs->dev, "error adding pins: %i\n", res);
return res;
--
1.7.4.1
function-mask property is a mask for a pin at each pin configure offset
in a pincontrol register.
Signed-off-by: Manjunathappa, Prakash <[email protected]>
---
arch/arm/boot/dts/da850.dtsi | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index 4d43046..9bec36c 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -37,7 +37,7 @@
#size-cells = <0>;
pinctrl-single,bit-per-mux;
pinctrl-single,register-width = <32>;
- pinctrl-single,function-mask = <0xffffffff>;
+ pinctrl-single,function-mask = <0xf>;
status = "disabled";
nand_cs3_pins: pinmux_nand_pins {
--
1.7.4.1
On Tue, May 21, 2013 at 4:07 PM, Manjunathappa, Prakash
<[email protected]> wrote:
> Based function-mask and submask preoperties patch allocates and registers pins.
> Patch is fixes the issue reported and discussed here:
> http://www.spinics.net/lists/arm-kernel/msg235213.html
I'd like Tony to ACK this, and Haojian to have a look at it before applying.
Yours,
Linus Walleij
On 24 May 2013 17:03, Linus Walleij <[email protected]> wrote:
> On Tue, May 21, 2013 at 4:07 PM, Manjunathappa, Prakash
> <[email protected]> wrote:
>
>> Based function-mask and submask preoperties patch allocates and registers pins.
>> Patch is fixes the issue reported and discussed here:
>> http://www.spinics.net/lists/arm-kernel/msg235213.html
>
> I'd like Tony to ACK this, and Haojian to have a look at it before applying.
>
> Yours,
> Linus Walleij
I'll give feedback in the next week.
Regards
Haojian
On Tue, May 21, 2013 at 10:08 PM, Manjunathappa, Prakash
<[email protected]> wrote:
> Add support to configure multiple pins in each register, existing
> implementation added by [1] does not support full fledge multiple pin
> configuration in single register, reports a pin clash when different
> modules configure different bits of same register. The issue reported
> and discussed here
> http://www.spinics.net/lists/arm-kernel/msg235213.html
>
> With pinctrl-single,bits-per-mux property specified, use function-mask
> property to find out number pins to configure. Allocate and register
> pin control functions based sub mask.
>
> Tested on da850/omap-l138 EVM.
> does not support variable submask for pins.
> does not support pinconf.
>
> [1] "pinctrl: pinctrl-single: Add pinctrl-single,bits type of mux"
> (9e605cb68a21d5704839a192a46ebcf387773704),
>
> Signed-off-by: Manjunathappa, Prakash <[email protected]>
> Reported-by: Lad, Prabhakar <[email protected]>
> Tested-by: Lad, Prabhakar <[email protected]>
Excuse me for response late.
Acked-by: Haojian Zhuang <[email protected]>
On Tue, May 21, 2013 at 10:08 PM, Manjunathappa, Prakash
<[email protected]> wrote:
> Take care to name pin names as
> register-offset.bit-pos-of-pin-in-register in case configuring multiple
> pins in register.
>
> Signed-off-by: Manjunathappa, Prakash <[email protected]>
> ---
Acked-by: Haojian Zhuang <[email protected]>
* Manjunathappa, Prakash <[email protected]> [130521 07:13]:
> Add support to configure multiple pins in each register, existing
> implementation added by [1] does not support full fledge multiple pin
> configuration in single register, reports a pin clash when different
> modules configure different bits of same register. The issue reported
> and discussed here
> http://www.spinics.net/lists/arm-kernel/msg235213.html
>
> With pinctrl-single,bits-per-mux property specified, use function-mask
> property to find out number pins to configure. Allocate and register
> pin control functions based sub mask.
Thanks for fixing this! Looks good to me, and things keep
working for me just fine with these applied:
Acked-by: Tony Lindgren <[email protected]>
* Haojian Zhuang <[email protected]> [130604 22:31]:
> On Tue, May 21, 2013 at 10:08 PM, Manjunathappa, Prakash
> <[email protected]> wrote:
> > Take care to name pin names as
> > register-offset.bit-pos-of-pin-in-register in case configuring multiple
> > pins in register.
> >
> > Signed-off-by: Manjunathappa, Prakash <[email protected]>
> > ---
>
> Acked-by: Haojian Zhuang <[email protected]>
Acked-by: Tony Lindgren <[email protected]>
On Tue, May 21, 2013 at 4:08 PM, Manjunathappa, Prakash
<[email protected]> wrote:
> Add support to configure multiple pins in each register, existing
> implementation added by [1] does not support full fledge multiple pin
> configuration in single register, reports a pin clash when different
> modules configure different bits of same register. The issue reported
> and discussed here
> http://www.spinics.net/lists/arm-kernel/msg235213.html
>
> With pinctrl-single,bits-per-mux property specified, use function-mask
> property to find out number pins to configure. Allocate and register
> pin control functions based sub mask.
>
> Tested on da850/omap-l138 EVM.
> does not support variable submask for pins.
> does not support pinconf.
>
> [1] "pinctrl: pinctrl-single: Add pinctrl-single,bits type of mux"
> (9e605cb68a21d5704839a192a46ebcf387773704),
>
> Signed-off-by: Manjunathappa, Prakash <[email protected]>
> Reported-by: Lad, Prabhakar <[email protected]>
> Tested-by: Lad, Prabhakar <[email protected]>
Patch applied with Haojian's and Tony's ACK.
Thanks!
Linus Walleij
On Tue, May 21, 2013 at 4:08 PM, Manjunathappa, Prakash
<[email protected]> wrote:
> Take care to name pin names as
> register-offset.bit-pos-of-pin-in-register in case configuring multiple
> pins in register.
>
> Signed-off-by: Manjunathappa, Prakash <[email protected]>
Applied with Haojian and Tony's ACKs.
Thanks!
Linus Walleij
Hi Sekhar,
On Tue, May 21, 2013 at 19:38:02, Manjunathappa, Prakash wrote:
> function-mask property is a mask for a pin at each pin configure offset
> in a pincontrol register.
>
Got 1/3 and 2/3 accepted, I do not know if this gets merged via DaVinci tree or
pincontrol tree. Could you please takecare of this?
Thanks,
Prakash
> Signed-off-by: Manjunathappa, Prakash <[email protected]>
> ---
> arch/arm/boot/dts/da850.dtsi | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
> index 4d43046..9bec36c 100644
> --- a/arch/arm/boot/dts/da850.dtsi
> +++ b/arch/arm/boot/dts/da850.dtsi
> @@ -37,7 +37,7 @@
> #size-cells = <0>;
> pinctrl-single,bit-per-mux;
> pinctrl-single,register-width = <32>;
> - pinctrl-single,function-mask = <0xffffffff>;
> + pinctrl-single,function-mask = <0xf>;
> status = "disabled";
>
> nand_cs3_pins: pinmux_nand_pins {
> --
> 1.7.4.1
>
>
On 6/24/2013 5:18 PM, Manjunathappa, Prakash wrote:
> Hi Sekhar,
>
> On Tue, May 21, 2013 at 19:38:02, Manjunathappa, Prakash wrote:
>> function-mask property is a mask for a pin at each pin configure offset
>> in a pincontrol register.
>>
>
> Got 1/3 and 2/3 accepted, I do not know if this gets merged via DaVinci tree or
> pincontrol tree. Could you please takecare of this?
I will send this via DaVinci tree. I had actually missed that there is a
bit waiting for me here. So thanks for asking.
Regards,
Sekhar