diff options
Diffstat (limited to 'drivers/pinctrl/sh-pfc/core.c')
-rw-r--r-- | drivers/pinctrl/sh-pfc/core.c | 101 |
1 files changed, 76 insertions, 25 deletions
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index f3fc66b24370..738f14f65cff 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -82,24 +82,20 @@ int sh_pfc_get_pin_index(struct sh_pfc *pfc, unsigned int pin) unsigned int offset; unsigned int i; - if (pfc->info->ranges == NULL) - return pin; - - for (i = 0, offset = 0; i < pfc->info->nr_ranges; ++i) { - const struct pinmux_range *range = &pfc->info->ranges[i]; + for (i = 0, offset = 0; i < pfc->nr_ranges; ++i) { + const struct sh_pfc_pin_range *range = &pfc->ranges[i]; if (pin <= range->end) - return pin >= range->begin - ? offset + pin - range->begin : -1; + return pin >= range->start + ? offset + pin - range->start : -1; - offset += range->end - range->begin + 1; + offset += range->end - range->start + 1; } return -EINVAL; } -static int sh_pfc_enum_in_range(pinmux_enum_t enum_id, - const struct pinmux_range *r) +static int sh_pfc_enum_in_range(u16 enum_id, const struct pinmux_range *r) { if (enum_id < r->begin) return 0; @@ -194,7 +190,7 @@ static void sh_pfc_write_config_reg(struct sh_pfc *pfc, sh_pfc_write_raw_reg(mapped_reg, crp->reg_width, data); } -static int sh_pfc_get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id, +static int sh_pfc_get_config_reg(struct sh_pfc *pfc, u16 enum_id, const struct pinmux_cfg_reg **crp, int *fieldp, int *valuep) { @@ -238,10 +234,10 @@ static int sh_pfc_get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id, return -EINVAL; } -static int sh_pfc_mark_to_enum(struct sh_pfc *pfc, pinmux_enum_t mark, int pos, - pinmux_enum_t *enum_idp) +static int sh_pfc_mark_to_enum(struct sh_pfc *pfc, u16 mark, int pos, + u16 *enum_idp) { - const pinmux_enum_t *data = pfc->info->gpio_data; + const u16 *data = pfc->info->gpio_data; int k; if (pos) { @@ -264,7 +260,7 @@ static int sh_pfc_mark_to_enum(struct sh_pfc *pfc, pinmux_enum_t mark, int pos, int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type) { const struct pinmux_cfg_reg *cr = NULL; - pinmux_enum_t enum_id; + u16 enum_id; const struct pinmux_range *range; int in_range, pos, field, value; int ret; @@ -283,14 +279,6 @@ int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type) range = &pfc->info->input; break; - case PINMUX_TYPE_INPUT_PULLUP: - range = &pfc->info->input_pu; - break; - - case PINMUX_TYPE_INPUT_PULLDOWN: - range = &pfc->info->input_pd; - break; - default: return -EINVAL; } @@ -350,6 +338,67 @@ int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type) return 0; } +static int sh_pfc_init_ranges(struct sh_pfc *pfc) +{ + struct sh_pfc_pin_range *range; + unsigned int nr_ranges; + unsigned int i; + + if (pfc->info->pins[0].pin == (u16)-1) { + /* Pin number -1 denotes that the SoC doesn't report pin numbers + * in its pin arrays yet. Consider the pin numbers range as + * continuous and allocate a single range. + */ + pfc->nr_ranges = 1; + pfc->ranges = devm_kzalloc(pfc->dev, sizeof(*pfc->ranges), + GFP_KERNEL); + if (pfc->ranges == NULL) + return -ENOMEM; + + pfc->ranges->start = 0; + pfc->ranges->end = pfc->info->nr_pins - 1; + pfc->nr_gpio_pins = pfc->info->nr_pins; + + return 0; + } + + /* Count, allocate and fill the ranges. The PFC SoC data pins array must + * be sorted by pin numbers, and pins without a GPIO port must come + * last. + */ + for (i = 1, nr_ranges = 1; i < pfc->info->nr_pins; ++i) { + if (pfc->info->pins[i-1].pin != pfc->info->pins[i].pin - 1) + nr_ranges++; + } + + pfc->nr_ranges = nr_ranges; + pfc->ranges = devm_kzalloc(pfc->dev, sizeof(*pfc->ranges) * nr_ranges, + GFP_KERNEL); + if (pfc->ranges == NULL) + return -ENOMEM; + + range = pfc->ranges; + range->start = pfc->info->pins[0].pin; + + for (i = 1; i < pfc->info->nr_pins; ++i) { + if (pfc->info->pins[i-1].pin == pfc->info->pins[i].pin - 1) + continue; + + range->end = pfc->info->pins[i-1].pin; + if (!(pfc->info->pins[i-1].configs & SH_PFC_PIN_CFG_NO_GPIO)) + pfc->nr_gpio_pins = range->end + 1; + + range++; + range->start = pfc->info->pins[i].pin; + } + + range->end = pfc->info->pins[i-1].pin; + if (!(pfc->info->pins[i-1].configs & SH_PFC_PIN_CFG_NO_GPIO)) + pfc->nr_gpio_pins = range->end + 1; + + return 0; +} + #ifdef CONFIG_OF static const struct of_device_id sh_pfc_of_table[] = { #ifdef CONFIG_PINCTRL_PFC_R8A73A4 @@ -440,6 +489,10 @@ static int sh_pfc_probe(struct platform_device *pdev) pinctrl_provide_dummies(); + ret = sh_pfc_init_ranges(pfc); + if (ret < 0) + return ret; + /* * Initialize pinctrl bindings first */ @@ -486,8 +539,6 @@ static int sh_pfc_remove(struct platform_device *pdev) if (pfc->info->ops && pfc->info->ops->exit) pfc->info->ops->exit(pfc); - platform_set_drvdata(pdev, NULL); - return 0; } |