summaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r--drivers/pinctrl/sh-pfc/core.c19
-rw-r--r--drivers/pinctrl/sh-pfc/core.h2
-rw-r--r--drivers/pinctrl/sh-pfc/gpio.c37
-rw-r--r--drivers/pinctrl/sh-pfc/pinctrl.c58
-rw-r--r--drivers/pinctrl/sh-pfc/sh_pfc.h2
5 files changed, 91 insertions, 27 deletions
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index 667db99fb510..798248261f30 100644
--- a/drivers/pinctrl/sh-pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -80,7 +80,24 @@ static void __iomem *sh_pfc_phys_to_virt(struct sh_pfc *pfc,
struct sh_pfc_pin *sh_pfc_get_pin(struct sh_pfc *pfc, unsigned int pin)
{
- return &pfc->info->pins[pin];
+ unsigned int offset;
+ unsigned int i;
+
+ if (pfc->info->ranges == NULL)
+ return &pfc->info->pins[pin];
+
+ for (i = 0, offset = 0; i < pfc->info->nr_ranges; ++i) {
+ const struct pinmux_range *range = &pfc->info->ranges[i];
+
+ if (pin <= range->end)
+ return pin >= range->begin
+ ? &pfc->info->pins[offset + pin - range->begin]
+ : NULL;
+
+ offset += range->end - range->begin + 1;
+ }
+
+ return NULL;
}
static int sh_pfc_enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h
index 6ea3d4f3d05e..b8b3e872cc19 100644
--- a/drivers/pinctrl/sh-pfc/core.h
+++ b/drivers/pinctrl/sh-pfc/core.h
@@ -32,6 +32,8 @@ struct sh_pfc {
unsigned int num_windows;
struct sh_pfc_window *window;
+ unsigned int nr_pins;
+
struct sh_pfc_chip *gpio;
struct sh_pfc_chip *func;
diff --git a/drivers/pinctrl/sh-pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c
index 32a9c7870a16..806e2dd62137 100644
--- a/drivers/pinctrl/sh-pfc/gpio.c
+++ b/drivers/pinctrl/sh-pfc/gpio.c
@@ -45,7 +45,7 @@ static int gpio_pin_request(struct gpio_chip *gc, unsigned offset)
struct sh_pfc *pfc = gpio_to_pfc(gc);
struct sh_pfc_pin *pin = sh_pfc_get_pin(pfc, offset);
- if (pin->enum_id == 0)
+ if (pin == NULL || pin->enum_id == 0)
return -EINVAL;
return pinctrl_request_gpio(offset);
@@ -127,7 +127,7 @@ static void gpio_pin_setup(struct sh_pfc_chip *chip)
gc->dev = pfc->dev;
gc->owner = THIS_MODULE;
gc->base = 0;
- gc->ngpio = pfc->info->nr_pins;
+ gc->ngpio = pfc->nr_pins;
}
/* -----------------------------------------------------------------------------
@@ -184,7 +184,7 @@ static void gpio_function_setup(struct sh_pfc_chip *chip)
gc->label = pfc->info->name;
gc->owner = THIS_MODULE;
- gc->base = pfc->info->nr_pins;
+ gc->base = pfc->nr_pins;
gc->ngpio = pfc->info->nr_func_gpios;
}
@@ -219,20 +219,43 @@ sh_pfc_add_gpiochip(struct sh_pfc *pfc, void(*setup)(struct sh_pfc_chip *))
int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
{
+ const struct pinmux_range *ranges;
+ struct pinmux_range def_range;
struct sh_pfc_chip *chip;
+ unsigned int nr_ranges;
+ unsigned int i;
int ret;
+ /* Register the real GPIOs chip. */
chip = sh_pfc_add_gpiochip(pfc, gpio_pin_setup);
if (IS_ERR(chip))
return PTR_ERR(chip);
pfc->gpio = chip;
- ret = gpiochip_add_pin_range(&chip->gpio_chip, dev_name(pfc->dev), 0, 0,
- chip->gpio_chip.ngpio);
- if (ret < 0)
- return ret;
+ /* Register the GPIO to pin mappings. */
+ if (pfc->info->ranges == NULL) {
+ def_range.begin = 0;
+ def_range.end = pfc->info->nr_pins - 1;
+ ranges = &def_range;
+ nr_ranges = 1;
+ } else {
+ ranges = pfc->info->ranges;
+ nr_ranges = pfc->info->nr_ranges;
+ }
+
+ for (i = 0; i < nr_ranges; ++i) {
+ const struct pinmux_range *range = &ranges[i];
+
+ ret = gpiochip_add_pin_range(&chip->gpio_chip,
+ dev_name(pfc->dev),
+ range->begin, range->begin,
+ range->end - range->begin + 1);
+ if (ret < 0)
+ return ret;
+ }
+ /* Register the function GPIOs chip. */
chip = sh_pfc_add_gpiochip(pfc, gpio_function_setup);
if (IS_ERR(chip))
return PTR_ERR(chip);
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c
index a60c317d988a..c9e9a1d95230 100644
--- a/drivers/pinctrl/sh-pfc/pinctrl.c
+++ b/drivers/pinctrl/sh-pfc/pinctrl.c
@@ -293,29 +293,48 @@ static const struct pinconf_ops sh_pfc_pinconf_ops = {
.pin_config_dbg_show = sh_pfc_pinconf_dbg_show,
};
-/* pinmux ranges -> pinctrl pin descs */
-static int sh_pfc_map_gpios(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
+/* PFC ranges -> pinctrl pin descs */
+static int sh_pfc_map_pins(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
{
- int i;
-
- pmx->nr_pads = pfc->info->nr_pins;
+ const struct pinmux_range *ranges;
+ struct pinmux_range def_range;
+ unsigned int nr_ranges;
+ unsigned int nr_pins;
+ unsigned int i;
+
+ if (pfc->info->ranges == NULL) {
+ def_range.begin = 0;
+ def_range.end = pfc->info->nr_pins - 1;
+ ranges = &def_range;
+ nr_ranges = 1;
+ } else {
+ ranges = pfc->info->ranges;
+ nr_ranges = pfc->info->nr_ranges;
+ }
- pmx->pads = devm_kzalloc(pfc->dev, sizeof(*pmx->pads) * pmx->nr_pads,
+ pmx->pads = devm_kzalloc(pfc->dev,
+ sizeof(*pmx->pads) * pfc->info->nr_pins,
GFP_KERNEL);
- if (unlikely(!pmx->pads)) {
- pmx->nr_pads = 0;
+ if (unlikely(!pmx->pads))
return -ENOMEM;
- }
- for (i = 0; i < pmx->nr_pads; i++) {
- struct pinctrl_pin_desc *pin = pmx->pads + i;
- struct sh_pfc_pin *gpio = pfc->info->pins + i;
+ for (i = 0, nr_pins = 0; i < nr_ranges; ++i) {
+ const struct pinmux_range *range = &ranges[i];
+ unsigned int number;
+
+ for (number = range->begin; number <= range->end;
+ number++, nr_pins++) {
+ struct pinctrl_pin_desc *pin = &pmx->pads[nr_pins];
+ struct sh_pfc_pin *info = &pfc->info->pins[nr_pins];
- pin->number = i;
- pin->name = gpio->name;
+ pin->number = number;
+ pin->name = info->name;
+ }
}
- return 0;
+ pfc->nr_pins = ranges[nr_ranges-1].end + 1;
+
+ return nr_ranges;
}
static int sh_pfc_map_functions(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
@@ -347,6 +366,7 @@ static int sh_pfc_map_functions(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
{
struct sh_pfc_pinctrl *pmx;
+ int nr_ranges;
int ret;
pmx = devm_kzalloc(pfc->dev, sizeof(*pmx), GFP_KERNEL);
@@ -356,9 +376,9 @@ int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
pmx->pfc = pfc;
pfc->pinctrl = pmx;
- ret = sh_pfc_map_gpios(pfc, pmx);
- if (unlikely(ret != 0))
- return ret;
+ nr_ranges = sh_pfc_map_pins(pfc, pmx);
+ if (unlikely(nr_ranges < 0))
+ return nr_ranges;
ret = sh_pfc_map_functions(pfc, pmx);
if (unlikely(ret != 0))
@@ -370,7 +390,7 @@ int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
pmx->pctl_desc.pmxops = &sh_pfc_pinmux_ops;
pmx->pctl_desc.confops = &sh_pfc_pinconf_ops;
pmx->pctl_desc.pins = pmx->pads;
- pmx->pctl_desc.npins = pmx->nr_pads;
+ pmx->pctl_desc.npins = pfc->info->nr_pins;
pmx->pctl = pinctrl_register(&pmx->pctl_desc, pfc->dev, pmx);
if (IS_ERR(pmx->pctl))
diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h
index 43c858d98321..dbcaa600ccc6 100644
--- a/drivers/pinctrl/sh-pfc/sh_pfc.h
+++ b/drivers/pinctrl/sh-pfc/sh_pfc.h
@@ -111,6 +111,8 @@ struct sh_pfc_soc_info {
struct sh_pfc_pin *pins;
unsigned int nr_pins;
+ const struct pinmux_range *ranges;
+ unsigned int nr_ranges;
struct pinmux_func *func_gpios;
unsigned int nr_func_gpios;
OpenPOWER on IntegriCloud