#include <linux/regmap.h>
#include "../core.h"
+#include "../pinconf.h"
#include "../pinmux.h"
#include "pinctrl-imx.h"
.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)
{
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;
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);
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);
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;
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;
#ifndef __DRIVERS_PINCTRL_IMX_H
#define __DRIVERS_PINCTRL_IMX_H
+#include <linux/pinctrl/pinconf-generic.h>
+
struct platform_device;
/**
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;
unsigned int flags;
const char *gpr_compatible;
struct mutex mutex;
+
+ /* 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