diff options
Diffstat (limited to 'drivers/pinctrl/freescale')
-rw-r--r-- | drivers/pinctrl/freescale/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pinctrl/freescale/pinctrl-imx.c | 135 | ||||
-rw-r--r-- | drivers/pinctrl/freescale/pinctrl-imx.h | 29 | ||||
-rw-r--r-- | drivers/pinctrl/freescale/pinctrl-imx7d.c | 6 | ||||
-rw-r--r-- | drivers/pinctrl/freescale/pinctrl-vf610.c | 2 |
5 files changed, 149 insertions, 25 deletions
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index cae05e76c111..0b266b2aecd4 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -2,7 +2,7 @@ config PINCTRL_IMX bool select GENERIC_PINCTRL_GROUPS select GENERIC_PINMUX_FUNCTIONS - select PINCONF + select GENERIC_PINCONF select REGMAP config PINCTRL_IMX1_CORE diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 74bd90dfd7b1..72aca758f4c6 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -27,6 +27,7 @@ #include <linux/regmap.h> #include "../core.h" +#include "../pinconf.h" #include "../pinmux.h" #include "pinctrl-imx.h" @@ -196,14 +197,16 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, if (info->flags & SHARE_MUX_CONF_REG) { u32 reg; reg = readl(ipctl->base + pin_reg->mux_reg); - reg &= ~(0x7 << 20); - reg |= (pin->mux_mode << 20); + reg &= ~info->mux_mask; + reg |= (pin->mux_mode << info->mux_shift); writel(reg, ipctl->base + pin_reg->mux_reg); + dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", + pin_reg->mux_reg, reg); } else { writel(pin->mux_mode, ipctl->base + pin_reg->mux_reg); + dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", + pin_reg->mux_reg, pin->mux_mode); } - dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", - pin_reg->mux_reg, pin->mux_mode); /* * If the select input value begins with 0xff, it's a quirky @@ -287,7 +290,7 @@ static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, mux_pin: reg = readl(ipctl->base + pin_reg->mux_reg); - reg &= ~(0x7 << 20); + reg &= ~info->mux_mask; reg |= imx_pin->config; writel(reg, ipctl->base + pin_reg->mux_reg); @@ -359,6 +362,62 @@ static const struct pinmux_ops imx_pmx_ops = { .gpio_set_direction = imx_pmx_gpio_set_direction, }; +/* decode generic config into raw register values */ +static u32 imx_pinconf_decode_generic_config(struct imx_pinctrl *ipctl, + unsigned long *configs, + unsigned int num_configs) +{ + struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_cfg_params_decode *decode; + enum pin_config_param param; + u32 raw_config = 0; + u32 param_val; + int i, j; + + WARN_ON(num_configs > info->num_decodes); + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + param_val = pinconf_to_config_argument(configs[i]); + decode = info->decodes; + for (j = 0; j < info->num_decodes; j++) { + if (param == decode->param) { + if (decode->invert) + param_val = !param_val; + raw_config |= (param_val << decode->shift) + & decode->mask; + break; + } + decode++; + } + } + + if (info->fixup) + info->fixup(configs, num_configs, &raw_config); + + return raw_config; +} + +static u32 imx_pinconf_parse_generic_config(struct device_node *np, + struct imx_pinctrl *ipctl) +{ + struct imx_pinctrl_soc_info *info = ipctl->info; + struct pinctrl_dev *pctl = ipctl->pctl; + unsigned int num_configs; + unsigned long *configs; + int ret; + + if (!info->generic_pinconf) + return 0; + + ret = pinconf_generic_parse_dt_config(np, pctl, &configs, + &num_configs); + if (ret) + return 0; + + return imx_pinconf_decode_generic_config(ipctl, configs, num_configs); +} + static int imx_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin_id, unsigned long *config) { @@ -375,7 +434,7 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev, *config = readl(ipctl->base + pin_reg->conf_reg); if (info->flags & SHARE_MUX_CONF_REG) - *config &= 0xffff; + *config &= ~info->mux_mask; return 0; } @@ -402,14 +461,16 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev, if (info->flags & SHARE_MUX_CONF_REG) { u32 reg; reg = readl(ipctl->base + pin_reg->conf_reg); - reg &= ~0xffff; + reg &= info->mux_mask; reg |= configs[i]; writel(reg, ipctl->base + pin_reg->conf_reg); + dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", + pin_reg->conf_reg, reg); } else { writel(configs[i], ipctl->base + pin_reg->conf_reg); + dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n", + pin_reg->conf_reg, configs[i]); } - dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n", - pin_reg->conf_reg, configs[i]); } /* for each config */ return 0; @@ -475,9 +536,10 @@ static const struct pinconf_ops imx_pinconf_ops = { static int imx_pinctrl_parse_groups(struct device_node *np, struct group_desc *grp, - struct imx_pinctrl_soc_info *info, + struct imx_pinctrl *ipctl, u32 index) { + struct imx_pinctrl_soc_info *info = ipctl->info; int size, pin_size; const __be32 *list; int i; @@ -489,25 +551,44 @@ static int imx_pinctrl_parse_groups(struct device_node *np, pin_size = SHARE_FSL_PIN_SIZE; else pin_size = FSL_PIN_SIZE; + + if (info->generic_pinconf) + pin_size -= 4; + /* Initialise group */ grp->name = np->name; /* * the binding format is fsl,pins = <PIN_FUNC_ID CONFIG ...>, * do sanity check and calculate pins number + * + * First try legacy 'fsl,pins' property, then fall back to the + * generic 'pins'. + * + * Note: for generic 'pins' case, there's no CONFIG part in + * the binding format. */ list = of_get_property(np, "fsl,pins", &size); if (!list) { - dev_err(info->dev, "no fsl,pins property in node %s\n", np->full_name); - return -EINVAL; + list = of_get_property(np, "pins", &size); + if (!list) { + dev_err(info->dev, + "no fsl,pins and pins property in node %s\n", + np->full_name); + return -EINVAL; + } } /* we do not check return since it's safe node passed down */ if (!size || size % pin_size) { - dev_err(info->dev, "Invalid fsl,pins property in node %s\n", np->full_name); + dev_err(info->dev, "Invalid fsl,pins or pins property in node %s\n", + np->full_name); return -EINVAL; } + /* first try to parse the generic pin config */ + config = imx_pinconf_parse_generic_config(np, ipctl); + grp->num_pins = size / pin_size; grp->data = devm_kzalloc(info->dev, grp->num_pins * sizeof(struct imx_pin), GFP_KERNEL); @@ -544,11 +625,18 @@ static int imx_pinctrl_parse_groups(struct device_node *np, pin->mux_mode = be32_to_cpu(*list++); pin->input_val = be32_to_cpu(*list++); - /* SION bit is in mux register */ - config = be32_to_cpu(*list++); - if (config & IMX_PAD_SION) - pin->mux_mode |= IOMUXC_CONFIG_SION; - pin->config = config & ~IMX_PAD_SION; + if (info->generic_pinconf) { + /* generic pin config decoded */ + pin->config = config; + } else { + /* legacy pin config read from devicetree */ + config = be32_to_cpu(*list++); + + /* SION bit is in mux register */ + if (config & IMX_PAD_SION) + pin->mux_mode |= IOMUXC_CONFIG_SION; + pin->config = config & ~IMX_PAD_SION; + } dev_dbg(info->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name, pin->mux_mode, pin->config); @@ -581,9 +669,10 @@ static int imx_pinctrl_parse_functions(struct device_node *np, dev_err(info->dev, "no groups defined in %s\n", np->full_name); return -EINVAL; } - func->group_names = devm_kzalloc(info->dev, - func->num_group_names * + func->group_names = devm_kcalloc(info->dev, func->num_group_names, sizeof(char *), GFP_KERNEL); + if (!func->group_names) + return -ENOMEM; for_each_child_of_node(np, child) { func->group_names[i] = child->name; @@ -598,7 +687,7 @@ static int imx_pinctrl_parse_functions(struct device_node *np, info->group_index++, grp); mutex_unlock(&info->mutex); - imx_pinctrl_parse_groups(child, grp, info, i++); + imx_pinctrl_parse_groups(child, grp, ipctl, i++); } return 0; @@ -769,6 +858,10 @@ int imx_pinctrl_probe(struct platform_device *pdev, imx_pinctrl_desc->confops = &imx_pinconf_ops; imx_pinctrl_desc->owner = THIS_MODULE; + /* for generic pinconf */ + imx_pinctrl_desc->custom_params = info->custom_params; + imx_pinctrl_desc->num_custom_params = info->num_custom_params; + mutex_init(&info->mutex); ipctl->info = info; diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h index ff2d3e56b7c5..880bba7fd1ab 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.h +++ b/drivers/pinctrl/freescale/pinctrl-imx.h @@ -15,6 +15,8 @@ #ifndef __DRIVERS_PINCTRL_IMX_H #define __DRIVERS_PINCTRL_IMX_H +#include <linux/pinctrl/pinconf-generic.h> + struct platform_device; /** @@ -44,6 +46,14 @@ struct imx_pin_reg { s16 conf_reg; }; +/* decode a generic config into raw register value */ +struct imx_cfg_params_decode { + enum pin_config_param param; + u32 mask; + u8 shift; + bool invert; +}; + struct imx_pinctrl_soc_info { struct device *dev; const struct pinctrl_pin_desc *pins; @@ -53,8 +63,27 @@ struct imx_pinctrl_soc_info { unsigned int flags; const char *gpr_compatible; struct mutex mutex; + + /* MUX_MODE shift and mask in case SHARE_MUX_CONF_REG */ + unsigned int mux_mask; + u8 mux_shift; + + /* generic pinconf */ + bool generic_pinconf; + const struct pinconf_generic_params *custom_params; + unsigned int num_custom_params; + struct imx_cfg_params_decode *decodes; + unsigned int num_decodes; + void (*fixup)(unsigned long *configs, unsigned int num_configs, + u32 *raw_config); }; +#define IMX_CFG_PARAMS_DECODE(p, m, o) \ + { .param = p, .mask = m, .shift = o, .invert = false, } + +#define IMX_CFG_PARAMS_DECODE_INVERT(p, m, o) \ + { .param = p, .mask = m, .shift = o, .invert = true, } + #define SHARE_MUX_CONF_REG 0x1 #define ZERO_OFFSET_VALID 0x2 diff --git a/drivers/pinctrl/freescale/pinctrl-imx7d.c b/drivers/pinctrl/freescale/pinctrl-imx7d.c index a465a66c3ef4..754159ee7b1e 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx7d.c +++ b/drivers/pinctrl/freescale/pinctrl-imx7d.c @@ -358,19 +358,19 @@ static const struct pinctrl_pin_desc imx7d_lpsr_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX7D_PAD_GPIO1_IO07), }; -static struct imx_pinctrl_soc_info imx7d_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx7d_pinctrl_info = { .pins = imx7d_pinctrl_pads, .npins = ARRAY_SIZE(imx7d_pinctrl_pads), .gpr_compatible = "fsl,imx7d-iomuxc-gpr", }; -static struct imx_pinctrl_soc_info imx7d_lpsr_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx7d_lpsr_pinctrl_info = { .pins = imx7d_lpsr_pinctrl_pads, .npins = ARRAY_SIZE(imx7d_lpsr_pinctrl_pads), .flags = ZERO_OFFSET_VALID, }; -static struct of_device_id imx7d_pinctrl_of_match[] = { +static const struct of_device_id imx7d_pinctrl_of_match[] = { { .compatible = "fsl,imx7d-iomuxc", .data = &imx7d_pinctrl_info, }, { .compatible = "fsl,imx7d-iomuxc-lpsr", .data = &imx7d_lpsr_pinctrl_info }, { /* sentinel */ } diff --git a/drivers/pinctrl/freescale/pinctrl-vf610.c b/drivers/pinctrl/freescale/pinctrl-vf610.c index 2b1e198e3092..3bd85564d1e4 100644 --- a/drivers/pinctrl/freescale/pinctrl-vf610.c +++ b/drivers/pinctrl/freescale/pinctrl-vf610.c @@ -299,6 +299,8 @@ static struct imx_pinctrl_soc_info vf610_pinctrl_info = { .pins = vf610_pinctrl_pads, .npins = ARRAY_SIZE(vf610_pinctrl_pads), .flags = SHARE_MUX_CONF_REG | ZERO_OFFSET_VALID, + .mux_mask = 0x700000, + .mux_shift = 20, }; static const struct of_device_id vf610_pinctrl_of_match[] = { |