diff options
author | Peter Ujfalusi <peter.ujfalusi@ti.com> | 2012-09-11 04:54:24 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2012-09-13 03:00:10 -0400 |
commit | 9e605cb68a21d5704839a192a46ebcf387773704 (patch) | |
tree | 11768cb28e03ee2600d4728f0b993fda4b53a168 /drivers/pinctrl/pinctrl-single.c | |
parent | 2830c3686be31f74cc788250eb54dc2d7a7e48d8 (diff) |
pinctrl: pinctrl-single: Add pinctrl-single,bits type of mux
With pinctrl-single,bits it is possible to update just part of the register
within the pinctrl-single,function-mask area.
This is useful when one register configures mmore than one pin's mux.
pinctrl-single,bits takes three parameters:
<reg offset, value, sub-mask>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
[Removed a misplaced comment]
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/pinctrl-single.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-single.c | 46 |
1 files changed, 36 insertions, 10 deletions
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 35086310b81d..aabecfa507b4 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c | |||
@@ -26,7 +26,8 @@ | |||
26 | #include "core.h" | 26 | #include "core.h" |
27 | 27 | ||
28 | #define DRIVER_NAME "pinctrl-single" | 28 | #define DRIVER_NAME "pinctrl-single" |
29 | #define PCS_MUX_NAME "pinctrl-single,pins" | 29 | #define PCS_MUX_PINS_NAME "pinctrl-single,pins" |
30 | #define PCS_MUX_BITS_NAME "pinctrl-single,bits" | ||
30 | #define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1) | 31 | #define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1) |
31 | #define PCS_OFF_DISABLED ~0U | 32 | #define PCS_OFF_DISABLED ~0U |
32 | 33 | ||
@@ -54,6 +55,7 @@ struct pcs_pingroup { | |||
54 | struct pcs_func_vals { | 55 | struct pcs_func_vals { |
55 | void __iomem *reg; | 56 | void __iomem *reg; |
56 | unsigned val; | 57 | unsigned val; |
58 | unsigned mask; | ||
57 | }; | 59 | }; |
58 | 60 | ||
59 | /** | 61 | /** |
@@ -139,6 +141,7 @@ struct pcs_device { | |||
139 | unsigned fshift; | 141 | unsigned fshift; |
140 | unsigned foff; | 142 | unsigned foff; |
141 | unsigned fmax; | 143 | unsigned fmax; |
144 | bool bits_per_mux; | ||
142 | struct pcs_name *names; | 145 | struct pcs_name *names; |
143 | struct pcs_data pins; | 146 | struct pcs_data pins; |
144 | struct radix_tree_root pgtree; | 147 | struct radix_tree_root pgtree; |
@@ -332,12 +335,17 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector, | |||
332 | 335 | ||
333 | for (i = 0; i < func->nvals; i++) { | 336 | for (i = 0; i < func->nvals; i++) { |
334 | struct pcs_func_vals *vals; | 337 | struct pcs_func_vals *vals; |
335 | unsigned val; | 338 | unsigned val, mask; |
336 | 339 | ||
337 | vals = &func->vals[i]; | 340 | vals = &func->vals[i]; |
338 | val = pcs->read(vals->reg); | 341 | val = pcs->read(vals->reg); |
339 | val &= ~pcs->fmask; | 342 | if (!vals->mask) |
340 | val |= (vals->val & pcs->fmask); | 343 | mask = pcs->fmask; |
344 | else | ||
345 | mask = pcs->fmask & vals->mask; | ||
346 | |||
347 | val &= ~mask; | ||
348 | val |= (vals->val & mask); | ||
341 | pcs->write(val, vals->reg); | 349 | pcs->write(val, vals->reg); |
342 | } | 350 | } |
343 | 351 | ||
@@ -657,18 +665,29 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, | |||
657 | { | 665 | { |
658 | struct pcs_func_vals *vals; | 666 | struct pcs_func_vals *vals; |
659 | const __be32 *mux; | 667 | const __be32 *mux; |
660 | int size, rows, *pins, index = 0, found = 0, res = -ENOMEM; | 668 | int size, params, rows, *pins, index = 0, found = 0, res = -ENOMEM; |
661 | struct pcs_function *function; | 669 | struct pcs_function *function; |
662 | 670 | ||
663 | mux = of_get_property(np, PCS_MUX_NAME, &size); | 671 | if (pcs->bits_per_mux) { |
664 | if ((!mux) || (size < sizeof(*mux) * 2)) { | 672 | params = 3; |
665 | dev_err(pcs->dev, "bad data for mux %s\n", | 673 | mux = of_get_property(np, PCS_MUX_BITS_NAME, &size); |
666 | np->name); | 674 | } else { |
675 | params = 2; | ||
676 | mux = of_get_property(np, PCS_MUX_PINS_NAME, &size); | ||
677 | } | ||
678 | |||
679 | if (!mux) { | ||
680 | dev_err(pcs->dev, "no valid property for %s\n", np->name); | ||
681 | return -EINVAL; | ||
682 | } | ||
683 | |||
684 | if (size < (sizeof(*mux) * params)) { | ||
685 | dev_err(pcs->dev, "bad data for %s\n", np->name); | ||
667 | return -EINVAL; | 686 | return -EINVAL; |
668 | } | 687 | } |
669 | 688 | ||
670 | size /= sizeof(*mux); /* Number of elements in array */ | 689 | size /= sizeof(*mux); /* Number of elements in array */ |
671 | rows = size / 2; /* Each row is a key value pair */ | 690 | rows = size / params; |
672 | 691 | ||
673 | vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL); | 692 | vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL); |
674 | if (!vals) | 693 | if (!vals) |
@@ -686,6 +705,10 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, | |||
686 | val = be32_to_cpup(mux + index++); | 705 | val = be32_to_cpup(mux + index++); |
687 | vals[found].reg = pcs->base + offset; | 706 | vals[found].reg = pcs->base + offset; |
688 | vals[found].val = val; | 707 | vals[found].val = val; |
708 | if (params == 3) { | ||
709 | val = be32_to_cpup(mux + index++); | ||
710 | vals[found].mask = val; | ||
711 | } | ||
689 | 712 | ||
690 | pin = pcs_get_pin_by_offset(pcs, offset); | 713 | pin = pcs_get_pin_by_offset(pcs, offset); |
691 | if (pin < 0) { | 714 | if (pin < 0) { |
@@ -883,6 +906,9 @@ static int __devinit pcs_probe(struct platform_device *pdev) | |||
883 | if (ret) | 906 | if (ret) |
884 | pcs->foff = PCS_OFF_DISABLED; | 907 | pcs->foff = PCS_OFF_DISABLED; |
885 | 908 | ||
909 | pcs->bits_per_mux = of_property_read_bool(np, | ||
910 | "pinctrl-single,bit-per-mux"); | ||
911 | |||
886 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 912 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
887 | if (!res) { | 913 | if (!res) { |
888 | dev_err(pcs->dev, "could not get resource\n"); | 914 | dev_err(pcs->dev, "could not get resource\n"); |