|
@@ -27,6 +27,7 @@
|
|
|
#include <linux/regmap.h>
|
|
|
|
|
|
#include "../core.h"
|
|
|
+#include "../pinconf.h"
|
|
|
#include "../pinmux.h"
|
|
|
#include "pinctrl-imx.h"
|
|
|
|
|
@@ -361,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)
|
|
|
{
|
|
@@ -479,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;
|
|
@@ -493,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);
|
|
@@ -548,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);
|
|
@@ -603,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;
|
|
@@ -774,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;
|