diff options
-rw-r--r-- | drivers/pinctrl/sh-pfc/core.c | 19 | ||||
-rw-r--r-- | drivers/pinctrl/sh-pfc/core.h | 2 | ||||
-rw-r--r-- | drivers/pinctrl/sh-pfc/gpio.c | 37 | ||||
-rw-r--r-- | drivers/pinctrl/sh-pfc/pinctrl.c | 58 | ||||
-rw-r--r-- | drivers/pinctrl/sh-pfc/sh_pfc.h | 2 |
5 files changed, 91 insertions, 27 deletions
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 667db99fb51..798248261f3 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 6ea3d4f3d05..b8b3e872cc1 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 32a9c7870a1..806e2dd6213 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 a60c317d988..c9e9a1d9523 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 43c858d9832..dbcaa600ccc 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; |