diff options
author | Haojian Zhuang <haojian.zhuang@linaro.org> | 2013-02-17 06:42:52 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-03-06 23:27:30 -0500 |
commit | a1a277eb76b3507df7c41774048a644aa4dfd096 (patch) | |
tree | 8f48089478f87dff9a37284af6a1c68ca7911a26 /drivers/pinctrl/pinctrl-single.c | |
parent | 39b70ee05199f9bea50641df104aee4dbd913d1d (diff) |
pinctrl: single: create new gpio function range
Since gpio driver could create gpio range in DTS, it could invoke
pinctrl_request_gpio(). In the pinctrl-single driver, it needs to
configure pins with gpio function mode.
A new gpio function range should be created in DTS file in below.
pinctrl-single,gpio-range = <phandle pin_offset nr_pins gpio_func>;
range: gpio-range {
#pinctrl-single,gpio-range-cells = <3>;
};
The gpio-ranges property is used in gpio driver and the
pinctrl-single,gpio-range property is used in pinctrl-single driver.
1. gpio-ranges is used for gpio driver in below.
gpio-ranges = <phandle gpio_offset_in_chip pin_offset nr_pins>
gpio-ranges = < &pmx0 0 89 1 &pmx0 1 89 1 &pmx0 2 90 1
&pmx0 3 90 1 &pmx0 4 91 1 &pmx0 5 92 1>;
2. gpio driver could get pin offset from gpio-ranges property.
pinctrl-single driver could get gpio function mode from gpio_func
that is stored in @gpiofuncs list in struct pcs_device.
This new pinctrl-single,gpio-range is used as complement for
gpio-ranges property in gpio driver.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
Acked-by: Tony Lindgren <tony@atomide.com>
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 | 73 |
1 files changed, 71 insertions, 2 deletions
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 0c0e2da9d880..f4bc602cdb08 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c | |||
@@ -77,6 +77,20 @@ struct pcs_function { | |||
77 | }; | 77 | }; |
78 | 78 | ||
79 | /** | 79 | /** |
80 | * struct pcs_gpiofunc_range - pin ranges with same mux value of gpio function | ||
81 | * @offset: offset base of pins | ||
82 | * @npins: number pins with the same mux value of gpio function | ||
83 | * @gpiofunc: mux value of gpio function | ||
84 | * @node: list node | ||
85 | */ | ||
86 | struct pcs_gpiofunc_range { | ||
87 | unsigned offset; | ||
88 | unsigned npins; | ||
89 | unsigned gpiofunc; | ||
90 | struct list_head node; | ||
91 | }; | ||
92 | |||
93 | /** | ||
80 | * struct pcs_data - wrapper for data needed by pinctrl framework | 94 | * struct pcs_data - wrapper for data needed by pinctrl framework |
81 | * @pa: pindesc array | 95 | * @pa: pindesc array |
82 | * @cur: index to current element | 96 | * @cur: index to current element |
@@ -123,6 +137,7 @@ struct pcs_name { | |||
123 | * @ftree: function index radix tree | 137 | * @ftree: function index radix tree |
124 | * @pingroups: list of pingroups | 138 | * @pingroups: list of pingroups |
125 | * @functions: list of functions | 139 | * @functions: list of functions |
140 | * @gpiofuncs: list of gpio functions | ||
126 | * @ngroups: number of pingroups | 141 | * @ngroups: number of pingroups |
127 | * @nfuncs: number of functions | 142 | * @nfuncs: number of functions |
128 | * @desc: pin controller descriptor | 143 | * @desc: pin controller descriptor |
@@ -148,6 +163,7 @@ struct pcs_device { | |||
148 | struct radix_tree_root ftree; | 163 | struct radix_tree_root ftree; |
149 | struct list_head pingroups; | 164 | struct list_head pingroups; |
150 | struct list_head functions; | 165 | struct list_head functions; |
166 | struct list_head gpiofuncs; | ||
151 | unsigned ngroups; | 167 | unsigned ngroups; |
152 | unsigned nfuncs; | 168 | unsigned nfuncs; |
153 | struct pinctrl_desc desc; | 169 | struct pinctrl_desc desc; |
@@ -403,9 +419,26 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector, | |||
403 | } | 419 | } |
404 | 420 | ||
405 | static int pcs_request_gpio(struct pinctrl_dev *pctldev, | 421 | static int pcs_request_gpio(struct pinctrl_dev *pctldev, |
406 | struct pinctrl_gpio_range *range, unsigned offset) | 422 | struct pinctrl_gpio_range *range, unsigned pin) |
407 | { | 423 | { |
408 | return -ENOTSUPP; | 424 | struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); |
425 | struct pcs_gpiofunc_range *frange = NULL; | ||
426 | struct list_head *pos, *tmp; | ||
427 | int mux_bytes = 0; | ||
428 | unsigned data; | ||
429 | |||
430 | list_for_each_safe(pos, tmp, &pcs->gpiofuncs) { | ||
431 | frange = list_entry(pos, struct pcs_gpiofunc_range, node); | ||
432 | if (pin >= frange->offset + frange->npins | ||
433 | || pin < frange->offset) | ||
434 | continue; | ||
435 | mux_bytes = pcs->width / BITS_PER_BYTE; | ||
436 | data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask; | ||
437 | data |= frange->gpiofunc; | ||
438 | pcs->write(data, pcs->base + pin * mux_bytes); | ||
439 | break; | ||
440 | } | ||
441 | return 0; | ||
409 | } | 442 | } |
410 | 443 | ||
411 | static const struct pinmux_ops pcs_pinmux_ops = { | 444 | static const struct pinmux_ops pcs_pinmux_ops = { |
@@ -879,6 +912,37 @@ static void pcs_free_resources(struct pcs_device *pcs) | |||
879 | 912 | ||
880 | static struct of_device_id pcs_of_match[]; | 913 | static struct of_device_id pcs_of_match[]; |
881 | 914 | ||
915 | static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) | ||
916 | { | ||
917 | const char *propname = "pinctrl-single,gpio-range"; | ||
918 | const char *cellname = "#pinctrl-single,gpio-range-cells"; | ||
919 | struct of_phandle_args gpiospec; | ||
920 | struct pcs_gpiofunc_range *range; | ||
921 | int ret, i; | ||
922 | |||
923 | for (i = 0; ; i++) { | ||
924 | ret = of_parse_phandle_with_args(node, propname, cellname, | ||
925 | i, &gpiospec); | ||
926 | /* Do not treat it as error. Only treat it as end condition. */ | ||
927 | if (ret) { | ||
928 | ret = 0; | ||
929 | break; | ||
930 | } | ||
931 | range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); | ||
932 | if (!range) { | ||
933 | ret = -ENOMEM; | ||
934 | break; | ||
935 | } | ||
936 | range->offset = gpiospec.args[0]; | ||
937 | range->npins = gpiospec.args[1]; | ||
938 | range->gpiofunc = gpiospec.args[2]; | ||
939 | mutex_lock(&pcs->mutex); | ||
940 | list_add_tail(&range->node, &pcs->gpiofuncs); | ||
941 | mutex_unlock(&pcs->mutex); | ||
942 | } | ||
943 | return ret; | ||
944 | } | ||
945 | |||
882 | static int pcs_probe(struct platform_device *pdev) | 946 | static int pcs_probe(struct platform_device *pdev) |
883 | { | 947 | { |
884 | struct device_node *np = pdev->dev.of_node; | 948 | struct device_node *np = pdev->dev.of_node; |
@@ -900,6 +964,7 @@ static int pcs_probe(struct platform_device *pdev) | |||
900 | mutex_init(&pcs->mutex); | 964 | mutex_init(&pcs->mutex); |
901 | INIT_LIST_HEAD(&pcs->pingroups); | 965 | INIT_LIST_HEAD(&pcs->pingroups); |
902 | INIT_LIST_HEAD(&pcs->functions); | 966 | INIT_LIST_HEAD(&pcs->functions); |
967 | INIT_LIST_HEAD(&pcs->gpiofuncs); | ||
903 | 968 | ||
904 | PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width, | 969 | PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width, |
905 | "register width not specified\n"); | 970 | "register width not specified\n"); |
@@ -975,6 +1040,10 @@ static int pcs_probe(struct platform_device *pdev) | |||
975 | goto free; | 1040 | goto free; |
976 | } | 1041 | } |
977 | 1042 | ||
1043 | ret = pcs_add_gpio_func(np, pcs); | ||
1044 | if (ret < 0) | ||
1045 | goto free; | ||
1046 | |||
978 | dev_info(pcs->dev, "%i pins at pa %p size %u\n", | 1047 | dev_info(pcs->dev, "%i pins at pa %p size %u\n", |
979 | pcs->desc.npins, pcs->base, pcs->size); | 1048 | pcs->desc.npins, pcs->base, pcs->size); |
980 | 1049 | ||