summaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/sunxi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/sunxi')
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-gr8.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c10
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c11
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c10
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c506
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.h8
15 files changed, 456 insertions, 179 deletions
diff --git a/drivers/pinctrl/sunxi/pinctrl-gr8.c b/drivers/pinctrl/sunxi/pinctrl-gr8.c
index 2904d2b7378b..2f232c3a0579 100644
--- a/drivers/pinctrl/sunxi/pinctrl-gr8.c
+++ b/drivers/pinctrl/sunxi/pinctrl-gr8.c
@@ -12,7 +12,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -525,7 +525,6 @@ static const struct of_device_id sun5i_gr8_pinctrl_match[] = {
{ .compatible = "nextthing,gr8-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun5i_gr8_pinctrl_match);
static struct platform_driver sun5i_gr8_pinctrl_driver = {
.probe = sun5i_gr8_pinctrl_probe,
@@ -534,8 +533,4 @@ static struct platform_driver sun5i_gr8_pinctrl_driver = {
.of_match_table = sun5i_gr8_pinctrl_match,
},
};
-module_platform_driver(sun5i_gr8_pinctrl_driver);
-
-MODULE_AUTHOR("Mylene Josserand <mylene.josserand@free-electrons.com");
-MODULE_DESCRIPTION("NextThing GR8 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun5i_gr8_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
index 862a096c5dba..fb30b86a97ee 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
@@ -10,7 +10,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -1035,7 +1035,6 @@ static const struct of_device_id sun4i_a10_pinctrl_match[] = {
{ .compatible = "allwinner,sun4i-a10-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun4i_a10_pinctrl_match);
static struct platform_driver sun4i_a10_pinctrl_driver = {
.probe = sun4i_a10_pinctrl_probe,
@@ -1044,8 +1043,4 @@ static struct platform_driver sun4i_a10_pinctrl_driver = {
.of_match_table = sun4i_a10_pinctrl_match,
},
};
-module_platform_driver(sun4i_a10_pinctrl_driver);
-
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
-MODULE_DESCRIPTION("Allwinner A10 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun4i_a10_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c b/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c
index f9a3f8f446f7..a5b57fdff9e1 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c
@@ -10,7 +10,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -674,7 +674,6 @@ static const struct of_device_id sun5i_a10s_pinctrl_match[] = {
{ .compatible = "allwinner,sun5i-a10s-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun5i_a10s_pinctrl_match);
static struct platform_driver sun5i_a10s_pinctrl_driver = {
.probe = sun5i_a10s_pinctrl_probe,
@@ -683,8 +682,4 @@ static struct platform_driver sun5i_a10s_pinctrl_driver = {
.of_match_table = sun5i_a10s_pinctrl_match,
},
};
-module_platform_driver(sun5i_a10s_pinctrl_driver);
-
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
-MODULE_DESCRIPTION("Allwinner A10s pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun5i_a10s_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c b/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c
index 2bb07b38834f..8575f3f6d3dd 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c
@@ -10,7 +10,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -392,7 +392,6 @@ static const struct of_device_id sun5i_a13_pinctrl_match[] = {
{ .compatible = "allwinner,sun5i-a13-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun5i_a13_pinctrl_match);
static struct platform_driver sun5i_a13_pinctrl_driver = {
.probe = sun5i_a13_pinctrl_probe,
@@ -401,8 +400,4 @@ static struct platform_driver sun5i_a13_pinctrl_driver = {
.of_match_table = sun5i_a13_pinctrl_match,
},
};
-module_platform_driver(sun5i_a13_pinctrl_driver);
-
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
-MODULE_DESCRIPTION("Allwinner A13 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun5i_a13_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c
index d4bc4f0e8be0..a22bd88a1f03 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c
@@ -12,7 +12,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -136,7 +136,6 @@ static const struct of_device_id sun6i_a31_r_pinctrl_match[] = {
{ .compatible = "allwinner,sun6i-a31-r-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun6i_a31_r_pinctrl_match);
static struct platform_driver sun6i_a31_r_pinctrl_driver = {
.probe = sun6i_a31_r_pinctrl_probe,
@@ -145,9 +144,4 @@ static struct platform_driver sun6i_a31_r_pinctrl_driver = {
.of_match_table = sun6i_a31_r_pinctrl_match,
},
};
-module_platform_driver(sun6i_a31_r_pinctrl_driver);
-
-MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com");
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
-MODULE_DESCRIPTION("Allwinner A31 R_PIO pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun6i_a31_r_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
index a70b52957e24..9e58926bef37 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
@@ -10,7 +10,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -934,7 +934,6 @@ static const struct of_device_id sun6i_a31_pinctrl_match[] = {
{ .compatible = "allwinner,sun6i-a31-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun6i_a31_pinctrl_match);
static struct platform_driver sun6i_a31_pinctrl_driver = {
.probe = sun6i_a31_pinctrl_probe,
@@ -943,8 +942,4 @@ static struct platform_driver sun6i_a31_pinctrl_driver = {
.of_match_table = sun6i_a31_pinctrl_match,
},
};
-module_platform_driver(sun6i_a31_pinctrl_driver);
-
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
-MODULE_DESCRIPTION("Allwinner A31 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun6i_a31_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c
index e570d5c93ecc..231a746a5356 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c
@@ -11,7 +11,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -798,7 +798,6 @@ static const struct of_device_id sun6i_a31s_pinctrl_match[] = {
{ .compatible = "allwinner,sun6i-a31s-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun6i_a31s_pinctrl_match);
static struct platform_driver sun6i_a31s_pinctrl_driver = {
.probe = sun6i_a31s_pinctrl_probe,
@@ -807,8 +806,4 @@ static struct platform_driver sun6i_a31s_pinctrl_driver = {
.of_match_table = sun6i_a31s_pinctrl_match,
},
};
-module_platform_driver(sun6i_a31s_pinctrl_driver);
-
-MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
-MODULE_DESCRIPTION("Allwinner A31s pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun6i_a31s_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c b/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c
index 435ad30f45db..b6f4c68ffb39 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c
@@ -10,7 +10,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -1045,7 +1045,6 @@ static const struct of_device_id sun7i_a20_pinctrl_match[] = {
{ .compatible = "allwinner,sun7i-a20-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun7i_a20_pinctrl_match);
static struct platform_driver sun7i_a20_pinctrl_driver = {
.probe = sun7i_a20_pinctrl_probe,
@@ -1054,8 +1053,4 @@ static struct platform_driver sun7i_a20_pinctrl_driver = {
.of_match_table = sun7i_a20_pinctrl_match,
},
};
-module_platform_driver(sun7i_a20_pinctrl_driver);
-
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
-MODULE_DESCRIPTION("Allwinner A20 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun7i_a20_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c
index 056287635873..2292e05a397b 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c
@@ -15,7 +15,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -123,7 +123,6 @@ static const struct of_device_id sun8i_a23_r_pinctrl_match[] = {
{ .compatible = "allwinner,sun8i-a23-r-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun8i_a23_r_pinctrl_match);
static struct platform_driver sun8i_a23_r_pinctrl_driver = {
.probe = sun8i_a23_r_pinctrl_probe,
@@ -132,10 +131,4 @@ static struct platform_driver sun8i_a23_r_pinctrl_driver = {
.of_match_table = sun8i_a23_r_pinctrl_match,
},
};
-module_platform_driver(sun8i_a23_r_pinctrl_driver);
-
-MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
-MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com");
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
-MODULE_DESCRIPTION("Allwinner A23 R_PIO pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun8i_a23_r_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c
index f9d661e5c14a..721b6935baf3 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c
@@ -14,7 +14,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -575,7 +575,6 @@ static const struct of_device_id sun8i_a23_pinctrl_match[] = {
{ .compatible = "allwinner,sun8i-a23-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun8i_a23_pinctrl_match);
static struct platform_driver sun8i_a23_pinctrl_driver = {
.probe = sun8i_a23_pinctrl_probe,
@@ -584,9 +583,4 @@ static struct platform_driver sun8i_a23_pinctrl_driver = {
.of_match_table = sun8i_a23_pinctrl_match,
},
};
-module_platform_driver(sun8i_a23_pinctrl_driver);
-
-MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
-MODULE_DESCRIPTION("Allwinner A23 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun8i_a23_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
index 3131cac2b76f..ef1e0bef4099 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
@@ -12,7 +12,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -498,7 +498,6 @@ static const struct of_device_id sun8i_a33_pinctrl_match[] = {
{ .compatible = "allwinner,sun8i-a33-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun8i_a33_pinctrl_match);
static struct platform_driver sun8i_a33_pinctrl_driver = {
.probe = sun8i_a33_pinctrl_probe,
@@ -507,8 +506,4 @@ static struct platform_driver sun8i_a33_pinctrl_driver = {
.of_match_table = sun8i_a33_pinctrl_match,
},
};
-module_platform_driver(sun8i_a33_pinctrl_driver);
-
-MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>");
-MODULE_DESCRIPTION("Allwinner a33 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun8i_a33_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
index 90b973e15982..9aec1d2232dd 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
@@ -12,7 +12,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -587,7 +587,6 @@ static const struct of_device_id sun8i_a83t_pinctrl_match[] = {
{ .compatible = "allwinner,sun8i-a83t-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun8i_a83t_pinctrl_match);
static struct platform_driver sun8i_a83t_pinctrl_driver = {
.probe = sun8i_a83t_pinctrl_probe,
@@ -596,8 +595,4 @@ static struct platform_driver sun8i_a83t_pinctrl_driver = {
.of_match_table = sun8i_a83t_pinctrl_match,
},
};
-module_platform_driver(sun8i_a83t_pinctrl_driver);
-
-MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>");
-MODULE_DESCRIPTION("Allwinner a83t pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun8i_a83t_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
index 1b580ba76453..bc14e954d7a2 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
@@ -10,7 +10,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -733,7 +733,6 @@ static const struct of_device_id sun9i_a80_pinctrl_match[] = {
{ .compatible = "allwinner,sun9i-a80-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun9i_a80_pinctrl_match);
static struct platform_driver sun9i_a80_pinctrl_driver = {
.probe = sun9i_a80_pinctrl_probe,
@@ -742,8 +741,4 @@ static struct platform_driver sun9i_a80_pinctrl_driver = {
.of_match_table = sun9i_a80_pinctrl_match,
},
};
-module_platform_driver(sun9i_a80_pinctrl_driver);
-
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
-MODULE_DESCRIPTION("Allwinner A80 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun9i_a80_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 0facbea5f465..0eb51e33cb1b 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -28,6 +28,8 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
#include "../core.h"
#include "pinctrl-sunxi.h"
@@ -145,6 +147,171 @@ static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
return 0;
}
+static bool sunxi_pctrl_has_bias_prop(struct device_node *node)
+{
+ return of_find_property(node, "bias-pull-up", NULL) ||
+ of_find_property(node, "bias-pull-down", NULL) ||
+ of_find_property(node, "bias-disable", NULL) ||
+ of_find_property(node, "allwinner,pull", NULL);
+}
+
+static bool sunxi_pctrl_has_drive_prop(struct device_node *node)
+{
+ return of_find_property(node, "drive-strength", NULL) ||
+ of_find_property(node, "allwinner,drive", NULL);
+}
+
+static int sunxi_pctrl_parse_bias_prop(struct device_node *node)
+{
+ u32 val;
+
+ /* Try the new style binding */
+ if (of_find_property(node, "bias-pull-up", NULL))
+ return PIN_CONFIG_BIAS_PULL_UP;
+
+ if (of_find_property(node, "bias-pull-down", NULL))
+ return PIN_CONFIG_BIAS_PULL_DOWN;
+
+ if (of_find_property(node, "bias-disable", NULL))
+ return PIN_CONFIG_BIAS_DISABLE;
+
+ /* And fall back to the old binding */
+ if (of_property_read_u32(node, "allwinner,pull", &val))
+ return -EINVAL;
+
+ switch (val) {
+ case SUN4I_PINCTRL_NO_PULL:
+ return PIN_CONFIG_BIAS_DISABLE;
+ case SUN4I_PINCTRL_PULL_UP:
+ return PIN_CONFIG_BIAS_PULL_UP;
+ case SUN4I_PINCTRL_PULL_DOWN:
+ return PIN_CONFIG_BIAS_PULL_DOWN;
+ }
+
+ return -EINVAL;
+}
+
+static int sunxi_pctrl_parse_drive_prop(struct device_node *node)
+{
+ u32 val;
+
+ /* Try the new style binding */
+ if (!of_property_read_u32(node, "drive-strength", &val)) {
+ /* We can't go below 10mA ... */
+ if (val < 10)
+ return -EINVAL;
+
+ /* ... and only up to 40 mA ... */
+ if (val > 40)
+ val = 40;
+
+ /* by steps of 10 mA */
+ return rounddown(val, 10);
+ }
+
+ /* And then fall back to the old binding */
+ if (of_property_read_u32(node, "allwinner,drive", &val))
+ return -EINVAL;
+
+ return (val + 1) * 10;
+}
+
+static const char *sunxi_pctrl_parse_function_prop(struct device_node *node)
+{
+ const char *function;
+ int ret;
+
+ /* Try the generic binding */
+ ret = of_property_read_string(node, "function", &function);
+ if (!ret)
+ return function;
+
+ /* And fall back to our legacy one */
+ ret = of_property_read_string(node, "allwinner,function", &function);
+ if (!ret)
+ return function;
+
+ return NULL;
+}
+
+static const char *sunxi_pctrl_find_pins_prop(struct device_node *node,
+ int *npins)
+{
+ int count;
+
+ /* Try the generic binding */
+ count = of_property_count_strings(node, "pins");
+ if (count > 0) {
+ *npins = count;
+ return "pins";
+ }
+
+ /* And fall back to our legacy one */
+ count = of_property_count_strings(node, "allwinner,pins");
+ if (count > 0) {
+ *npins = count;
+ return "allwinner,pins";
+ }
+
+ return NULL;
+}
+
+static unsigned long *sunxi_pctrl_build_pin_config(struct device_node *node,
+ unsigned int *len)
+{
+ unsigned long *pinconfig;
+ unsigned int configlen = 0, idx = 0;
+ int ret;
+
+ if (sunxi_pctrl_has_drive_prop(node))
+ configlen++;
+ if (sunxi_pctrl_has_bias_prop(node))
+ configlen++;
+
+ /*
+ * If we don't have any configuration, bail out
+ */
+ if (!configlen)
+ return NULL;
+
+ pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL);
+ if (!pinconfig)
+ return ERR_PTR(-ENOMEM);
+
+ if (sunxi_pctrl_has_drive_prop(node)) {
+ int drive = sunxi_pctrl_parse_drive_prop(node);
+ if (drive < 0) {
+ ret = drive;
+ goto err_free;
+ }
+
+ pinconfig[idx++] = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
+ drive);
+ }
+
+ if (sunxi_pctrl_has_bias_prop(node)) {
+ int pull = sunxi_pctrl_parse_bias_prop(node);
+ int arg = 0;
+ if (pull < 0) {
+ ret = pull;
+ goto err_free;
+ }
+
+ if (pull != PIN_CONFIG_BIAS_DISABLE)
+ arg = 1; /* hardware uses weak pull resistors */
+
+ pinconfig[idx++] = pinconf_to_config_packed(pull, arg);
+ }
+
+
+ *len = configlen;
+ return pinconfig;
+
+err_free:
+ kfree(pinconfig);
+ return ERR_PTR(ret);
+}
+
static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *node,
struct pinctrl_map **map,
@@ -153,38 +320,48 @@ static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
unsigned long *pinconfig;
struct property *prop;
- const char *function;
+ const char *function, *pin_prop;
const char *group;
- int ret, nmaps, i = 0;
- u32 val;
+ int ret, npins, nmaps, configlen = 0, i = 0;
*map = NULL;
*num_maps = 0;
- ret = of_property_read_string(node, "allwinner,function", &function);
- if (ret) {
- dev_err(pctl->dev,
- "missing allwinner,function property in node %s\n",
+ function = sunxi_pctrl_parse_function_prop(node);
+ if (!function) {
+ dev_err(pctl->dev, "missing function property in node %s\n",
node->name);
return -EINVAL;
}
- nmaps = of_property_count_strings(node, "allwinner,pins") * 2;
- if (nmaps < 0) {
- dev_err(pctl->dev,
- "missing allwinner,pins property in node %s\n",
+ pin_prop = sunxi_pctrl_find_pins_prop(node, &npins);
+ if (!pin_prop) {
+ dev_err(pctl->dev, "missing pins property in node %s\n",
node->name);
return -EINVAL;
}
+ /*
+ * We have two maps for each pin: one for the function, one
+ * for the configuration (bias, strength, etc).
+ *
+ * We might be slightly overshooting, since we might not have
+ * any configuration.
+ */
+ nmaps = npins * 2;
*map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL);
if (!*map)
return -ENOMEM;
- of_property_for_each_string(node, "allwinner,pins", prop, group) {
+ pinconfig = sunxi_pctrl_build_pin_config(node, &configlen);
+ if (IS_ERR(pinconfig)) {
+ ret = PTR_ERR(pinconfig);
+ goto err_free_map;
+ }
+
+ of_property_for_each_string(node, pin_prop, prop, group) {
struct sunxi_pinctrl_group *grp =
sunxi_pinctrl_find_group_by_name(pctl, group);
- int j = 0, configlen = 0;
if (!grp) {
dev_err(pctl->dev, "unknown pin %s", group);
@@ -205,45 +382,31 @@ static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
i++;
- (*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
- (*map)[i].data.configs.group_or_pin = group;
-
- if (of_find_property(node, "allwinner,drive", NULL))
- configlen++;
- if (of_find_property(node, "allwinner,pull", NULL))
- configlen++;
-
- pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL);
- if (!pinconfig) {
- kfree(*map);
- return -ENOMEM;
+ if (pinconfig) {
+ (*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ (*map)[i].data.configs.group_or_pin = group;
+ (*map)[i].data.configs.configs = pinconfig;
+ (*map)[i].data.configs.num_configs = configlen;
+ i++;
}
-
- if (!of_property_read_u32(node, "allwinner,drive", &val)) {
- u16 strength = (val + 1) * 10;
- pinconfig[j++] =
- pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
- strength);
- }
-
- if (!of_property_read_u32(node, "allwinner,pull", &val)) {
- enum pin_config_param pull = PIN_CONFIG_END;
- if (val == 1)
- pull = PIN_CONFIG_BIAS_PULL_UP;
- else if (val == 2)
- pull = PIN_CONFIG_BIAS_PULL_DOWN;
- pinconfig[j++] = pinconf_to_config_packed(pull, 0);
- }
-
- (*map)[i].data.configs.configs = pinconfig;
- (*map)[i].data.configs.num_configs = configlen;
-
- i++;
}
- *num_maps = nmaps;
+ *num_maps = i;
+
+ /*
+ * We know have the number of maps we need, we can resize our
+ * map array
+ */
+ *map = krealloc(*map, i * sizeof(struct pinctrl_map), GFP_KERNEL);
+ if (!*map)
+ return -ENOMEM;
return 0;
+
+err_free_map:
+ kfree(*map);
+ *map = NULL;
+ return ret;
}
static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
@@ -252,9 +415,17 @@ static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
{
int i;
- for (i = 0; i < num_maps; i++) {
- if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
- kfree(map[i].data.configs.configs);
+ /* pin config is never in the first map */
+ for (i = 1; i < num_maps; i++) {
+ if (map[i].type != PIN_MAP_TYPE_CONFIGS_GROUP)
+ continue;
+
+ /*
+ * All the maps share the same pin config,
+ * free only the first one we find.
+ */
+ kfree(map[i].data.configs.configs);
+ break;
}
kfree(map);
@@ -268,15 +439,91 @@ static const struct pinctrl_ops sunxi_pctrl_ops = {
.get_group_pins = sunxi_pctrl_get_group_pins,
};
+static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param,
+ u32 *offset, u32 *shift, u32 *mask)
+{
+ switch (param) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ *offset = sunxi_dlevel_reg(pin);
+ *shift = sunxi_dlevel_offset(pin);
+ *mask = DLEVEL_PINS_MASK;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_DISABLE:
+ *offset = sunxi_pull_reg(pin);
+ *shift = sunxi_pull_offset(pin);
+ *mask = PULL_PINS_MASK;
+ break;
+
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ u32 offset, shift, mask, val;
+ u16 arg;
+ int ret;
+
+ pin -= pctl->desc->pin_base;
+
+ ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
+ if (ret < 0)
+ return ret;
+
+ val = (readl(pctl->membase + offset) >> shift) & mask;
+
+ switch (pinconf_to_config_param(*config)) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ arg = (val + 1) * 10;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (val != SUN4I_PINCTRL_PULL_UP)
+ return -EINVAL;
+ arg = 1; /* hardware is weak pull-up */
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (val != SUN4I_PINCTRL_PULL_DOWN)
+ return -EINVAL;
+ arg = 1; /* hardware is weak pull-down */
+ break;
+
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (val != SUN4I_PINCTRL_NO_PULL)
+ return -EINVAL;
+ arg = 0;
+ break;
+
+ default:
+ /* sunxi_pconf_reg should catch anything unsupported */
+ WARN_ON(1);
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return 0;
+}
+
static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev,
unsigned group,
unsigned long *config)
{
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct sunxi_pinctrl_group *g = &pctl->groups[group];
- *config = pctl->groups[group].config;
-
- return 0;
+ /* We only support 1 pin per group. Chain it to the pin callback */
+ return sunxi_pconf_get(pctldev, g->pin, config);
}
static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
@@ -286,23 +533,27 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
{
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct sunxi_pinctrl_group *g = &pctl->groups[group];
- unsigned long flags;
unsigned pin = g->pin - pctl->desc->pin_base;
- u32 val, mask;
- u16 strength;
- u8 dlevel;
int i;
- spin_lock_irqsave(&pctl->lock, flags);
-
for (i = 0; i < num_configs; i++) {
- switch (pinconf_to_config_param(configs[i])) {
+ enum pin_config_param param;
+ unsigned long flags;
+ u32 offset, shift, mask, reg;
+ u16 arg, val;
+ int ret;
+
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
+ if (ret < 0)
+ return ret;
+
+ switch (param) {
case PIN_CONFIG_DRIVE_STRENGTH:
- strength = pinconf_to_config_argument(configs[i]);
- if (strength > 40) {
- spin_unlock_irqrestore(&pctl->lock, flags);
+ if (arg < 10 || arg > 40)
return -EINVAL;
- }
/*
* We convert from mA to what the register expects:
* 0: 10mA
@@ -310,38 +561,40 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
* 2: 30mA
* 3: 40mA
*/
- dlevel = strength / 10 - 1;
- val = readl(pctl->membase + sunxi_dlevel_reg(pin));
- mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(pin);
- writel((val & ~mask)
- | dlevel << sunxi_dlevel_offset(pin),
- pctl->membase + sunxi_dlevel_reg(pin));
+ val = arg / 10 - 1;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ val = 0;
break;
case PIN_CONFIG_BIAS_PULL_UP:
- val = readl(pctl->membase + sunxi_pull_reg(pin));
- mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
- writel((val & ~mask) | 1 << sunxi_pull_offset(pin),
- pctl->membase + sunxi_pull_reg(pin));
+ if (arg == 0)
+ return -EINVAL;
+ val = 1;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- val = readl(pctl->membase + sunxi_pull_reg(pin));
- mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
- writel((val & ~mask) | 2 << sunxi_pull_offset(pin),
- pctl->membase + sunxi_pull_reg(pin));
+ if (arg == 0)
+ return -EINVAL;
+ val = 2;
break;
default:
- break;
+ /* sunxi_pconf_reg should catch anything unsupported */
+ WARN_ON(1);
+ return -ENOTSUPP;
}
- /* cache the config value */
- g->config = configs[i];
- } /* for each config */
- spin_unlock_irqrestore(&pctl->lock, flags);
+ spin_lock_irqsave(&pctl->lock, flags);
+ reg = readl(pctl->membase + offset);
+ reg &= ~(mask << shift);
+ writel(reg | val << shift, pctl->membase + offset);
+ spin_unlock_irqrestore(&pctl->lock, flags);
+ } /* for each config */
return 0;
}
static const struct pinconf_ops sunxi_pconf_ops = {
+ .is_generic = true,
+ .pin_config_get = sunxi_pconf_get,
.pin_config_group_get = sunxi_pconf_group_get,
.pin_config_group_set = sunxi_pconf_group_set,
};
@@ -870,6 +1123,91 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
return 0;
}
+static int sunxi_pinctrl_get_debounce_div(struct clk *clk, int freq, int *diff)
+{
+ unsigned long clock = clk_get_rate(clk);
+ unsigned int best_diff, best_div;
+ int i;
+
+ best_diff = abs(freq - clock);
+ best_div = 0;
+
+ for (i = 1; i < 8; i++) {
+ int cur_diff = abs(freq - (clock >> i));
+
+ if (cur_diff < best_diff) {
+ best_diff = cur_diff;
+ best_div = i;
+ }
+ }
+
+ *diff = best_diff;
+ return best_div;
+}
+
+static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
+ struct device_node *node)
+{
+ unsigned int hosc_diff, losc_diff;
+ unsigned int hosc_div, losc_div;
+ struct clk *hosc, *losc;
+ u8 div, src;
+ int i, ret;
+
+ /* Deal with old DTs that didn't have the oscillators */
+ if (of_count_phandle_with_args(node, "clocks", "#clock-cells") != 3)
+ return 0;
+
+ /* If we don't have any setup, bail out */
+ if (!of_find_property(node, "input-debounce", NULL))
+ return 0;
+
+ losc = devm_clk_get(pctl->dev, "losc");
+ if (IS_ERR(losc))
+ return PTR_ERR(losc);
+
+ hosc = devm_clk_get(pctl->dev, "hosc");
+ if (IS_ERR(hosc))
+ return PTR_ERR(hosc);
+
+ for (i = 0; i < pctl->desc->irq_banks; i++) {
+ unsigned long debounce_freq;
+ u32 debounce;
+
+ ret = of_property_read_u32_index(node, "input-debounce",
+ i, &debounce);
+ if (ret)
+ return ret;
+
+ if (!debounce)
+ continue;
+
+ debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC, debounce);
+ losc_div = sunxi_pinctrl_get_debounce_div(losc,
+ debounce_freq,
+ &losc_diff);
+
+ hosc_div = sunxi_pinctrl_get_debounce_div(hosc,
+ debounce_freq,
+ &hosc_diff);
+
+ if (hosc_diff < losc_diff) {
+ div = hosc_div;
+ src = 1;
+ } else {
+ div = losc_div;
+ src = 0;
+ }
+
+ writel(src | div << 4,
+ pctl->membase +
+ sunxi_irq_debounce_reg_from_bank(i,
+ pctl->desc->irq_bank_base));
+ }
+
+ return 0;
+}
+
int sunxi_pinctrl_init(struct platform_device *pdev,
const struct sunxi_pinctrl_desc *desc)
{
@@ -1032,6 +1370,8 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
pctl);
}
+ sunxi_pinctrl_setup_debounce(pctl, node);
+
dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
return 0;
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index 0afce1ab12d0..f78a44a03189 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -69,6 +69,8 @@
#define IRQ_STATUS_IRQ_BITS 1
#define IRQ_STATUS_IRQ_MASK ((1 << IRQ_STATUS_IRQ_BITS) - 1)
+#define IRQ_DEBOUNCE_REG 0x218
+
#define IRQ_MEM_SIZE 0x20
#define IRQ_EDGE_RISING 0x00
@@ -109,7 +111,6 @@ struct sunxi_pinctrl_function {
struct sunxi_pinctrl_group {
const char *name;
- unsigned long config;
unsigned pin;
};
@@ -266,6 +267,11 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
return irq_num * IRQ_CTRL_IRQ_BITS;
}
+static inline u32 sunxi_irq_debounce_reg_from_bank(u8 bank, unsigned bank_base)
+{
+ return IRQ_DEBOUNCE_REG + (bank_base + bank) * IRQ_MEM_SIZE;
+}
+
static inline u32 sunxi_irq_status_reg_from_bank(u8 bank, unsigned bank_base)
{
return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE;